Compare commits

...

No commits in common. "da35228277439b05d4844d94b75c7457d7f3a121" and "685136ce8aefb2ca8f97bc82e6ac5efb659befce" have entirely different histories.

161 changed files with 10756 additions and 1 deletions

5
.gitignore vendored Executable file
View File

@ -0,0 +1,5 @@
*.json
!settings.json
!TestPlugin.json
**/*.pro.user
push.sh

73
Commerical-LICENSE Normal file
View File

@ -0,0 +1,73 @@
WingSummer Commercial License
Last Updated: June 11, 2022.
COMMERCIAL SOFTWARE LICENSE AGREEMENT
PLEASE READ THE FOLLOWING TERMS AND CONDITIONS CAREFULLY BEFORE DOWNLOADING, INSTALLING OR USING THE SOFTWARE THAT ACCOMPANIES THIS SOFTWARE LICENSE AGREEMENT OR ANY ACCOMPANYING DOCUMENTATION (COLLECTIVELY, AND INCLUDING ANY UPDATES THERETO PROVIDED BY WINGSUMMER, THE “SOFTWARE”).
THE TERMS AND CONDITIONS OF THIS SOFTWARE LICENSE AGREEMENT AND THE ORDER FOR THE SOFTWARE THAT YOU AGREED TO (“ORDER”) AND, [COLLECTIVELY WITH THE ORDER AND] THIS SOFTWARE LICENSE AGREEMENT, THIS “AGREEMENT”) ARE AN AGREEMENT BETWEEN YOU AND WINGSUMMER AND GOVERN USE OF THE SOFTWARE, UNLESS YOU AND WINGSUMMER HAVE EXECUTED A SEPARATE WRITTEN AGREEMENT GOVERNING USE OF THE SOFTWARE.
WingSummer is willing to license the Software to you only upon the condition that you accept all the terms contained in this Agreement. By downloading, installing or using the Software, you have indicated that you understand this Agreement and accept all of its terms. If you are accepting the terms of this Agreement on behalf of a company or other legal entity, you represent and warrant that you have the authority to bind that company or other legal entity to the terms of this Agreement, and, in such event, “you” and “your” will refer to that company or other legal entity. If you do not accept all of the terms of this Agreement, then WingSummer is unwilling to license the Software to you, and you must return the Software to WingSummer or destroy all copies of the Software.
1. License.
1.1 License Grant. Subject to your compliance with the terms and conditions of this Agreement (including payment of the applicable fees in accordance with Section 3), WingSummer grants to you a non-exclusive, non-transferable, non-sublicenseable, worldwide limited license to (a) use the software products internally, in executable code form, and related Documentation (as defined in Section 6.1), as specified in the Order, including any error corrections, modifications and updates thereto provided by WingSummer to you under this Agreement (the “Software”), but only in the Licensed Configuration and only during the term of this Agreement and (b) copy and adapt the Software as provided herein. For purposes of this Agreement, “Licensed Configuration” means the features and usage limits for a specified time period, in each case, as specified in the Order. Your use of the Software is further limited according to the license type and other terms in the Order. You may copy the Software, as reasonably required to exercise your rights under this Section 1.1, and you may make a reasonable number of copies for backup or archival purposes.
1.2 Benefit of Third Parties. If the Order specifies a Right to Embed the Software for the benefit of end users, then the license in Section 1.1 shall be modified to allow you to operate the Software within a Customer Application (identified on the Order Form) and allow your end user customers (“End Users”) to access the Software as a part of the Customer Application.
1.3. Distribution License. If the Order specifies a Right to Distribute, then subject to your compliance with the terms and conditions of this Agreement (including payment of the applicable fees in accordance with Section 3), WingSummer grants to you a non-exclusive, non-transferable, non-sublicenseable, worldwide limited license to distribute the Software to End Users (i) as embedded in the Customer Application identified in the Order Form, (ii) solely for use by the end users of the Customer Application and not for further distribution and (iii) provided the End User executes an end user license agreement that protects WingSummer to the same extent this Agreement protects WingSummer (“End User License Agreement”).
1.4. Source Code Access; Modifications. Solely if your license type and pricing tier, as specified in the Order, includes access to the source code of the Software, subject to your compliance with the terms and conditions of this Agreement (including payment of the applicable fees in accordance with Section 3), WingSummer grants to you a non-exclusive, non-transferable, worldwide limited license to (i) use, reproduce, modify and create derivative works based upon the Software, solely for the purpose of customizing the Software to interface, embed, combine, or otherwise use with your products or services (as distributed to your customers). Notwithstanding anything to the contrary, you agree that you have the right to use any and all modifications, customizations, enhancements and extensions to the Software to the same extent, and solely to such extent, that you have the right to use the Software pursuant to this Agreement and your valid subscription. In addition, WingSummer prohibits you from modifying, and you agree not to modify, the Software (a) to enable features not available to customers at your license type and pricing tier by contacting me; or (b) to disable usage limits.
1.5. Limited Rights; License Restrictions. Your rights in the Software will be limited to those expressly granted in this Agreement. WingSummer reserves all rights and licenses in and to the Software not expressly granted to you under this Agreement. Except as expressly provided in this Agreement, you will not: (i) copy or modify the Software, in whole or in part; (ii) transfer, sublicense, lease, lend or rent or otherwise distribute the Software to any third party; (iii) make the functionality of the Software available to third-party users through any means; or (iv) disassemble, decompile or reverse engineer the Software or permit or authorize a third party to do so, except to the extent such restrictions are expressly prohibited by law.
1.6. Ownership. You expressly acknowledge that, as between WingSummer and you, WingSummer and its licensors own all worldwide right, title and interest in and to the Software, including all worldwide patent rights, copyrights, trade secrets, know-how and any other intellectual property rights embodied therein. You will not delete or in any manner alter the copyright, trademark or other proprietary rights notices appearing on the Software as delivered to you. You will reproduce such notices on all copies you make of the Software. Subject to Section 1.4, you will own your modifications to the Software (“Modifications”); provided that your ownership thereof will be subject to WingSummerss underlying intellectual property rights in the Software. At your option, you may submit your Modifications to the WingSummer open source project. In addition, you own all worldwide right, title and interest in and to all your data that is processed by the Software and the analyses that are generated by the Software based on such data.
1.7. Verification and Audit. At WingSummers written request, you will furnish WingSummer with an officers written certification verifying that the Software is being used in accordance with the terms of this Agreement. Upon at least thirty (30) days prior written notice, WingSummer may audit your use of the Software to ensure that you are in compliance with the terms of this Agreement, provided that no audit may take longer than 30 days to complete, and further provided that all individuals involved in the audit must sign a non-disclosure agreement consistent with Section 5, make no copies of documents, remove no materials from your premises, and agree to comply with all of your reasonable rules, policies and instructions that apply to persons accessing your premises or systems . If an audit reveals that you have underpaid fees to WingSummer during the period audited, then you will promptly pay WingSummer for such underpaid fees based on WingSummers price list in effect at the time the audit is completed.
2. Obligations and Support.
2.1 Customer Support by WingSummer. Subject to your compliance with the terms and conditions of this Agreement (including payment of the applicable fees in accordance with Section 3), WingSummer will make available to you at no additional cost WingSummers standard support for the license type and pricing tier specified in the Order in accordance with WingSummers then-standard support terms. WingSummer reserves the right to designate any additional new content or features as requiring separate payment or purchase of a separate subscription at any time. If you have entered into a separate support or similar agreement with WingSummer, then WingSummer will provide Software maintenance and support in accordance with the terms of that agreement, not this Agreement. For the avoidance of doubt, WingSummer shall have no obligation to provide support to End Users or any users of the Customer Application.
2.2 Customer Obligations. Customer shall make no representations or warranties with respect to the Software or any related services beyond those contained herein. Customer shall be solely responsible for, and WingSummer shall have no legal obligation to honor, any warranties that Customer provides to End Users to the extent that such warranties are broader or greater in scope than those made by WingSummer to Customer hereunder. Customer shall defend, indemnify and hold WingSummer and its affiliated companies harmless from any and all costs, losses, damages, liabilities and expenses (including reasonable attorneys fees and costs of litigation) resulting from Customers failure to comply with this Section.
3. Payment.
3.1 Subscription Fees. You will pay the fees and charges stated in the Order (“Subscription Fees”) for use of the Software. The base Subscription Fee for each Subscription Term (as defined in Section 4) will be specified in the Order (“Base Subscription Fee”) and is payable and charged at the beginning of each Subscription Term.
3.2 Units; True-Up. If specified in the Order, Subscription Fees will be calculated based on units of use of the Software (such as per server, per installation, per customer or per user) (each, a “Unit”). Where applicable, the Base Subscription Fee includes the number of Units specified in the Order for each Subscription Term. At the end of each Subscription Term, you will promptly confirm in writing to WingSummer (at the latest within five (5) business days of a request from WingSummer) the number of Units used by you during that Subscription Term. If your actual usage of the Software exceeds the Units covered by the Base Subscription Fee prepaid by you for a Subscription Term, WingSummer will charge you for the difference between the Units covered by the Base Subscription Fee and the number of Units actually used by you during that Subscription Term (“Additional Units Fee”).
3.3 Payment Terms. Because it is my own project,and is not the project of any company,only Wechat payment and Alipay payment are allowed.The payment QR codes are shown in the WingHexExplorer's code repository ,and I'm very sorry I can not issue an invoice to you.All amounts are stated and shall be paid in yuan and are exclusive of taxes. You are responsible for payment of all Taxes and any related interest and/or penalties resulting from any payments made to us, other than any taxes based on WingSummers net income. Except as specifically outlined in Section 4 and Section 7.3, all fees are non-refundable.
4. Term and Termination.
This Agreement will commence on the Effective Date and, unless terminated earlier in accordance with the terms of this Section 4, will continue in effect for the initial subscription term specified in the Order. At the end of such initial subscription term and each renewal subscription term thereafter, subject always to timely payment of the Subscription Fees, this Agreement will automatically renew for additional renewal subscription terms having the duration specified in the Order (or if no renewal term length is stated in the Order, having the same duration as the Initial Subscription Term), unless either party provides at least 30 days prior written notice of non-renewal. Such initial subscription term and each renewal subscription term are each individually referred to herein as a “Subscription Term.” Each party will have the right to terminate this Agreement if the other party breaches this Agreement and fails to cure such breach within 10 days after written notice thereof, provided that, for breaches that cannot be cured using reasonable efforts within 10 days, then up to an additional 20 days to cure. Notwithstanding the foregoing, if you fail to pay the applicable fees as specified in the Order and this Agreement, and that failure persists for 5 days after written notice, your license to the Software ends automatically. You acknowledge that upon expiration or termination of this Agreement, the Software and any license key may automatically de-activate and you may no longer be able to access and use the Software. Upon termination: (1), you must, at WingSummers option, either promptly destroy or return to WingSummer all copies of the Software and any WingSummer Confidential Information in your possession or control, provided that, upon agreeing to pay 25% of the prior years fee, we will allow you and your customers to continue to use the WingSummer Software for an additional three months; and (2) you shall not be entitled to a refund of any pre-paid fees, except that you will be entitled to a refund of pre-paid fees if this Agreement is terminated by you for our breach and as provided in Section 7.3. Sections 4, 5, 6.3, 8, 9 and 10 will survive any expiration or termination of the Agreement. Upon termination of this Agreement for any reason, the rights granted in Section 1.1 and 1.2 and 1.3 shall immediately terminate and you must ensure that your End Users delete the Customer Application.
5. Confidentiality.
Continuing until 5 years after the expiration or termination of this Agreement, each party (as such, a “recipient”) agrees to keep all information, documents and data received from the other party (as such, a “discloser”), which are marked as or which would reasonably be considered to be confidential (“Confidential Information”) as strictly confidential and to use such information only as follows: (i) with respect to WingSummer Confidential Information, within the scope of the licenses granted to you, and (ii) with respect to your Confidential Information, only as needed to provide you with the Software and services contemplated by this Agreement. The Software and its pricing are WingSummers Confidential Information. Notwithstanding the foregoing, “Confidential Information” shall not include any information, proven by documentation, which: (i) becomes generally available to the public other than as a result of a disclosure by the recipient; (ii) was available to the recipient on a non-confidential basis prior to its disclosure by the discloser; (iii) becomes available to the recipient on a non-confidential basis from a source other than the discloser, provided that such source is not known by the recipient to be bound by any duty to the discloser or another entity, to keep such information confidential; or (iv) is independently developed by the recipient, without use of the disclosers Confidential Information.
6. Warranties.
6.1. Limited Software Warranty WingSummer warrants that, for thirty (30) days following the Effective Date, the Software will perform in all material respects in accordance with the standard user documentation for the Software that WingSummer makes generally available to its customers (“Documentation”). As your sole and exclusive remedy and WingSummers entire liability for any breach of this limited warranty, WingSummer will at its option and expense promptly correct or replace the Software so that it conforms to this limited warranty. WingSummer does not warrant that the Software will meet your requirements, that the Software will operate in the combinations that you may select, that the operation of the Software will be error-free or uninterrupted, or that all Software errors will be corrected. The limited warranty set forth in this Section 6.1 does not apply to the extent that WingSummer provides you with the Software (or portions of the Software) for beta, evaluation, testing, or demonstration purposes.
6.2. No Excluded Licenses The Software and Documentation do not incorporate, combine with, or use software or materials distributed under an Excluded License (“Open Source Materials”). “Excluded License” means a license that requires, as a condition of use, modification, and/or distribution of such Open Source Materials that other software incorporated into, derived from, or distributed with such Open Source Materials be (i) disclosed or distributed in source code form, (ii) licensed for the purpose of making derivative works, or (iii) redistributedable at no charge.
6.3. Disclaimer EXCEPT AS EXPRESSLY SET FORTH ABOVE, THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND. WINGSUMMER DISCLAIMS ALL OTHER WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT, AND ANY WARRANTIES ARISING OUT OF COURSE OF DEALING OR USAGE OF TRADE. NO ADVICE OR INFORMATION, WHETHER ORAL OR WRITTEN, OBTAINED FROM WINGSUMMER OR ELSEWHERE WILL CREATE ANY WARRANTY NOT EXPRESSLY STATED IN THIS AGREEMENT.
7. Indemnification.
7.1 WingSummer Indemnity. WingSummer will defend, indemnify and hold you harmless from and against any damages, costs and expenses (including reasonable attorneys fees and other professional fees) awarded against you in a final non-appealable judgment or that are agreed to in settlement, to the extent based on a third-party claim that the Software, as provided by WingSummer to you, infringes any patent, copyright or misappropriates any trade secret of any third party; provided that you: (a) promptly notify WingSummer in writing of any such claim; (b) grant WingSummer sole control of the defense and settlement of the claim; and (c) provide WingSummer, at WingSummers expense, with all assistance, information and authority reasonably required for the defense and settlement of the claim. You have the right to retain counsel, at your expense, to participate in the defense or settlement of any claim. WingSummer will not be liable for any settlement or compromise that you enter into without WingSummers prior written consent.
7.2 Exclusions. WingSummers obligation to indemnify you pursuant to Section 7.1 will not apply to the extent any claim results from or is based on: (i) any combination, operation or use of the Software with any product, system, device, method or data not provided by WingSummer, if such claim would have been avoided but for such combination, operation or use; (ii) modification of the Software by anyone other than WingSummer, if a claim would have been avoided but for such modification; (iii) your failure to install and use any upgrades to the Software furnished by WingSummer, if such claim could have been avoided by such installation and use of such upgrades; or (iv) use of the Software other than in accordance with this Agreement. You will indemnify, defend and hold WingSummer harmless and will pay any costs damages and reasonable attorneys fees in connection with any third party claim to the extent it results from any of the foregoing activities in this Section 7.2, provided that WingSummer (a) promptly notifies you in writing of any such claim; (b) grants you sole control of the defense and settlement of the claim; and (c) provides you, at your expense, with all assistance, information and authority reasonably required for the defense and settlement of the claim.
7.3 Injunction. If your use of the Software is, or in WingSummers opinion is likely to be, enjoined due to the type of claim specified in Section 7.1, then WingSummer will at its sole option and expense: procure for you the right to continue using the Software under the terms of this Agreement; (ii) replace or modify the Software to make it non-infringing and of equivalent functionality; or (iii) if WingSummer is unable to accomplish either (i) or despite using its reasonable efforts, then WingSummer may terminate your rights and WingSummers obligation under this Agreement with respect to such Software and refund to you a pro-rata portion of the prepaid license fees you paid for such Software.
7.4 Customer Indemnity. In the event Customer has rights granted under Sections 1.2 and 1.3 herein, Customer agrees to defend and indemnify WingSummer, at Customers expense, against any legal action brought against WingSummer by a third party to the extent that it is based on a claim that Customer Application or any software, hardware, materials or technology therein (except for Software), or the combination of the Software with any other software, hardware, materials or technology used by Customer as part of the applicable Customer Application, infringes a patent, copyright or trademark of such third party or makes unlawful use of such partys trade secret, and Customer shall pay any settlement of such claim or final judgment against WingSummer in any such action if attributable to any such claim. However, such defense and payments are subject to the conditions that WingSummer must: (i) notify Customer promptly in writing of such claim, (ii) permit Customer to have sole control of the defense, compromise or settlement of such claim, including any appeals, and (iii) fully cooperate with Customer, at Customers expense, in the defense or settlement of such claim.
7.5 Sole Remedy. THIS SECTION 7 SETS FORTH WINGSUMMERS SOLE AND EXCLUSIVE OBLIGATIONS, AND YOUR SOLE AND EXCLUSIVE REMEDIES, WITH RESPECT TO INFRINGEMENT OR MISAPPROPRIATION OF INTELLECTUAL PROPERTY RIGHTS OF ANY KIND.
8. Limitation of Liability.
IN NO EVENT WILL EITHER PARTY BE LIABLE FOR ANY SPECIAL, INCIDENTAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL DAMAGES, OR FOR ANY LOSS OF USE, LOSS OF DATA, LOSS OF PROFITS OR LOSS OF GOODWILL, OR THE COSTS OF PROCURING SUBSTITUTE PRODUCTS, WHETHER OR NOT FORESEEABLE, ARISING OUT OF OR IN CONNECTION WITH THIS AGREEMENT OR THE USE, OPERATION OR PERFORMANCE OF THE SOFTWARE, WHETHER SUCH LIABILITY ARISES FROM ANY CLAIM BASED UPON CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCT LIABILITY OR OTHERWISE, AND WHETHER OR NOT WINGSUMMER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGE. EACH PARTYS TOTAL AGGREGATE LIABILITY ARISING UNDER THIS AGREEMENT, FROM ALL CAUSES OF ACTION AND ALL THEORIES OF LIABILITY, WILL NOT EXCEED THE AMOUNTS PAID TO WINGSUMMER BY YOU FOR THE SPECIFIC SOFTWARE GIVING RISE TO A CLAIM FOR LIABILITY HEREUNDER DURING THE 12 MONTH PERIOD PRIOR TO THE FIRST CLAIM, PROVIDED THAT THIS SHALL NOT RELEASE YOU FROM PAYING ALL FEES AND CHARGES DUE HEREUNDER. The parties agree that the limitations and exclusions contained in this Section 8 and elsewhere in this Agreement will (a) not apply to any claims under indemnity and (b) survive and apply even if any exclusive remedy specified in this Agreement is found to have failed of its essential purpose.
9. Feedback; Modifications.
If you make any Modifications or provide any ideas, suggestions, or recommendations regarding the Software (“Feedback,” which term does not include Modifications), WingSummer will be free to use, disclose, reproduce, license or otherwise distribute, and exploit such Feedback as it sees fit, entirely without obligation or restriction of any kind; but shall not be free to use your Modifications (or any of your other intellectual property) without an express written license or grant of rights by you. By providing Feedback, you grant WingSummer a worldwide, perpetual, irrevocable, sublicenseable, fully-paid and royalty-free license to use and exploit in any manner such Feedback.
10. General.
This Agreement will be governed by and construed in accordance with the laws of China, without regard to or application of conflict of laws rules or principles. Any legal action or proceeding arising under this Agreement will be brought exclusively in courts located in China and each party irrevocably consents to the personal jurisdiction thereof and venue therein. You may not assign or transfer this Agreement or any rights granted hereunder, by operation of law or otherwise, without WingSummers prior written consent, and any attempt by you to do so, without such consent, will be void. WingSummer may freely assign this Agreement. Except as expressly set forth in this Agreement, the exercise by either party of any of its remedies under this Agreement will be without prejudice to its other remedies under this Agreement or otherwise. All notices or approvals required or permitted under this Agreement will be in writing and delivered by confirmed email transmission, by overnight delivery service, or by certified mail, and in each instance will be deemed given upon receipt. All notices or approvals will be sent to the addresses set forth in the Order or to such other address as may be specified by either party to the other in accordance with this Section. The failure by either party to enforce any provision of this Agreement will not constitute a waiver of future enforcement of that or any other provision. Any waiver, modification or amendment of any provision of this Agreement will be effective only if in writing and signed by authorized representatives of both parties. If any provision of this Agreement is held to be unenforceable or invalid, that provision will be enforced to the maximum extent possible, and the other provisions will remain in full force and effect. This Agreement is the complete and exclusive understanding and agreement between the parties regarding its subject matter, and supersedes all proposals, understandings or communications between the parties, oral or written, regarding its subject matter. This Agreement may be executed in counterparts, each of which will be deemed an original, but all of which together will constitute one and the same instrument.
11. Contact Information.
If you have any questions regarding this Agreement, you may contact WingSummer on Gitee or by the email wing-summer@qq.com .

7
LICENSE Normal file
View File

@ -0,0 +1,7 @@
Source code in this repository is variously licensed under the WingSummer OpenSource Lincense (OpenSource-LICENSE), or the WingHexExplorer Commercial License (Commerical-LICENSE).
本仓库的源代码采用多协议的授权模式: “羽夏开源协议” 和 “羽夏商业协议”,它们分别在 OpenSource-LICENSE 和 Commerical-LICENSE 有详细的说明。
When built, binary files are generated for the AGPL source code. Binaries located at my Gitee or Github repository and the spark store are released under the AGPL.
当你编译代码时,二进制文件遵守 “羽夏开源协议”。在我的 Gitee 或 Github 和星火商店发布的二进制都遵守 “羽夏开源协议”。

160
OpenSource-LICENSE Normal file
View File

@ -0,0 +1,160 @@
WingSummer OpenSource Lincense
Version 1,13 June 2022
Copyright (c) WingSummer
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
TERMS AND CONDITIONS
0. Definitions.
“This License” refers to WingSummer OpenSource Lincense.
“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.
To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.
A “covered work” means either the unmodified Program or a work based on the Program.
To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
1. Source Code.
The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.
A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program, subject to section 13. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
Subject to section 13, you may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
4. Conveying Verbatim Copies.
You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may not charge any price for each copy that you convey, but you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also only can convey the machine-readable Corresponding Source under the terms of this License free of charge.
A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
7. Additional Terms.
“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work for ANY COMMERICAL PURPOSE except as expressly provided under this License. Any attempt otherwise to propagate or modify FOR COMMERICAL PURPOSE it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
In other words,you can fork my repository and propagate or modify it for NON-COMMERICAL USE freely.It doesn't mean you can not make a profit from it for anyway.Any INCOME from any donation to maintain an open source code repository is allowed.
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
11. Patents.
A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”.
A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 30 May 2022.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 use, propagate or convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not use, propagate or convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
13. Offering the Program as a Service.
If you make the functionality of the Program or a modified version available to third parties as a service, you must make the Service Source Code available via network download to everyone at no charge, under the terms of this License. Making the functionality of the Program or modified version available to third parties as a service includes, without limitation, enabling third parties to interact with the functionality of the Program or modified version remotely through a computer network, offering a service the value of which entirely or primarily derives from the value of the Program or modified version, or offering a service that accomplishes for users the primary purpose of the Program or modified version.
14. Revised Versions of this License.
WingSummer may publish revised and/or new versions of the WingSummer OpenSource Lincense 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 that a certain numbered version of the WingSummer OpenSource Lincense “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by WingSummer. If the Program does not specify a version number of the WingSummer OpenSource Lincense, you may choose any version ever published by MongoDB, Inc.
If the Program specifies that a proxy can decide which future versions of the Server Side Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
15. Disclaimer of Warranty.
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.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS

195
README.md
View File

@ -1,2 +1,195 @@
# WingSummer_WingHexExplorer
<h1 align="center"> WingSummer.WingHexExplorer</h1>
<p align="center">
<img alt="PEHexExplorer" src="WingHexExplorer/images/icon.png">
<p align="center">羽云十六进制浏览器</p>
</p>
<p align="center">
<img alt="作者" src="authorband.svg">
<img alt="开源协议" src="olband.svg">
<img alt="商用协议" src="clband.svg">
</p>
* 开源不易,给个 [Star](https://gitee.com/wingsummer/be.-windows.-forms.-hex-box/star) 或者 [捐助](#捐助) 吧
## 鸣谢
&emsp;&emsp;在此之前鸣谢大家的支持和帮助,如下是参与贡献和进行打赏捐助的同志:
|昵称|方式|备注|
|:--:|:--:|:--:|
|神末shenmo|打赏捐助|Deepin 论坛|
|lv36|打赏捐助|Deepin 论坛|
## WingHexExplorer
&emsp;&emsp;本软件是基于 QT 编写的十六进制编辑器,采用 C++ 进行开发,目的是让 Deepin 上具有强大而免费的十六进制编辑器。目前只有 010 Editor 具有强大的十六进制编辑功能,但它是商用的。关注我开发动态的应该知道我开发了在 Windows 上用 C# 开发的`WingSummer.WingCloudHexExplorer`,目的是方便专业人士修改分析 PE 文件,并可作为学习 PE 结构的重要辅助工具。该项目具有 31 个 Star 和 9 个 Fork ,我也不打算维护了,因为我主力系统不是 Windows ,也没有充分的资金支持,全是本人的一腔热血和一厢情愿。没有任何人参与该仓库任何形式的贡献,这或许就是在中国个人搞开源的现状吧。
&emsp;&emsp;本项目从 2022/5/30 开始筹备,直到今天 2022/6/8 第一个开源可用的版本终于完成了但还是有很多需要待完善的地方。2022/6/10 竣工了,插件系统已完全完成,测试了驱动器打开测试,虽然有点卡(我的测试是打开 600GB 的分区,虽然不到 1S ,但肉眼可见的短暂性卡顿)。
&emsp;&emsp;最近几天我大概率没多少时间维护该项目,希望大家指出要改进的地方的同时,最好贡献一下代码或者给出参考示例,以便我快速完善。要不然你提出一个看似简单的功能,其实需要大量的代码进行实现,这或许是“产品经理”和“程序员”之间的矛盾所在。提建议的时候不要天马行空,注意本软件只提供最基本的十六进制编辑和浏览服务,比如 010 Editor 里面的模版和脚本等服务,还需大家一起通过插件来实现(插件系统还没有完全完成,只是能用)!希望大家不要只提需求,更要提出建设性建议和解决方案,共同维护开源社区。具体详情将会在后面进行介绍。
### 软件架构
* TestPlugin : 虽然名字表面意思是测试插件,但它是编写该软件支持的插件一个非常重要的教程,重要性不可忽略。
* WingHexExplorer : 主程序,具有最基本的编辑十六进制编辑的能力,支持强大的插件系统,提供 GUI 交互。
* QHexView : 本软件十六进制编辑器的基础组件,仓库维护者`Dax89`,具体详情将在后面介绍。
* QHexEdit2 : 本软件打开超大文件模块相关代码,原打算使用该组件作为基础组件,但 Bug 多的我改不过来了,故弃用,保留了我所需关键代码,仓库维护者`Simsys`,具体详情将在后面介绍。
### 使用声明
1. 开发本软件目的是让 Deepin 上具有强大而免费的十六进制编辑器,同时也便于本人巩固或者学习 QT Linux 相关编程的知识。
2. 本软件仅供学习交流使用,不得私自用于商业用途。如需将本软件某些部分用于商业用途,必须找我购买商业授权,价格私聊。
3. 本人学生,由于本软件是用我的业余时间编写,不能及时修复 Bug 或者提供技术支持,请见谅。
4. 本人非计算机专业,编写程序难免有 Bug ,欢迎提交 PR 。
### 参与贡献
1. 如果您有想参与本软件代码开发递交,请在 pull request 联系我。
2. 本项目支持捐助,如有意愿请到本仓库通过微信或者支付宝的方式进行,一瓶水的价钱足以提高我的维护该项目的热情,感谢大家的支持。
3. 如果您想提交修复或者增进程序的代码,请在 pull request 递交。
4. 任何成功参与代码 Bug 修复以及增进程序功能的同志和 Sponsor ,都会在本仓库 ReadMe 和附属说明文件中体现,您如果是其中之一,本人可以按照您合理的意愿来进行说明。
**加入我们并不意味着就是代码的维护,你可以选择下列一项或多项进行参与:**
1. 代码维护:实现新功能或修复 BUG ,对代码进行维护和升级。
2. 文档编辑:主要是接口文档和教程需要撰写编辑,这很重要。
3. 参与讨论:主要是讨论本项目未来发展和方向等。
4. 编写插件:一起增强该软件的功能。
### 协议
&emsp;&emsp;本软件如果用于非商业用途,采用`WingSummer OpenSource Lincense`协议,对应的协议内容在仓库`OpenSource-LICENSE`文件。 **没有我的任何授权,不得将该软件用于任何形式的商业用途,包括我改良的部分,除非你直接使用原组件,不限于商业二次开发、换 UI 套壳、二手转卖等,我不允许任何人随意把我当作免费劳动力作为赚钱的工具!** 我的初衷是让 Linux 的生态更加完整,早日让祖国推动操作系统国产化。我不希望“吸血鬼”们利益归自己,脏活累活给开源,都那么理所当然,开源就是这么被败坏的。我不希望因为版权的事情牵扯了大量的精力。本人初次深入接触开源协议,不太会根据自己真正的需要来选择合适的协议,感谢`Deepin`前辈`BLumia`给我提供相关的建议和指导。由于本人一直在`README`一直强调商业用途相关事宜,本开源协议和我强调的内容相一致,故适用于目前所有本仓库的代码及其`fork`分支以及所有发行版。
&emsp;&emsp;如果你想将本软件或者本软件的部分代码用于商业用途,必须亲自咨询我,商讨商业授权相关事宜。如果得到授权则采用`WingSummer Commerical License`协议,也就是本仓库的`Commerical-LICENSE`文件的内容。
### issue 前必读
&emsp;&emsp;如果你有任何形式的建议,在提交 issue 之前,请一定要阅读下面的声明,以免浪费我们双方宝贵的时间:
1. 本人不考虑兼容 Windows 系统,虽然 QT 是跨平台的,但有些代码是依赖特定平台的,且十六进制编辑组件在 Windows 上会有一些已知问题,本人没有时间也没有义务来搞跨平台的东西。
2. 本人不考虑多语言支持,主要是没时间和资金。由于本人是中国人,本人不考虑其他语言使用者。但如果使用其他语言,如果你有语言包,只需要简单的替换文件即可。
3. 本人不考虑二进制安装包的分发,没时间和精力搞额外的东西。
4. 本人不考虑其他插件的开发,如果插件有使用问题,请联系开发者(不排除我会开发一些插件,这样可以直接联系我)。
5. 本人不考虑主题 UI 层面的问题,开发软件一切采用 DTK 原生样式,觉得丑找官方,或者自己写个样式编译加载。
6. 图标在暗黑模式下可能会有点丑不太明显我美工不好希望有同志能够提供一套图标不要有版权纷争的图标PR 给我进行审核采纳。但如果你没有,就不要给我提。
7. 本人仅仅考虑适配 Deepin 系统,虽然 Deepin 是目前基于 Debian ,基本所有的 Debian 甚至其他 Linux 系统理论上也可以用,但不排除有问题,如果出问题,我也不会进行修复。
&emsp;&emsp;上面一切的一切,如果你是志同道合的开源贡献者,欢迎 fork 我的仓库进行相应的维护!
&emsp;&emsp;如果出现比较严重的 Bug ,本人也可能不会及时的响应,目前我面临大学毕业的难题,顶着未来未知的压力和艰难的就业和研究生大军现状,谢绝站在道德的制高点不嫌冷的指指点点。
### 有关 QHexView
&emsp;&emsp;本软件基于`QHexView`作为十六进制编辑器为基础进行开发,本人在改组件基础上添加新功能和进行代码的深度定制。如下是原仓库的必要说明,详情请点击 [此链接](https://github.com/Dax89/QHexView/tree/master)
---
QHexView
========
QHexView is a hexadecimal widget for Qt5
Features
-----
- Customizable data backend (see more below).
- Document/View based.
- Unlimited Undo/Redo.
- Fully Customizable.
- Fast rendering.
- Easy to Use.
Buffer Backends
-----
These are the available buffer backends:
- QMemoryBuffer: A simple, flat memory array.
- QMemoryRefBuffer: QHexView just display the referenced data, editing is disabled.
It's also possible to create new data backends from scratch.
License
-----
QHexEdit is released under MIT license
---
&emsp;&emsp;本人对改组件的改进如下:
1. 增加有关描述文件状态相关的功能:指示是否被修改、是否具有可写权限、是否锁定文件以防修改、是否可以增改字节数
2. 增加可隐藏地址蓝栏和 ASCII 解码字符栏以及表头的功能
3. 实现超大文件超出2GB读写功能模块原组件并未实现此功能
4. 修改地址显示长度,以适应地址的使用习惯
5. 简化编码方式,删除一些冗余代码
6. 增加更多的信号,充分控制 QHexView 组件
7. 增加书签使用和管理功能
8. 修复滚动条有关内容完全仍能够显示但仍滚动内容的 Bug
9. 修复粘贴指针闪动位置保持不变问题,修改粘贴限制策略
### 有关 QHexEdit2
&emsp;&emsp;起初我打算使用`QHexEdit2`作为十六进制编辑器为基础进行开发,该组件虽然轻松打开超大文件,但是它的编辑功能能用是能用,但有很多大大小小的 Bug ,我还逐一修了修,但发现仅仅我的力量和时间是杯水车薪。然后我找到了`QHexView`,也就是上面所属的组件,但它有一个致命的缺陷,无法打开超大文件,被我 Pass 掉了,后来我尝试用了它,发现开发者在开发改组件是下了足够大的功夫的,编辑十分流畅。最近看到`QHexView`贡献者们想搞一个`QHexView 5.0`,对代码进行了重构,但并没有实现任何功能,差不多是个空空的框架,不过从接口看出更强大的易用性,这个是原组件所不具有的,这花费我比较多的时间来阅读源代码,并向外扩展接口以适应我的开发需求。
&emsp;&emsp;然后我想,既然`QHexEdit2`具有强大的打开文件的能力,而`QHexView`不具备,但它具有强大的编辑界面,于是乎,我移植`QHexEdit2`的打开超大文件的代码到`QHexView`当中,并做好了适配,但有一个 Bug :如果以大文件打开的方式来新建新文件,就无法插入新的字节,除非开头有一个字节。实际上,我们一般都是打开大文件,而不是新建一个超大文件来进行添加编辑(谁闲的没事干,手动打超过 2GB 字节的文件),所以我默认如果新建文件采用原组件原生模块,也就是无法存储超过`2GB`的。但如果你修复了改 Bug ,我会考虑支持新建超大文件这个选项。改仓库的链接: https://github.com/Simsys/qhexedit2 ,它的协议如下:
Copyright (C) 2015-2016 Winfried Simon
This software may be used under the terms of the GNU Lesser General
Public License version 2.1 as published by the Free Software Foundation
and appearing in the file license.txt included in the packaging of this file.
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 General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
## 效果图
<p align="center">
<img alt="效果图" src="screenshot.png">
<p align="center">羽云十六进制浏览器</p>
</p>
## 捐助
**<p align="center">您的每一份支持都将是本项目推进的强大动力,十分感谢您的支持</p>**
<p align="center">
<img alt="支付宝" src="WingHexExplorer/支付宝捐助.jpg" height=50% width=50%>
<p align="center">感谢支持</p>
</p>
<p align="center">
<img alt="微信" src="WingHexExplorer/微信捐助.png" height=50% width=50%>
<p align="center">感谢支持</p>
</p>
## 鸣谢
&emsp;&emsp;此程序的完成基本是我现学现卖,因为 QT 在此之前我虽然学过但几乎没有写过一个完整的项目。DTK 也是我新接触的但总的说来文档还是有点差劲一点都不全不过官方开源了文本编辑器的源码我对此对我感兴趣需要实现的代码进行了研读实现了我想要的功能在此感谢。如果没有该项目我无法独自完成这个项目。里面有一些地方会有深度文本编辑器的影子这在所难免因为这个是我学习在借鉴使用魔改形成的代码比如单例且传参的实现、DTK 设置对话框的使用以及国际化,跳转条的样式和代码结构。
## 其他下载方式
&emsp;&emsp;鉴于 Gitee 下载发行版必须登录注册这对于用户体验来说极差于是乎我给了个蓝奏云的之后所有的发行版本都会同步上传上去https://wwu.lanzoul.com/b021fkd5c -- 密码:ewtv 。
## 应用商店
&emsp;&emsp;目前我已把安装包投递到星火商店,欢迎大家下载安装:
<p align="center">
<img alt="星火商店" src="spark-store.png">
<p align="center">星火商店</p>
</p>
&emsp;&emsp;Spk分享链接spk://store/store/com.wingsummer.winghexexplorer

View File

@ -0,0 +1,3 @@
{
"Keys" : [ ]
}

View File

@ -0,0 +1,9 @@
SOURCES += \
testplugin.cpp
HEADERS += \
../WingHexExplorer/plugin/iwingplugin.h \
../WingHexExplorer/plugin/hexviewshadow.h\
testplugin.h
DISTFILES += TestPlugin.json
DEFINES += WINGPLUGIN

28
TestPlugin/TestPlugin.pro Normal file
View File

@ -0,0 +1,28 @@
#-------------------------------------------------
#
# Project created by QtCreator 2022-06-02T15:00:06
#
#-------------------------------------------------
QT += core gui
TARGET = TestPlugin
TEMPLATE = lib
CONFIG += plugin
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
include($$PWD/TestPlugin.pri)
HEADERS +=

94
TestPlugin/iwingplugin.h Normal file
View File

@ -0,0 +1,94 @@
#ifndef IWINGPLUGIN_H
#define IWINGPLUGIN_H
#include <QCryptographicHash>
#include <QDockWidget>
#include <QList>
#include <QMenu>
#include <QObject>
#include <QWidget>
enum WingPluginMessage {
PluginLoading,
PluginLoaded,
PluginUnLoading,
PluginUnLoaded,
ErrorMessage,
PluginCall
};
enum CallTableIndex {
NewFile,
OpenFile,
OpenFileGUI,
CloseFile,
SaveFile,
SaveAsFile,
ExportFile,
Undo,
Redo,
WriteFileBytes,
ReadFileBytes,
DeleteFileBytes,
FindFileBytes,
GotFileOffset,
GotoFileLine,
};
class IWingPlugin {
public:
virtual bool init(QList<IWingPlugin *> loadedplugins) = 0;
virtual ~IWingPlugin() {}
virtual void unload() = 0;
virtual QMenu *registerMenu() = 0;
virtual QDockWidget *registerDockWidget() = 0;
virtual QString pluginName() = 0;
virtual QString pluginAuthor() = 0;
virtual uint pluginVersion() = 0;
virtual QString puid() = 0;
virtual QString signature() = 0;
virtual QString comment() = 0;
virtual QList<QVariant> optionalInfos() = 0;
IWingPlugin *self;
signals:
void host2MessagePipe(IWingPlugin *sender, WingPluginMessage type,
QList<QVariant> msg);
public slots:
virtual void plugin2MessagePipe(WingPluginMessage type,
QList<QVariant> msg) = 0;
};
const QString sign = "wingsummer";
class PluginUtils {
public:
static QString GetPUID(IWingPlugin *plugin) {
auto str = QString("%1%2%3%4%5")
.arg(sign)
.arg(plugin->pluginName())
.arg(plugin->pluginAuthor())
.arg(plugin->comment())
.arg(plugin->pluginVersion());
return QCryptographicHash::hash(str.toLatin1(), QCryptographicHash::Md5)
.toHex();
}
static QString GetPuid(QString pluginName, QString author, QString comment,
uint version) {
auto str = QString("%1%2%3%4%5")
.arg(sign)
.arg(pluginName)
.arg(author)
.arg(comment)
.arg(version);
return QCryptographicHash::hash(str.toLatin1(), QCryptographicHash::Md5)
.toHex();
}
};
#define IWINGPLUGIN_INTERFACE_IID "com.wingsummer.iwingplugin"
Q_DECLARE_INTERFACE(IWingPlugin, IWINGPLUGIN_INTERFACE_IID)
#endif // IWINGPLUGIN_H

78
TestPlugin/testplugin.cpp Normal file
View File

@ -0,0 +1,78 @@
#include "testplugin.h"
#include <QMessageBox>
#include <QStringList>
TestPlugin::TestPlugin(QObject *parent){Q_UNUSED(parent)}
TestPlugin::~TestPlugin() {}
bool TestPlugin::init(QList<IWingPlugin *> loadedplugins) {
if (loadedplugins.length() > 0) {
QString ps;
for (auto item : loadedplugins) {
ps.append(item->pluginName());
ps.append('\n');
}
QMessageBox::information(nullptr, "Test", ps);
}
testmenu = new QMenu;
testmenu->setTitle("TestPlugin");
auto action = new QAction("ClickMe!", this);
connect(action, &QAction::triggered, [=] {
QMessageBox::information(nullptr, "戳我", "经典Hello World!");
});
testmenu->addAction(action);
return true;
}
void TestPlugin::unload() { testmenu->deleteLater(); }
QString TestPlugin::puid() { return PluginUtils::GetPUID(this); }
QString TestPlugin::pluginName() { return "TestPlugin"; }
QString TestPlugin::pluginAuthor() { return "Wingsummer"; }
QString TestPlugin::comment() {
return "A Sample Plugin for WingHex Explorer by Wingsummer!";
}
uint TestPlugin::pluginVersion() { return 1; }
QString TestPlugin::signature() { return WINGSUMMER; }
QList<QVariant> TestPlugin::optionalInfos() { return QList<QVariant>(); }
void TestPlugin::plugin2MessagePipe(WingPluginMessage type,
QList<QVariant> msg) {
Q_UNUSED(msg)
if (type == WingPluginMessage::PluginLoaded) {
emit host2MessagePipe(this, WingPluginMessage::GetHexViewShadow,
QList<QVariant>());
return;
}
if (type == WingPluginMessage::GetHexViewShadow) {
auto hvs = extractHexViewShadow(msg);
if (hvs) {
if (hvs->shadowControl(this)) {
QMessageBox::information(nullptr, "信息",
"获取组件控制权,下面开始表演!");
hvs->newFile();
hvs->switchDocument(0);
auto str = QString("HelloWorld!").toUtf8();
hvs->insert(0, str);
hvs->shadowRelease(this);
}
}
}
}
QMenu *TestPlugin::registerMenu() { return testmenu; }
QDockWidget *TestPlugin::registerDockWidget() { return nullptr; }
Qt::DockWidgetArea TestPlugin::registerDockWidgetDockArea() {
return Qt::DockWidgetArea::NoDockWidgetArea;
}
HookIndex TestPlugin::getHookSubscribe() { return HookIndex::None; }

40
TestPlugin/testplugin.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef GENERICPLUGIN_H
#define GENERICPLUGIN_H
#include "../WingHexExplorer/plugin/iwingplugin.h"
#include <QList>
#include <QObject>
class TestPlugin : public IWingPlugin {
Q_OBJECT
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID IWINGPLUGIN_INTERFACE_IID FILE "TestPlugin.json")
// Q_PLUGIN_METADATA(IID IWINGPLUGIN_SHADOWINTERFACE_IID)
#endif // QT_VERSION >= 0x050000
Q_INTERFACES(IWingPlugin)
public:
TestPlugin(QObject *parent = nullptr);
bool init(QList<IWingPlugin *> loadedplugins) override;
~TestPlugin() override;
void unload() override;
QMenu *registerMenu() override;
QDockWidget *registerDockWidget() override;
QString pluginName() override;
QString pluginAuthor() override;
uint pluginVersion() override;
QString puid() override;
QString signature() override;
QString comment() override;
QList<QVariant> optionalInfos() override;
void plugin2MessagePipe(WingPluginMessage type, QList<QVariant> msg) override;
Qt::DockWidgetArea registerDockWidgetDockArea() override;
HookIndex getHookSubscribe() override;
private:
QMenu *testmenu;
};
#endif // GENERICPLUGIN_H

View File

@ -0,0 +1,284 @@
#include "chunks.h"
#include <limits.h>
#define NORMAL 0
#define HIGHLIGHTED 1
#define BUFFER_SIZE 0x10000
#define CHUNK_SIZE 0x1000
#define READ_CHUNK_MASK Q_UINT64_C(0xfffffffffffff000)
/*this file is modified by wingsummer in order to fit the QHexView*/
// ***************************************** Constructors and file settings
Chunks::Chunks(QObject *parent) : QObject(parent) {}
Chunks::Chunks(QIODevice *ioDevice, QObject *parent) : QObject(parent) {
setIODevice(ioDevice);
if (ioDevice)
ioDevice->setParent(this);
}
Chunks::~Chunks() {}
bool Chunks::setIODevice(QIODevice *ioDevice) {
_ioDevice = ioDevice;
if (_ioDevice &&
(_ioDevice->isOpen() ||
_ioDevice->open(QIODevice::ReadOnly))) // Try to open IODevice
{
_size = quint64(_ioDevice->size());
_ioDevice->close();
} else // Fallback is an empty buffer
{
QBuffer *buf = new QBuffer(this);
_ioDevice = buf;
_size = 0;
}
_chunks.clear();
_pos = 0;
return true;
}
// ***************************************** Getting data out of Chunks
QByteArray Chunks::data(quint64 pos, qint64 maxSize, QByteArray *changed) {
quint64 ioDelta = 0;
int chunkIdx = 0;
Chunk chunk;
QByteArray buffer;
// Do some checks and some arrangements
if (changed)
changed->clear();
if (pos >= _size)
return buffer;
if (maxSize < 0)
maxSize = qint64(_size);
else if ((pos + quint64(maxSize)) > _size)
maxSize = qint64(_size - pos);
_ioDevice->open(QIODevice::ReadOnly);
while (maxSize > 0) {
chunk.absPos = LLONG_MAX;
bool chunksLoopOngoing = true;
while ((chunkIdx < _chunks.count()) && chunksLoopOngoing) {
// In this section, we track changes before our required data and
// we take the editdet data, if availible. ioDelta is a difference
// counter to justify the read pointer to the original data, if
// data in between was deleted or inserted.
chunk = _chunks[chunkIdx];
if (chunk.absPos > pos)
chunksLoopOngoing = false;
else {
chunkIdx += 1;
qint64 count;
qint64 chunkOfs = qint64(pos - chunk.absPos);
if (maxSize > (chunk.data.size() - chunkOfs)) {
count = qint64(chunk.data.size()) - chunkOfs;
ioDelta += CHUNK_SIZE - quint64(chunk.data.size());
} else
count = maxSize;
if (count > 0) {
buffer += chunk.data.mid(int(chunkOfs), int(count));
maxSize -= count;
pos += quint64(count);
if (changed)
*changed += chunk.dataChanged.mid(int(chunkOfs), int(count));
}
}
}
if ((maxSize > 0) && (pos < chunk.absPos)) {
// In this section, we read data from the original source. This only will
// happen, whe no copied data is available
qint64 byteCount;
QByteArray readBuffer;
if ((chunk.absPos - pos) > quint64(maxSize))
byteCount = maxSize;
else
byteCount = qint64(chunk.absPos - pos);
maxSize -= byteCount;
_ioDevice->seek(qint64(pos + ioDelta));
readBuffer = _ioDevice->read(byteCount);
buffer += readBuffer;
if (changed)
*changed += QByteArray(readBuffer.size(), NORMAL);
pos += quint64(readBuffer.size());
}
}
_ioDevice->close();
return buffer;
}
bool Chunks::write(QIODevice *iODevice, quint64 pos, qint64 count) {
if (count == -1)
count = qint64(_size);
bool ok = iODevice->open(QIODevice::WriteOnly);
if (ok) {
for (quint64 idx = pos; idx < quint64(count); idx += BUFFER_SIZE) {
QByteArray ba = data(idx, BUFFER_SIZE);
iODevice->write(ba);
}
iODevice->close();
}
return ok;
}
// ***************************************** Set and get highlighting infos
void Chunks::setDataChanged(quint64 pos, bool dataChanged) {
if (pos >= _size)
return;
int chunkIdx = getChunkIndex(pos);
quint64 posInBa = pos - _chunks[chunkIdx].absPos;
_chunks[chunkIdx].dataChanged[int(posInBa)] = char(dataChanged);
}
bool Chunks::dataChanged(quint64 pos) {
QByteArray highlighted;
data(pos, 1, &highlighted);
// fix the bug
if (highlighted.isEmpty())
return true;
return bool(highlighted.at(0));
}
// ***************************************** Search API
qint64 Chunks::indexOf(const QByteArray &ba, qint64 from) {
qint64 result = -1;
QByteArray buffer;
for (quint64 pos = quint64(from); (pos < _size) && (result < 0);
pos += BUFFER_SIZE) {
buffer = data(pos, BUFFER_SIZE + ba.size() - 1);
int findPos = buffer.indexOf(ba);
if (findPos >= 0)
result = qint64(pos + uint(findPos));
}
return result;
}
qint64 Chunks::lastIndexOf(const QByteArray &ba, qint64 from) {
qint64 result = -1;
QByteArray buffer;
for (quint64 pos = quint64(from); (pos > 0) && (result < 0);
pos -= BUFFER_SIZE) {
quint64 sPos = pos - BUFFER_SIZE - uint(ba.size()) + 1;
/*if (sPos < 0)
sPos = 0;*/
buffer = data(sPos, qint64(pos - sPos));
int findPos = buffer.lastIndexOf(ba);
if (findPos >= 0)
result = qint64(sPos + uint(findPos));
}
return result;
}
// ***************************************** Char manipulations
bool Chunks::insert(quint64 pos, char b) {
if (pos > _size)
return false;
int chunkIdx;
if (pos == _size) {
chunkIdx = getChunkIndex(pos - 1);
} else
chunkIdx = getChunkIndex(pos);
quint64 posInBa = pos - _chunks[chunkIdx].absPos;
_chunks[chunkIdx].data.insert(int(posInBa), b);
_chunks[chunkIdx].dataChanged.insert(int(posInBa), char(1));
for (int idx = chunkIdx + 1; idx < _chunks.size(); idx++)
_chunks[idx].absPos += 1;
_size += 1;
_pos = pos;
return true;
}
bool Chunks::overwrite(quint64 pos, char b) {
if (pos >= _size)
return false;
int chunkIdx = getChunkIndex(pos);
quint64 posInBa = pos - _chunks[chunkIdx].absPos;
_chunks[chunkIdx].data[int(posInBa)] = b;
_chunks[chunkIdx].dataChanged[int(posInBa)] = char(1);
_pos = pos;
return true;
}
bool Chunks::removeAt(quint64 pos) {
if (pos >= _size)
return false;
int chunkIdx = getChunkIndex(pos);
quint64 posInBa = pos - _chunks[chunkIdx].absPos;
_chunks[chunkIdx].data.remove(int(posInBa), 1);
_chunks[chunkIdx].dataChanged.remove(int(posInBa), 1);
for (int idx = chunkIdx + 1; idx < _chunks.size(); idx++)
_chunks[idx].absPos -= 1;
_size -= 1;
_pos = pos;
return true;
}
// ***************************************** Utility functions
char Chunks::operator[](quint64 pos) {
auto d = data(pos, 1);
if (d.isEmpty())
return '0';
return d.at(0);
}
quint64 Chunks::pos() { return _pos; }
quint64 Chunks::size() { return _size; }
int Chunks::getChunkIndex(quint64 absPos) {
// This routine checks, if there is already a copied chunk available. If so,
// it returns a reference to it. If there is no copied chunk available,
// original data will be copied into a new chunk.
int foundIdx = -1;
int insertIdx = 0;
quint64 ioDelta = 0;
for (int idx = 0; idx < _chunks.size(); idx++) {
Chunk chunk = _chunks[idx];
if ((absPos >= chunk.absPos) &&
(absPos < (chunk.absPos + quint64(chunk.data.size())))) {
foundIdx = idx;
break;
}
if (absPos < chunk.absPos) {
insertIdx = idx;
break;
}
ioDelta += uint(chunk.data.size()) - CHUNK_SIZE;
insertIdx = idx + 1;
}
if (foundIdx == -1) {
Chunk newChunk;
quint64 readAbsPos = absPos - ioDelta;
quint64 readPos = (readAbsPos & READ_CHUNK_MASK);
_ioDevice->open(QIODevice::ReadOnly);
_ioDevice->seek(qint64(readPos));
newChunk.data = _ioDevice->read(CHUNK_SIZE);
_ioDevice->close();
newChunk.absPos = absPos - (readAbsPos - readPos);
newChunk.dataChanged = QByteArray(newChunk.data.size(), char(0));
_chunks.insert(insertIdx, newChunk);
foundIdx = insertIdx;
}
return foundIdx;
}

View File

@ -0,0 +1,79 @@
#ifndef CHUNKS_H
#define CHUNKS_H
/** \cond docNever */
/*! The Chunks class is the storage backend for QHexEdit.
*
* When QHexEdit loads data, Chunks access them using a QIODevice interface.
* When the app uses a QByteArray interface, QBuffer is used to provide again a
* QIODevice like interface. No data will be changed, therefore Chunks opens the
* QIODevice in QIODevice::ReadOnly mode. After every access Chunks closes the
* QIODevice, that's why external applications can overwrite files while
* QHexEdit shows them.
*
* When the the user starts to edit the data, Chunks creates a local copy of a
* chunk of data (4 kilobytes) and notes all changes there. Parallel to that
* chunk, there is a second chunk, which keep track of which bytes are changed
* and which not.
*
*/
#include <QtCore>
struct Chunk {
QByteArray data;
QByteArray dataChanged;
quint64 absPos;
};
class Chunks : public QObject {
Q_OBJECT
public:
// Constructors and file settings
Chunks(QObject *parent = nullptr);
Chunks(QIODevice *ioDevice, QObject *parent);
~Chunks();
bool setIODevice(QIODevice *ioDevice);
// Getting data out of Chunks
QByteArray data(quint64 pos = 0, qint64 maxSize = -1,
QByteArray *changed = nullptr);
bool write(QIODevice *iODevice, quint64 pos = 0, qint64 count = -1);
// Set and get highlighting infos
void setDataChanged(quint64 pos, bool dataChanged);
bool dataChanged(quint64 pos);
// Search API
qint64 indexOf(const QByteArray &ba, qint64 from);
qint64 lastIndexOf(const QByteArray &ba, qint64 from);
// Char manipulations
bool insert(quint64 pos, char b);
bool overwrite(quint64 pos, char b);
bool removeAt(quint64 pos);
// Utility functions
char operator[](quint64 pos);
quint64 pos();
quint64 size();
private:
int getChunkIndex(quint64 absPos);
QIODevice *_ioDevice;
quint64 _pos;
quint64 _size;
QList<Chunk> _chunks;
#ifdef MODUL_TEST
public:
int chunkSize();
#endif
};
/** \endcond docNever */
#endif // CHUNKS_H

View File

@ -0,0 +1,32 @@
cmake_minimum_required(VERSION 3.12)
project(QHexView
LANGUAGES CXX
)
find_package(Qt5 COMPONENTS Widgets REQUIRED)
add_library(qhexview-lib STATIC
document/buffer/qfilebuffer.cpp
document/buffer/qhexbuffer.cpp
document/buffer/qmemorybuffer.cpp
document/buffer/qmemoryrefbuffer.cpp
document/commands/hexcommand.cpp
document/commands/insertcommand.cpp
document/commands/removecommand.cpp
document/commands/replacecommand.cpp
document/qhexcursor.cpp
document/qhexdocument.cpp
document/qhexmetadata.cpp
document/qhexrenderer.cpp
qhexview.cpp
)
set_target_properties(qhexview-lib PROPERTIES
AUTOMOC ON
CXX_STANDARD 11
CXX_STANDARD_REQUIRED ON
)
target_link_libraries(qhexview-lib PRIVATE Qt5::Widgets)
target_include_directories(qhexview-lib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")

View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2014 Dax89
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.

View File

@ -0,0 +1,31 @@
QT += widgets
HEADERS += $$PWD/document/commands/hexcommand.h \
$$PWD/document/commands/insertcommand.h \
$$PWD/document/commands/removecommand.h \
$$PWD/document/commands/replacecommand.h \
$$PWD/document/buffer/qhexbuffer.h \
$$PWD/document/buffer/qmemoryrefbuffer.h \
$$PWD/document/buffer/qmemorybuffer.h \
$$PWD/document/buffer/qfilebuffer.h \
$$PWD/document/qhexcursor.h \
$$PWD/document/qhexdocument.h \
$$PWD/document/qhexmetadata.h \
$$PWD/document/qhexrenderer.h \
$$PWD/qhexview.h
SOURCES += $$PWD/document/commands/hexcommand.cpp \
$$PWD/document/commands/insertcommand.cpp \
$$PWD/document/commands/removecommand.cpp \
$$PWD/document/commands/replacecommand.cpp \
$$PWD/document/buffer/qhexbuffer.cpp \
$$PWD/document/buffer/qmemoryrefbuffer.cpp \
$$PWD/document/buffer/qmemorybuffer.cpp \
$$PWD/document/buffer/qfilebuffer.cpp \
$$PWD/document/qhexcursor.cpp \
$$PWD/document/qhexdocument.cpp \
$$PWD/document/qhexmetadata.cpp \
$$PWD/document/qhexrenderer.cpp \
$$PWD/qhexview.cpp
INCLUDEPATH += $$PWD

View File

@ -0,0 +1,63 @@
QHexView
========
QHexView is a hexadecimal widget for Qt5
<p align="center">
<img height="400" src="https://raw.githubusercontent.com/Dax89/QHexEdit/master/screenshots/QHexView.png"><br>
<img src="https://img.shields.io/badge/license-MIT-8e725e.svg?style=flat-square">
<a href="https://github.com/ellerbrock/open-source-badges/">
<img src="https://badges.frapsoft.com/os/v1/open-source.png?v=103">
</a>
</p>
Features
-----
- Customizable data backend (see more below).
- Document/View based.
- Unlimited Undo/Redo.
- Fully Customizable.
- Fast rendering.
- Easy to Use.
Buffer Backends
-----
These are the available buffer backends:
- QMemoryBuffer: A simple, flat memory array.
- QMemoryRefBuffer: QHexView just display the referenced data, editing is disabled.<br>
<br>
It's also possible to create new data backends from scratch.
Usage
-----
The data is managed by QHexView through QHexDocument class.<br>
You can load a generic QIODevice using the method fromDevice() of QHexDocument class with various buffer backends.<br>
Helper methods are provided in order to load a QFile a In-Memory buffer in QHexView:<br>
```cpp
// Load data from In-Memory Buffer...
QHexDocument* document = QHexDocument::fromMemory<QMemoryBuffer>(bytearray);
// ...from a generic I/O device...
QHexDocument* document = QHexDocument::fromDevice<QMemoryBuffer>(iodevice);
/* ...or from File */
QHexDocument* document = QHexDocument::fromFile<QMemoryBuffer>("data.bin");
QHexView* hexview = new QHexView();
hexview->setDocument(document); // Associate QHexEditData with this QHexEdit
// Document editing
QByteArray data = document->read(24, 78); // Read 78 bytes starting to offset 24
document->insert(4, "Hello QHexEdit"); // Insert a string to offset 4
document->remove(6, 10); // Delete bytes from offset 6 to offset 10
document->replace(30, "New Data"); // Replace bytes from offset 30 with the string "New Data"
// Metatadata management
QHexMetadata* hexmetadata = document->metadata();
hexmetadata->background(6, 0, 10, Qt::Red); // Highlight background to line 6, from 0 to 10
hexmetadata->foreground(8, 0, 15, Qt::darkBLue); // Highlight foreground to line 8, from 0 to 15
hexmetadata->comment(16, "I'm a comment!"); // Add a comment to line 16
hexmetadata->clear(); // Reset styling
```
License
-----
QHexEdit is released under MIT license

View File

@ -0,0 +1,51 @@
#include "qfilebuffer.h"
#include <climits>
/*
* this file is implemented by wingsummer,
* 使 QHexEdit2 访 GB
*
*/
QFileBuffer::QFileBuffer(QObject *parent) : QHexBuffer(parent) {
_chunks = new Chunks(parent);
}
QFileBuffer::~QFileBuffer() {}
uchar QFileBuffer::at(qint64 idx) {
return uchar(_chunks->data(quint64(idx), 1)[0]);
}
qint64 QFileBuffer::length() const { return qint64(_chunks->size()); }
void QFileBuffer::insert(qint64 offset, const QByteArray &data) {
for (int i = 0; i < data.length(); i++) {
_chunks->insert(quint64(offset + i), data.at(i));
}
}
void QFileBuffer::remove(qint64 offset, int length) {
for (uint i = 0; i < uint(length); i++) {
_chunks->removeAt(quint64(offset) + i);
}
}
QByteArray QFileBuffer::read(qint64 offset, int length) {
return _chunks->data(quint64(offset), length);
}
bool QFileBuffer::read(QIODevice *device) {
_chunks->setIODevice(device);
return true;
}
void QFileBuffer::write(QIODevice *device) { _chunks->write(device); }
qint64 QFileBuffer::indexOf(const QByteArray &ba, qint64 from) {
return _chunks->indexOf(ba, from);
}
qint64 QFileBuffer::lastIndexOf(const QByteArray &ba, qint64 from) {
return _chunks->lastIndexOf(ba, from);
}

View File

@ -0,0 +1,30 @@
#ifndef QFILEBUFFER_H
#define QFILEBUFFER_H
#include "QHexEdit2/chunks.h"
#include "qhexbuffer.h"
#include <QFile>
class QFileBuffer : public QHexBuffer {
Q_OBJECT
public:
explicit QFileBuffer(QObject *parent = nullptr);
~QFileBuffer() override;
uchar at(qint64 idx) override;
qint64 length() const override;
void insert(qint64 offset, const QByteArray &data) override;
void remove(qint64 offset, int length) override;
QByteArray read(qint64 offset, int length) override;
bool read(QIODevice *device) override;
void write(QIODevice *device) override;
qint64 indexOf(const QByteArray &ba, qint64 from) override;
qint64 lastIndexOf(const QByteArray &ba, qint64 from) override;
private:
Chunks *_chunks;
uchar *m_memory;
};
#endif // QFILEBUFFER_H

View File

@ -0,0 +1,32 @@
#include "qhexbuffer.h"
#include <QBuffer>
QHexBuffer::QHexBuffer(QObject *parent) : QObject(parent) {}
uchar QHexBuffer::at(qint64 idx) { return uchar(this->read(idx, 1)[0]); }
bool QHexBuffer::isEmpty() const { return this->length() <= 0; }
void QHexBuffer::replace(qint64 offset, const QByteArray &data) {
this->remove(offset, data.length());
this->insert(offset, data);
}
void QHexBuffer::read(char *data, int size) {
QBuffer *buffer = new QBuffer(this);
buffer->setData(data, size);
if (!buffer->isOpen())
buffer->open(QBuffer::ReadWrite);
this->read(buffer);
}
void QHexBuffer::read(const QByteArray &ba) {
QBuffer *buffer = new QBuffer(this);
buffer->setData(ba);
if (!buffer->isOpen())
buffer->open(QBuffer::ReadWrite);
this->read(buffer);
}

View File

@ -0,0 +1,32 @@
#ifndef QHEXBUFFER_H
#define QHEXBUFFER_H
#include <QIODevice>
#include <QObject>
class QHexBuffer : public QObject {
Q_OBJECT
public:
explicit QHexBuffer(QObject *parent = nullptr);
bool isEmpty() const;
public:
virtual uchar at(qint64 idx);
virtual void replace(qint64 offset, const QByteArray &data);
virtual void read(char *data, int size);
virtual void read(const QByteArray &ba);
public:
virtual qint64 length() const = 0;
virtual void insert(qint64 offset, const QByteArray &data) = 0;
virtual void remove(qint64 offset, int length) = 0;
virtual QByteArray read(qint64 offset, int length) = 0;
virtual bool read(QIODevice *iodevice) = 0;
virtual void write(QIODevice *iodevice) = 0;
virtual qint64 indexOf(const QByteArray &ba, qint64 from) = 0;
virtual qint64 lastIndexOf(const QByteArray &ba, qint64 from) = 0;
};
#endif // QHEXBUFFER_H

View File

@ -0,0 +1,27 @@
#include "qmemorybuffer.h"
QMemoryBuffer::QMemoryBuffer(QObject *parent) : QHexBuffer(parent) {}
uchar QMemoryBuffer::at(qint64 idx) { return uchar(m_buffer.at(int(idx))); }
qint64 QMemoryBuffer::length() const { return qint64(m_buffer.length()); }
void QMemoryBuffer::insert(qint64 offset, const QByteArray &data) {
m_buffer.insert(int(offset), data);
}
void QMemoryBuffer::remove(qint64 offset, int length) {
m_buffer.remove(int(offset), length);
}
QByteArray QMemoryBuffer::read(qint64 offset, int length) {
return m_buffer.mid(int(offset), length);
}
bool QMemoryBuffer::read(QIODevice *device) {
m_buffer = device->readAll();
return true;
}
void QMemoryBuffer::write(QIODevice *device) { device->write(m_buffer); }
qint64 QMemoryBuffer::indexOf(const QByteArray &ba, qint64 from) {
return m_buffer.indexOf(ba, int(from));
}
qint64 QMemoryBuffer::lastIndexOf(const QByteArray &ba, qint64 from) {
return m_buffer.lastIndexOf(ba, int(from));
}

View File

@ -0,0 +1,26 @@
#ifndef QMEMORYBUFFER_H
#define QMEMORYBUFFER_H
#include "qhexbuffer.h"
class QMemoryBuffer : public QHexBuffer {
Q_OBJECT
public:
explicit QMemoryBuffer(QObject *parent = nullptr);
uchar at(qint64 idx) override;
qint64 length() const override;
void insert(qint64 offset, const QByteArray &data) override;
void remove(qint64 offset, int length) override;
QByteArray read(qint64 offset, int length) override;
bool read(QIODevice *device) override;
void write(QIODevice *device) override;
qint64 indexOf(const QByteArray &ba, qint64 from) override;
qint64 lastIndexOf(const QByteArray &ba, qint64 from) override;
private:
QByteArray m_buffer;
};
#endif // QMEMORYBUFFER_H

View File

@ -0,0 +1,99 @@
#include "qmemoryrefbuffer.h"
#include <climits>
#include <QObject>
QMemoryRefBuffer::QMemoryRefBuffer(QObject *parent): QHexBuffer(parent) { }
qint64 QMemoryRefBuffer::length() const { return m_buffer->size(); }
void QMemoryRefBuffer::insert(qint64 offset, const QByteArray &data)
{
Q_UNUSED(offset)
Q_UNUSED(data)
/* Insertion unsupported */
}
void QMemoryRefBuffer::remove(qint64 offset, int length)
{
Q_UNUSED(offset)
Q_UNUSED(length)
/* Deletion unsupported */
}
QByteArray QMemoryRefBuffer::read(qint64 offset, int length)
{
m_buffer->seek(offset);
return m_buffer->read(length);
}
bool QMemoryRefBuffer::read(QIODevice *device)
{
m_buffer = qobject_cast<QBuffer*>(device);
if (m_buffer) {
m_buffer->setParent(this);
return true;
}
return false;
}
void QMemoryRefBuffer::write(QIODevice *device)
{
m_buffer->seek(0);
if (m_buffer->size() < INT_MAX) {
device->write(m_buffer->readAll());
} else {
while (m_buffer->pos() < m_buffer->size()) {
char tmpBuf[4096];
qint64 chunkLen = m_buffer->read(tmpBuf, 4096);
if (chunkLen == -1)
break;
if (chunkLen > 0) {
device->write(tmpBuf, chunkLen);
m_buffer->seek(m_buffer->pos() + chunkLen);
}
}
}
}
qint64 QMemoryRefBuffer::indexOf(const QByteArray& ba, qint64 from)
{
qint64 findPos = -1;
if (from < m_buffer->size()) {
findPos = from;
m_buffer->seek(from);
while (findPos < m_buffer->size()) {
QByteArray data = m_buffer->read(INT_MAX);
int idx = data.indexOf(ba);
if (idx >= 0) {
findPos += idx;
break;
}
if (findPos + data.size() >= m_buffer->size())
return -1;
m_buffer->seek(m_buffer->pos() + data.size() - ba.size());
}
}
return findPos;
}
qint64 QMemoryRefBuffer::lastIndexOf(const QByteArray& ba, qint64 from)
{
qint64 findPos = -1;
if (from >= 0 && ba.size() < INT_MAX) {
qint64 currPos = from;
while (currPos >= 0) {
qint64 readPos = (currPos < INT_MAX) ? 0 : currPos - INT_MAX;
m_buffer->seek(readPos);
QByteArray data = m_buffer->read(currPos - readPos);
int idx = data.lastIndexOf(ba, from);
if (idx >= 0) {
findPos = readPos + idx;
break;
}
if (readPos <= 0)
break;
currPos = readPos + ba.size();
}
}
return findPos;
}

View File

@ -0,0 +1,26 @@
#ifndef QMEMORYREFBUFFER_H
#define QMEMORYREFBUFFER_H
#include "qbuffer.h"
#include "qhexbuffer.h"
class QMemoryRefBuffer : public QHexBuffer {
Q_OBJECT
public:
explicit QMemoryRefBuffer(QObject *parent = nullptr);
qint64 length() const override;
void insert(qint64 offset, const QByteArray &data) override;
void remove(qint64 offset, int length) override;
QByteArray read(qint64 offset, int length) override;
bool read(QIODevice *device) override;
void write(QIODevice *device) override;
qint64 indexOf(const QByteArray &ba, qint64 from) override;
qint64 lastIndexOf(const QByteArray &ba, qint64 from) override;
private:
QBuffer *m_buffer;
};
#endif // QMEMORYREFBUFFER_H

View File

@ -0,0 +1,4 @@
#include "hexcommand.h"
HexCommand::HexCommand(QHexBuffer *buffer, QUndoCommand *parent)
: QUndoCommand(parent), m_buffer(buffer), m_offset(0), m_length(0) {}

View File

@ -0,0 +1,19 @@
#ifndef HEXCOMMAND_H
#define HEXCOMMAND_H
#include <QUndoCommand>
#include "../buffer/qhexbuffer.h"
class HexCommand: public QUndoCommand
{
public:
HexCommand(QHexBuffer* buffer, QUndoCommand* parent = nullptr);
protected:
QHexBuffer* m_buffer;
qint64 m_offset;
int m_length;
QByteArray m_data;
};
#endif // HEXCOMMAND_H

View File

@ -0,0 +1,11 @@
#include "insertcommand.h"
InsertCommand::InsertCommand(QHexBuffer *buffer, qint64 offset,
const QByteArray &data, QUndoCommand *parent)
: HexCommand(buffer, parent) {
m_offset = offset;
m_data = data;
}
void InsertCommand::undo() { m_buffer->remove(m_offset, m_data.length()); }
void InsertCommand::redo() { m_buffer->insert(m_offset, m_data); }

View File

@ -0,0 +1,14 @@
#ifndef INSERTCOMMAND_H
#define INSERTCOMMAND_H
#include "hexcommand.h"
class InsertCommand: public HexCommand
{
public:
InsertCommand(QHexBuffer* buffer, qint64 offset, const QByteArray& data, QUndoCommand* parent = nullptr);
void undo() override;
void redo() override;
};
#endif // INSERTCOMMAND_H

View File

@ -0,0 +1,15 @@
#include "removecommand.h"
RemoveCommand::RemoveCommand(QHexBuffer *buffer, qint64 offset, int length,
QUndoCommand *parent)
: HexCommand(buffer, parent) {
m_offset = offset;
m_length = length;
}
void RemoveCommand::undo() { m_buffer->insert(m_offset, m_data); }
void RemoveCommand::redo() {
m_data = m_buffer->read(m_offset, m_length); // Backup data
m_buffer->remove(m_offset, m_length);
}

View File

@ -0,0 +1,14 @@
#ifndef REMOVECOMMAND_H
#define REMOVECOMMAND_H
#include "hexcommand.h"
class RemoveCommand: public HexCommand
{
public:
RemoveCommand(QHexBuffer* buffer, qint64 offset, int length, QUndoCommand* parent = nullptr);
void undo() override;
void redo() override;
};
#endif // REMOVECOMMAND_H

View File

@ -0,0 +1,15 @@
#include "replacecommand.h"
ReplaceCommand::ReplaceCommand(QHexBuffer *buffer, qint64 offset,
const QByteArray &data, QUndoCommand *parent)
: HexCommand(buffer, parent) {
m_offset = offset;
m_data = data;
}
void ReplaceCommand::undo() { m_buffer->replace(m_offset, m_olddata); }
void ReplaceCommand::redo() {
m_olddata = m_buffer->read(m_offset, m_data.length());
m_buffer->replace(m_offset, m_data);
}

View File

@ -0,0 +1,17 @@
#ifndef REPLACECOMMAND_H
#define REPLACECOMMAND_H
#include "hexcommand.h"
class ReplaceCommand: public HexCommand
{
public:
ReplaceCommand(QHexBuffer* buffer, qint64 offset, const QByteArray& data, QUndoCommand* parent = nullptr);
void undo() override;
void redo() override;
private:
QByteArray m_olddata;
};
#endif // REPLACECOMMAND_H

View File

@ -0,0 +1,133 @@
#include "qhexcursor.h"
#include <QWidget>
QHexCursor::QHexCursor(QObject *parent)
: QObject(parent), m_insertionmode(QHexCursor::OverwriteMode) {
m_position.line = m_position.column = 0;
m_position.line = m_position.column = 0;
m_selection.line = m_selection.column = 0;
m_selection.line = m_selection.column = 0;
m_position.nibbleindex = m_selection.nibbleindex = 1;
setLineWidth(DEFAULT_HEX_LINE_LENGTH);
}
const QHexPosition &QHexCursor::selectionStart() const {
if (m_position.line < m_selection.line)
return m_position;
if (m_position.line == m_selection.line) {
if (m_position.column < m_selection.column)
return m_position;
}
return m_selection;
}
const QHexPosition &QHexCursor::selectionEnd() const {
if (m_position.line > m_selection.line)
return m_position;
if (m_position.line == m_selection.line) {
if (m_position.column > m_selection.column)
return m_position;
}
return m_selection;
}
const QHexPosition &QHexCursor::position() const { return m_position; }
QHexCursor::InsertionMode QHexCursor::insertionMode() const {
return m_insertionmode;
}
int QHexCursor::selectionLength() const {
return this->selectionEnd() - this->selectionStart() + 1;
}
quint64 QHexCursor::currentLine() const { return m_position.line; }
int QHexCursor::currentColumn() const { return m_position.column; }
int QHexCursor::currentNibble() const { return m_position.nibbleindex; }
quint64 QHexCursor::selectionLine() const { return m_selection.line; }
int QHexCursor::selectionColumn() const { return m_selection.column; }
int QHexCursor::selectionNibble() const { return m_selection.nibbleindex; }
bool QHexCursor::isLineSelected(quint64 line) const {
if (!this->hasSelection())
return false;
quint64 first = std::min(m_position.line, m_selection.line);
quint64 last = std::max(m_position.line, m_selection.line);
if ((line < first) || (line > last))
return false;
return true;
}
bool QHexCursor::hasSelection() const { return m_position != m_selection; }
void QHexCursor::clearSelection() {
m_selection = m_position;
emit positionChanged();
}
void QHexCursor::moveTo(const QHexPosition &pos) {
this->moveTo(pos.line, pos.column, pos.nibbleindex);
}
void QHexCursor::select(const QHexPosition &pos) {
this->select(pos.line, pos.column, pos.nibbleindex);
}
void QHexCursor::moveTo(quint64 line, int column, int nibbleindex) {
m_selection.line = line;
m_selection.column = column;
m_selection.nibbleindex = nibbleindex;
this->select(line, column, nibbleindex);
}
void QHexCursor::select(quint64 line, int column, int nibbleindex) {
m_position.line = line;
m_position.column = column;
m_position.nibbleindex = nibbleindex;
emit positionChanged();
}
void QHexCursor::moveTo(qint64 offset) {
qint64 line = offset / m_lineWidth;
this->moveTo(quint64(line), int(offset - (line * m_lineWidth)));
}
void QHexCursor::select(int length) {
this->select(m_position.line,
std::min(m_lineWidth - 1, m_position.column + length - 1));
}
void QHexCursor::selectOffset(qint64 offset, int length) {
this->moveTo(offset);
this->select(length);
}
void QHexCursor::setInsertionMode(QHexCursor::InsertionMode mode) {
bool differentmode = (m_insertionmode != mode);
m_insertionmode = mode;
if (differentmode)
emit insertionModeChanged();
}
void QHexCursor::setLineWidth(quint8 width) {
m_lineWidth = width;
m_position.lineWidth = width;
m_selection.lineWidth = width;
}
void QHexCursor::switchInsertionMode() {
if (m_insertionmode == QHexCursor::OverwriteMode)
m_insertionmode = QHexCursor::InsertMode;
else
m_insertionmode = QHexCursor::OverwriteMode;
emit insertionModeChanged();
}

View File

@ -0,0 +1,80 @@
#ifndef QHEXCURSOR_H
#define QHEXCURSOR_H
#include <QObject>
#define DEFAULT_HEX_LINE_LENGTH 0x10
#define DEFAULT_AREA_IDENTATION 0x01
struct QHexPosition {
quint64 line;
int column;
quint8 lineWidth;
int nibbleindex;
QHexPosition() = default;
inline qint64 offset() const {
return static_cast<qint64>(line * lineWidth) + column;
}
inline int operator-(const QHexPosition &rhs) const {
return int(this->offset() - rhs.offset());
}
inline bool operator==(const QHexPosition &rhs) const {
return (line == rhs.line) && (column == rhs.column) &&
(nibbleindex == rhs.nibbleindex);
}
inline bool operator!=(const QHexPosition &rhs) const {
return (line != rhs.line) || (column != rhs.column) ||
(nibbleindex != rhs.nibbleindex);
}
};
class QHexCursor : public QObject {
Q_OBJECT
public:
enum InsertionMode { OverwriteMode, InsertMode };
public:
explicit QHexCursor(QObject *parent = nullptr);
public:
const QHexPosition &selectionStart() const;
const QHexPosition &selectionEnd() const;
const QHexPosition &position() const;
InsertionMode insertionMode() const;
int selectionLength() const;
quint64 currentLine() const;
int currentColumn() const;
int currentNibble() const;
quint64 selectionLine() const;
int selectionColumn() const;
int selectionNibble() const;
bool atEnd() const;
bool isLineSelected(quint64 line) const;
bool hasSelection() const;
void clearSelection();
public:
void moveTo(const QHexPosition &pos);
void moveTo(quint64 line, int column, int nibbleindex = 1);
void moveTo(qint64 offset);
void select(const QHexPosition &pos);
void select(quint64 line, int column, int nibbleindex = 1);
void select(int length);
void selectOffset(qint64 offset, int length);
void setInsertionMode(InsertionMode mode);
void setLineWidth(quint8 width);
void switchInsertionMode();
signals:
void positionChanged();
void insertionModeChanged();
private:
InsertionMode m_insertionmode;
quint8 m_lineWidth;
QHexPosition m_position, m_selection;
};
#endif // QHEXCURSOR_H

View File

@ -0,0 +1,335 @@
#include "qhexdocument.h"
#include "buffer/qfilebuffer.h"
#include "commands/insertcommand.h"
#include "commands/removecommand.h"
#include "commands/replacecommand.h"
#include <QApplication>
#include <QBuffer>
#include <QClipboard>
#include <QFile>
/*======================*/
// added by wingsummer
bool QHexDocument::isReadOnly() { return m_readonly; }
bool QHexDocument::isKeepSize() { return m_keepsize; }
bool QHexDocument::isLocked() { return m_islocked; }
bool QHexDocument::setLockedFile(bool b) {
if (m_readonly)
return false;
m_islocked = b;
m_cursor->setInsertionMode(QHexCursor::OverwriteMode);
return true;
}
bool QHexDocument::setKeepSize(bool b) {
if (m_readonly)
return false;
m_keepsize = b;
if (b)
m_cursor->setInsertionMode(QHexCursor::OverwriteMode);
return true;
}
bool QHexDocument::isModified() { return !m_undostack.isClean(); }
void QHexDocument::getBookMarks(QList<BookMarkStruct> &bookmarks) {
bookmarks.clear();
bookmarks.append(this->bookmarks);
}
void QHexDocument::addBookMark(QString comment) {
BookMarkStruct b{m_cursor->position().offset(), comment};
bookmarks.append(b);
}
BookMarkStruct QHexDocument::bookMark(int index) {
if (index >= 0 && index < bookmarks.count()) {
return bookmarks.at(index);
} else {
BookMarkStruct b;
b.pos = -1;
return b;
}
}
void QHexDocument::removeBookMark(int index) {
if (index >= 0 && index < bookmarks.count()) {
bookmarks.removeAt(index);
}
}
void QHexDocument::clearBookMark() { bookmarks.clear(); }
void QHexDocument::gotoBookMark(int index) {
if (index >= 0 && index < bookmarks.count()) {
auto bookmark = bookmarks.at(index);
m_cursor->moveTo(qlonglong(bookmark.pos));
}
}
bool QHexDocument::existBookMark(int &index) {
auto curpos = m_cursor->position().offset();
int i = 0;
for (auto item : bookmarks) {
if (item.pos == curpos) {
index = i;
return true;
}
i++;
}
return false;
}
QList<BookMarkStruct> QHexDocument::getAllBookMarks() { return bookmarks; }
void QHexDocument::applyBookMarks(QList<BookMarkStruct> books) {
bookmarks.append(books);
}
void QHexDocument::FindAllBytes(qint64 begin, qint64 end, QByteArray b,
QList<quint64> &results, int maxCount) {
results.clear();
qlonglong p = begin > 0 ? begin : 0;
qlonglong e = end > begin ? end : -1;
auto offset = b.count();
while (1) {
p = m_buffer->indexOf(b, p);
if (p < 0 || (e > 0 && p > e) ||
(maxCount > 0 && results.count() >= maxCount)) {
break;
}
results.append(quint64(p));
p += offset + 1;
}
}
/*======================*/
// modified by wingsummer
QHexDocument::QHexDocument(QHexBuffer *buffer, bool readonly, QObject *parent)
: QObject(parent), m_baseaddress(0), m_readonly(false), m_keepsize(false),
m_islocked(false) {
m_buffer = buffer;
m_buffer->setParent(this); // Take Ownership
m_areaindent = DEFAULT_AREA_IDENTATION;
m_hexlinewidth = DEFAULT_HEX_LINE_LENGTH;
/*=======================*/
// added by wingsummer
m_readonly = readonly;
if (m_readonly) {
m_islocked = true;
m_keepsize = true;
}
/*=======================*/
m_cursor = new QHexCursor(this);
m_cursor->setLineWidth(m_hexlinewidth);
m_metadata = new QHexMetadata(this);
m_metadata->setLineWidth(m_hexlinewidth);
connect(m_metadata, &QHexMetadata::metadataChanged, this,
&QHexDocument::lineChanged);
connect(m_metadata, &QHexMetadata::metadataCleared, this,
&QHexDocument::documentChanged);
connect(&m_undostack, &QUndoStack::canUndoChanged, this,
&QHexDocument::canUndoChanged);
connect(&m_undostack, &QUndoStack::canRedoChanged, this,
&QHexDocument::canRedoChanged);
}
bool QHexDocument::isEmpty() const { return m_buffer->isEmpty(); }
bool QHexDocument::atEnd() const {
return m_cursor->position().offset() >= m_buffer->length();
}
bool QHexDocument::canUndo() const { return m_undostack.canUndo(); }
bool QHexDocument::canRedo() const { return m_undostack.canRedo(); }
qint64 QHexDocument::length() const { return m_buffer->length(); }
quint64 QHexDocument::baseAddress() const { return m_baseaddress; }
QHexCursor *QHexDocument::cursor() const { return m_cursor; }
int QHexDocument::areaIndent() const { return m_areaindent; }
void QHexDocument::setAreaIndent(quint8 value) { m_areaindent = value; }
int QHexDocument::hexLineWidth() const { return m_hexlinewidth; }
void QHexDocument::setHexLineWidth(quint8 value) {
m_hexlinewidth = value;
m_cursor->setLineWidth(value);
m_metadata->setLineWidth(value);
}
QHexMetadata *QHexDocument::metadata() const { return m_metadata; }
QByteArray QHexDocument::read(qint64 offset, int len) {
return m_buffer->read(offset, len);
}
bool QHexDocument::removeSelection() {
if (!m_cursor->hasSelection())
return false;
auto res = this->remove(m_cursor->selectionStart().offset(),
m_cursor->selectionLength());
if (res)
m_cursor->clearSelection();
return res;
}
QByteArray QHexDocument::selectedBytes() const {
if (!m_cursor->hasSelection())
return QByteArray();
return m_buffer->read(m_cursor->selectionStart().offset(),
m_cursor->selectionLength());
}
char QHexDocument::at(int offset) const { return char(m_buffer->at(offset)); }
void QHexDocument::setBaseAddress(quint64 baseaddress) {
if (m_baseaddress == baseaddress)
return;
m_baseaddress = baseaddress;
emit documentChanged();
}
void QHexDocument::sync() { emit documentChanged(); }
void QHexDocument::undo() {
m_undostack.undo();
emit documentChanged();
}
void QHexDocument::redo() {
m_undostack.redo();
emit documentChanged();
}
bool QHexDocument::cut(bool hex) {
if (!m_cursor->hasSelection() || m_keepsize)
return false;
this->copy(hex);
return this->removeSelection();
}
void QHexDocument::copy(bool hex) {
if (!m_cursor->hasSelection())
return;
QClipboard *c = qApp->clipboard();
QByteArray bytes = this->selectedBytes();
if (hex)
bytes = bytes.toHex(' ').toUpper();
c->setText(bytes);
}
// modified by wingsummer
void QHexDocument::paste(bool hex) {
QClipboard *c = qApp->clipboard();
QByteArray data = c->text().toUtf8();
if (data.isEmpty())
return;
this->removeSelection();
if (hex)
data = QByteArray::fromHex(data);
auto pos = m_cursor->position().offset();
if (!m_keepsize) {
this->insert(pos, data);
m_cursor->moveTo(pos + data.length()); // added by wingsummer
} else
this->replace(pos, data);
}
void QHexDocument::insert(qint64 offset, uchar b) {
if (m_keepsize || m_readonly || m_islocked)
return;
this->insert(offset, QByteArray(1, char(b)));
}
void QHexDocument::replace(qint64 offset, uchar b) {
if (m_readonly || m_islocked)
return;
this->replace(offset, QByteArray(1, char(b)));
}
void QHexDocument::insert(qint64 offset, const QByteArray &data) {
if (m_keepsize || m_readonly || m_islocked)
return;
m_undostack.push(new InsertCommand(m_buffer, offset, data));
emit documentChanged();
}
void QHexDocument::replace(qint64 offset, const QByteArray &data) {
m_undostack.push(new ReplaceCommand(m_buffer, offset, data));
emit documentChanged();
}
bool QHexDocument::remove(qint64 offset, int len) {
if (m_keepsize || m_readonly || m_islocked)
return false;
m_undostack.push(new RemoveCommand(m_buffer, offset, len));
emit documentChanged();
return true;
}
QByteArray QHexDocument::read(qint64 offset, int len) const {
return m_buffer->read(offset, len);
}
bool QHexDocument::saveTo(QIODevice *device, bool cleanUndo) {
if (!device->isWritable())
return false;
m_buffer->write(device);
if (cleanUndo)
m_undostack.setClean(); // added by wingsummer
emit documentSaved();
return true;
}
qint64 QHexDocument::searchForward(const QByteArray &ba) {
qint64 startPos = m_cursor->position().offset();
qint64 findPos = m_buffer->indexOf(ba, startPos);
if (findPos > -1) {
m_cursor->clearSelection();
m_cursor->moveTo(findPos);
m_cursor->select(ba.length());
}
return findPos;
}
qint64 QHexDocument::searchBackward(const QByteArray &ba) {
qint64 startPos = m_cursor->position().offset() - 1;
if (m_cursor->hasSelection()) {
startPos = m_cursor->selectionStart().offset() - 1;
}
qint64 findPos = m_buffer->lastIndexOf(ba, startPos);
if (findPos > -1) {
m_cursor->clearSelection();
m_cursor->moveTo(findPos);
m_cursor->select(ba.length());
}
return findPos;
}
QHexDocument *QHexDocument::fromLargeFile(QString filename, bool readonly,
QObject *parent) {
QFile *f = new QFile(filename);
QHexBuffer *hexbuffer = new QFileBuffer();
if (hexbuffer->read(f)) {
return new QHexDocument(hexbuffer, readonly,
parent); // modified by wingsummer
} else {
delete hexbuffer;
}
return nullptr;
}

View File

@ -0,0 +1,196 @@
#ifndef QHEXDOCUMENT_H
#define QHEXDOCUMENT_H
#include "buffer/qhexbuffer.h"
#include "qhexcursor.h"
#include "qhexmetadata.h"
#include <QFile>
#include <QMap>
#include <QUndoStack>
/*=========================*/
// added by wingsummer
struct BookMarkStruct {
qlonglong pos;
QString comment;
};
/*=========================*/
class QHexDocument : public QObject {
Q_OBJECT
private:
explicit QHexDocument(QHexBuffer *buffer, bool readonly = false,
QObject *parent = nullptr); // modified by wingsummer
public:
bool isEmpty() const;
bool atEnd() const;
bool canUndo() const;
bool canRedo() const;
qint64 length() const;
quint64 baseAddress() const;
QHexCursor *cursor() const;
QHexMetadata *metadata() const;
int areaIndent() const;
void setAreaIndent(quint8 value);
int hexLineWidth() const;
void setHexLineWidth(quint8 value);
/*======================*/
// added by wingsummer
bool setLockedFile(bool b);
bool setKeepSize(bool b);
bool isReadOnly();
bool isKeepSize();
bool isLocked();
bool isModified();
void addBookMark(QString comment);
BookMarkStruct bookMark(int index);
QList<BookMarkStruct> getAllBookMarks();
void applyBookMarks(QList<BookMarkStruct> books);
void removeBookMark(int index);
void clearBookMark();
void getBookMarks(QList<BookMarkStruct> &bookmarks);
void gotoBookMark(int index);
bool existBookMark(int &index);
void FindAllBytes(qint64 begin, qint64 end, QByteArray b,
QList<quint64> &results, int maxCount = -1);
/*======================*/
public:
bool removeSelection();
QByteArray read(qint64 offset, int len = 0);
QByteArray selectedBytes() const;
char at(int offset) const;
void setBaseAddress(quint64 baseaddress);
void sync();
public slots:
void undo();
void redo();
bool cut(bool hex = false);
void copy(bool hex = false);
void paste(bool hex = false);
void insert(qint64 offset, uchar b);
void replace(qint64 offset, uchar b);
void insert(qint64 offset, const QByteArray &data);
void replace(qint64 offset, const QByteArray &data);
bool remove(qint64 offset, int len);
QByteArray read(qint64 offset, int len) const;
bool saveTo(QIODevice *device, bool cleanUndo);
qint64 searchForward(const QByteArray &ba);
qint64 searchBackward(const QByteArray &ba);
/*================================*/
// modified by wingsummer
public:
template <typename T>
static QHexDocument *fromDevice(QIODevice *iodevice, bool readonly = false,
QObject *parent = nullptr);
template <typename T>
static QHexDocument *fromFile(QString filename, bool readonly = false,
QObject *parent = nullptr);
template <typename T>
static QHexDocument *fromMemory(char *data, int size, bool readonly = false,
QObject *parent = nullptr);
template <typename T>
static QHexDocument *fromMemory(const QByteArray &ba, bool readonly = false,
QObject *parent = nullptr);
static QHexDocument *fromLargeFile(QString filename, bool readonly = false,
QObject *parent = nullptr);
signals:
void documentSaved();
/*================================*/
void canUndoChanged(bool canUndo);
void canRedoChanged(bool canRedo);
void documentChanged();
void lineChanged(quint64 line);
private:
QHexBuffer *m_buffer;
QHexMetadata *m_metadata;
QUndoStack m_undostack;
QHexCursor *m_cursor;
quint64 m_baseaddress;
quint8 m_areaindent;
quint8 m_hexlinewidth;
/*======================*/
// added by wingsummer
bool m_readonly;
bool m_keepsize;
bool m_islocked;
QList<BookMarkStruct> bookmarks;
/*======================*/
};
/*====================================*/
// modified by wingsummer
template <typename T>
QHexDocument *QHexDocument::fromDevice(QIODevice *iodevice, bool readonly,
QObject *parent) {
bool needsclose = false;
if (!iodevice->isOpen()) {
needsclose = true;
iodevice->open(readonly ? QIODevice::ReadOnly
: QIODevice::ReadWrite); // modifed by wingsummer
}
QHexBuffer *hexbuffer = new T();
if (hexbuffer->read(iodevice)) {
if (needsclose)
iodevice->close();
return new QHexDocument(hexbuffer, readonly, parent);
} else {
delete hexbuffer;
}
return nullptr;
}
template <typename T>
QHexDocument *QHexDocument::fromFile(QString filename, bool readonly,
QObject *parent) {
QFile f(filename);
f.open(QFile::ReadOnly);
QHexDocument *doc = QHexDocument::fromDevice<T>(&f, readonly, parent);
f.close();
return doc;
}
template <typename T>
QHexDocument *QHexDocument::fromMemory(char *data, int size, bool readonly,
QObject *parent) {
QHexBuffer *hexbuffer = new T();
hexbuffer->read(data, size);
return new QHexDocument(hexbuffer, readonly, parent);
}
template <typename T>
QHexDocument *QHexDocument::fromMemory(const QByteArray &ba, bool readonly,
QObject *parent) {
QHexBuffer *hexbuffer = new T();
hexbuffer->read(ba);
return new QHexDocument(hexbuffer, readonly, parent);
}
/*================================================*/
#endif // QHEXEDITDATA_H

View File

@ -0,0 +1,206 @@
#include "qhexmetadata.h"
QHexMetadata::QHexMetadata(QObject *parent) : QObject(parent) {}
const QHexLineMetadata &QHexMetadata::get(quint64 line) const {
auto it = m_metadata.find(line);
return it.value();
}
/*==================================*/
// added by wingsummer
QHash<quint64, QHexLineMetadata> QHexMetadata::getallMetas() {
return m_metadata;
}
bool QHexMetadata::removeMetadata(qint64 offset,
QList<QHexMetadataItem> refer) {
QList<QHexMetadataAbsoluteItem> delneeded;
for (auto item : m_absoluteMetadata) {
if (offset >= item.begin && offset <= item.end) {
delneeded.push_back(item);
}
}
for (auto item : delneeded) {
m_absoluteMetadata.removeOne(item);
quint64 firstRow = quint64(item.begin / m_lineWidth);
quint64 lastRow = quint64(item.end / m_lineWidth);
for (auto i = firstRow; i <= lastRow; i++) {
QList<QHexMetadataItem> delmeta;
auto it = m_metadata.find(i);
if (it != m_metadata.end()) {
for (auto iitem : *it) {
for (auto ritem : refer) {
if (iitem.foreground == ritem.foreground &&
iitem.background == ritem.background &&
iitem.comment == ritem.comment) {
delmeta.push_back(iitem);
}
}
}
}
for (auto iitem : delmeta) {
it->remove(iitem);
}
}
}
return true;
}
QList<QHexMetadataItem> QHexMetadata::gets(qint64 offset) {
QList<QHexMetadataItem> items;
auto res = lldiv(offset, m_lineWidth);
quint64 line = quint64(res.quot);
auto m = res.rem;
auto it = m_metadata.find(line);
if (it != m_metadata.end()) {
for (auto item : *it) {
if (item.start <= m && m <= item.start + item.length) {
items.push_back(item);
}
}
}
return items;
}
void QHexMetadata::applyMetas(QHash<quint64, QHexLineMetadata> metas) {
m_metadata.insert(metas);
}
/*==================================*/
QString QHexMetadata::comments(quint64 line, int column) const {
if (!this->lineHasMetadata(line))
return QString();
QString s;
const auto &linemetadata = this->get(line);
for (auto &mi : linemetadata) {
if (!(mi.start <= column && column < mi.start + mi.length))
continue;
if (mi.comment.isEmpty())
continue;
if (!s.isEmpty())
s += "\n";
s += mi.comment;
}
return s;
}
bool QHexMetadata::lineHasMetadata(quint64 line) const {
return m_metadata.contains(line);
}
void QHexMetadata::clear(quint64 line) {
auto it = m_metadata.find(line);
if (it == m_metadata.end())
return;
m_metadata.erase(it);
emit metadataChanged(line);
}
void QHexMetadata::clear() {
m_absoluteMetadata.clear();
m_metadata.clear();
emit metadataCleared();
}
void QHexMetadata::metadata(qint64 begin, qint64 end, const QColor &fgcolor,
const QColor &bgcolor, const QString &comment) {
m_absoluteMetadata.append({begin, end, fgcolor, bgcolor, comment});
setAbsoluteMetadata(m_absoluteMetadata.back());
}
void QHexMetadata::setAbsoluteMetadata(const QHexMetadataAbsoluteItem &mai) {
const quint64 firstRow = quint64(mai.begin / m_lineWidth);
const quint64 lastRow = quint64(mai.end / m_lineWidth);
for (quint64 row = firstRow; row <= lastRow; ++row) {
int start, length;
if (row == firstRow) {
start = mai.begin % m_lineWidth;
} else {
start = 0;
}
if (row == lastRow) {
const int lastChar = mai.end % m_lineWidth;
length = lastChar - start;
} else {
length = m_lineWidth;
}
if (length > 0) {
setMetadata(
{row, start, length, mai.foreground, mai.background, mai.comment});
}
}
}
void QHexMetadata::setLineWidth(quint8 width) {
if (width != m_lineWidth) {
m_lineWidth = width;
// clean m_metadata
m_metadata.clear();
// and regenerate with new line width size
for (int i = 0; i < m_absoluteMetadata.size(); ++i) {
setAbsoluteMetadata(m_absoluteMetadata[i]);
}
}
}
void QHexMetadata::metadata(quint64 line, int start, int length,
const QColor &fgcolor, const QColor &bgcolor,
const QString &comment) {
const qint64 begin = qint64(line * m_lineWidth + uint(start));
const qint64 end = begin + length;
// delegate to the new interface
this->metadata(begin, end, fgcolor, bgcolor, comment);
}
void QHexMetadata::color(quint64 line, int start, int length,
const QColor &fgcolor, const QColor &bgcolor) {
this->metadata(line, start, length, fgcolor, bgcolor, QString());
}
void QHexMetadata::foreground(quint64 line, int start, int length,
const QColor &fgcolor) {
this->color(line, start, length, fgcolor, QColor());
}
void QHexMetadata::background(quint64 line, int start, int length,
const QColor &bgcolor) {
this->color(line, start, length, QColor(), bgcolor);
}
void QHexMetadata::comment(quint64 line, int start, int length,
const QString &comment) {
this->metadata(line, start, length, QColor(), QColor(), comment);
}
void QHexMetadata::setMetadata(const QHexMetadataItem &mi) {
if (!m_metadata.contains(mi.line)) {
QHexLineMetadata linemetadata;
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
linemetadata << mi;
#else
linemetadata.push_back(mi);
#endif
m_metadata[mi.line] = linemetadata;
} else {
QHexLineMetadata &linemetadata = m_metadata[mi.line];
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
linemetadata << mi;
#else
linemetadata.push_back(mi);
#endif
}
emit metadataChanged(mi.line);
}

View File

@ -0,0 +1,104 @@
#ifndef QHEXMETADATA_H
#define QHEXMETADATA_H
#include <QObject>
#include <QtGlobal>
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
#include <QLinkedList>
#else
#include <list>
#endif
#include <QColor>
#include <QHash>
#include <QVector>
struct QHexMetadataAbsoluteItem {
qint64 begin;
qint64 end;
QColor foreground, background;
QString comment;
// added by wingsummer
bool operator==(const QHexMetadataAbsoluteItem &item) {
return begin == item.begin && end == item.end &&
foreground == item.foreground && background == item.background &&
comment == item.comment;
}
};
struct QHexMetadataItem {
quint64 line;
int start, length;
QColor foreground, background;
QString comment;
// added by wingsummer
bool operator==(const QHexMetadataItem &item) {
return line == item.line && start == item.start &&
foreground == item.foreground && background == item.background &&
comment == item.comment;
}
};
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
typedef QLinkedList<QHexMetadataItem> QHexLineMetadata;
#else
typedef std::list<QHexMetadataItem> QHexLineMetadata;
#endif
class QHexMetadata : public QObject {
Q_OBJECT
public:
explicit QHexMetadata(QObject *parent = nullptr);
const QHexLineMetadata &get(quint64 line) const;
QString comments(quint64 line, int column) const;
bool lineHasMetadata(quint64 line) const; // modified by wingsummer
/*============================*/
// added by wingsummer
bool removeMetadata(qint64 offset, QList<QHexMetadataItem> refer);
QList<QHexMetadataItem> gets(qint64 offset);
void applyMetas(QHash<quint64, QHexLineMetadata> metas);
/*============================*/
void
clear(quint64 line); // this is transient till next call to setLineWidth()
void clear();
void setLineWidth(quint8 width);
public:
// new interface with begin, end
void metadata(qint64 begin, qint64 end, const QColor &fgcolor,
const QColor &bgcolor, const QString &comment);
// old interface with line, start, length
void metadata(quint64 line, int start, int length, const QColor &fgcolor,
const QColor &bgcolor, const QString &comment);
void color(quint64 line, int start, int length, const QColor &fgcolor,
const QColor &bgcolor);
void foreground(quint64 line, int start, int length, const QColor &fgcolor);
void background(quint64 line, int start, int length, const QColor &bgcolor);
void comment(quint64 line, int start, int length, const QString &comment);
QHash<quint64, QHexLineMetadata>
getallMetas(); // added by wingsummer to support workspace
private:
void setMetadata(const QHexMetadataItem &mi);
void setAbsoluteMetadata(const QHexMetadataAbsoluteItem &mi);
signals:
void metadataChanged(quint64 line);
void metadataCleared();
private:
quint8 m_lineWidth;
QHash<quint64, QHexLineMetadata> m_metadata;
QVector<QHexMetadataAbsoluteItem> m_absoluteMetadata;
};
#endif // QHEXMETADATA_H

View File

@ -0,0 +1,573 @@
#include "qhexrenderer.h"
#include <QApplication>
#include <QTextCodec>
#include <QTextCursor>
#include <QWidget>
#include <cctype>
#include <cmath>
#define HEX_UNPRINTABLE_CHAR '.'
/*===================================*/
// added by wingsummer
bool QHexRenderer::asciiVisible() { return m_asciiVisible; }
void QHexRenderer::setAsciiVisible(bool b) { m_asciiVisible = b; }
bool QHexRenderer::headerVisible() { return m_headerVisible; }
void QHexRenderer::setHeaderVisible(bool b) { m_headerVisible = b; }
bool QHexRenderer::addressVisible() { return m_addressVisible; }
void QHexRenderer::setAddressVisible(bool b) { m_addressVisible = b; }
QString QHexRenderer::encoding() { return m_encoding; }
bool QHexRenderer::setEncoding(QString encoding) {
if (QTextCodec::codecForName(encoding.toUtf8())) {
m_encoding = encoding;
return true;
}
return false;
}
/*===================================*/
QHexRenderer::QHexRenderer(QHexDocument *document,
const QFontMetricsF &fontmetrics, QObject *parent)
: QObject(parent), m_document(document), m_fontmetrics(fontmetrics),
m_encoding("ASCII") {
m_selectedarea = QHexRenderer::HexArea;
m_cursorenabled = false;
/*===================================*/
// added by wingsummer
m_asciiVisible = true;
m_addressVisible = true;
m_headerVisible = true;
/*===================================*/
}
// modified by wingsummer
void QHexRenderer::renderFrame(QPainter *painter) {
QRect rect = painter->window();
int hexx = this->getHexColumnX();
int asciix = this->getAsciiColumnX();
int endx = this->getEndColumnX();
// x coordinates are in absolute space
// y coordinates are in viewport space
// see QHexView::paintEvent where the painter has been shifted horizontally
if (m_headerVisible)
painter->drawLine(0, this->headerLineCount() * this->lineHeight() - 1, endx,
this->headerLineCount() * this->lineHeight() - 1);
if (m_addressVisible)
painter->drawLine(hexx, rect.top(), hexx, rect.bottom());
painter->drawLine(asciix, rect.top(), asciix, rect.bottom());
if (m_asciiVisible)
painter->drawLine(endx, rect.top(), endx, rect.bottom());
}
// modified by wingsummer
void QHexRenderer::render(QPainter *painter, quint64 begin, quint64 end,
quint64 firstline) {
QPalette palette = qApp->palette();
if (m_headerVisible)
this->drawHeader(painter, palette);
quint64 documentLines = this->documentLines();
for (quint64 line = begin; line < std::min(end, documentLines); line++) {
QRect linerect = this->getLineRect(line, firstline);
if (line % 2)
painter->fillRect(linerect, palette.brush(QPalette::Window));
else
painter->fillRect(linerect, palette.brush(QPalette::Base));
if (m_addressVisible)
this->drawAddress(painter, palette, linerect, line);
this->drawHex(painter, palette, linerect, line);
if (m_asciiVisible)
this->drawString(painter, palette, linerect, line, m_encoding);
}
}
void QHexRenderer::updateMetrics(const QFontMetricsF &fm) {
m_fontmetrics = fm;
}
void QHexRenderer::enableCursor(bool b) { m_cursorenabled = b; }
void QHexRenderer::selectArea(const QPoint &pt) {
int area = this->hitTestArea(pt);
if (!this->editableArea(area))
return;
m_selectedarea = area;
}
bool QHexRenderer::hitTest(const QPoint &pt, QHexPosition *position,
quint64 firstline) const {
int area = this->hitTestArea(pt);
if (!this->editableArea(area))
return false;
position->line = std::min(firstline + quint64(pt.y() / this->lineHeight()) -
quint64(headerLineCount()),
this->documentLastLine());
position->lineWidth = quint8(this->hexLineWidth());
if (area == QHexRenderer::HexArea) {
int relx = pt.x() - this->getHexColumnX() - this->borderSize();
int column = int(relx / this->getCellWidth());
position->column = column / 3;
// first char is nibble 1, 2nd and space are 0
position->nibbleindex = (column % 3 == 0) ? 1 : 0;
} else {
int relx = pt.x() - this->getAsciiColumnX() - this->borderSize();
position->column = int(relx / this->getCellWidth());
position->nibbleindex = 1;
}
if (position->line == this->documentLastLine()) // Check last line's columns
{
QByteArray ba = this->getLine(position->line);
position->column =
std::min(position->column, static_cast<int>(ba.length()));
} else
position->column = std::min(position->column, hexLineWidth() - 1);
return true;
}
int QHexRenderer::hitTestArea(const QPoint &pt) const {
if (pt.y() < headerLineCount() * lineHeight())
return QHexRenderer::HeaderArea;
if ((pt.x() >= this->borderSize()) &&
(pt.x() <= (this->getHexColumnX() - this->borderSize())))
return QHexRenderer::AddressArea;
if ((pt.x() > (this->getHexColumnX() + this->borderSize())) &&
(pt.x() < (this->getAsciiColumnX() - this->borderSize())))
return QHexRenderer::HexArea;
if ((pt.x() > (this->getAsciiColumnX() + this->borderSize())) &&
(pt.x() < (this->getEndColumnX() - this->borderSize())))
return QHexRenderer::AsciiArea;
return QHexRenderer::ExtraArea;
}
int QHexRenderer::selectedArea() const { return m_selectedarea; }
bool QHexRenderer::editableArea(int area) const {
return (area == QHexRenderer::HexArea || area == QHexRenderer::AsciiArea);
}
quint64 QHexRenderer::documentLastLine() const {
return this->documentLines() - 1;
}
int QHexRenderer::documentLastColumn() const {
return this->getLine(this->documentLastLine()).length();
}
quint64 QHexRenderer::documentLines() const {
return quint64(std::ceil(this->rendererLength() / float(hexLineWidth())));
}
int QHexRenderer::documentWidth() const { return this->getEndColumnX(); }
int QHexRenderer::lineHeight() const { return qRound(m_fontmetrics.height()); }
QRect QHexRenderer::getLineRect(quint64 line, quint64 firstline) const {
return QRect(0,
int((line - firstline + quint64(headerLineCount())) *
quint64(lineHeight())),
this->getEndColumnX(), lineHeight());
}
// modified by wingsummer
int QHexRenderer::headerLineCount() const { return m_headerVisible ? 1 : 0; }
int QHexRenderer::borderSize() const {
if (m_document)
return this->getNCellsWidth(m_document->areaIndent());
return this->getNCellsWidth(DEFAULT_AREA_IDENTATION);
}
int QHexRenderer::hexLineWidth() const {
if (m_document)
return m_document->hexLineWidth();
return DEFAULT_HEX_LINE_LENGTH;
}
QString QHexRenderer::hexString(quint64 line, QByteArray *rawline) const {
QByteArray lrawline = this->getLine(line);
if (rawline)
*rawline = lrawline;
return lrawline.toHex(' ').toUpper() + " ";
}
// modified by wingsummer
QString QHexRenderer::decodeString(quint64 line, QString encoding,
QByteArray *rawline) const {
QByteArray lrawline = this->getLine(line);
if (rawline)
*rawline = lrawline;
if (encoding.toLower() == "ascii") {
QByteArray ascii = lrawline;
this->unprintableChars(ascii);
return ascii;
} else {
auto enc = QTextCodec::codecForName(encoding.toUtf8());
auto d = enc->makeDecoder();
auto unicode = d->toUnicode(lrawline);
this->unprintableWChars(unicode);
return unicode;
}
}
QByteArray QHexRenderer::getLine(quint64 line) const {
return m_document->read(qint64(line * quint64(hexLineWidth())),
hexLineWidth());
}
void QHexRenderer::blinkCursor() { m_cursorenabled = !m_cursorenabled; }
qint64 QHexRenderer::rendererLength() const { return m_document->length() + 1; }
// modified by wingsummer
int QHexRenderer::getAddressWidth() const {
quint64 maxAddr = m_document->baseAddress() + quint64(this->rendererLength());
if (maxAddr <= 0xFFFFFFFF)
return 8;
else
return 16;
return QString::number(maxAddr, 16).length();
}
int QHexRenderer::getHexColumnX() const {
if (m_addressVisible) {
return this->getNCellsWidth(this->getAddressWidth()) +
2 * this->borderSize();
}
return 0;
}
int QHexRenderer::getAsciiColumnX() const {
return this->getHexColumnX() + this->getNCellsWidth(hexLineWidth() * 3) +
2 * this->borderSize();
}
int QHexRenderer::getEndColumnX() const {
if (m_asciiVisible) {
return this->getAsciiColumnX() + this->getNCellsWidth(hexLineWidth()) +
2 * this->borderSize();
}
return this->getAsciiColumnX();
}
qreal QHexRenderer::getCellWidth() const {
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
return m_fontmetrics.horizontalAdvance(" ");
#else
return m_fontmetrics.width(" ");
#endif
}
int QHexRenderer::getNCellsWidth(int n) const {
return qRound(n * getCellWidth());
}
void QHexRenderer::unprintableChars(QByteArray &ascii) const {
for (char &ch : ascii) {
if (std::isprint(static_cast<unsigned char>(ch)))
continue;
ch = HEX_UNPRINTABLE_CHAR;
}
}
// added by wingsummer
void QHexRenderer::unprintableWChars(QString &unicode) const {
for (QChar &ch : unicode) {
if (std::iswprint(ch.unicode()))
continue;
ch = HEX_UNPRINTABLE_CHAR;
}
}
void QHexRenderer::applyDocumentStyles(QPainter *painter,
QTextDocument *textdocument) const {
textdocument->setDocumentMargin(0);
textdocument->setUndoRedoEnabled(false);
textdocument->setDefaultFont(painter->font());
}
void QHexRenderer::applyBasicStyle(QTextCursor &textcursor,
const QByteArray &rawline,
Factor factor) const {
QPalette palette = qApp->palette();
QColor color = palette.color(QPalette::WindowText);
if (color.lightness() < 50) {
if (color == Qt::black)
color = Qt::gray;
else
color = color.darker();
} else
color = color.lighter();
QTextCharFormat charformat;
charformat.setForeground(color);
for (int i = 0; i < rawline.length(); i++) {
if ((rawline[i] != 0x00) && (uchar(rawline[i]) != 0xFF))
continue;
textcursor.setPosition(i * factor);
textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor,
factor);
textcursor.setCharFormat(charformat);
}
}
void QHexRenderer::applyMetadata(QTextCursor &textcursor, quint64 line,
Factor factor) const {
QHexMetadata *metadata = m_document->metadata();
if (!metadata->lineHasMetadata(line))
return;
const QHexLineMetadata &linemetadata = metadata->get(line);
for (const QHexMetadataItem &mi : linemetadata) {
QTextCharFormat charformat;
if (mi.background.isValid())
charformat.setBackground(mi.background);
if (mi.foreground.isValid())
charformat.setForeground(mi.foreground);
if (!mi.comment.isEmpty())
charformat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
textcursor.setPosition(mi.start * factor);
textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor,
(mi.length * factor) - (factor > 1 ? 1 : 0));
textcursor.setCharFormat(charformat);
}
}
void QHexRenderer::applySelection(QTextCursor &textcursor, quint64 line,
Factor factor) const {
QHexCursor *cursor = m_document->cursor();
if (!cursor->isLineSelected(line))
return;
const QHexPosition &startsel = cursor->selectionStart();
const QHexPosition &endsel = cursor->selectionEnd();
if (startsel.line == endsel.line) {
textcursor.setPosition(startsel.column * factor);
textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor,
((endsel.column - startsel.column + 1) * factor));
} else {
if (line == startsel.line)
textcursor.setPosition(startsel.column * factor);
else
textcursor.setPosition(0);
if (line == endsel.line)
textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor,
((endsel.column + 1) * factor));
else
textcursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
}
if (factor == Hex)
textcursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1);
QPalette palette = qApp->palette();
QTextCharFormat charformat;
charformat.setBackground(palette.color(QPalette::Highlight));
charformat.setForeground(palette.color(QPalette::HighlightedText));
textcursor.setCharFormat(charformat);
}
void QHexRenderer::applyCursorAscii(QTextCursor &textcursor,
quint64 line) const {
QHexCursor *cursor = m_document->cursor();
if ((line != cursor->currentLine()) || !m_cursorenabled)
return;
textcursor.clearSelection();
textcursor.setPosition(m_document->cursor()->currentColumn());
textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
QPalette palette = qApp->palette();
QTextCharFormat charformat;
if ((cursor->insertionMode() == QHexCursor::OverwriteMode) ||
(m_selectedarea != QHexRenderer::AsciiArea)) {
charformat.setForeground(palette.color(QPalette::Window));
if (m_selectedarea == QHexRenderer::AsciiArea)
charformat.setBackground(palette.color(QPalette::WindowText));
else
charformat.setBackground(
palette.color(QPalette::WindowText).lighter(250));
} else
charformat.setUnderlineStyle(
QTextCharFormat::UnderlineStyle::SingleUnderline);
textcursor.setCharFormat(charformat);
}
void QHexRenderer::applyCursorHex(QTextCursor &textcursor, quint64 line) const {
QHexCursor *cursor = m_document->cursor();
if ((line != cursor->currentLine()) || !m_cursorenabled)
return;
textcursor.clearSelection();
textcursor.setPosition(m_document->cursor()->currentColumn() * 3);
if ((m_selectedarea == QHexRenderer::HexArea) &&
!m_document->cursor()->currentNibble())
textcursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor);
textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
if (m_selectedarea == QHexRenderer::AsciiArea)
textcursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
QPalette palette = qApp->palette();
QTextCharFormat charformat;
if ((cursor->insertionMode() == QHexCursor::OverwriteMode) ||
(m_selectedarea != QHexRenderer::HexArea)) {
charformat.setForeground(palette.color(QPalette::Window));
if (m_selectedarea == QHexRenderer::HexArea)
charformat.setBackground(palette.color(QPalette::WindowText));
else
charformat.setBackground(
palette.color(QPalette::WindowText).lighter(250));
} else
charformat.setUnderlineStyle(
QTextCharFormat::UnderlineStyle::SingleUnderline);
textcursor.setCharFormat(charformat);
}
void QHexRenderer::drawAddress(QPainter *painter, const QPalette &palette,
const QRect &linerect, quint64 line) {
quint64 addr = line * quint64(hexLineWidth()) + m_document->baseAddress();
QString addrStr =
QString::number(addr, 16)
.rightJustified(this->getAddressWidth(), QLatin1Char('0'))
.toUpper();
QRect addressrect = linerect;
addressrect.setWidth(this->getHexColumnX());
painter->save();
painter->setPen(palette.color(QPalette::Highlight));
painter->drawText(addressrect, Qt::AlignHCenter | Qt::AlignVCenter, addrStr);
painter->restore();
}
void QHexRenderer::drawHex(QPainter *painter, const QPalette &palette,
const QRect &linerect, quint64 line) {
Q_UNUSED(palette)
QTextDocument textdocument;
QTextCursor textcursor(&textdocument);
QByteArray rawline;
textcursor.insertText(this->hexString(line, &rawline));
if (line == this->documentLastLine())
textcursor.insertText(" ");
QRect hexrect = linerect;
hexrect.setX(this->getHexColumnX() + this->borderSize());
this->applyDocumentStyles(painter, &textdocument);
this->applyBasicStyle(textcursor, rawline, Hex);
this->applyMetadata(textcursor, line, Hex);
this->applySelection(textcursor, line, Hex);
this->applyCursorHex(textcursor, line);
painter->save();
painter->translate(hexrect.topLeft());
textdocument.drawContents(painter);
painter->restore();
}
void QHexRenderer::drawString(QPainter *painter, const QPalette &palette,
const QRect &linerect, quint64 line,
QString encoding) {
Q_UNUSED(palette)
QTextDocument textdocument;
QTextCursor textcursor(&textdocument);
QByteArray rawline;
// modified by wingsummer
textcursor.insertText(this->decodeString(line, encoding, &rawline));
if (line == this->documentLastLine())
textcursor.insertText(" ");
QRect asciirect = linerect;
asciirect.setX(this->getAsciiColumnX() + this->borderSize());
this->applyDocumentStyles(painter, &textdocument);
this->applyBasicStyle(textcursor, rawline, String);
this->applyMetadata(textcursor, line, String);
this->applySelection(textcursor, line, String);
this->applyCursorAscii(textcursor, line);
painter->save();
painter->translate(asciirect.topLeft());
textdocument.drawContents(painter);
painter->restore();
}
void QHexRenderer::drawHeader(QPainter *painter, const QPalette &palette) {
QRect rect = QRect(0, 0, this->getEndColumnX(),
this->headerLineCount() * this->lineHeight());
QString hexheader;
for (quint8 i = 0; i < this->hexLineWidth(); i++)
hexheader.append(
QString("%1 ")
.arg(QString::number(i, 16).rightJustified(2, QChar('0')))
.toUpper());
QRect addressrect = rect;
addressrect.setWidth(this->getHexColumnX());
QRect hexrect = rect;
hexrect.setX(m_addressVisible ? this->getHexColumnX() + this->borderSize()
: this->borderSize());
hexrect.setWidth(this->getNCellsWidth(hexLineWidth() * 3));
QRect asciirect = rect;
asciirect.setX(this->getAsciiColumnX());
asciirect.setWidth(this->getEndColumnX() - this->getAsciiColumnX());
painter->save();
painter->setPen(palette.color(QPalette::Highlight));
if (m_addressVisible)
painter->drawText(addressrect, Qt::AlignHCenter | Qt::AlignVCenter,
QString("Offset"));
// align left for maximum consistency with drawHex() which prints from the
// left. so hex and positions are aligned vertically
painter->drawText(hexrect, Qt::AlignLeft | Qt::AlignVCenter, hexheader);
if (m_asciiVisible)
painter->drawText(asciirect, Qt::AlignHCenter | Qt::AlignVCenter,
m_encoding);
painter->restore();
}

View File

@ -0,0 +1,125 @@
#ifndef QHEXRENDERER_H
#define QHEXRENDERER_H
/*
* Nibble encoding:
* AB -> [A][B]
* Nibble Index: 1 0
*/
#include "qhexdocument.h"
#include <QPainter>
#include <QTextDocument>
class QHexRenderer : public QObject {
Q_OBJECT
public:
enum { HeaderArea, AddressArea, HexArea, AsciiArea, ExtraArea };
public:
explicit QHexRenderer(QHexDocument *document,
const QFontMetricsF &fontmetrics,
QObject *parent = nullptr);
void renderFrame(QPainter *painter);
void render(QPainter *painter, quint64 start, quint64 end,
quint64 firstline); // begin included, end excluded
void updateMetrics(const QFontMetricsF &fm);
void enableCursor(bool b = true);
void selectArea(const QPoint &pt);
/*==============================*/
// added by wingsummer
void setAsciiVisible(bool b);
bool asciiVisible();
void setAddressVisible(bool b);
bool addressVisible();
void setHeaderVisible(bool b);
bool headerVisible();
QString encoding();
bool setEncoding(QString encoding);
/*==============================*/
public:
void blinkCursor();
bool hitTest(const QPoint &pt, QHexPosition *position,
quint64 firstline) const;
int hitTestArea(const QPoint &pt) const;
int selectedArea() const;
bool editableArea(int area) const;
quint64 documentLastLine() const;
int documentLastColumn() const;
quint64 documentLines() const;
int documentWidth() const;
int lineHeight() const;
QRect getLineRect(quint64 line, quint64 firstline) const;
int headerLineCount() const;
int borderSize() const;
int hexLineWidth() const;
private:
QString hexString(quint64 line, QByteArray *rawline = nullptr) const;
/*======================================*/
// added by wingsummer
QString decodeString(quint64 line, QString encoding,
QByteArray *rawline = nullptr) const;
void unprintableWChars(QString &unicode) const;
/*======================================*/
QByteArray getLine(quint64 line) const;
qint64 rendererLength() const;
int getAddressWidth() const;
int getHexColumnX() const;
int getAsciiColumnX() const;
int getEndColumnX() const;
qreal getCellWidth() const;
int getNCellsWidth(int n) const;
void unprintableChars(QByteArray &ascii) const;
private:
// modified by wingsummer
enum Factor { String = 1, Hex = 3 };
void applyDocumentStyles(QPainter *painter,
QTextDocument *textdocument) const;
void applyBasicStyle(QTextCursor &textcursor, const QByteArray &rawline,
Factor factor) const;
void applyMetadata(QTextCursor &textcursor, quint64 line,
Factor factor) const;
void applySelection(QTextCursor &textcursor, quint64 line,
Factor factor) const;
void applyCursorAscii(QTextCursor &textcursor, quint64 line) const;
void applyCursorHex(QTextCursor &textcursor, quint64 line) const;
void drawAddress(QPainter *painter, const QPalette &palette,
const QRect &linerect, quint64 line);
void drawHex(QPainter *painter, const QPalette &palette,
const QRect &linerect, quint64 line);
void drawString(QPainter *painter, const QPalette &palette,
const QRect &linerect, quint64 line,
QString encoding = "ASCII");
void drawHeader(QPainter *painter, const QPalette &palette);
private:
QHexDocument *m_document;
QFontMetricsF m_fontmetrics;
int m_selectedarea;
bool m_cursorenabled;
/*==============================*/
// added by wingsummer
bool m_asciiVisible;
bool m_addressVisible;
bool m_headerVisible;
QString m_encoding;
/*==============================*/
};
#endif // QHEXRENDERER_H

View File

@ -0,0 +1,761 @@
#include "qhexview.h"
#include "document/buffer/qmemorybuffer.h"
#include <QApplication>
#include <QFontDatabase>
#include <QHelpEvent>
#include <QPaintEvent>
#include <QPainter>
#include <QScrollBar>
#include <QTextCursor>
#include <QToolTip>
#include <cmath>
#define CURSOR_BLINK_INTERVAL 500 // ms
#define DOCUMENT_WHEEL_LINES 3
/*======================*/
// added by wingsummer
QHexRenderer *QHexView::renderer() { return m_renderer; }
void QHexView::switchDocument(QHexDocument *document, QHexRenderer *renderer,
int vBarValue) {
if (document && renderer) {
m_document = document;
m_renderer = renderer;
this->adjustScrollBars();
this->viewport()->update();
auto vbar = this->verticalScrollBar();
if (vBarValue >= 0 && vBarValue <= vbar->maximum())
vbar->setValue(vBarValue);
m_blinktimer->start(); // let mouse blink
emit documentStatusChanged();
emit documentSwitched();
}
}
bool QHexView::isReadOnly() { return m_document->isReadOnly(); }
bool QHexView::isKeepSize() { return m_document->isKeepSize(); }
bool QHexView::isLocked() { return m_document->isLocked(); }
bool QHexView::setLockedFile(bool b) {
bool res = m_document->setLockedFile(b);
emit documentStatusChanged();
return res;
}
bool QHexView::setKeepSize(bool b) {
bool res = m_document->setKeepSize(b);
emit documentStatusChanged();
return res;
}
quint64 QHexView::documentLines() { return m_renderer->documentLines(); }
quint64 QHexView::documentBytes() { return quint64(m_document->length()); }
quint64 QHexView::currentRow() {
return quint64(m_document->cursor()->currentLine());
}
quint64 QHexView::currentColumn() {
return quint64(m_document->cursor()->currentColumn());
}
quint64 QHexView::currentOffset() {
return quint64(m_document->cursor()->position().offset());
}
quint64 QHexView::selectlength() {
return quint64(m_document->cursor()->selectionLength());
}
bool QHexView::asciiVisible() { return m_renderer->asciiVisible(); }
bool QHexView::headerVisible() { return m_renderer->headerVisible(); }
bool QHexView::addressVisible() { return m_renderer->addressVisible(); }
void QHexView::setAsciiVisible(bool b) {
m_renderer->setAsciiVisible(b);
this->adjustScrollBars();
this->viewport()->update();
}
void QHexView::setAddressVisible(bool b) {
m_renderer->setAddressVisible(b);
this->adjustScrollBars();
this->viewport()->update();
}
void QHexView::setHeaderVisible(bool b) {
m_renderer->setHeaderVisible(b);
this->adjustScrollBars();
this->viewport()->update();
}
quint64 QHexView::addressBase() { return m_document->baseAddress(); }
void QHexView::setAddressBase(quint64 base) {
m_document->setBaseAddress(base);
}
bool QHexView::isModified() { return m_document->isModified(); }
QFont QHexView::getHexeditorFont() {
QFont f = QFontDatabase::systemFont(QFontDatabase::FixedFont);
if (f.styleHint() != QFont::TypeWriter) {
f.setFamily("Monospace"); // Force Monospaced font
f.setStyleHint(QFont::TypeWriter);
}
return f;
}
/*======================*/
QHexView::QHexView(QWidget *parent)
: QAbstractScrollArea(parent), m_document(nullptr), m_renderer(nullptr) {
QFont f = QFontDatabase::systemFont(QFontDatabase::FixedFont);
if (f.styleHint() != QFont::TypeWriter) {
f.setFamily("Monospace"); // Force Monospaced font
f.setStyleHint(QFont::TypeWriter);
}
this->setFont(f);
this->setFocusPolicy(Qt::StrongFocus);
this->setMouseTracking(true);
this->verticalScrollBar()->setSingleStep(1);
this->verticalScrollBar()->setPageStep(1);
m_blinktimer = new QTimer(this);
m_blinktimer->setInterval(CURSOR_BLINK_INTERVAL);
connect(m_blinktimer, &QTimer::timeout, this, &QHexView::blinkCursor);
this->setDocument(
QHexDocument::fromMemory<QMemoryBuffer>(QByteArray(), false, this));
}
QHexDocument *QHexView::document() { return m_document; }
void QHexView::setDocument(QHexDocument *document) {
// modified by wingsummer
// if (m_renderer)
// m_renderer->deleteLater();
// if (m_document)
// m_document->deleteLater();
m_document = document;
m_renderer = new QHexRenderer(m_document, this->fontMetrics(), this);
connect(m_document, &QHexDocument::documentChanged, this, [&]() {
this->adjustScrollBars();
this->viewport()->update();
emit documentChanged(); // added by wingsummer
});
connect(m_document, &QHexDocument::documentSaved, this,
[&]() { emit documentStatusChanged(); }); // added by wingsummer
connect(m_document->cursor(), &QHexCursor::positionChanged, this,
&QHexView::moveToSelection);
connect(m_document->cursor(), &QHexCursor::insertionModeChanged, this,
&QHexView::renderCurrentLine);
this->adjustScrollBars();
this->viewport()->update();
emit documentChanged(); // added by wingsummer
emit documentStatusChanged();
emit documentSwitched();
}
bool QHexView::event(QEvent *e) {
if (m_renderer && (e->type() == QEvent::FontChange)) {
m_renderer->updateMetrics(QFontMetricsF(this->font()));
return true;
}
if (m_document && m_renderer && (e->type() == QEvent::ToolTip)) {
QHelpEvent *helpevent = static_cast<QHelpEvent *>(e);
QHexPosition position;
QPoint abspos = absolutePosition(helpevent->pos());
if (m_renderer->hitTest(abspos, &position, this->firstVisibleLine())) {
QString comments =
m_document->metadata()->comments(position.line, position.column);
if (!comments.isEmpty())
QToolTip::showText(helpevent->globalPos(), comments, this);
}
return true;
}
return QAbstractScrollArea::event(e);
}
void QHexView::keyPressEvent(QKeyEvent *e) {
if (!m_renderer || !m_document) {
QAbstractScrollArea::keyPressEvent(e);
return;
}
QHexCursor *cur = m_document->cursor();
m_blinktimer->stop();
m_renderer->enableCursor();
bool handled = this->processMove(cur, e);
if (!handled)
handled = this->processAction(cur, e);
if (!handled)
handled = this->processTextInput(cur, e);
if (!handled)
QAbstractScrollArea::keyPressEvent(e);
m_blinktimer->start();
}
QPoint QHexView::absolutePosition(const QPoint &pos) const {
QPoint shift(horizontalScrollBar()->value(), 0);
return pos + shift;
}
void QHexView::mousePressEvent(QMouseEvent *e) {
QAbstractScrollArea::mousePressEvent(e);
if (!m_renderer || (e->buttons() != Qt::LeftButton))
return;
QHexPosition position;
QPoint abspos = absolutePosition(e->pos());
if (!m_renderer->hitTest(abspos, &position, this->firstVisibleLine()))
return;
m_renderer->selectArea(abspos);
if (m_renderer->editableArea(m_renderer->selectedArea()))
m_document->cursor()->moveTo(position);
e->accept();
}
void QHexView::mouseMoveEvent(QMouseEvent *e) {
QAbstractScrollArea::mouseMoveEvent(e);
if (!m_renderer || !m_document)
return;
QPoint abspos = absolutePosition(e->pos());
if (e->buttons() == Qt::LeftButton) {
if (m_blinktimer->isActive()) {
m_blinktimer->stop();
m_renderer->enableCursor(false);
}
QHexCursor *cursor = m_document->cursor();
QHexPosition position;
if (!m_renderer->hitTest(abspos, &position, this->firstVisibleLine()))
return;
cursor->select(position.line, position.column, 0);
e->accept();
}
if (e->buttons() != Qt::NoButton)
return;
int hittest = m_renderer->hitTestArea(abspos);
if (m_renderer->editableArea(hittest))
this->setCursor(Qt::IBeamCursor);
else
this->setCursor(Qt::ArrowCursor);
}
void QHexView::mouseReleaseEvent(QMouseEvent *e) {
QAbstractScrollArea::mouseReleaseEvent(e);
if (e->button() != Qt::LeftButton)
return;
if (!m_blinktimer->isActive())
m_blinktimer->start();
e->accept();
}
void QHexView::focusInEvent(QFocusEvent *e) {
QAbstractScrollArea::focusInEvent(e);
if (!m_renderer)
return;
m_renderer->enableCursor();
m_blinktimer->start();
}
void QHexView::focusOutEvent(QFocusEvent *e) {
QAbstractScrollArea::focusOutEvent(e);
if (!m_renderer)
return;
m_blinktimer->stop();
m_renderer->enableCursor(true); // modified by wingsummer : false -> true
}
void QHexView::wheelEvent(QWheelEvent *e) {
if (e->angleDelta().y() == 0) {
int value = this->verticalScrollBar()->value();
if (e->angleDelta().x() < 0) // Scroll Down
this->verticalScrollBar()->setValue(value + DOCUMENT_WHEEL_LINES);
else if (e->angleDelta().x() > 0) // Scroll Up
this->verticalScrollBar()->setValue(value - DOCUMENT_WHEEL_LINES);
return;
}
QAbstractScrollArea::wheelEvent(e);
}
void QHexView::resizeEvent(QResizeEvent *e) {
QAbstractScrollArea::resizeEvent(e);
this->adjustScrollBars();
}
void QHexView::paintEvent(QPaintEvent *e) {
if (!m_document)
return;
QPainter painter(this->viewport());
painter.setFont(this->font());
const QRect &r = e->rect();
const quint64 firstVisible = this->firstVisibleLine();
const int lineHeight = m_renderer->lineHeight();
const int headerCount = m_renderer->headerLineCount();
// these are lines from the point of view of the visible rect
// where the first "headerCount" are taken by the header
const int first = (r.top() / lineHeight); // included
const int lastPlusOne = (r.bottom() / lineHeight) + 1; // excluded
// compute document lines, adding firstVisible and removing the header
// the max is necessary if the rect covers the header
const quint64 begin =
firstVisible + quint64(std::max(first - headerCount, 0));
const quint64 end =
firstVisible + quint64(std::max(lastPlusOne - headerCount, 0));
painter.save();
painter.translate(-this->horizontalScrollBar()->value(), 0);
m_renderer->render(&painter, begin, end, firstVisible);
m_renderer->renderFrame(&painter);
painter.restore();
}
void QHexView::moveToSelection() {
QHexCursor *cur = m_document->cursor();
if (!this->isLineVisible(cur->currentLine())) {
QScrollBar *vscrollbar = this->verticalScrollBar();
int scrollPos = static_cast<int>(
std::max(quint64(0), (cur->currentLine() - this->visibleLines() / 2)) /
quint64(documentSizeFactor()));
vscrollbar->setValue(scrollPos);
} else
this->viewport()->update();
emit cursorLocationChanged(); // added by wingsummer
}
void QHexView::blinkCursor() {
if (!m_renderer)
return;
m_renderer->blinkCursor();
this->renderCurrentLine();
}
void QHexView::moveNext(bool select) {
QHexCursor *cur = m_document->cursor();
quint64 line = cur->currentLine();
int column = cur->currentColumn();
bool lastcell = (line >= m_renderer->documentLastLine()) &&
(column >= m_renderer->documentLastColumn());
if ((m_renderer->selectedArea() == QHexRenderer::AsciiArea) && lastcell)
return;
int nibbleindex = cur->currentNibble();
if (m_renderer->selectedArea() == QHexRenderer::HexArea) {
if (lastcell && !nibbleindex)
return;
if (cur->position().offset() >= m_document->length() && nibbleindex)
return;
}
if ((m_renderer->selectedArea() == QHexRenderer::HexArea)) {
nibbleindex++;
nibbleindex %= 2;
if (nibbleindex)
column++;
} else {
nibbleindex = 1;
column++;
}
if (column > m_renderer->hexLineWidth() - 1) {
line = std::min(m_renderer->documentLastLine(), line + 1);
column = 0;
nibbleindex = 1;
}
if (select)
cur->select(line, std::min(m_renderer->hexLineWidth() - 1, column),
nibbleindex);
else
cur->moveTo(line, std::min(m_renderer->hexLineWidth() - 1, column),
nibbleindex);
}
void QHexView::movePrevious(bool select) {
QHexCursor *cur = m_document->cursor();
quint64 line = cur->currentLine();
int column = cur->currentColumn();
bool firstcell = !line && !column;
if ((m_renderer->selectedArea() == QHexRenderer::AsciiArea) && firstcell)
return;
int nibbleindex = cur->currentNibble();
if ((m_renderer->selectedArea() == QHexRenderer::HexArea) && firstcell &&
nibbleindex)
return;
if ((m_renderer->selectedArea() == QHexRenderer::HexArea)) {
nibbleindex--;
nibbleindex %= 2;
if (!nibbleindex)
column--;
} else {
nibbleindex = 1;
column--;
}
if (column < 0) {
line = std::max(quint64(0), line - 1);
column = m_renderer->hexLineWidth() - 1;
nibbleindex = 0;
}
if (select)
cur->select(line, std::max(0, column), nibbleindex);
else
cur->moveTo(line, std::max(0, column), nibbleindex);
}
void QHexView::renderCurrentLine() {
if (m_document)
this->renderLine(m_document->cursor()->currentLine());
}
bool QHexView::processAction(QHexCursor *cur, QKeyEvent *e) {
if (isReadOnly() || isLocked())
return false;
if (e->modifiers() != Qt::NoModifier) {
if (e->matches(QKeySequence::SelectAll)) {
m_document->cursor()->moveTo(0, 0);
m_document->cursor()->select(m_renderer->documentLastLine(),
m_renderer->documentLastColumn() - 1);
} else if (e->matches(QKeySequence::Undo))
m_document->undo();
else if (e->matches(QKeySequence::Redo))
m_document->redo();
else if (e->matches(QKeySequence::Cut))
m_document->cut((m_renderer->selectedArea() == QHexRenderer::HexArea));
else if (e->matches(QKeySequence::Copy))
m_document->copy((m_renderer->selectedArea() == QHexRenderer::HexArea));
else if (e->matches(QKeySequence::Paste))
m_document->paste((m_renderer->selectedArea() == QHexRenderer::HexArea));
else
return false;
return true;
}
if ((e->key() == Qt::Key_Backspace) || (e->key() == Qt::Key_Delete)) {
if (!cur->hasSelection()) {
const QHexPosition &pos = cur->position();
if (pos.offset() <= 0)
return true;
// modified by wingsummer
if (isKeepSize()) {
if (e->key() == Qt::Key_Backspace)
m_document->replace(cur->position().offset() - 1, uchar(0));
else
m_document->replace(cur->position().offset(), uchar(0));
} else {
if (e->key() == Qt::Key_Backspace)
m_document->remove(cur->position().offset() - 1, 1);
else
m_document->remove(cur->position().offset(), 1);
}
} else {
QHexPosition oldpos = cur->selectionStart();
m_document->removeSelection();
cur->moveTo(oldpos.line, oldpos.column + 1);
}
if (e->key() == Qt::Key_Backspace) {
if (m_renderer->selectedArea() == QHexRenderer::HexArea)
this->movePrevious();
this->movePrevious();
}
} else if (e->key() == Qt::Key_Insert)
cur->switchInsertionMode();
else
return false;
return true;
}
bool QHexView::processMove(QHexCursor *cur, QKeyEvent *e) {
if (e->matches(QKeySequence::MoveToNextChar) ||
e->matches(QKeySequence::SelectNextChar))
this->moveNext(e->matches(QKeySequence::SelectNextChar));
else if (e->matches(QKeySequence::MoveToPreviousChar) ||
e->matches(QKeySequence::SelectPreviousChar))
this->movePrevious(e->matches(QKeySequence::SelectPreviousChar));
else if (e->matches(QKeySequence::MoveToNextLine) ||
e->matches(QKeySequence::SelectNextLine)) {
if (m_renderer->documentLastLine() == cur->currentLine())
return true;
quint64 nextline = cur->currentLine() + 1;
if (e->matches(QKeySequence::MoveToNextLine))
cur->moveTo(nextline, cur->currentColumn());
else
cur->select(nextline, cur->currentColumn());
} else if (e->matches(QKeySequence::MoveToPreviousLine) ||
e->matches(QKeySequence::SelectPreviousLine)) {
if (!cur->currentLine())
return true;
quint64 prevline = cur->currentLine() - 1;
if (e->matches(QKeySequence::MoveToPreviousLine))
cur->moveTo(prevline, cur->currentColumn());
else
cur->select(prevline, cur->currentColumn());
} else if (e->matches(QKeySequence::MoveToNextPage) ||
e->matches(QKeySequence::SelectNextPage)) {
if (m_renderer->documentLastLine() == cur->currentLine())
return true;
quint64 pageline = std::min(m_renderer->documentLastLine(),
cur->currentLine() + this->visibleLines());
if (e->matches(QKeySequence::MoveToNextPage))
cur->moveTo(pageline, cur->currentColumn());
else
cur->select(pageline, cur->currentColumn());
} else if (e->matches(QKeySequence::MoveToPreviousPage) ||
e->matches(QKeySequence::SelectPreviousPage)) {
if (!cur->currentLine())
return true;
quint64 pageline =
std::max(quint64(0), cur->currentLine() - this->visibleLines());
if (e->matches(QKeySequence::MoveToPreviousPage))
cur->moveTo(pageline, cur->currentColumn());
else
cur->select(pageline, cur->currentColumn());
} else if (e->matches(QKeySequence::MoveToStartOfDocument) ||
e->matches(QKeySequence::SelectStartOfDocument)) {
if (!cur->currentLine())
return true;
if (e->matches(QKeySequence::MoveToStartOfDocument))
cur->moveTo(0, 0);
else
cur->select(0, 0);
} else if (e->matches(QKeySequence::MoveToEndOfDocument) ||
e->matches(QKeySequence::SelectEndOfDocument)) {
if (m_renderer->documentLastLine() == cur->currentLine())
return true;
if (e->matches(QKeySequence::MoveToEndOfDocument))
cur->moveTo(m_renderer->documentLastLine(),
m_renderer->documentLastColumn());
else
cur->select(m_renderer->documentLastLine(),
m_renderer->documentLastColumn());
} else if (e->matches(QKeySequence::MoveToStartOfLine) ||
e->matches(QKeySequence::SelectStartOfLine)) {
if (e->matches(QKeySequence::MoveToStartOfLine))
cur->moveTo(cur->currentLine(), 0);
else
cur->select(cur->currentLine(), 0);
} else if (e->matches(QKeySequence::MoveToEndOfLine) ||
e->matches(QKeySequence::SelectEndOfLine)) {
if (e->matches(QKeySequence::MoveToEndOfLine)) {
if (cur->currentLine() == m_renderer->documentLastLine())
cur->moveTo(cur->currentLine(), m_renderer->documentLastColumn());
else
cur->moveTo(cur->currentLine(), m_renderer->hexLineWidth() - 1, 0);
} else {
if (cur->currentLine() == m_renderer->documentLastLine())
cur->select(cur->currentLine(), m_renderer->documentLastColumn());
else
cur->select(cur->currentLine(), m_renderer->hexLineWidth() - 1, 0);
}
} else
return false;
return true;
}
bool QHexView::processTextInput(QHexCursor *cur, QKeyEvent *e) {
if (isReadOnly() || isLocked() || (e->modifiers() & Qt::ControlModifier))
return false;
uchar key = static_cast<uchar>(e->text()[0].toLatin1());
if ((m_renderer->selectedArea() == QHexRenderer::HexArea)) {
if (!((key >= '0' && key <= '9') ||
(key >= 'a' && key <= 'f'))) // Check if is a Hex Char
return false;
uchar val = uchar(QString(static_cast<char>(key)).toUInt(nullptr, 16));
m_document->removeSelection();
if (m_document->atEnd() ||
(cur->currentNibble() && !isKeepSize() &&
cur->insertionMode() == QHexCursor::InsertMode)) {
m_document->insert(cur->position().offset(), uchar(val << 4)); // X0 byte
this->moveNext();
return true;
}
uchar ch = uchar(m_document->at(int(cur->position().offset())));
if (cur->currentNibble()) // X0
val = uchar((ch & 0x0F) | (val << 4));
else // 0X
val = (ch & 0xF0) | val;
m_document->replace(cur->position().offset(), val);
this->moveNext();
return true;
}
if ((m_renderer->selectedArea() == QHexRenderer::AsciiArea)) {
if (!(key >= 0x20 && key <= 0x7E)) // Check if is a Printable Char
return false;
m_document->removeSelection();
if (!m_document->atEnd() &&
(cur->insertionMode() == QHexCursor::OverwriteMode))
m_document->replace(cur->position().offset(), key);
else
m_document->insert(cur->position().offset(), key);
QKeyEvent keyevent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier);
qApp->sendEvent(this, &keyevent);
return true;
}
return false;
}
void QHexView::adjustScrollBars() {
QScrollBar *vscrollbar = this->verticalScrollBar();
int sizeFactor = this->documentSizeFactor();
vscrollbar->setSingleStep(sizeFactor);
quint64 docLines = m_renderer->documentLines();
quint64 visLines = this->visibleLines();
// modified by wingsummer,fix the scrollbar bug
if (docLines > visLines && !m_document->isEmpty()) {
this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
vscrollbar->setMaximum(int((docLines - visLines) / uint(sizeFactor) + 1));
} else {
this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
vscrollbar->setValue(0);
vscrollbar->setMaximum(0);
}
QScrollBar *hscrollbar = this->horizontalScrollBar();
int documentWidth = m_renderer->documentWidth();
int viewportWidth = viewport()->width();
if (documentWidth > viewportWidth) {
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
// +1 to see the rightmost vertical line, +2 seems more pleasant to the eyes
hscrollbar->setMaximum(documentWidth - viewportWidth + 2);
} else {
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
hscrollbar->setValue(0);
hscrollbar->setMaximum(documentWidth);
}
}
void QHexView::renderLine(quint64 line) {
if (!this->isLineVisible(line))
return;
this->viewport()->update(
/*m_renderer->getLineRect(line, this->firstVisibleLine())*/);
}
quint64 QHexView::firstVisibleLine() const {
return quint64(this->verticalScrollBar()->value()) *
uint(documentSizeFactor());
}
quint64 QHexView::lastVisibleLine() const {
return this->firstVisibleLine() + this->visibleLines() - 1;
}
quint64 QHexView::visibleLines() const {
quint64 visLines =
quint64(std::ceil(this->height() / m_renderer->lineHeight()) -
m_renderer->headerLineCount());
return std::min(visLines, m_renderer->documentLines());
}
bool QHexView::isLineVisible(quint64 line) const {
if (!m_document)
return false;
if (line < this->firstVisibleLine())
return false;
if (line > this->lastVisibleLine())
return false;
return true;
}
int QHexView::documentSizeFactor() const {
int factor = 1;
if (m_document) {
quint64 docLines = m_renderer->documentLines();
if (docLines >= INT_MAX)
factor = int(docLines / INT_MAX) + 1;
}
return factor;
}

View File

@ -0,0 +1,102 @@
#ifndef QHEXVIEW_H
#define QHEXVIEW_H
#define QHEXVIEW_VERSION 3.0
#include "document/qhexdocument.h"
#include "document/qhexrenderer.h"
#include <QAbstractScrollArea>
#include <QTimer>
class QHexView : public QAbstractScrollArea {
Q_OBJECT
public:
explicit QHexView(QWidget *parent = nullptr);
QHexDocument *document();
void setDocument(QHexDocument *document);
/*=============================*/
// added by wingsummer
QHexRenderer *renderer();
void switchDocument(QHexDocument *document, QHexRenderer *renderer,
int vBarValue);
bool setLockedFile(bool b);
bool setKeepSize(bool b);
bool isReadOnly();
bool isKeepSize();
bool isLocked();
quint64 documentLines();
quint64 documentBytes();
quint64 currentRow();
quint64 currentColumn();
quint64 currentOffset();
quint64 selectlength();
void setAsciiVisible(bool b);
bool asciiVisible();
void setAddressVisible(bool b);
bool addressVisible();
void setHeaderVisible(bool b);
bool headerVisible();
quint64 addressBase();
void setAddressBase(quint64 base);
bool isModified();
static QFont getHexeditorFont();
signals:
void cursorLocationChanged();
void documentChanged();
void documentStatusChanged();
void documentSwitched();
/*=============================*/
protected:
virtual bool event(QEvent *e);
virtual void keyPressEvent(QKeyEvent *e);
virtual void mousePressEvent(QMouseEvent *e);
virtual void mouseMoveEvent(QMouseEvent *e);
virtual void mouseReleaseEvent(QMouseEvent *e);
virtual void focusInEvent(QFocusEvent *e);
virtual void focusOutEvent(QFocusEvent *e);
virtual void wheelEvent(QWheelEvent *e);
virtual void resizeEvent(QResizeEvent *e);
virtual void paintEvent(QPaintEvent *e);
private slots:
void renderCurrentLine();
void moveToSelection();
void blinkCursor();
private:
void moveNext(bool select = false);
void movePrevious(bool select = false);
private:
bool processMove(QHexCursor *cur, QKeyEvent *e);
bool processTextInput(QHexCursor *cur, QKeyEvent *e);
bool processAction(QHexCursor *cur, QKeyEvent *e);
void adjustScrollBars();
void renderLine(quint64 line);
quint64 firstVisibleLine() const;
quint64 lastVisibleLine() const;
quint64 visibleLines() const;
bool isLineVisible(quint64 line) const;
int documentSizeFactor() const;
QPoint absolutePosition(const QPoint &pos) const;
private:
QHexDocument *m_document;
QHexRenderer *m_renderer;
QTimer *m_blinktimer;
};
#endif // QHEXVIEW_H

134
WingHexExplorer/README.md Normal file
View File

@ -0,0 +1,134 @@
## WingHexExplorer
&emsp;&emsp;本软件是基于 QT 编写的十六进制编辑器,采用 C++ 进行开发,目的是让 Deepin 上具有强大而免费的十六进制编辑器。目前只有 010 Editor 具有强大的十六进制编辑功能,但它是商用的。关注我开发动态的应该知道我开发了在 Windows 上用 C# 开发的`WingSummer.WingCloudHexExplorer`,目的是方便专业人士修改分析 PE 文件,并可作为学习 PE 结构的重要辅助工具。该项目具有 31 个 Star 和 9 个 Fork ,我也不打算维护了,因为我主力系统不是 Windows ,也没有充分的资金支持,全是本人的一腔热血和一厢情愿。没有任何人参与该仓库任何形式的贡献,这或许就是在中国个人搞开源的现状吧。
## 鸣谢
&emsp;&emsp;在此之前鸣谢大家的支持和帮助,如下是参与贡献和进行打赏捐助的同志:
|昵称|方式|备注|
|:--:|:--:|:--:|
|神末shenmo|打赏捐助|Deepin 论坛|
|lv36|打赏捐助|Deepin 论坛|
### 软件架构
* TestPlugin : 虽然名字表面意思是测试插件,但它是编写该软件支持的插件一个非常重要的教程,重要性不可忽略。
* WingHexExplorer : 主程序,具有最基本的编辑十六进制编辑的能力,支持强大的插件系统,提供 GUI 交互。
* QHexView : 本软件十六进制编辑器的基础组件,仓库维护者`Dax89`,具体详情将在后面介绍。
* QHexEdit2 : 本软件打开超大文件模块相关代码,原打算使用该组件作为基础组件,但 Bug 多的我改不过来了,故弃用,保留了我所需关键代码,仓库维护者`Simsys`,具体详情将在后面介绍。
### 使用声明
1. 开发本软件目的是让 Deepin 上具有强大而免费的十六进制编辑器,同时也便于本人巩固或者学习 QT Linux 相关编程的知识。
2. 本软件仅供学习交流使用,不得私自用于商业用途。如需将本软件某些部分用于商业用途,必须找我购买商业授权,价格私聊。
3. 本人学生,由于本软件是用我的业余时间编写,不能及时修复 Bug 或者提供技术支持,请见谅。
4. 本人非计算机专业,编写程序难免有 Bug ,欢迎提交 PR 。
### 参与贡献
1. 如果您有想参与本软件代码开发递交,请在 pull request 联系我。
2. 本项目支持捐助,如有意愿请到本仓库通过微信或者支付宝的方式进行,一瓶水的价钱足以提高我的维护该项目的热情,感谢大家的支持。
3. 如果您想提交修复或者增进程序的代码,请在 pull request 递交。
4. 任何成功参与代码 Bug 修复以及增进程序功能的同志和 Sponsor ,都会在本仓库 ReadMe 和附属说明文件中体现,您如果是其中之一,本人可以按照您合理的意愿来进行说明。
**加入我们并不意味着就是代码的维护,你可以选择下列一项或多项进行参与:**
1. 代码维护:实现新功能或修复 BUG ,对代码进行维护和升级。
2. 文档编辑:主要是接口文档和教程需要撰写编辑,这很重要。
3. 参与讨论:主要是讨论本项目未来发展和方向等。
4. 编写插件:一起增强该软件的功能。
### 协议
&emsp;&emsp;本软件如果用于非商业用途,采用`WingSummer OpenSource Lincense`协议,对应的协议内容在仓库`OpenSource-LICENSE`文件。 **没有我的任何授权,不得将该软件用于任何形式的商业用途,包括我改良的部分,除非你直接使用原组件,不限于商业二次开发、换 UI 套壳、二手转卖等,我不允许任何人随意把我当作免费劳动力作为赚钱的工具!** 我的初衷是让 Linux 的生态更加完整,早日让祖国推动操作系统国产化。我不希望“吸血鬼”们利益归自己,脏活累活给开源,都那么理所当然,开源就是这么被败坏的。我不希望因为版权的事情牵扯了大量的精力。本人初次深入接触开源协议,不太会根据自己真正的需要来选择合适的协议,感谢`Deepin`前辈`BLumia`给我提供相关的建议和指导。由于本人一直在`README`一直强调商业用途相关事宜,本开源协议和我强调的内容相一致,故适用于目前所有本仓库的代码及其`fork`分支以及所有发行版。
&emsp;&emsp;如果你想将本软件或者本软件的部分代码用于商业用途,必须亲自咨询我,商讨商业授权相关事宜。如果得到授权则采用`WingSummer Commerical License`协议,也就是本仓库的`Commerical-LICENSE`文件的内容。
### issue 前必读
&emsp;&emsp;如果你有任何形式的建议,在提交 issue 之前,请一定要阅读下面的声明,以免浪费我们双方宝贵的时间:
1. 本人不考虑兼容 Windows 系统,虽然 QT 是跨平台的,但有些代码是依赖特定平台的,且十六进制编辑组件在 Windows 上会有一些已知问题,本人没有时间也没有义务来搞跨平台的东西。
2. 本人不考虑多语言支持,主要是没时间和资金。由于本人是中国人,本人不考虑其他语言使用者。但如果使用其他语言,如果你有语言包,只需要简单的替换文件即可。
3. 本人不考虑二进制安装包的分发,没时间和精力搞额外的东西。
4. 本人不考虑其他插件的开发,如果插件有使用问题,请联系开发者(不排除我会开发一些插件,这样可以直接联系我)。
5. 本人不考虑主题 UI 层面的问题,开发软件一切采用 DTK 原生样式,觉得丑找官方,或者自己写个样式编译加载。
6. 图标在暗黑模式下可能会有点丑不太明显我美工不好希望有同志能够提供一套图标不要有版权纷争的图标PR 给我进行审核采纳。但如果你没有,就不要给我提。
7. 本人仅仅考虑适配 Deepin 系统,虽然 Deepin 是目前基于 Debian ,基本所有的 Debian 甚至其他 Linux 系统理论上也可以用,但不排除有问题,如果出问题,我也不会进行修复。
&emsp;&emsp;上面一切的一切,如果你是志同道合的开源贡献者,欢迎 fork 我的仓库进行相应的维护!
&emsp;&emsp;如果出现比较严重的 Bug ,本人也可能不会及时的响应,目前我面临大学毕业的难题,顶着未来未知的压力和艰难的就业和研究生大军现状,谢绝站在道德的制高点不嫌冷的指指点点。
### 有关 QHexView
&emsp;&emsp;本软件基于`QHexView`作为十六进制编辑器为基础进行开发,本人在改组件基础上添加新功能和进行代码的深度定制。如下是原仓库的必要说明,详情请点击 [此链接](https://github.com/Dax89/QHexView/tree/master)
---
QHexView
========
QHexView is a hexadecimal widget for Qt5
Features
-----
- Customizable data backend (see more below).
- Document/View based.
- Unlimited Undo/Redo.
- Fully Customizable.
- Fast rendering.
- Easy to Use.
Buffer Backends
-----
These are the available buffer backends:
- QMemoryBuffer: A simple, flat memory array.
- QMemoryRefBuffer: QHexView just display the referenced data, editing is disabled.
It's also possible to create new data backends from scratch.
License
-----
QHexEdit is released under MIT license
---
&emsp;&emsp;本人对改组件的改进如下:
1. 增加有关描述文件状态相关的功能:指示是否被修改、是否具有可写权限、是否锁定文件以防修改、是否可以增改字节数
2. 增加可隐藏地址蓝栏和 ASCII 解码字符栏以及表头的功能
3. 实现超大文件超出2GB读写功能模块原组件并未实现此功能
4. 修改地址显示长度,以适应地址的使用习惯
5. 简化编码方式,删除一些冗余代码
6. 增加更多的信号,充分控制 QHexView 组件
7. 增加书签使用和管理功能
8. 修复滚动条有关内容完全仍能够显示但仍滚动内容的 Bug
9. 修复粘贴指针闪动位置保持不变问题,修改粘贴限制策略
### 有关 QHexEdit2
&emsp;&emsp;起初我打算使用`QHexEdit2`作为十六进制编辑器为基础进行开发,该组件虽然轻松打开超大文件,但是它的编辑功能能用是能用,但有很多大大小小的 Bug ,我还逐一修了修,但发现仅仅我的力量和时间是杯水车薪。然后我找到了`QHexView`,也就是上面所属的组件,但它有一个致命的缺陷,无法打开超大文件,被我 Pass 掉了,后来我尝试用了它,发现开发者在开发改组件是下了足够大的功夫的,编辑十分流畅。最近看到`QHexView`贡献者们想搞一个`QHexView 5.0`,对代码进行了重构,但并没有实现任何功能,差不多是个空空的框架,不过从接口看出更强大的易用性,这个是原组件所不具有的,这花费我比较多的时间来阅读源代码,并向外扩展接口以适应我的开发需求。
&emsp;&emsp;然后我想,既然`QHexEdit2`具有强大的打开文件的能力,而`QHexView`不具备,但它具有强大的编辑界面,于是乎,我移植`QHexEdit2`的打开超大文件的代码到`QHexView`当中,并做好了适配,但有一个 Bug :如果以大文件打开的方式来新建新文件,就无法插入新的字节,除非开头有一个字节。实际上,我们一般都是打开大文件,而不是新建一个超大文件来进行添加编辑(谁闲的没事干,手动打超过 2GB 字节的文件),所以我默认如果新建文件采用原组件原生模块,也就是无法存储超过`2GB`的。但如果你修复了改 Bug ,我会考虑支持新建超大文件这个选项。改仓库的链接: https://github.com/Simsys/qhexedit2 ,它的协议如下:
Copyright (C) 2015-2016 Winfried Simon
This software may be used under the terms of the GNU Lesser General
Public License version 2.1 as published by the Free Software Foundation
and appearing in the file license.txt included in the packaging of this file.
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 General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
## 其他
&emsp;&emsp;本篇仅仅是本软件的简介,具体请到我的仓库,一切以我的仓库说明为准: https://gitee.com/wingsummer/wing-hex-explorer

View File

@ -0,0 +1,51 @@
SOURCES += \
$$PWD/main.cpp \
$$PWD/dialog/mainwindow.cpp \
$$PWD/QHexEdit2/chunks.cpp \
$$PWD/class/appmanager.cpp \
$$PWD/control/gotobar.cpp \
$$PWD/settings.cpp \
$$PWD/dialog/finddialog.cpp \
$$PWD/dialog/pluginwindow.cpp \
$$PWD/plugin/pluginsystem.cpp \
$$PWD/dialog/metadialog.cpp \
$$PWD/dialog/driverselectordialog.cpp \
$$PWD/dialog/aboutsoftwaredialog.cpp \
$$PWD/dialog/sponsordialog.cpp \
$$PWD/class/logger.cpp \
$$PWD/winghexapplication.cpp \
$$PWD/settingdialog.cpp \
$$PWD/plugin/hexviewshadow.cpp \
$$PWD/dialog/encodingdialog.cpp \
$$PWD/class/workspacemanager.cpp
RESOURCES += resources.qrc
DISTFILES += \
README.md
HEADERS += \
$$PWD/dialog/mainwindow.h \
$$PWD/utilities.h \
$$PWD/QHexEdit2/chunks.h \
$$PWD/class/appmanager.h \
$$PWD/control/gotobar.h \
$$PWD/settings.h \
$$PWD/dialog/finddialog.h \
$$PWD/dialog/pluginwindow.h \
$$PWD/plugin/pluginsystem.h \
$$PWD/plugin/iwingplugin.h \
$$PWD/dialog/metadialog.h \
$$PWD/dialog/driverselectordialog.h \
$$PWD/dialog/aboutsoftwaredialog.h \
$$PWD/dialog/sponsordialog.h \
$$PWD/class/logger.h \
$$PWD/winghexapplication.h \
$$PWD/plugin/hexviewshadow.h \
$$PWD/dialog/encodingdialog.h \
$$PWD/class/workspacemanager.h
TRANSLATIONS += \
$$PWD/lang/zh.ts

View File

@ -0,0 +1,9 @@
QT += core gui dtkwidget dbus
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = WingHexExplorer
TEMPLATE = app
include($$PWD/QHexView/QHexView.pri)
include($$PWD/WingHexExplorer.pri)

View File

@ -0,0 +1,27 @@
#include "appmanager.h"
AppManager *AppManager::m_instance = nullptr;
MainWindow *AppManager::mWindow = nullptr;
AppManager::AppManager(QObject *parent) : QObject(parent) {}
AppManager *AppManager::instance() {
if (m_instance == nullptr) {
m_instance = new AppManager;
}
return m_instance;
}
void AppManager::openFiles(QStringList files) {
if (mWindow) {
for (auto file : files) {
if (mWindow->openWorkSpace(file) != ErrFile::Success)
mWindow->openFile(file);
}
//通过dbus接口从任务栏激活窗口
if (!Q_LIKELY(Utilities::activeWindowFromDock(mWindow->winId()))) {
mWindow->activateWindow();
}
}
}

View File

@ -0,0 +1,26 @@
#ifndef APPMANAGER_H
#define APPMANAGER_H
#include "./dialog/mainwindow.h"
#include <QObject>
// 参考Deepin 自带的文本编辑器的单例通信方式
class AppManager : public QObject {
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.Wingsummer.WingHexExplorer")
public:
static AppManager *instance();
explicit AppManager(QObject *parent = nullptr);
static MainWindow *mWindow;
private:
static AppManager *m_instance;
signals:
public slots:
Q_SCRIPTABLE void openFiles(QStringList files);
};
#endif // APPMANAGER_H

View File

@ -0,0 +1,14 @@
#include "logger.h"
Logger *Logger::instance = nullptr;
Logger::Logger(QObject *parent) : QObject(parent) { instance = this; }
void Logger::logMessage(QString msg) { emit log(msg); }
Logger *Logger::getInstance() {
if (instance == nullptr) {
instance = new Logger;
}
return instance;
}

View File

@ -0,0 +1,23 @@
#ifndef LOGGER_H
#define LOGGER_H
#include <QObject>
#define INFOLOG(msg) "<font color=\"green\">" + msg + "</font><br />"
#define ERRLOG(msg) "<font color=\"red\">" + msg + "</font><br />"
#define WARNLOG(msg) "<font color=\"yellow\">" + msg + "</font><br />"
class Logger : public QObject {
Q_OBJECT
public:
explicit Logger(QObject *parent = nullptr);
static Logger *getInstance();
void logMessage(QString msg);
signals:
void log(QString msg);
public slots:
private:
static Logger *instance;
};
#endif // LOGGER_H

View File

@ -0,0 +1,178 @@
#include "workspacemanager.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QMap>
WorkSpaceManager::WorkSpaceManager(QObject *parent) : QObject(parent) {}
bool WorkSpaceManager::loadWorkSpace(QString filename, QString &file,
QList<BookMarkStruct> &bookmarks,
QHash<quint64, QHexLineMetadata> &metas) {
QFile f(filename);
if (f.exists()) {
QJsonParseError err;
if (!f.open(QFile::ReadOnly))
return false;
QJsonDocument doc = QJsonDocument::fromJson(f.readAll(), &err);
f.close();
if (err.error == QJsonParseError::NoError) {
auto jobj = doc.object();
auto t = jobj.value("type");
if (!t.isUndefined() && t.isString()) {
auto type = t.toString();
if (!QString::compare(type, "workspace", Qt::CaseInsensitive)) {
auto ff = jobj.value("file");
if (!ff.isUndefined() && t.isString()) {
auto fi = ff.toString();
QFileInfo finfo(f);
file = fi[0] != '/' ? finfo.absoluteDir().path() + "/" + fi : fi;
auto values = jobj.value("metas");
if (!values.isUndefined() && values.isArray()) {
auto metaitems = values.toArray();
for (auto item : metaitems) {
if (!item.isUndefined() && item.isObject()) {
auto sitem = item.toObject();
auto ipos = sitem.value("pos");
if (!ipos.isUndefined() && ipos.isString()) {
bool b = false;
auto pos = ipos.toString().toULongLong(&b);
if (!b)
continue;
auto ivalues = sitem.value("value");
if (!ivalues.isUndefined() && ivalues.isArray()) {
QHexLineMetadata linemetas;
for (auto v : ivalues.toArray()) {
if (!v.isUndefined() && v.isObject()) {
auto linem = v.toObject();
auto line = linem.value("line");
auto start = linem.value("start");
auto length = linem.value("length");
auto comment = linem.value("comment");
auto fgcolor = linem.value("fgcolor");
auto bgcolor = linem.value("bgcolor");
if (!line.isUndefined() && line.isString() &&
!start.isUndefined() && start.isString() &&
!length.isUndefined() && length.isString() &&
!comment.isUndefined() && comment.isString() &&
!fgcolor.isUndefined() && fgcolor.isString() &&
!bgcolor.isUndefined() && bgcolor.isString()) {
auto nline = line.toString().toULongLong(&b);
if (!b)
continue;
auto nstart = start.toString().toInt(&b);
if (!b)
continue;
auto nlength = length.toString().toInt(&b);
if (!b)
continue;
auto nf = fgcolor.toString().toUInt(&b, 16);
if (!b)
continue;
auto nb = bgcolor.toString().toUInt(&b, 16);
if (!b)
continue;
auto fcolor = QColor::fromRgba(nf);
auto bcolor = QColor::fromRgba(nb);
QHexMetadataItem hmi;
hmi.line = nline;
hmi.start = nstart;
hmi.length = nlength;
hmi.comment = comment.toString();
hmi.foreground = fcolor;
hmi.background = bcolor;
linemetas.push_back(hmi);
}
}
}
if (!linemetas.size())
continue;
metas.insert(pos, linemetas);
}
}
}
}
}
values = jobj.value("bookmarks");
if (!values.isUndefined() && values.isArray()) {
for (auto item : values.toArray()) {
if (!item.isUndefined() && item.isObject()) {
auto sitem = item.toObject();
auto pos = sitem.value("pos");
auto comment = sitem.value("comment");
if (!pos.isUndefined() && pos.isString() &&
!comment.isUndefined() && comment.isString()) {
auto b = false;
auto ipos = pos.toString().toLongLong(&b);
if (!b)
continue;
BookMarkStruct book;
book.pos = ipos;
book.comment = comment.toString();
bookmarks.append(book);
}
}
}
}
return true;
}
}
}
}
}
return false;
}
bool WorkSpaceManager::saveWorkSpace(
QString filename, QString file, QList<BookMarkStruct> bookmarklist,
QHash<quint64, QHexLineMetadata> metalist) {
QFile f(filename);
if (f.open(QFile::WriteOnly)) {
QJsonObject jobj;
jobj.insert("type", "workspace");
if (file[0] == '/') {
QDir dir(QFileInfo(f).absoluteDir());
QFileInfo fi(file);
file = dir.relativeFilePath(fi.absoluteFilePath());
}
jobj.insert("file", file);
QJsonArray metas;
for (auto meta : metalist.keys()) {
QJsonObject i;
QJsonArray linemetas;
i.insert("pos", QString::number(meta));
for (auto line : metalist.value(meta)) {
QJsonObject lineobj;
lineobj.insert("line", QString::number(line.line));
lineobj.insert("start", QString::number(line.start));
lineobj.insert("length", QString::number(line.length));
lineobj.insert("comment", line.comment);
lineobj.insert("fgcolor", QString::number(line.foreground.rgba(), 16));
lineobj.insert("bgcolor", QString::number(line.background.rgba(), 16));
linemetas.append(lineobj);
}
i.insert("value", linemetas);
metas.append(i);
}
jobj.insert("metas", metas);
QJsonArray bookmarks;
for (auto item : bookmarklist) {
QJsonObject i;
i.insert("pos", QString::number(item.pos));
i.insert("comment", item.comment);
bookmarks.append(i);
}
jobj.insert("bookmarks", bookmarks);
QJsonDocument jdoc(jobj);
if (f.write(jdoc.toJson(QJsonDocument::JsonFormat::Indented)) >= 0) {
f.close();
return true;
}
}
return false;
}

View File

@ -0,0 +1,31 @@
#ifndef WORKSPACEMANAGER_H
#define WORKSPACEMANAGER_H
#include "QHexView/document/qhexdocument.h"
#include "QHexView/document/qhexmetadata.h"
#include <QHash>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QList>
#include <QObject>
#include <QStringList>
class WorkSpaceManager : public QObject {
Q_OBJECT
public:
explicit WorkSpaceManager(QObject *parent = nullptr);
bool static saveWorkSpace(QString filename, QString file,
QList<BookMarkStruct> bookmarks,
QHash<quint64, QHexLineMetadata> metas);
bool static loadWorkSpace(QString filename, QString &file,
QList<BookMarkStruct> &bookmarks,
QHash<quint64, QHexLineMetadata> &metas);
signals:
public slots:
};
#endif // WORKSPACEMANAGER_H

View File

@ -0,0 +1,198 @@
#include "gotobar.h"
#include "utilities.h"
#include <QShortcut>
const int nJumpLineBarWidth = 212;
const int nJumpLineBarHeight = 60;
GotoBar::GotoBar(QWidget *parent) : DFloatingWidget(parent) {
m_layout = new QHBoxLayout(this);
m_layout->setContentsMargins(20, 6, 20, 6);
m_close = new DIconButton(this);
m_close->setIcon(ICONRES("closefile"));
m_close->setFixedSize(25, 25);
m_layout->addWidget(m_close);
m_label = new QLabel(this);
m_label->setText(tr("Goto"));
m_editLine = new DLineEdit(this);
m_layout->addWidget(m_label);
m_layout->addWidget(m_editLine);
m_line = new DRadioButton(this);
m_line->setText(tr("Line"));
m_layout->addWidget(m_line);
m_offset = new DRadioButton(this);
m_offset->setText(tr("Offset"));
m_offset->setChecked(true);
m_layout->addWidget(m_offset);
m_goto = new DIconButton(this);
m_goto->setIcon(ICONRES("goto"));
m_goto->setFixedSize(50, 30);
m_layout->addWidget(m_goto);
this->setLayout(m_layout);
setFixedHeight(nJumpLineBarHeight);
connect(m_close, &DIconButton::clicked, this, &GotoBar::jumpCancel);
connect(m_editLine, &DLineEdit::returnPressed, this, &GotoBar::jumpConfirm);
connect(m_editLine, &DLineEdit::textChanged, this,
&GotoBar::handleLineChanged);
connect(m_goto, &DIconButton::clicked, this, &GotoBar::jumpConfirm);
auto sc = QKeySequence(Qt::Key_Escape);
m_close->setShortcut(sc);
QShortcut s(QKeySequence(Qt::Key_Escape), this);
s.setContext(Qt::ShortcutContext::WidgetShortcut);
}
void GotoBar::focus() { m_editLine->lineEdit()->setFocus(); }
bool GotoBar::isFocus() { return m_editLine->lineEdit()->hasFocus(); }
void GotoBar::activeInput(int oldrow, int oldcolumn, quint64 oldoffset,
quint64 maxfilebytes, int maxfilelines) {
m_rowBeforeJump = oldrow;
m_columnBeforeJump = oldcolumn;
m_oldFileOffsetBeforeJump = oldoffset;
m_maxFileBytes = maxfilebytes;
m_maxFilelines = maxfilelines;
auto edit = m_editLine->lineEdit();
edit->clear();
edit->setFocus();
setVisible(true);
}
void GotoBar::handleLineChanged() {
QString content = m_editLine->lineEdit()->text();
if (content != "") {
auto ps = SEEKPOS::Invaild;
auto isline = m_line->isChecked();
auto p = Convert2Pos(content, ps, isline);
if (ps != SEEKPOS::Invaild)
jumpToLine(p, isline);
else
m_editLine->showAlertMessage(tr("InvalidContent"), 1500);
}
}
void GotoBar::jumpCancel() {
jumpToLine(qlonglong(m_oldFileOffsetBeforeJump), false);
setVisible(false);
}
void GotoBar::jumpConfirm() {
handleLineChanged();
setVisible(false);
}
qint64 GotoBar::Convert2Pos(QString value, SEEKPOS &ps, bool isline) {
qint64 res = 0;
if (value.length() > 0) {
auto ch = value.at(0);
if (ch == '+') {
ps = SEEKPOS::Relative;
value = value.remove(0, 1);
bool ok = false;
res = value.toLongLong(&ok, 0);
if (!ok) {
ps = SEEKPOS::Invaild;
} else {
if (isline) {
if (res + m_rowBeforeJump > m_maxFilelines) {
ps = SEEKPOS::Invaild;
res = 0;
} else {
res += m_rowBeforeJump;
}
} else {
if (qulonglong(res) + m_oldFileOffsetBeforeJump > m_maxFileBytes) {
ps = SEEKPOS::Invaild;
res = 0;
} else {
res += m_oldFileOffsetBeforeJump;
}
}
}
} else if (ch == '-') {
ps = SEEKPOS::Relative;
value = value.remove(0, 1);
bool ok = false;
res = value.toLongLong(&ok, 0);
if (!ok) {
ps = SEEKPOS::Invaild;
} else {
if (isline) {
if (res - m_rowBeforeJump < 0) {
ps = SEEKPOS::Invaild;
res = 0;
} else {
res -= m_rowBeforeJump;
}
} else {
if (qlonglong(m_oldFileOffsetBeforeJump) - res < 0) {
ps = SEEKPOS::Invaild;
res = 0;
} else {
res = qlonglong(m_oldFileOffsetBeforeJump) - res;
}
}
}
} else if (ch == '<') {
ps = SEEKPOS::End;
value = value.remove(0, 1);
bool ok = false;
res = value.toLongLong(&ok, 0);
if (!ok || res < 0) {
ps = SEEKPOS::Invaild;
} else {
if (isline) {
if (m_maxFilelines - res < 0) {
ps = SEEKPOS::Invaild;
res = 0;
} else {
res = m_maxFilelines - res;
}
} else {
if (qlonglong(m_maxFileBytes) - res < 0) {
ps = SEEKPOS::Invaild;
res = 0;
} else {
res = qlonglong(m_maxFileBytes) - res;
}
}
}
} else {
ps = SEEKPOS::Start;
bool ok = false;
res = value.toInt(&ok, 0);
if (!ok) {
ps = SEEKPOS::Invaild;
} else {
if (res < 0 || quint64(res) > (isline ? quint64(m_maxFilelines)
: m_maxFileBytes)) {
ps = SEEKPOS::Invaild;
res = 0;
}
}
}
}
return res;
}

View File

@ -0,0 +1,58 @@
#ifndef GOTOBAR_H
#define GOTOBAR_H
#include <DFloatingWidget>
#include <DIconButton>
#include <DLineEdit>
#include <DRadioButton>
#include <QFile>
#include <QHBoxLayout>
#include <QLabel>
#include <QObject>
#include <QPushButton>
DWIDGET_USE_NAMESPACE
enum SEEKPOS { Invaild, Start, End, Relative };
class GotoBar : public DFloatingWidget {
Q_OBJECT
public:
GotoBar(QWidget *parent = nullptr);
public slots:
void focus();
bool isFocus();
void activeInput(int oldrow, int oldcolumn, quint64 oldoffset,
quint64 maxfilebytes, int maxfilelines);
void handleLineChanged();
void jumpCancel();
void jumpConfirm();
signals:
void jumpToLine(qlonglong pos, bool isline);
void pressEsc();
private:
DIconButton *m_close;
DIconButton *m_goto;
DLineEdit *m_editLine;
QHBoxLayout *m_layout;
DRadioButton *m_line;
DRadioButton *m_offset;
QLabel *m_label;
quint64 m_oldFileOffsetBeforeJump;
quint64 m_maxFileBytes;
int m_maxFilelines;
int m_rowBeforeJump;
int m_columnBeforeJump;
private:
qint64 Convert2Pos(QString value, SEEKPOS &ps, bool isline);
};
#endif // GOTOBAR_H

View File

@ -0,0 +1,23 @@
#include "aboutsoftwaredialog.h"
#include <DLabel>
#include <DTextBrowser>
#include <QPixmap>
AboutSoftwareDialog::AboutSoftwareDialog(DMainWindow *parent)
: DDialog(parent) {
QPixmap pic;
pic.load(":/images/author.jpg");
auto l = new DLabel(this);
l->setFixedSize(100, 100);
l->setScaledContents(true);
l->setPixmap(pic);
addContent(l, Qt::AlignHCenter);
addSpacing(10);
auto b = new DTextBrowser(this);
b->setSearchPaths(QStringList({":/resources", ":/images"}));
b->setSource(QUrl("README.md"), QTextDocument::MarkdownResource);
b->setFixedSize(800, 500);
b->setOpenExternalLinks(true);
addContent(b);
}

View File

@ -0,0 +1,20 @@
#ifndef ABOUTSOFTWAREDIALOG_H
#define ABOUTSOFTWAREDIALOG_H
#include <DDialog>
#include <DMainWindow>
#include <QObject>
DWIDGET_USE_NAMESPACE
class AboutSoftwareDialog : public DDialog {
Q_OBJECT
public:
explicit AboutSoftwareDialog(DMainWindow *parent = nullptr);
signals:
public slots:
};
#endif // ABOUTSOFTWAREDIALOG_H

View File

@ -0,0 +1,71 @@
#include "driverselectordialog.h"
#include "utilities.h"
#include <DDialogButtonBox>
#include <DLabel>
#include <QShortcut>
DriverSelectorDialog::DriverSelectorDialog(DMainWindow *parent)
: DDialog(parent) {
setWindowTitle(tr("OpenDriver"));
drivers = new DListWidget(this);
drivers->setSortingEnabled(false);
QStorageInfo si;
auto ico = ICONRES("opendriver");
auto infos = si.mountedVolumes();
addContent(new DLabel("PleaseChooseDriver", this));
addSpacing(5);
for (auto item : infos) {
if (item.device()[0] == '/') {
drivers->addItem(new QListWidgetItem(ico, item.device()));
m_infos.push_back(item);
}
}
addContent(drivers);
addSpacing(5);
infob = new DTextBrowser(this);
addContent(infob);
addSpacing(5);
addContent(new DLabel(tr("DriverTips"), this));
addSpacing(5);
auto dbbox =
new DDialogButtonBox(DDialogButtonBox::Ok | DDialogButtonBox::Cancel);
connect(dbbox, &DDialogButtonBox::accepted, this,
&DriverSelectorDialog::on_accepted);
connect(dbbox, &DDialogButtonBox::rejected, this,
&DriverSelectorDialog::on_rejected);
addContent(dbbox);
auto key = QKeySequence(Qt::Key_Return);
auto s = new QShortcut(key, this);
connect(s, &QShortcut::activated, this, &DriverSelectorDialog::on_accepted);
connect(drivers, &QListWidget::itemSelectionChanged, this,
&DriverSelectorDialog::on_list_selectionChanged);
}
void DriverSelectorDialog::on_list_selectionChanged() {
infob->clear();
#define Info(mem, info) infob->append(mem + " : " + info)
auto item = m_infos.at(drivers->currentRow());
Info(tr("device"), item.device());
Info(tr("displayName"), item.displayName());
Info(tr("fileSystemType"), item.fileSystemType());
Info(tr("name"), item.name());
if (item.isReady()) {
Info(tr("isReady"), "True");
Info(tr("bytesAvailable"),
Utilities::ProcessBytesCount(item.bytesAvailable()));
Info(tr("bytesTotal"), Utilities::ProcessBytesCount(item.bytesTotal()));
} else {
Info(tr("isReady"), "False");
}
}
void DriverSelectorDialog::on_accepted() {
m_si = m_infos.at(drivers->currentRow());
done(1);
}
void DriverSelectorDialog::on_rejected() { done(0); }
QStorageInfo DriverSelectorDialog::GetResult() { return m_si; }

View File

@ -0,0 +1,32 @@
#ifndef DRIVERSELECTORDIALOG_H
#define DRIVERSELECTORDIALOG_H
#include <DDialog>
#include <DListWidget>
#include <DMainWindow>
#include <DTextBrowser>
#include <QList>
#include <QObject>
#include <QStorageInfo>
DWIDGET_USE_NAMESPACE
class DriverSelectorDialog : public DDialog {
Q_OBJECT
public:
DriverSelectorDialog(DMainWindow *parent = nullptr);
QStorageInfo GetResult();
private:
DListWidget *drivers;
DTextBrowser *infob;
QList<QStorageInfo> m_infos;
QStorageInfo m_si;
void on_list_selectionChanged();
void on_accepted();
void on_rejected();
};
#endif // DRIVERSELECTORDIALOG_H

View File

@ -0,0 +1,44 @@
#include "encodingdialog.h"
#include "utilities.h"
#include <DLabel>
#include <DPushButton>
#include <QAction>
#include <QListWidgetItem>
#include <QShortcut>
EncodingDialog::EncodingDialog(DMainWindow *parent) {
Q_UNUSED(parent);
this->setWindowTitle(tr("Encoding"));
this->setFixedSize(500, 600);
auto l = new DLabel(tr("ChooseEncoding"), this);
addContent(l);
addSpacing(5);
enclist = new DListWidget(this);
for (auto item : Utilities::GetEncodings()) {
enclist->addItem(item);
}
addContent(enclist);
addSpacing(10);
auto dbbox = new DDialogButtonBox(
DDialogButtonBox::Ok | DDialogButtonBox::Cancel, this);
connect(dbbox, &DDialogButtonBox::accepted, this, &EncodingDialog::on_accept);
connect(dbbox, &DDialogButtonBox::rejected, this, &EncodingDialog::on_reject);
auto key = QKeySequence(Qt::Key_Return);
auto s = new QShortcut(key, this);
connect(s, &QShortcut::activated, this, &EncodingDialog::on_accept);
addContent(dbbox);
}
QString EncodingDialog::getResult() { return result; }
void EncodingDialog::on_accept() {
auto s = enclist->selectedItems();
if (s.count() > 0) {
result = s.first()->text();
done(1);
} else {
done(0);
}
}
void EncodingDialog::on_reject() { done(0); }

View File

@ -0,0 +1,27 @@
#ifndef ENCODINGDIALOG_H
#define ENCODINGDIALOG_H
#include <DDialog>
#include <DDialogButtonBox>
#include <DListWidget>
#include <DMainWindow>
#include <QTextCodec>
DWIDGET_USE_NAMESPACE
class EncodingDialog : public DDialog {
Q_OBJECT
public:
EncodingDialog(DMainWindow *parent = nullptr);
QString getResult();
private:
void on_accept();
void on_reject();
private:
DListWidget *enclist;
QString result;
};
#endif // ENCODINGDIALOG_H

View File

@ -0,0 +1,116 @@
#include "finddialog.h"
#include "utilities.h"
#include <DButtonBox>
#include <DDialogButtonBox>
#include <DPushButton>
#include <QShortcut>
#include <QTextCodec>
FindDialog::FindDialog(bool sel, DMainWindow *parent) : DDialog(parent) {
this->setFixedSize(500, 600);
this->setWindowTitle(tr("find"));
m_string = new DRadioButton(this);
m_string->setText(tr("findstring"));
addContent(m_string);
addSpacing(3);
m_encodings = new DComboBox(this);
m_encodings->addItems(Utilities::GetEncodings());
m_encodings->setCurrentIndex(0);
m_encodings->setEnabled(false);
connect(m_string, &DRadioButton::toggled, m_encodings,
&DComboBox::setEnabled);
addContent(m_encodings);
addSpacing(3);
m_lineeditor = new DLineEdit(this);
m_lineeditor->setEnabled(false);
connect(m_string, &DRadioButton::toggled, m_lineeditor,
&DLineEdit::setEnabled);
addContent(m_lineeditor);
addSpacing(3);
m_hex = new DRadioButton(this);
m_hex->setText(tr("findhex"));
addContent(m_hex);
addSpacing(3);
m_hexeditor = new QHexView(this);
m_hexeditor->setAsciiVisible(false);
m_hexeditor->setAddressVisible(false);
m_hexeditor->setEnabled(true);
connect(m_hex, &DRadioButton::toggled, m_hexeditor, &QHexView::setEnabled);
addContent(m_hexeditor);
addSpacing(10);
m_hex->setChecked(true);
auto group = new DButtonBox(this);
QList<DButtonBoxButton *> blist;
auto b = new DButtonBoxButton(tr("BeforeCursor"), this);
connect(b, &DButtonBoxButton::toggled, [=](bool b) {
if (b)
_dir = SearchDirection::Foreword;
});
blist.push_back(b);
b = new DButtonBoxButton(tr("AfterCursor"), this);
connect(b, &DButtonBoxButton::toggled, [=](bool b) {
if (b)
_dir = SearchDirection::Backword;
});
blist.push_back(b);
b = new DButtonBoxButton(tr("Selection"), this);
if (sel) {
connect(b, &DButtonBoxButton::toggled, [=](bool b) {
if (b)
_dir = SearchDirection::Selection;
});
} else {
b->setEnabled(false);
}
blist.push_back(b);
b = new DButtonBoxButton(tr("None"), this);
connect(b, &DButtonBoxButton::toggled, [=](bool b) {
if (b)
_dir = SearchDirection::None;
});
blist.push_front(b);
group->setButtonList(blist, true);
b->setChecked(true);
addContent(group);
addSpacing(20);
auto dbbox = new DDialogButtonBox(
DDialogButtonBox::Ok | DDialogButtonBox::Cancel, this);
connect(dbbox, &DDialogButtonBox::accepted, this, &FindDialog::on_accept);
connect(dbbox, &DDialogButtonBox::rejected, this, &FindDialog::on_reject);
auto key = QKeySequence(Qt::Key_Return);
auto s = new QShortcut(key, this);
connect(s, &QShortcut::activated, this, &FindDialog::on_accept);
addContent(dbbox);
}
QByteArray FindDialog::getResult(SearchDirection &dir) {
dir = _dir;
return _findarr;
}
void FindDialog::on_accept() {
if (m_string->isChecked()) {
auto en = QTextCodec::codecForName(m_encodings->currentText().toUtf8());
auto e = en->makeEncoder();
_findarr = e->fromUnicode(m_lineeditor->text());
} else {
_findarr =
m_hexeditor->document()->read(0, int(m_hexeditor->documentBytes()));
}
done(1);
}
void FindDialog::on_reject() {
_findarr.clear();
done(0);
}

View File

@ -0,0 +1,37 @@
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
#include "./QHexView/qhexview.h"
#include <DComboBox>
#include <DDialog>
#include <DLineEdit>
#include <DMainWindow>
#include <DRadioButton>
#include <QObject>
DWIDGET_USE_NAMESPACE
enum class SearchDirection { None, Foreword, Backword, Selection };
class FindDialog : public DDialog {
Q_OBJECT
public:
FindDialog(bool sel = true, DMainWindow *parent = nullptr);
QByteArray getResult(SearchDirection &dir);
private:
void on_accept();
void on_reject();
private:
QHexView *m_hexeditor;
DLineEdit *m_lineeditor;
DRadioButton *m_string;
DRadioButton *m_hex;
DComboBox *m_encodings;
QByteArray _findarr;
SearchDirection _dir = SearchDirection::None;
};
#endif // FINDDIALOG_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,281 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "QHexView/document/qhexdocument.h"
#include "QHexView/qhexview.h"
#include "class/logger.h"
#include "class/workspacemanager.h"
#include "control/gotobar.h"
#include "plugin/pluginsystem.h"
#include "settings.h"
#include "utilities.h"
#include <DApplicationHelper>
#include <DDockWidget>
#include <DIconButton>
#include <DLabel>
#include <DLineEdit>
#include <DMainWindow>
#include <DMenu>
#include <DMenuBar>
#include <DStatusBar>
#include <DTabBar>
#include <DTableWidget>
#include <DToolBar>
#include <QFile>
#include <QList>
#include <QMutex>
#include <QObject>
#include <QPixmap>
#include <QPoint>
#include <QTextBrowser>
#include <QVBoxLayout>
#include <QWidget>
DWIDGET_USE_NAMESPACE
class MainWindow : public DMainWindow {
Q_OBJECT
enum NumTableIndex {
Byte,
Char,
Ushort,
Short,
Uint32,
Int32,
Uint64,
Int64,
NumTableIndexCount
};
enum class ToolBoxIndex {
New,
OpenFile,
OpenDriver,
Save,
SaveAs,
SaveSel,
Export,
OpenWorkSpace,
SaveWorkSpace,
SaveAsWorkSpace,
Undo,
Redo,
Cut,
CutHex,
Copy,
CopyHex,
Paste,
PasteHex,
Del,
Find,
Goto,
Fill,
FillNop,
FillZero,
Meta,
DelMeta,
ClsMeta,
BookMark,
DelBookMark,
ClsBookMark,
Encoding
};
public:
MainWindow(DMainWindow *parent = nullptr);
~MainWindow() override;
protected:
void showEvent(QShowEvent *event) override;
void closeEvent(QCloseEvent *event) override;
private slots:
void on_hexeditor_customContextMenuRequested(const QPoint &pos);
void on_tabs_currentChanged(int index);
private:
QWidget *w;
DTabBar *tabs;
DToolBar *toolbar;
QVBoxLayout *vlayout;
DStatusBar *status;
DLabel *lblloc;
DLabel *lblsellen;
// DDockWidget *dw;
DMenu *hexeditorMenu;
DMenu *findresultMenu;
QAction *settingplg;
private:
QHexView *hexeditor;
QFile file;
GotoBar *gotobar;
private:
void setTheme(DGuiApplicationHelper::ColorType theme);
public:
ErrFile openFile(QString filename, bool readonly = false,
QString workspace = "");
ErrFile openWorkSpace(QString filename);
private:
void newFile();
ErrFile openDriver(QString driver);
ErrFile closeFile(int index, bool force = false);
ErrFile saveFile(int index);
ErrFile exportFile(QString filename, int index);
ErrFile saveasFile(QString filename, int index);
ErrFile closeCurrentFile(bool force = false);
ErrFile saveCurrentFile();
bool isModified(int index);
void FindFileBytes(int index, QByteArray arr, QList<int> &indices);
void FindAllBytes(QByteArray arr, QList<FindResult> &res);
void gotoFileLine(int index, quint64 offset);
void gotoCurrentLine(quint64 offset);
void undoCurrent();
void setEditModeEnabled(bool b, bool isdriver = false);
void redoCurrent();
void undoFile(int index);
void redoFile(int index);
void copyFileBytes(int index, quint64 pos, qint64 len, QByteArray &arr);
void copyCurrentBytes(quint64 pos, qint64 len, QByteArray &arr);
void cutFileBytes(int index, quint64 pos, qint64 len, QByteArray &arr);
void cutCurrentBytes(quint64 pos, qint64 len, QByteArray &arr);
void pasteFileBytes(int index, QByteArray arr, qint64 len = -1);
void pasteCurrentBytes(quint64 pos, QByteArray arr, qint64 len = -1);
bool saveWorkSpace();
bool saveAsWorkSpace(QString filename);
private:
void setFilePage(int index);
void on_newfile();
void on_openfile();
void on_redofile();
void on_undofile();
void on_copyfile();
void on_copyhex();
void on_pastehex();
void on_exportfile();
void on_cutfile();
void on_cuthex();
void on_savesel();
void on_delete();
void on_pastefile();
void on_gotoline();
void on_findfile();
void on_tabCloseRequested(int index);
void on_tabAddRequested();
void on_tabMoved(int from, int to);
void on_opendriver();
void on_savefile();
void on_saveasfile();
void on_exit();
void on_setting_general();
void on_setting_plugin();
void on_gotobar(int pos, bool isline);
void on_locChanged();
void on_documentChanged();
void on_documentSwitched();
void on_documentStatusChanged();
void on_metadata();
void on_metadatadel();
void on_metadatacls();
void on_bookmark();
void on_bookmarkdel();
void on_bookmarkcls();
void on_restoreLayout();
void on_about();
void on_sponsor();
void on_fillnop();
void on_fillzero();
void on_fill();
void on_exportfindresult();
void on_clearfindresult();
void on_loadplg();
void on_encoding();
void on_openworkspace();
void on_saveworkspace();
void on_saveasworkspace();
private:
QList<HexFile> hexfiles;
QMap<ToolBoxIndex, QAction *> toolbartools;
QMap<ToolBoxIndex, QAction *> toolmenutools;
QMap<ToolBoxIndex, QAction *> conmenutools;
uint defaultindex = 1; //表示新建使用的累计索引
int _currentfile = -1; //表示正在使用文件的索引,编辑器使用
int _pcurfile = -1; //表示正在使用文件的索引,插件使用
Settings *m_settings;
PluginSystem *plgsys;
private:
void PluginMenuNeedAdd(QMenu *menu);
void PluginDockWidgetAdd(QDockWidget *dockw, Qt::DockWidgetArea align);
void connectShadow(HexViewShadow *shadow);
void connectShadowSlot(HexViewShadow *shadow);
// shadow
bool shadowIsValid(IWingPlugin *plugin);
bool shadowControl(IWingPlugin *plugin);
bool shadowRelease(IWingPlugin *plugin);
void shadowDestory(IWingPlugin *plugin);
void enableDirverLimit(bool b);
private:
DMenu *plgmenu;
DMenu *toolmenu;
QMutex mutex;
DIconButton *iSetBaseAddr;
DIconButton *iColInfo;
DIconButton *iHeaderInfo;
DIconButton *iAsciiString;
DLabel *iReadWrite;
DLabel *iSaved;
DIconButton *iLocked;
DIconButton *iOver;
QPixmap infoSaved;
QPixmap infoUnsaved;
QPixmap infoSaveg;
QPixmap infoReadonly;
QPixmap infoWriteable;
QPixmap inforwg;
QIcon infoCanOver;
QIcon infoCannotOver;
QIcon infoOverg;
QIcon infoLock;
QIcon infoUnLock;
QIcon infoLockg;
QTextBrowser *pluginInfo;
DTableWidget *numshowtable;
DTableWidget *findresult;
DListWidget *bookmarks;
QTableWidgetItem *numsitem = nullptr;
QTableWidgetItem (*findresitem)[3] = {nullptr};
Logger *logger;
private:
// hexview default setting
bool _showheader = true;
bool _showaddr = true;
bool _showascii = true;
QFont _font;
QFont _hexeditorfont;
QString _windowmode;
QString _encoding;
bool _enableplugin = true;
bool _rootenableplugin = false;
int _findmax = 100;
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,105 @@
#include "metadialog.h"
#include <DDialogButtonBox>
#include <QShortcut>
MetaDialog::MetaDialog(DMainWindow *parent) : DDialog(parent) {
setWindowTitle(tr("Metadata"));
cforeground = new DCheckBox(this);
cforeground->setText(tr("foreground"));
addContent(cforeground);
addSpacing(2);
iforeground = new DPushButton(this);
iforeground->setText(tr("foreground"));
iforeground->setEnabled(false);
addContent(iforeground);
addSpacing(2);
cbackground = new DCheckBox(this);
cbackground->setText(tr("background"));
addContent(cbackground);
addSpacing(2);
ibackground = new DPushButton(this);
ibackground->setText(tr("background"));
ibackground->setEnabled(false);
addContent(ibackground);
addSpacing(2);
ccomment = new DCheckBox(this);
ccomment->setText(tr("comment"));
addContent(ccomment);
addSpacing(2);
m_comment = new DLineEdit(this);
addContent(m_comment);
m_comment->setEnabled(false);
addSpacing(5);
auto dbbox = new DDialogButtonBox(
DDialogButtonBox::Ok | DDialogButtonBox::Cancel, this);
addContent(dbbox);
addSpacing(2);
connect(cforeground, &DCheckBox::clicked, iforeground,
&DPushButton::setEnabled);
connect(cbackground, &DCheckBox::clicked, ibackground,
&DPushButton::setEnabled);
connect(ccomment, &DCheckBox::clicked, m_comment, &DPushButton::setEnabled);
connect(iforeground, &DPushButton::clicked, [=] {
QColorDialog cd;
if (cd.exec()) {
QPalette pe;
pe.setColor(QPalette::ButtonText, cd.currentColor());
iforeground->setPalette(pe);
_foreground = cd.currentColor();
}
});
connect(ibackground, &DPushButton::clicked, [=] {
QColorDialog cd;
if (cd.exec()) {
QPalette pe;
pe.setColor(QPalette::ButtonText, cd.currentColor());
ibackground->setPalette(pe);
_background = cd.currentColor();
}
});
connect(dbbox, &DDialogButtonBox::accepted, this, &MetaDialog::on_accept);
connect(dbbox, &DDialogButtonBox::rejected, this, &MetaDialog::on_reject);
auto key = QKeySequence(Qt::Key_Return);
auto s = new QShortcut(key, this);
connect(s, &QShortcut::activated, this, &MetaDialog::on_accept);
}
void MetaDialog::on_accept() {
_comment = ccomment->text();
done(1);
}
void MetaDialog::on_reject() { done(0); }
QString MetaDialog::comment() {
if (ccomment->isChecked())
return m_comment->text();
else
return "";
}
QColor MetaDialog::foreGroundColor() {
if (cforeground->isChecked())
return _foreground;
else
return QColor::fromRgba(qRgba(0, 0, 0, 0));
}
QColor MetaDialog::backGroundColor() {
if (cbackground->isChecked())
return _background;
else
return QColor::fromRgba(qRgba(0, 0, 0, 0));
}

View File

@ -0,0 +1,44 @@
#ifndef METADIALOG_H
#define METADIALOG_H
#include <DCheckBox>
#include <DColorDialog>
#include <DDialog>
#include <DLabel>
#include <DLineEdit>
#include <DMainWindow>
#include <DPushButton>
#include <QColor>
#include <QObject>
#include <QPalette>
DWIDGET_USE_NAMESPACE
class MetaDialog : public DDialog {
Q_OBJECT
public:
explicit MetaDialog(DMainWindow *parent = nullptr);
QColor foreGroundColor();
QColor backGroundColor();
QString comment();
void setForeGroundColor(QColor color);
void setBackGroundColor(QColor color);
void setComment(QString comment);
signals:
private:
void on_accept();
void on_reject();
private:
DCheckBox *cforeground, *cbackground, *ccomment;
DLineEdit *m_comment;
DPushButton *iforeground, *ibackground;
QColor _foreground;
QColor _background;
QString _comment;
};
#endif // METADIALOG_H

View File

@ -0,0 +1,43 @@
#include "pluginwindow.h"
#include "utilities.h"
#include <DLabel>
#include <QListWidgetItem>
PluginWindow::PluginWindow(DMainWindow *parent) : DDialog(parent) {
this->setFixedSize(500, 600);
this->setWindowTitle(tr("plugin"));
plglist = new DListWidget(this);
plglist->setFixedHeight(200);
this->addContent(plglist);
txtb = new DTextBrowser(this);
this->addContent(txtb);
connect(plglist, &QListWidget::itemSelectionChanged, this,
&PluginWindow::on_list_selchanged);
}
PluginWindow::~PluginWindow() {}
void PluginWindow::setPluginSystem(PluginSystem *pluginsys) {
m_pluginsys = pluginsys;
auto pico = ICONRES("plugin");
for (auto item : pluginsys->plugins()) {
plglist->addItem(new QListWidgetItem(pico, item->pluginName()));
}
}
void PluginWindow::on_list_selchanged() {
txtb->clear();
#define Info(mem, info) txtb->append(mem + " : " + info)
auto plg = m_pluginsys->plugins().at(plglist->currentRow());
Info(tr("pluginName"), plg->pluginName());
Info(tr("pluginAuthor"), plg->pluginAuthor());
Info(tr("pluginVersion"), QString::number(plg->pluginVersion()));
Info(tr("pluginComment"), plg->comment());
Info(tr("PUID"), plg->puid());
int i = 0;
Info(tr("optionalInfos"), "");
for (auto item : plg->optionalInfos()) {
Info(QString::number(i), item.toString());
}
}

View File

@ -0,0 +1,29 @@
#ifndef PLUGINWINDOW_H
#define PLUGINWINDOW_H
#include "plugin/pluginsystem.h"
#include <DDialog>
#include <DListWidget>
#include <DMainWindow>
#include <DTextBrowser>
#include <QObject>
#include <QWidget>
DWIDGET_USE_NAMESPACE
class PluginWindow : public DDialog {
Q_OBJECT
public:
PluginWindow(DMainWindow *parent = nullptr);
void setPluginSystem(PluginSystem *pluginsys);
~PluginWindow();
private:
PluginSystem *m_pluginsys;
DListWidget *plglist;
DTextBrowser *txtb;
void on_list_selchanged();
};
#endif // PLUGINWINDOW_H

View File

@ -0,0 +1,3 @@
#include "settingwindow.h"
SettingWindow::SettingWindow(DMainWindow *parent) {}

View File

@ -0,0 +1,17 @@
#ifndef SETTINGWINDOW_H
#define SETTINGWINDOW_H
#include <DDialog>
#include <DMainWindow>
#include <DSettingsDialog>
#include <QObject>
DWIDGET_USE_NAMESPACE
class SettingWindow : public DSettingsDialog {
Q_OBJECT
public:
SettingWindow(DMainWindow *parent = nullptr);
};
#endif // SETTINGWINDOW_H

View File

@ -0,0 +1,17 @@
#include "sponsordialog.h"
#include <DLabel>
#include <QPixmap>
SponsorDialog::SponsorDialog(DMainWindow *parent) : DDialog(parent) {
setWindowTitle(tr("Sponsor"));
addSpacing(5);
addContent(new DLabel(tr("ThanksForSponsor"), this), Qt::AlignHCenter);
addSpacing(5);
QPixmap sponsor(":/resources/sponsor.png");
auto l = new DLabel(this);
l->setPixmap(sponsor);
l->setScaledContents(true);
addContent(l);
}

View File

@ -0,0 +1,19 @@
#ifndef SPONSORDIALOG_H
#define SPONSORDIALOG_H
#include <DDialog>
#include <DMainWindow>
#include <QObject>
DWIDGET_USE_NAMESPACE
class SponsorDialog : public DDialog {
Q_OBJECT
public:
explicit SponsorDialog(DMainWindow *parent = nullptr);
signals:
public slots:
};
#endif // SPONSORDIALOG_H

BIN
WingHexExplorer/images/author.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
WingHexExplorer/images/author.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
WingHexExplorer/images/copy.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
WingHexExplorer/images/cut.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
WingHexExplorer/images/cuthex.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
WingHexExplorer/images/del.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
WingHexExplorer/images/edit.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
WingHexExplorer/images/exit.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
WingHexExplorer/images/export.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
WingHexExplorer/images/file.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
WingHexExplorer/images/fill.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
WingHexExplorer/images/find.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
WingHexExplorer/images/goto.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
WingHexExplorer/images/jmp.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
WingHexExplorer/images/layout.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Some files were not shown because too many files have changed in this diff Show More