initial commit
21
Jenkinsfile
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
pipeline {
|
||||
agent {
|
||||
docker {
|
||||
image 'maven:3-jdk-11'
|
||||
args '-v /home/docker/jenkins/files/m2:/root/.m2'
|
||||
}
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'mvn -B -DskipTests clean package'
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
archiveArtifacts artifacts: 'target/*-jar-with-dependencies.jar', onlyIfSuccessful: true
|
||||
}
|
||||
}
|
||||
}
|
674
LICENSE
Normal file
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"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. 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.
|
||||
|
||||
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 charge any price or no price for each copy that you convey,
|
||||
and 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 convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
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 except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
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 28 March 2007.
|
||||
|
||||
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 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 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. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "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 the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General 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
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
16
README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# konogonka
|
||||
|
||||
Deep WIP multi-tool to work with XCI/NSP/NCA/NRO(?) files
|
||||
|
||||
### License
|
||||
|
||||
[GNU General Public License v3](https://github.com/developersu/konogonka/blob/master/LICENSE)
|
||||
|
||||
### Used libraries & resources
|
||||
* [Java-XTS-AES](https://github.com/horrorho/Java-XTS-AES) by horrorho with minimal changes.
|
||||
* [OpenJFX](https://wiki.openjdk.java.net/display/OpenJFX/Main)
|
||||
* Few icons taken from: [materialdesignicons.com](http://materialdesignicons.com/)
|
||||
|
||||
### System requirements
|
||||
|
||||
JRE/JDK 8u60 or higher.
|
215
pom.xml
Normal file
|
@ -0,0 +1,215 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>loper</groupId>
|
||||
<name>konogonka</name>
|
||||
|
||||
<artifactId>konogonka</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
|
||||
<url>https://github.com/developersu/${project.name}}/</url>
|
||||
<description>
|
||||
NSP and XCI multitool
|
||||
</description>
|
||||
<inceptionYear>2019</inceptionYear>
|
||||
<organization>
|
||||
<name>Dmitry Isaenko</name>
|
||||
<url>https://developersu.blogspot.com/</url>
|
||||
</organization>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>GPLv3</name>
|
||||
<url>LICENSE</url>
|
||||
<distribution>manual</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>developer.su</id>
|
||||
<name>Dmitry Isaenko</name>
|
||||
<roles>
|
||||
<role>Developer</role>
|
||||
</roles>
|
||||
<timezone>+3</timezone>
|
||||
<url>https://developersu.blogspot.com/</url>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<issueManagement>
|
||||
<system>GitHub</system>
|
||||
<url>https://github.com/developer_su/${project.artifactId}/issues</url>
|
||||
</issueManagement>
|
||||
<!-- openJFX Linux -->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>linux</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-media</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>linux</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>linux</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>linux</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- openJFX Windows -->
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>win</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-media</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>win</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>win</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>win</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- openJFX MAC -->
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>mac</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-media</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>mac</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>mac</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>11</version>
|
||||
<classifier>mac</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- For AES XTS using bouncycastle -->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<version>1.54</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.jcip</groupId>
|
||||
<artifactId>jcip-annotations</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Consider removing
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-core</artifactId>
|
||||
<version>1.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pl.pragmatists</groupId>
|
||||
<artifactId>JUnitParams</artifactId>
|
||||
<version>1.0.5</version>
|
||||
</dependency>
|
||||
-->
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- Don't generate default JAR without dependencies -->
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-jar</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- Generate JAR with dependencies -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>konogonka.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id> <!-- this is used for inheritance merges -->
|
||||
<phase>package</phase> <!-- bind to the packaging phase -->
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
89
src/main/java/konogonka/AppPreferences.java
Normal file
|
@ -0,0 +1,89 @@
|
|||
package konogonka;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
public class AppPreferences {
|
||||
private static final AppPreferences INSTANCE = new AppPreferences();
|
||||
public static AppPreferences getInstance() { return INSTANCE; }
|
||||
|
||||
private Preferences preferences;
|
||||
|
||||
private AppPreferences(){ preferences = Preferences.userRoot().node("konogonka"); }
|
||||
|
||||
public void setAll(
|
||||
String xciHeaderKey,
|
||||
String headerKey,
|
||||
String applicationKey0,
|
||||
String applicationKey1,
|
||||
String applicationKey2,
|
||||
String applicationKey3,
|
||||
String applicationKey4,
|
||||
String applicationKey5,
|
||||
String oceanKey0,
|
||||
String oceanKey1,
|
||||
String oceanKey2,
|
||||
String oceanKey3,
|
||||
String oceanKey4,
|
||||
String oceanKey5,
|
||||
String systemKey0,
|
||||
String systemKey1,
|
||||
String systemKey2,
|
||||
String systemKey3,
|
||||
String systemKey4,
|
||||
String systemKey5
|
||||
) {
|
||||
setXciHeaderKey(xciHeaderKey);
|
||||
setHeaderKey(headerKey);
|
||||
|
||||
setApplicationKey(0, applicationKey0);
|
||||
setApplicationKey(1, applicationKey1);
|
||||
setApplicationKey(2, applicationKey2);
|
||||
setApplicationKey(3, applicationKey3);
|
||||
setApplicationKey(4, applicationKey4);
|
||||
setApplicationKey(5, applicationKey5);
|
||||
|
||||
setOceanKey(0, oceanKey0);
|
||||
setOceanKey(1, oceanKey1);
|
||||
setOceanKey(2, oceanKey2);
|
||||
setOceanKey(3, oceanKey3);
|
||||
setOceanKey(4, oceanKey4);
|
||||
setOceanKey(5, oceanKey5);
|
||||
|
||||
setSystemKey(0, systemKey0);
|
||||
setSystemKey(1, systemKey1);
|
||||
setSystemKey(2, systemKey2);
|
||||
setSystemKey(3, systemKey3);
|
||||
setSystemKey(4, systemKey4);
|
||||
setSystemKey(5, systemKey5);
|
||||
}
|
||||
|
||||
public String getRecentPath(){return preferences.get("recent_path", System.getProperty("user.home"));}
|
||||
public void setRecentPath(String path){preferences.put("recent_path", path);}
|
||||
|
||||
/*
|
||||
public HashMap<String, String> getKeys(){
|
||||
|
||||
}
|
||||
public void setKeys(HashMap<String, String> keysMap){
|
||||
preferences.put("xci_header_key", );
|
||||
preferences.put("header_key", );
|
||||
}
|
||||
*/
|
||||
|
||||
public String getXciHeaderKey(){ return preferences.get("xci_header_key", "");}
|
||||
public void setXciHeaderKey(String key){ preferences.put("xci_header_key", key); }
|
||||
|
||||
public String getHeaderKey(){ return preferences.get("header_key", "");}
|
||||
public void setHeaderKey(String key){ preferences.put("header_key", key); }
|
||||
|
||||
public String getApplicationKey(int number){ return preferences.get("key_area_key_application_0"+number, "");}
|
||||
public void setApplicationKey(int number, String key){ preferences.put("key_area_key_application_0"+number, key); }
|
||||
|
||||
public String getOceanKey(int number){ return preferences.get("key_area_key_ocean_0"+number, "");}
|
||||
public void setOceanKey(int number, String key){ preferences.put("key_area_key_ocean_0"+number, key); }
|
||||
|
||||
public String getSystemKey(int number){ return preferences.get("key_area_key_system_0"+number, "");}
|
||||
public void setSystemKey(int number, String key){ preferences.put("key_area_key_system_0"+number, key); }
|
||||
|
||||
}
|
10
src/main/java/konogonka/Controllers/IRowModel.java
Normal file
|
@ -0,0 +1,10 @@
|
|||
package konogonka.Controllers;
|
||||
|
||||
public interface IRowModel {
|
||||
int getNumber();
|
||||
String getFileName();
|
||||
long getFileSize();
|
||||
long getFileOffset();
|
||||
boolean isMarkSelected();
|
||||
void setMarkSelected(boolean value);
|
||||
}
|
120
src/main/java/konogonka/Controllers/MainController.java
Normal file
|
@ -0,0 +1,120 @@
|
|||
package konogonka.Controllers;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.stage.FileChooser;
|
||||
import konogonka.AppPreferences;
|
||||
import konogonka.Controllers.NCA.NCAController;
|
||||
import konogonka.Controllers.NSP.NSPController;
|
||||
import konogonka.Controllers.XCI.XCIController;
|
||||
import konogonka.MediatorControl;
|
||||
import konogonka.Settings.SettingsWindow;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class MainController implements Initializable {
|
||||
@FXML
|
||||
private SplitPane splitPane;
|
||||
@FXML
|
||||
private AnchorPane logPane;
|
||||
@FXML
|
||||
private TabPane tabPane;
|
||||
|
||||
@FXML
|
||||
public TextArea logArea;
|
||||
@FXML
|
||||
public ProgressBar progressBar;
|
||||
@FXML
|
||||
private Label filenameSelected;
|
||||
@FXML
|
||||
private Button analyzeBtn, settingsBtn;
|
||||
|
||||
private String previouslyOpenedPath;
|
||||
|
||||
@FXML
|
||||
private NSPController NSPTabController;
|
||||
@FXML
|
||||
private XCIController XCITabController;
|
||||
@FXML
|
||||
private NCAController NCATabController;
|
||||
|
||||
private File selectedFile;
|
||||
|
||||
private ResourceBundle rb;
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
this.rb = resourceBundle;
|
||||
MediatorControl.getInstance().setController(this);
|
||||
|
||||
progressBar.setPrefWidth(Double.POSITIVE_INFINITY);
|
||||
previouslyOpenedPath = AppPreferences.getInstance().getRecentPath();
|
||||
|
||||
analyzeBtn.setOnAction(e->this.analyzeFile());
|
||||
|
||||
splitPane.getItems().remove(logPane);
|
||||
settingsBtn.setOnAction(e->{
|
||||
new SettingsWindow();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Functionality for selecting NSP button.
|
||||
* */
|
||||
public void selectFilesBtnAction(){
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle(rb.getString("btnFileOpen"));
|
||||
|
||||
File validator = new File(previouslyOpenedPath);
|
||||
if (validator.exists())
|
||||
fileChooser.setInitialDirectory(validator);
|
||||
else
|
||||
fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
|
||||
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NS ROM", "*.nsp", "*.xci", "*.nca"));
|
||||
|
||||
this.selectedFile = fileChooser.showOpenDialog(analyzeBtn.getScene().getWindow());
|
||||
|
||||
analyzeBtn.setDisable(true);
|
||||
NSPTabController.resetTab();
|
||||
XCITabController.resetTab();
|
||||
NCATabController.resetTab();
|
||||
|
||||
if (this.selectedFile != null && this.selectedFile.exists()) {
|
||||
filenameSelected.setText(this.selectedFile.getAbsolutePath());
|
||||
previouslyOpenedPath = this.selectedFile.getParent();
|
||||
analyzeBtn.setDisable(false);
|
||||
if (this.selectedFile.getName().toLowerCase().endsWith(".nsp"))
|
||||
tabPane.getSelectionModel().select(0);
|
||||
else if (this.selectedFile.getName().toLowerCase().endsWith(".xci"))
|
||||
tabPane.getSelectionModel().select(1);
|
||||
else if (this.selectedFile.getName().toLowerCase().endsWith(".nca"))
|
||||
tabPane.getSelectionModel().select(2);
|
||||
}
|
||||
|
||||
logArea.clear();
|
||||
}
|
||||
/**
|
||||
* Start analyze
|
||||
* */
|
||||
private void analyzeFile(){
|
||||
if (selectedFile.getName().toLowerCase().endsWith("nsp"))
|
||||
NSPTabController.analyze(selectedFile); // TODO: NSP OR XCI
|
||||
else if (selectedFile.getName().toLowerCase().endsWith("xci"))
|
||||
XCITabController.analyze(selectedFile);
|
||||
else if (selectedFile.getName().toLowerCase().endsWith("nca"))
|
||||
NCATabController.analyze(selectedFile);
|
||||
}
|
||||
@FXML
|
||||
private void showHideLogs(){
|
||||
if (splitPane.getItems().size() == 2)
|
||||
splitPane.getItems().remove(logPane);
|
||||
else
|
||||
splitPane.getItems().add(logPane);
|
||||
}
|
||||
|
||||
public void exit(){ AppPreferences.getInstance().setRecentPath(previouslyOpenedPath); }
|
||||
}
|
187
src/main/java/konogonka/Controllers/NCA/NCAController.java
Normal file
|
@ -0,0 +1,187 @@
|
|||
package konogonka.Controllers.NCA;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import konogonka.AppPreferences;
|
||||
import konogonka.Controllers.TabController;
|
||||
import konogonka.Tools.NCA.NCAContentPFS0;
|
||||
import konogonka.Tools.NCA.NCAProvider;
|
||||
import konogonka.Workers.AnalyzerNCA;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static konogonka.LoperConverter.byteArrToHexString;
|
||||
|
||||
public class NCAController implements TabController {
|
||||
|
||||
private File selectedFile;
|
||||
@FXML
|
||||
private NCASectionHeaderBlockController
|
||||
NCASectionHeaderFirstController,
|
||||
NCASectionHeaderSecondController,
|
||||
NCASectionHeaderThirdController,
|
||||
NCASectionHeaderFourthController;
|
||||
@FXML
|
||||
private NCASectionContentController
|
||||
NCASectionContentFirstController,
|
||||
NCASectionContentSecondController,
|
||||
NCASectionContentThirdController,
|
||||
NCASectionContentFourthController;
|
||||
@FXML
|
||||
private NCATableController
|
||||
NCATable1Controller,
|
||||
NCATable2Controller,
|
||||
NCATable3Controller,
|
||||
NCATable4Controller;
|
||||
@FXML
|
||||
private Label
|
||||
magicnumLbl,
|
||||
systemOrGcIndLbl,
|
||||
contentTypeLbl,
|
||||
cryptoType1Lbl,
|
||||
keyIndexLbl,
|
||||
ncaSizeLbl,
|
||||
titleIdLbl,
|
||||
sdkVersionLbl,
|
||||
cryptoType2Lbl,
|
||||
ticketLbl;
|
||||
@FXML
|
||||
private TextField
|
||||
rsa2048oneTF,
|
||||
rsa2048twoTF,
|
||||
sha256section1TF,
|
||||
sha256section2TF,
|
||||
sha256section3TF,
|
||||
sha256section4TF,
|
||||
keyAreaEnKey0TF,
|
||||
keyAreaEnKey1TF,
|
||||
keyAreaEnKey2TF,
|
||||
keyAreaEnKey3TF,
|
||||
keyAreaDecKey0TF,
|
||||
keyAreaDecKey1TF,
|
||||
keyAreaDecKey2TF,
|
||||
keyAreaDecKey3TF;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void analyze(File file) {
|
||||
this.selectedFile = file;
|
||||
HashMap<String, String> keysMap = new HashMap<>();
|
||||
keysMap.put("header_key", AppPreferences.getInstance().getHeaderKey());
|
||||
for (int i = 0; i < 6; i++){
|
||||
keysMap.put("key_area_key_application_0"+i, AppPreferences.getInstance().getApplicationKey(i));
|
||||
keysMap.put("key_area_key_ocean_0"+i, AppPreferences.getInstance().getOceanKey(i));
|
||||
keysMap.put("key_area_key_system_0"+i, AppPreferences.getInstance().getSystemKey(i));
|
||||
}
|
||||
|
||||
AnalyzerNCA analyzerNCA = new AnalyzerNCA(file, keysMap);
|
||||
analyzerNCA.setOnSucceeded(e->{
|
||||
populateFields(analyzerNCA.getValue());
|
||||
});
|
||||
Thread workThread = new Thread(analyzerNCA);
|
||||
workThread.setDaemon(true);
|
||||
workThread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetTab() {
|
||||
// Header
|
||||
rsa2048oneTF.setText("-");
|
||||
rsa2048twoTF.setText("-");
|
||||
magicnumLbl.setText("-");
|
||||
systemOrGcIndLbl.setText("-");
|
||||
contentTypeLbl.setText("-");
|
||||
cryptoType1Lbl.setText("-");
|
||||
keyIndexLbl.setText("-");
|
||||
ncaSizeLbl.setText("-");
|
||||
titleIdLbl.setText("-");
|
||||
sdkVersionLbl.setText("-");
|
||||
cryptoType2Lbl.setText("-");
|
||||
ticketLbl.setText("-");
|
||||
sha256section1TF.setText("-");
|
||||
sha256section2TF.setText("-");
|
||||
sha256section3TF.setText("-");
|
||||
sha256section4TF.setText("-");
|
||||
keyAreaEnKey0TF.setText("-");
|
||||
keyAreaEnKey1TF.setText("-");
|
||||
keyAreaEnKey2TF.setText("-");
|
||||
keyAreaEnKey3TF.setText("-");
|
||||
|
||||
keyAreaDecKey0TF.setText("-");
|
||||
keyAreaDecKey1TF.setText("-");
|
||||
keyAreaDecKey2TF.setText("-");
|
||||
keyAreaDecKey3TF.setText("-");
|
||||
// Tables
|
||||
NCATable1Controller.resetTab();
|
||||
NCATable2Controller.resetTab();
|
||||
NCATable3Controller.resetTab();
|
||||
NCATable4Controller.resetTab();
|
||||
// Table blocks
|
||||
NCASectionHeaderFirstController.resetTab();
|
||||
NCASectionHeaderSecondController.resetTab();
|
||||
NCASectionHeaderThirdController.resetTab();
|
||||
NCASectionHeaderFourthController.resetTab();
|
||||
// Section content blocks
|
||||
NCASectionContentFirstController.resetTab();
|
||||
NCASectionContentSecondController.resetTab();
|
||||
NCASectionContentThirdController.resetTab();
|
||||
NCASectionContentFourthController.resetTab();
|
||||
}
|
||||
|
||||
private void populateFields(NCAProvider ncaProvider){
|
||||
if (ncaProvider != null){
|
||||
rsa2048oneTF.setText(byteArrToHexString(ncaProvider.getRsa2048one()));
|
||||
rsa2048twoTF.setText(byteArrToHexString(ncaProvider.getRsa2048two()));
|
||||
magicnumLbl.setText(ncaProvider.getMagicnum());
|
||||
systemOrGcIndLbl.setText(Byte.toString(ncaProvider.getSystemOrGcIndicator()));
|
||||
contentTypeLbl.setText(Byte.toString(ncaProvider.getContentType()));
|
||||
cryptoType1Lbl.setText(Byte.toString(ncaProvider.getCryptoType1()));
|
||||
keyIndexLbl.setText(Byte.toString(ncaProvider.getKeyIndex()));
|
||||
ncaSizeLbl.setText(Long.toString(ncaProvider.getNcaSize()));
|
||||
titleIdLbl.setText(byteArrToHexString(ncaProvider.getTitleId()));
|
||||
sdkVersionLbl.setText(ncaProvider.getSdkVersion()[3]
|
||||
+"."+ncaProvider.getSdkVersion()[2]
|
||||
+"."+ncaProvider.getSdkVersion()[1]
|
||||
+"."+ncaProvider.getSdkVersion()[0]);
|
||||
cryptoType2Lbl.setText(Byte.toString(ncaProvider.getCryptoType2()));
|
||||
ticketLbl.setText(byteArrToHexString(ncaProvider.getRightsId()));
|
||||
sha256section1TF.setText(byteArrToHexString(ncaProvider.getSha256hash0()));
|
||||
sha256section2TF.setText(byteArrToHexString(ncaProvider.getSha256hash1()));
|
||||
sha256section3TF.setText(byteArrToHexString(ncaProvider.getSha256hash2()));
|
||||
sha256section4TF.setText(byteArrToHexString(ncaProvider.getSha256hash3()));
|
||||
keyAreaEnKey0TF.setText(byteArrToHexString(ncaProvider.getEncryptedKey0()));
|
||||
keyAreaEnKey1TF.setText(byteArrToHexString(ncaProvider.getEncryptedKey1()));
|
||||
keyAreaEnKey2TF.setText(byteArrToHexString(ncaProvider.getEncryptedKey2()));
|
||||
keyAreaEnKey3TF.setText(byteArrToHexString(ncaProvider.getEncryptedKey3()));
|
||||
|
||||
keyAreaDecKey0TF.setText(byteArrToHexString(ncaProvider.getDecryptedKey0()));
|
||||
keyAreaDecKey1TF.setText(byteArrToHexString(ncaProvider.getDecryptedKey1()));
|
||||
keyAreaDecKey2TF.setText(byteArrToHexString(ncaProvider.getDecryptedKey2()));
|
||||
keyAreaDecKey3TF.setText(byteArrToHexString(ncaProvider.getDecryptedKey3()));
|
||||
// Tables
|
||||
NCATable1Controller.populateTab(ncaProvider.getTableEntry0());
|
||||
NCATable2Controller.populateTab(ncaProvider.getTableEntry1());
|
||||
NCATable3Controller.populateTab(ncaProvider.getTableEntry2());
|
||||
NCATable4Controller.populateTab(ncaProvider.getTableEntry3());
|
||||
// Table blocks
|
||||
NCASectionHeaderFirstController.populateTab(ncaProvider.getSectionBlock0());
|
||||
NCASectionHeaderSecondController.populateTab(ncaProvider.getSectionBlock1());
|
||||
NCASectionHeaderThirdController.populateTab(ncaProvider.getSectionBlock2());
|
||||
NCASectionHeaderFourthController.populateTab(ncaProvider.getSectionBlock3());
|
||||
// Section content blocks
|
||||
// TODO: FIX: This code executes getNCAContentPFS0() method twice
|
||||
NCASectionContentFirstController.populateFields(ncaProvider.getNCAContentPFS0(0).getPfs0(), selectedFile, ncaProvider.getNCAContentPFS0(0).getSHA256hashes());
|
||||
NCASectionContentSecondController.populateFields(ncaProvider.getNCAContentPFS0(1).getPfs0(), selectedFile, ncaProvider.getNCAContentPFS0(1).getSHA256hashes());
|
||||
NCASectionContentThirdController.populateFields(ncaProvider.getNCAContentPFS0(2).getPfs0(), selectedFile, ncaProvider.getNCAContentPFS0(2).getSHA256hashes());
|
||||
NCASectionContentFourthController.populateFields(ncaProvider.getNCAContentPFS0(3).getPfs0(), selectedFile, ncaProvider.getNCAContentPFS0(3).getSHA256hashes());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package konogonka.Controllers.NCA;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import konogonka.Controllers.NSP.NSPController;
|
||||
import konogonka.LoperConverter;
|
||||
import konogonka.Tools.PFS0.PFS0Provider;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class NCASectionContentController{
|
||||
@FXML
|
||||
private NSPController SectionPFS0Controller;
|
||||
@FXML
|
||||
private VBox sha256pane;
|
||||
|
||||
public void resetTab() {
|
||||
SectionPFS0Controller.resetTab();
|
||||
sha256pane.getChildren().clear();
|
||||
}
|
||||
|
||||
public void populateFields(PFS0Provider pfs0, File file, LinkedList<byte[]> sha256hashList) {
|
||||
resetTab();
|
||||
SectionPFS0Controller.setData(pfs0, file);
|
||||
if (sha256hashList != null){
|
||||
for (int i = 0; i < sha256hashList.size(); i++){
|
||||
Label numberLblTmp = new Label(String.format("%10d", i));
|
||||
numberLblTmp.setPadding(new Insets(5.0, 5.0, 5.0, 5.0));
|
||||
Label sha256LblTmp = new Label(LoperConverter.byteArrToHexString(sha256hashList.get(i)));
|
||||
sha256LblTmp.setPadding(new Insets(5.0, 5.0, 5.0, 5.0));
|
||||
|
||||
sha256pane.getChildren().add(new HBox(numberLblTmp, sha256LblTmp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
package konogonka.Controllers.NCA;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.TitledPane;
|
||||
import konogonka.Tools.NCA.NCASectionTableBlock.NCASectionBlock;
|
||||
|
||||
import static konogonka.LoperConverter.byteArrToHexString;
|
||||
|
||||
public class NCASectionHeaderBlockController {
|
||||
@FXML
|
||||
private Label
|
||||
versionLbl,
|
||||
fsTypeLbl,
|
||||
hashTypeLbl,
|
||||
cryptoTypeLbl,
|
||||
paddingLbl;
|
||||
@FXML
|
||||
private TextField
|
||||
BKTRHeaderTf;
|
||||
@FXML
|
||||
private TitledPane
|
||||
romFsTitlePanel,
|
||||
pfs0TitlePanel;
|
||||
// PFS0Provider
|
||||
@FXML
|
||||
private Label
|
||||
pfs0blockSizeLbl,
|
||||
pfs0unknownNumberTwoLbl,
|
||||
pfs0hashTableOffsetLbl,
|
||||
pfs0hashTableSizeLbl,
|
||||
pfs0relativeToSectionStartOffsetLbl,
|
||||
pfs0sizePfs0Lbl;
|
||||
@FXML
|
||||
private TextField
|
||||
pfs0SHA256hashTf,
|
||||
pfs0zeroesTf;
|
||||
// RomFS (IVFC)
|
||||
@FXML
|
||||
private Label
|
||||
romFsMagicLbl,
|
||||
romFsMagicNumberLbl,
|
||||
romFsMasterHashSizeLbl,
|
||||
romFsTotalNumberOfLevelsLbl,
|
||||
romFsLvl1OffsetLbl,
|
||||
romFsLvl1SizeLbl,
|
||||
romFsLvl1SBlockSizeLbl,
|
||||
romFsReserved1Lbl,
|
||||
|
||||
romFsLvl2OffsetLbl,
|
||||
romFsLvl2SizeLbl,
|
||||
romFsLvl2SBlockSizeLbl,
|
||||
romFsReserved2Lbl,
|
||||
|
||||
romFsLvl3OffsetLbl,
|
||||
romFsLvl3SizeLbl,
|
||||
romFsLvl3SBlockSizeLbl,
|
||||
romFsReserved3Lbl,
|
||||
|
||||
romFsLvl4OffsetLbl,
|
||||
romFsLvl4SizeLbl,
|
||||
romFsLvl4SBlockSizeLbl,
|
||||
romFsReserved4Lbl,
|
||||
|
||||
romFsLvl5OffsetLbl,
|
||||
romFsLvl5SizeLbl,
|
||||
romFsLvl5SBlockSizeLbl,
|
||||
romFsReserved5Lbl,
|
||||
|
||||
romFsLvl6OffsetLbl,
|
||||
romFsLvl6SizeLbl,
|
||||
romFsLvl6SBlockSizeLbl,
|
||||
romFsReserved6Lbl;
|
||||
@FXML
|
||||
private TextField
|
||||
romFsUnknownTf,
|
||||
romFsHashTf;
|
||||
|
||||
@FXML
|
||||
private Label
|
||||
BKTRoffsetSection1Lbl,
|
||||
BKTRsizeSection1Lbl,
|
||||
BKTRmagicSection1Lbl,
|
||||
BKTRu32Section1Lbl,
|
||||
BKTRs32Section1Lbl,
|
||||
BKTRunknownSection1Lbl,
|
||||
BKTRoffsetSection2Lbl,
|
||||
BKTRsizeSection2Lbl,
|
||||
BKTRmagicSection2Lbl,
|
||||
BKTRu32Section2Lbl,
|
||||
BKTRs32Section2Lbl,
|
||||
BKTRunknownSection2Lbl,
|
||||
BKTRunknown1Lbl,
|
||||
BKTRunknown2Lbl;
|
||||
|
||||
public void resetTab() {
|
||||
versionLbl.setText("-");
|
||||
fsTypeLbl.setText("-");
|
||||
hashTypeLbl.setText("-");
|
||||
cryptoTypeLbl.setText("-");
|
||||
paddingLbl.setText("-");
|
||||
|
||||
romFsTitlePanel.setDisable(false);
|
||||
romFsTitlePanel.setExpanded(false);
|
||||
pfs0TitlePanel.setDisable(false);
|
||||
pfs0TitlePanel.setExpanded(false);
|
||||
//RomFS
|
||||
romFsMagicLbl.setText("-");
|
||||
romFsMagicNumberLbl.setText("-");
|
||||
romFsMasterHashSizeLbl.setText("-");
|
||||
romFsTotalNumberOfLevelsLbl.setText("-");
|
||||
romFsLvl1OffsetLbl.setText("-");
|
||||
romFsLvl1SizeLbl.setText("-");
|
||||
romFsLvl1SBlockSizeLbl.setText("-");
|
||||
romFsReserved1Lbl.setText("-");
|
||||
|
||||
romFsLvl2OffsetLbl.setText("-");
|
||||
romFsLvl2SizeLbl.setText("-");
|
||||
romFsLvl2SBlockSizeLbl.setText("-");
|
||||
romFsReserved2Lbl.setText("-");
|
||||
|
||||
romFsLvl3OffsetLbl.setText("-");
|
||||
romFsLvl3SizeLbl.setText("-");
|
||||
romFsLvl3SBlockSizeLbl.setText("-");
|
||||
romFsReserved3Lbl.setText("-");
|
||||
|
||||
romFsLvl4OffsetLbl.setText("-");
|
||||
romFsLvl4SizeLbl.setText("-");
|
||||
romFsLvl4SBlockSizeLbl.setText("-");
|
||||
romFsReserved4Lbl.setText("-");
|
||||
|
||||
romFsLvl5OffsetLbl.setText("-");
|
||||
romFsLvl5SizeLbl.setText("-");
|
||||
romFsLvl5SBlockSizeLbl.setText("-");
|
||||
romFsReserved5Lbl.setText("-");
|
||||
|
||||
romFsLvl6OffsetLbl.setText("-");
|
||||
romFsLvl6SizeLbl.setText("-");
|
||||
romFsLvl6SBlockSizeLbl.setText("-");
|
||||
romFsReserved6Lbl.setText("-");
|
||||
|
||||
romFsUnknownTf.setText("-");
|
||||
romFsHashTf.setText("-");
|
||||
|
||||
// PFS0Provider
|
||||
pfs0SHA256hashTf.setText("-");
|
||||
pfs0blockSizeLbl.setText("-");
|
||||
pfs0unknownNumberTwoLbl.setText("-");
|
||||
pfs0hashTableOffsetLbl.setText("-");
|
||||
pfs0hashTableSizeLbl.setText("-");
|
||||
pfs0relativeToSectionStartOffsetLbl.setText("-");
|
||||
pfs0sizePfs0Lbl.setText("-");
|
||||
pfs0zeroesTf.setText("-");
|
||||
|
||||
BKTRHeaderTf.setText("-");
|
||||
BKTRoffsetSection1Lbl.setText("-");
|
||||
BKTRsizeSection1Lbl.setText("-");
|
||||
BKTRmagicSection1Lbl.setText("-");
|
||||
BKTRu32Section1Lbl.setText("-");
|
||||
BKTRs32Section1Lbl.setText("-");
|
||||
BKTRunknownSection1Lbl.setText("-");
|
||||
BKTRoffsetSection2Lbl.setText("-");
|
||||
BKTRsizeSection2Lbl.setText("-");
|
||||
BKTRmagicSection2Lbl.setText("-");
|
||||
BKTRu32Section2Lbl.setText("-");
|
||||
BKTRs32Section2Lbl.setText("-");
|
||||
BKTRunknownSection2Lbl.setText("-");
|
||||
BKTRunknown1Lbl.setText("-");
|
||||
BKTRunknown2Lbl.setText("-");
|
||||
}
|
||||
|
||||
public void populateTab(NCASectionBlock ncaSectionBlock){
|
||||
versionLbl.setText(byteArrToHexString(ncaSectionBlock.getVersion()));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(String.format("%02x ", ncaSectionBlock.getFsType()));
|
||||
if (ncaSectionBlock.getFsType() == 0)
|
||||
sb.append("(RomFS)");
|
||||
else if (ncaSectionBlock.getFsType() == 1)
|
||||
sb.append("(PFS0)");
|
||||
fsTypeLbl.setText(sb.toString());
|
||||
sb = new StringBuilder();
|
||||
sb.append(String.format("%02x ", ncaSectionBlock.getHashType()));
|
||||
if (ncaSectionBlock.getHashType() == 0x3)
|
||||
sb.append("(RomFS)");
|
||||
else if (ncaSectionBlock.getHashType() == 0x2)
|
||||
sb.append("(PFS0)");
|
||||
hashTypeLbl.setText(sb.toString());
|
||||
cryptoTypeLbl.setText(String.format("%02x ", ncaSectionBlock.getCryptoType()));
|
||||
paddingLbl.setText(String.format("%02x ", ncaSectionBlock.getPadding()));
|
||||
if ((ncaSectionBlock.getFsType() == 0) && (ncaSectionBlock.getHashType() == 0x3)){
|
||||
romFsMagicLbl.setText(ncaSectionBlock.getSuperBlockIVFC().getMagic());
|
||||
romFsMagicNumberLbl.setText(ncaSectionBlock.getSuperBlockIVFC().getMagicNumber()
|
||||
+(ncaSectionBlock.getSuperBlockIVFC().getMagicNumber() == 0x20000? " (OK)":" (wrong magic number)"));
|
||||
romFsMasterHashSizeLbl.setText(Integer.toString(ncaSectionBlock.getSuperBlockIVFC().getMasterHashSize()));
|
||||
romFsTotalNumberOfLevelsLbl.setText(Integer.toString(ncaSectionBlock.getSuperBlockIVFC().getTotalNumberOfLevels()));
|
||||
romFsLvl1OffsetLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl1Offset()));
|
||||
romFsLvl1SizeLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl1Size()));
|
||||
romFsLvl1SBlockSizeLbl.setText(Integer.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl1SBlockSize()));
|
||||
romFsReserved1Lbl.setText(byteArrToHexString(ncaSectionBlock.getSuperBlockIVFC().getReserved1()));
|
||||
|
||||
romFsLvl2OffsetLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl2Offset()));
|
||||
romFsLvl2SizeLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl2Size()));
|
||||
romFsLvl2SBlockSizeLbl.setText(Integer.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl2SBlockSize()));
|
||||
romFsReserved2Lbl.setText(byteArrToHexString(ncaSectionBlock.getSuperBlockIVFC().getReserved2()));
|
||||
|
||||
romFsLvl3OffsetLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl3Offset()));
|
||||
romFsLvl3SizeLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl3Size()));
|
||||
romFsLvl3SBlockSizeLbl.setText(Integer.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl3SBlockSize()));
|
||||
romFsReserved3Lbl.setText(byteArrToHexString(ncaSectionBlock.getSuperBlockIVFC().getReserved3()));
|
||||
|
||||
romFsLvl4OffsetLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl4Offset()));
|
||||
romFsLvl4SizeLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl4Size()));
|
||||
romFsLvl4SBlockSizeLbl.setText(Integer.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl4SBlockSize()));
|
||||
romFsReserved4Lbl.setText(byteArrToHexString(ncaSectionBlock.getSuperBlockIVFC().getReserved4()));
|
||||
|
||||
romFsLvl5OffsetLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl5Offset()));
|
||||
romFsLvl5SizeLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl5Size()));
|
||||
romFsLvl5SBlockSizeLbl.setText(Integer.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl5SBlockSize()));
|
||||
romFsReserved5Lbl.setText(byteArrToHexString(ncaSectionBlock.getSuperBlockIVFC().getReserved5()));
|
||||
|
||||
romFsLvl6OffsetLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl6Offset()));
|
||||
romFsLvl6SizeLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl6Size()));
|
||||
romFsLvl6SBlockSizeLbl.setText(Integer.toString(ncaSectionBlock.getSuperBlockIVFC().getLvl6SBlockSize()));
|
||||
romFsReserved6Lbl.setText(byteArrToHexString(ncaSectionBlock.getSuperBlockIVFC().getReserved6()));
|
||||
|
||||
romFsUnknownTf.setText(byteArrToHexString(ncaSectionBlock.getSuperBlockIVFC().getUnknown()));
|
||||
romFsHashTf.setText(byteArrToHexString(ncaSectionBlock.getSuperBlockIVFC().getHash()));
|
||||
pfs0TitlePanel.setDisable(true);
|
||||
}
|
||||
else if ((ncaSectionBlock.getFsType() == 0x1) && (ncaSectionBlock.getHashType() == 0x2)){
|
||||
pfs0SHA256hashTf.setText(byteArrToHexString(ncaSectionBlock.getSuperBlockPFS0().getSHA256hash()));
|
||||
pfs0blockSizeLbl.setText(Integer.toString(ncaSectionBlock.getSuperBlockPFS0().getBlockSize()));
|
||||
pfs0unknownNumberTwoLbl.setText(Integer.toString(ncaSectionBlock.getSuperBlockPFS0().getUnknownNumberTwo()));
|
||||
pfs0hashTableOffsetLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockPFS0().getHashTableOffset()));
|
||||
pfs0hashTableSizeLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockPFS0().getHashTableSize()));
|
||||
pfs0relativeToSectionStartOffsetLbl.setText(Long.toString(ncaSectionBlock.getSuperBlockPFS0().getPfs0offset()));
|
||||
pfs0sizePfs0Lbl.setText(Long.toString(ncaSectionBlock.getSuperBlockPFS0().getPfs0size()));
|
||||
pfs0zeroesTf.setText(byteArrToHexString(ncaSectionBlock.getSuperBlockPFS0().getZeroes()));
|
||||
romFsTitlePanel.setDisable(true);
|
||||
}
|
||||
else {
|
||||
pfs0TitlePanel.setDisable(true);
|
||||
romFsTitlePanel.setDisable(true);
|
||||
}
|
||||
BKTRHeaderTf.setText(byteArrToHexString(ncaSectionBlock.getBKTRfullHeader()));
|
||||
BKTRoffsetSection1Lbl.setText(Long.toString(ncaSectionBlock.getBKTRoffsetSection1()));
|
||||
BKTRsizeSection1Lbl.setText(Long.toString(ncaSectionBlock.getBKTRsizeSection1()));
|
||||
BKTRmagicSection1Lbl.setText(ncaSectionBlock.getBKTRmagicSection1());
|
||||
BKTRu32Section1Lbl.setText(Integer.toString(ncaSectionBlock.getBKTRu32Section1()));
|
||||
BKTRs32Section1Lbl.setText(Integer.toString(ncaSectionBlock.getBKTRs32Section1()));
|
||||
BKTRunknownSection1Lbl.setText(byteArrToHexString(ncaSectionBlock.getBKTRunknownSection1()));
|
||||
BKTRoffsetSection2Lbl.setText(Long.toString(ncaSectionBlock.getBKTRoffsetSection2()));
|
||||
BKTRsizeSection2Lbl.setText(Long.toString(ncaSectionBlock.getBKTRsizeSection2()));
|
||||
BKTRmagicSection2Lbl.setText(ncaSectionBlock.getBKTRmagicSection2());
|
||||
BKTRu32Section2Lbl.setText(Integer.toString(ncaSectionBlock.getBKTRu32Section2()));
|
||||
BKTRs32Section2Lbl.setText(Integer.toString(ncaSectionBlock.getBKTRs32Section2()));
|
||||
BKTRunknownSection2Lbl.setText(byteArrToHexString(ncaSectionBlock.getBKTRunknownSection2()));
|
||||
BKTRunknown1Lbl.setText(byteArrToHexString(ncaSectionBlock.getBKTRunknown1()));
|
||||
BKTRunknown2Lbl.setText(byteArrToHexString(ncaSectionBlock.getBKTRunknown2()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package konogonka.Controllers.NCA;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
import konogonka.Tools.NCA.NCAHeaderTableEntry;
|
||||
|
||||
import static konogonka.LoperConverter.byteArrToHexString;
|
||||
|
||||
public class NCATableController {
|
||||
@FXML
|
||||
private Label
|
||||
mediaStartOffsetLbl,
|
||||
mediaEndOffsetLbl,
|
||||
unknwn1Lbl,
|
||||
unknwn2Lbl;
|
||||
|
||||
public void resetTab() {
|
||||
mediaStartOffsetLbl.setText("-");
|
||||
mediaEndOffsetLbl.setText("-");
|
||||
unknwn1Lbl.setText("-");
|
||||
unknwn2Lbl.setText("-");
|
||||
}
|
||||
|
||||
public void populateTab(NCAHeaderTableEntry ncaHeaderTableEntry){
|
||||
mediaStartOffsetLbl.setText(Long.toString(ncaHeaderTableEntry.getMediaStartOffset()));
|
||||
mediaEndOffsetLbl.setText(Long.toString(ncaHeaderTableEntry.getMediaEndOffset()));
|
||||
unknwn1Lbl.setText(byteArrToHexString(ncaHeaderTableEntry.getUnknwn1()));
|
||||
unknwn2Lbl.setText(byteArrToHexString(ncaHeaderTableEntry.getUnknwn2()));
|
||||
}
|
||||
}
|
129
src/main/java/konogonka/Controllers/NSP/NSPController.java
Normal file
|
@ -0,0 +1,129 @@
|
|||
package konogonka.Controllers.NSP;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import konogonka.Controllers.IRowModel;
|
||||
import konogonka.Controllers.TabController;
|
||||
import konogonka.MediatorControl;
|
||||
import konogonka.Tools.PFS0.PFS0Provider;
|
||||
import konogonka.Workers.AnalyzerNSP;
|
||||
import konogonka.Workers.NspXciExtractor;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static konogonka.LoperConverter.byteArrToHexString;
|
||||
|
||||
public class NSPController implements TabController {
|
||||
|
||||
@FXML
|
||||
private Button extractBtn;
|
||||
@FXML
|
||||
private Pfs0TableViewController tableFilesListController;
|
||||
@FXML
|
||||
private Label filesCountLbl,
|
||||
RawDataStartLbl,
|
||||
NSPSizeLbl,
|
||||
magicLbl,
|
||||
stringTableSizeLbl,
|
||||
paddingLbl,
|
||||
fileEntryTableSizeLbl,
|
||||
stringsTableSizeLbl,
|
||||
stringsTableOffsetLbl,
|
||||
rawFileDataOffsetLbl;
|
||||
|
||||
private long rawFileDataStart;
|
||||
|
||||
private File selectedFile;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
extractBtn.setOnAction(e->this.extractFiles());
|
||||
}
|
||||
|
||||
private void extractFiles(){
|
||||
List<IRowModel> models = tableFilesListController.getFilesForDump();
|
||||
if (models != null && !models.isEmpty()){
|
||||
|
||||
File dir = new File(System.getProperty("user.dir")+File.separator+selectedFile.getName()+" extracted");
|
||||
try {
|
||||
dir.mkdir();
|
||||
}
|
||||
catch (SecurityException se){
|
||||
MediatorControl.getInstance().getContoller().logArea.setText("Can't create dir to store files.");
|
||||
}
|
||||
if (!dir.exists())
|
||||
return;
|
||||
|
||||
extractBtn.setDisable(true);
|
||||
|
||||
NspXciExtractor extractor = new NspXciExtractor(rawFileDataStart, models, dir.getAbsolutePath()+File.separator, selectedFile);
|
||||
extractor.setOnSucceeded(e->{
|
||||
extractBtn.setDisable(false);
|
||||
});
|
||||
Thread workThread = new Thread(extractor);
|
||||
workThread.setDaemon(true);
|
||||
workThread.start();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void resetTab(){
|
||||
tableFilesListController.setNSPToTable(null);
|
||||
filesCountLbl.setText("-");
|
||||
RawDataStartLbl.setText("-");
|
||||
NSPSizeLbl.setText("-");
|
||||
magicLbl.setText("-");
|
||||
stringTableSizeLbl.setText("-");
|
||||
paddingLbl.setText("-");
|
||||
fileEntryTableSizeLbl.setText("X");
|
||||
stringsTableSizeLbl.setText("Y");
|
||||
stringsTableOffsetLbl.setText("0x10+X");
|
||||
rawFileDataOffsetLbl.setText("0x10+X+Y");
|
||||
selectedFile = null;
|
||||
}
|
||||
/**
|
||||
* Start analyze NSP
|
||||
* */
|
||||
@Override
|
||||
public void analyze(File selectedFile){
|
||||
this.selectedFile = selectedFile;
|
||||
AnalyzerNSP analyzerNSP = new AnalyzerNSP(selectedFile);
|
||||
analyzerNSP.setOnSucceeded(e->{
|
||||
PFS0Provider pfs0 = analyzerNSP.getValue();
|
||||
this.setData(pfs0, null);
|
||||
});
|
||||
Thread workThread = new Thread(analyzerNSP);
|
||||
workThread.setDaemon(true);
|
||||
workThread.start();
|
||||
}
|
||||
/**
|
||||
* Just populate fields by already analyzed PFS0
|
||||
* */
|
||||
public void setData(PFS0Provider pfs0, File fileWithNca){
|
||||
if (pfs0 != null){
|
||||
if (fileWithNca != null)
|
||||
this.selectedFile = fileWithNca;
|
||||
filesCountLbl.setText(Integer.toString(pfs0.getFilesCount()));
|
||||
RawDataStartLbl.setText(Long.toString(pfs0.getRawFileDataStart()));
|
||||
rawFileDataStart = pfs0.getRawFileDataStart();
|
||||
tableFilesListController.setNSPToTable(pfs0);
|
||||
if (fileWithNca != null)
|
||||
NSPSizeLbl.setText("skipping calculation for in-file PFS0");
|
||||
else
|
||||
NSPSizeLbl.setText(Long.toString(selectedFile.length()));
|
||||
|
||||
extractBtn.setDisable(false);
|
||||
magicLbl.setText(pfs0.getMagic());
|
||||
stringTableSizeLbl.setText(Integer.toString(pfs0.getStringTableSize()));
|
||||
paddingLbl.setText(byteArrToHexString(pfs0.getPadding()));
|
||||
|
||||
fileEntryTableSizeLbl.setText(String.format("0x%02x", 0x18* pfs0.getFilesCount()));
|
||||
stringsTableSizeLbl.setText(String.format("0x%02x", pfs0.getStringTableSize()));
|
||||
stringsTableOffsetLbl.setText(String.format("0x%02x", 0x18* pfs0.getFilesCount()+0x10));
|
||||
rawFileDataOffsetLbl.setText(String.format("0x%02x", 0x18* pfs0.getFilesCount()+0x10+ pfs0.getStringTableSize())); // same to RawFileDataStart for NSP ONLY
|
||||
}
|
||||
}
|
||||
}
|
40
src/main/java/konogonka/Controllers/NSP/Pfs0RowModel.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package konogonka.Controllers.NSP;
|
||||
|
||||
import konogonka.Controllers.IRowModel;
|
||||
|
||||
public class Pfs0RowModel implements IRowModel {
|
||||
|
||||
private static int numberCnt = 0;
|
||||
public static void resetNumCnt(){ numberCnt = 0; }
|
||||
|
||||
private int number;
|
||||
private String fileName;
|
||||
private long fileSize;
|
||||
private long fileOffset;
|
||||
private boolean markForUpload;
|
||||
|
||||
Pfs0RowModel(String fileName, long size, long offset){
|
||||
this.markForUpload = false;
|
||||
this.fileName = fileName;
|
||||
this.fileOffset = offset;
|
||||
this.fileSize = size;
|
||||
this.number = numberCnt++;
|
||||
}
|
||||
// Model methods start
|
||||
public int getNumber(){
|
||||
return number;
|
||||
}
|
||||
public String getFileName(){
|
||||
return fileName;
|
||||
}
|
||||
public long getFileSize() { return fileSize; }
|
||||
public long getFileOffset() {return fileOffset; }
|
||||
public boolean isMarkSelected() {
|
||||
return markForUpload;
|
||||
}
|
||||
// Model methods end
|
||||
|
||||
public void setMarkSelected(boolean value){
|
||||
markForUpload = value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
package konogonka.Controllers.NSP;
|
||||
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.util.Callback;
|
||||
import konogonka.Controllers.IRowModel;
|
||||
import konogonka.Tools.PFS0.PFS0Provider;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class Pfs0TableViewController implements Initializable {
|
||||
@FXML
|
||||
private TableView<Pfs0RowModel> table;
|
||||
private ObservableList<Pfs0RowModel> rowsObsLst;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
rowsObsLst = FXCollections.observableArrayList();
|
||||
|
||||
table.setPlaceholder(new Label());
|
||||
table.setEditable(false); // At least with hacks it works as expected. Otherwise - null pointer exception
|
||||
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
table.setOnKeyPressed(new EventHandler<KeyEvent>() {
|
||||
@Override
|
||||
public void handle(KeyEvent keyEvent) {
|
||||
if (!rowsObsLst.isEmpty()) {
|
||||
if (keyEvent.getCode() == KeyCode.SPACE) {
|
||||
for (Pfs0RowModel item : table.getSelectionModel().getSelectedItems()) {
|
||||
item.setMarkSelected(!item.isMarkSelected());
|
||||
}
|
||||
table.refresh();
|
||||
}
|
||||
}
|
||||
keyEvent.consume();
|
||||
}
|
||||
});
|
||||
|
||||
TableColumn<Pfs0RowModel, Integer> numberColumn = new TableColumn<>(resourceBundle.getString("tableNumberLbl"));
|
||||
TableColumn<Pfs0RowModel, String> fileNameColumn = new TableColumn<>(resourceBundle.getString("tableFileNameLbl"));
|
||||
TableColumn<Pfs0RowModel, Long> fileOffsetColumn = new TableColumn<>(resourceBundle.getString("tableOffsetLbl"));
|
||||
TableColumn<Pfs0RowModel, Long> fileSizeColumn = new TableColumn<>(resourceBundle.getString("tableSizeLbl"));
|
||||
TableColumn<Pfs0RowModel, Boolean> uploadColumn = new TableColumn<>(resourceBundle.getString("tableUploadLbl"));
|
||||
|
||||
numberColumn.setEditable(false);
|
||||
fileNameColumn.setEditable(false);
|
||||
fileOffsetColumn.setEditable(false);
|
||||
fileSizeColumn.setEditable(false);
|
||||
uploadColumn.setEditable(true);
|
||||
|
||||
// See https://bugs.openjdk.java.net/browse/JDK-8157687
|
||||
numberColumn.setMinWidth(30.0);
|
||||
numberColumn.setPrefWidth(30.0);
|
||||
numberColumn.setMaxWidth(30.0);
|
||||
numberColumn.setResizable(false);
|
||||
|
||||
fileNameColumn.setMinWidth(25.0);
|
||||
|
||||
fileOffsetColumn.setMinWidth(130.0);
|
||||
fileOffsetColumn.setPrefWidth(130.0);
|
||||
fileOffsetColumn.setMaxWidth(130.0);
|
||||
fileOffsetColumn.setResizable(false);
|
||||
|
||||
fileSizeColumn.setMinWidth(120.0);
|
||||
fileSizeColumn.setPrefWidth(120.0);
|
||||
fileSizeColumn.setMaxWidth(120.0);
|
||||
fileSizeColumn.setResizable(false);
|
||||
|
||||
uploadColumn.setMinWidth(120.0);
|
||||
uploadColumn.setPrefWidth(120.0);
|
||||
uploadColumn.setMaxWidth(120.0);
|
||||
uploadColumn.setResizable(false);
|
||||
|
||||
numberColumn.setCellValueFactory(new PropertyValueFactory<>("number"));
|
||||
fileNameColumn.setCellValueFactory(new PropertyValueFactory<>("fileName"));
|
||||
fileSizeColumn.setCellValueFactory(new PropertyValueFactory<>("fileSize"));
|
||||
fileOffsetColumn.setCellValueFactory(new PropertyValueFactory<>("fileOffset"));
|
||||
// ><
|
||||
uploadColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Pfs0RowModel, Boolean>, ObservableValue<Boolean>>() {
|
||||
@Override
|
||||
public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Pfs0RowModel, Boolean> paramFeatures) {
|
||||
Pfs0RowModel model = paramFeatures.getValue();
|
||||
|
||||
SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(model.isMarkSelected());
|
||||
|
||||
booleanProperty.addListener(new ChangeListener<Boolean>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldValue, Boolean newValue) {
|
||||
model.setMarkSelected(newValue);
|
||||
table.refresh();
|
||||
}
|
||||
});
|
||||
return booleanProperty;
|
||||
}
|
||||
});
|
||||
|
||||
uploadColumn.setCellFactory(new Callback<TableColumn<Pfs0RowModel, Boolean>, TableCell<Pfs0RowModel, Boolean>>() {
|
||||
@Override
|
||||
public TableCell<Pfs0RowModel, Boolean> call(TableColumn<Pfs0RowModel, Boolean> paramFeatures) {
|
||||
CheckBoxTableCell<Pfs0RowModel, Boolean> cell = new CheckBoxTableCell<>();
|
||||
return cell;
|
||||
}
|
||||
});
|
||||
table.setRowFactory( // this shit is made to implement context menu. It's such a pain..
|
||||
new Callback<TableView<Pfs0RowModel>, TableRow<Pfs0RowModel>>() {
|
||||
@Override
|
||||
public TableRow<Pfs0RowModel> call(TableView<Pfs0RowModel> nslRowModelTableView) {
|
||||
final TableRow<Pfs0RowModel> row = new TableRow<>();
|
||||
row.setOnMouseClicked(new EventHandler<MouseEvent>() { // Just.. don't ask..
|
||||
@Override
|
||||
public void handle(MouseEvent mouseEvent) {
|
||||
if (!row.isEmpty() && mouseEvent.getButton() == MouseButton.PRIMARY){
|
||||
Pfs0RowModel thisItem = row.getItem();
|
||||
thisItem.setMarkSelected(!thisItem.isMarkSelected());
|
||||
table.refresh();
|
||||
}
|
||||
mouseEvent.consume();
|
||||
}
|
||||
});
|
||||
return row;
|
||||
}
|
||||
}
|
||||
);
|
||||
table.setItems(rowsObsLst);
|
||||
table.getColumns().addAll(numberColumn, fileNameColumn, fileOffsetColumn, fileSizeColumn, uploadColumn);
|
||||
}
|
||||
/**
|
||||
* Add files when user selected them
|
||||
* */
|
||||
public void setNSPToTable(PFS0Provider pfs){
|
||||
rowsObsLst.clear();
|
||||
Pfs0RowModel.resetNumCnt();
|
||||
if (pfs == null) {
|
||||
table.refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i=0; i < pfs.getFilesCount(); i++){
|
||||
rowsObsLst.add(new Pfs0RowModel(
|
||||
pfs.getPfs0subFiles()[i].getName(),
|
||||
pfs.getPfs0subFiles()[i].getSize(),
|
||||
pfs.getPfs0subFiles()[i].getOffset()
|
||||
));
|
||||
}
|
||||
table.refresh();
|
||||
}
|
||||
/**
|
||||
* Return files ready for upload. Requested from NSLMainController only -> uploadBtnAction() //TODO: set undefined
|
||||
* @return null if no files marked for upload
|
||||
* List<File> if there are files
|
||||
* */
|
||||
public List<IRowModel> getFilesForDump(){
|
||||
List<IRowModel> models = new ArrayList<>();
|
||||
if (rowsObsLst.isEmpty())
|
||||
return null;
|
||||
for (Pfs0RowModel model: rowsObsLst) {
|
||||
if (model.isMarkSelected()) {
|
||||
models.add(model);
|
||||
}
|
||||
}
|
||||
return models;
|
||||
}
|
||||
}
|
10
src/main/java/konogonka/Controllers/TabController.java
Normal file
|
@ -0,0 +1,10 @@
|
|||
package konogonka.Controllers;
|
||||
|
||||
import javafx.fxml.Initializable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface TabController extends Initializable {
|
||||
void analyze(File file);
|
||||
void resetTab();
|
||||
}
|
116
src/main/java/konogonka/Controllers/XCI/HFSBlockController.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
package konogonka.Controllers.XCI;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TitledPane;
|
||||
import konogonka.Controllers.IRowModel;
|
||||
import konogonka.MediatorControl;
|
||||
import konogonka.Tools.XCI.HFS0Provider;
|
||||
import konogonka.Workers.NspXciExtractor;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class HFSBlockController implements Initializable {
|
||||
@FXML
|
||||
private TitledPane currentTitledPane;
|
||||
|
||||
@FXML
|
||||
private Button extractMainBtn;
|
||||
|
||||
@FXML
|
||||
private Label hfs0mainMagicNumLbl,
|
||||
hfs0mainFileCntLbl,
|
||||
hfs0mainStrTblSizeLbl,
|
||||
hfs0mainPaddingLbl,
|
||||
hfs0mainRawFileDataStartLbl;
|
||||
|
||||
@FXML
|
||||
private Hfs0TableViewController
|
||||
hfs0tableFilesListMainController;
|
||||
|
||||
private long bodySize;
|
||||
private String
|
||||
type,
|
||||
paneName;
|
||||
|
||||
private static File selectedFile;
|
||||
|
||||
public static void setSelectedFile(File file){
|
||||
selectedFile = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
extractMainBtn.setOnAction(e->{
|
||||
extractFiles();
|
||||
});
|
||||
}
|
||||
|
||||
public void setTitlePaneTypeName(String type, String name){
|
||||
this.currentTitledPane.setText(name);
|
||||
paneName = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void resetTab(){
|
||||
currentTitledPane.setExpanded(false);
|
||||
hfs0mainMagicNumLbl.setText("-");
|
||||
hfs0mainFileCntLbl.setText("-");
|
||||
hfs0mainStrTblSizeLbl.setText("-");
|
||||
hfs0mainPaddingLbl.setText("-");
|
||||
hfs0mainRawFileDataStartLbl.setText("-");
|
||||
hfs0tableFilesListMainController.setContentToTable(null);
|
||||
extractMainBtn.setDisable(true);
|
||||
currentTitledPane.setText(paneName);
|
||||
}
|
||||
public void populateTab(HFS0Provider hfs0Provider){
|
||||
if (hfs0Provider != null){
|
||||
bodySize = hfs0Provider.getRawFileDataStart();
|
||||
hfs0mainMagicNumLbl.setText(Boolean.toString(hfs0Provider.isMagicHFS0()));
|
||||
hfs0mainFileCntLbl.setText(Integer.toString(hfs0Provider.getFilesCnt()));
|
||||
hfs0mainStrTblSizeLbl.setText(Integer.toString(hfs0Provider.getStringTableSize()));
|
||||
hfs0mainPaddingLbl.setText(Boolean.toString(hfs0Provider.isPaddingHfs0()));
|
||||
hfs0mainRawFileDataStartLbl.setText(Long.toString(hfs0Provider.getRawFileDataStart()));
|
||||
hfs0tableFilesListMainController.setContentToTable(hfs0Provider);
|
||||
if (hfs0Provider.getFilesCnt() > 0)
|
||||
extractMainBtn.setDisable(false);
|
||||
}
|
||||
else {
|
||||
currentTitledPane.setText(paneName+" (doesn't exist in this file)");
|
||||
currentTitledPane.setExpanded(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void extractFiles(){
|
||||
List<IRowModel> models;
|
||||
|
||||
models = hfs0tableFilesListMainController.getFilesForDump();
|
||||
|
||||
if (models != null && !models.isEmpty()){
|
||||
File dir = new File(System.getProperty("user.dir")+File.separator+selectedFile.getName()+" "+type+" extracted");
|
||||
try {
|
||||
dir.mkdir();
|
||||
}
|
||||
catch (SecurityException se){
|
||||
MediatorControl.getInstance().getContoller().logArea.setText("Can't create dir to store files.");
|
||||
}
|
||||
if (!dir.exists())
|
||||
return;
|
||||
|
||||
extractMainBtn.setDisable(true);
|
||||
System.out.println(dir.getAbsolutePath()+File.separator);
|
||||
NspXciExtractor extractor = new NspXciExtractor(bodySize, models, dir.getAbsolutePath()+File.separator, selectedFile);
|
||||
extractor.setOnSucceeded(e->{
|
||||
extractMainBtn.setDisable(false);
|
||||
});
|
||||
Thread workThread = new Thread(extractor);
|
||||
workThread.setDaemon(true);
|
||||
workThread.start();
|
||||
}
|
||||
}
|
||||
}
|
53
src/main/java/konogonka/Controllers/XCI/Hfs0RowModel.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
package konogonka.Controllers.XCI;
|
||||
|
||||
import konogonka.Controllers.IRowModel;
|
||||
|
||||
public class Hfs0RowModel implements IRowModel {
|
||||
|
||||
private static int numberCnt = 0;
|
||||
public static void resetNumCnt(){ numberCnt = 0; }
|
||||
|
||||
private int number;
|
||||
private String fileName;
|
||||
private long fileSize;
|
||||
private long fileOffset;
|
||||
private long hashedRegionSize;
|
||||
private boolean padding;
|
||||
private String SHA256Hash;
|
||||
private boolean markForUpload;
|
||||
|
||||
Hfs0RowModel(String fileName, long size, long offset, long hashedRegionSize, boolean padding, byte[] SHA256Hash){
|
||||
this.markForUpload = false;
|
||||
this.fileName = fileName;
|
||||
this.fileOffset = offset;
|
||||
this.fileSize = size;
|
||||
this.hashedRegionSize = hashedRegionSize;
|
||||
this.padding = padding;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b: SHA256Hash)
|
||||
sb.append(String.format("%02x", b));
|
||||
this.SHA256Hash = sb.toString();
|
||||
this.number = numberCnt++;
|
||||
}
|
||||
// Model methods start
|
||||
public int getNumber(){
|
||||
return number;
|
||||
}
|
||||
public String getFileName(){
|
||||
return fileName;
|
||||
}
|
||||
public long getFileSize() { return fileSize; }
|
||||
public long getFileOffset() {return fileOffset; }
|
||||
|
||||
public long getHashedRegionSize() { return hashedRegionSize; }
|
||||
public boolean isPadding() { return padding; }
|
||||
public String getSHA256Hash() { return SHA256Hash; }
|
||||
|
||||
public boolean isMarkSelected() {
|
||||
return markForUpload;
|
||||
}
|
||||
// Model methods end
|
||||
public void setMarkSelected(boolean value){
|
||||
markForUpload = value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
package konogonka.Controllers.XCI;
|
||||
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.util.Callback;
|
||||
import konogonka.Controllers.IRowModel;
|
||||
import konogonka.Tools.XCI.HFS0Provider;
|
||||
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class Hfs0TableViewController implements Initializable {
|
||||
@FXML
|
||||
private TableView<Hfs0RowModel> table;
|
||||
private ObservableList<Hfs0RowModel> rowsObsLst;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
rowsObsLst = FXCollections.observableArrayList();
|
||||
|
||||
table.setPlaceholder(new Label());
|
||||
table.setEditable(false); // At least with hacks it works as expected. Otherwise - null pointer exception
|
||||
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
table.setOnKeyPressed(new EventHandler<KeyEvent>() {
|
||||
@Override
|
||||
public void handle(KeyEvent keyEvent) {
|
||||
if (!rowsObsLst.isEmpty()) {
|
||||
if (keyEvent.getCode() == KeyCode.SPACE) {
|
||||
for (Hfs0RowModel item : table.getSelectionModel().getSelectedItems()) {
|
||||
item.setMarkSelected(!item.isMarkSelected());
|
||||
}
|
||||
table.refresh();
|
||||
}
|
||||
}
|
||||
keyEvent.consume();
|
||||
}
|
||||
});
|
||||
|
||||
TableColumn<Hfs0RowModel, Integer> numberColumn = new TableColumn<>(resourceBundle.getString("tableNumberLbl"));
|
||||
TableColumn<Hfs0RowModel, String> fileNameColumn = new TableColumn<>(resourceBundle.getString("tableFileNameLbl"));
|
||||
TableColumn<Hfs0RowModel, Long> fileOffsetColumn = new TableColumn<>(resourceBundle.getString("tableOffsetLbl"));
|
||||
TableColumn<Hfs0RowModel, Long> fileSizeColumn = new TableColumn<>(resourceBundle.getString("tableSizeLbl"));
|
||||
TableColumn<Hfs0RowModel, Long> fileHashedRegionSizeColumn = new TableColumn<>("Hashed Region Size");
|
||||
TableColumn<Hfs0RowModel, Boolean> filePaddingColumn = new TableColumn<>("Padding");
|
||||
TableColumn<Hfs0RowModel, String> fileSHA256HashColumn = new TableColumn<>("SHA-256 Hash");
|
||||
TableColumn<Hfs0RowModel, Boolean> uploadColumn = new TableColumn<>(resourceBundle.getString("tableUploadLbl"));
|
||||
|
||||
numberColumn.setEditable(false);
|
||||
fileNameColumn.setEditable(false);
|
||||
fileOffsetColumn.setEditable(false);
|
||||
fileSizeColumn.setEditable(false);
|
||||
fileHashedRegionSizeColumn.setEditable(false);
|
||||
uploadColumn.setEditable(true);
|
||||
|
||||
// See https://bugs.openjdk.java.net/browse/JDK-8157687
|
||||
numberColumn.setMinWidth(50.0);
|
||||
numberColumn.setPrefWidth(50.0);
|
||||
numberColumn.setMaxWidth(50.0);
|
||||
numberColumn.setResizable(false);
|
||||
|
||||
fileNameColumn.setMinWidth(25.0);
|
||||
|
||||
fileOffsetColumn.setMinWidth(130.0);
|
||||
fileOffsetColumn.setPrefWidth(130.0);
|
||||
fileOffsetColumn.setMaxWidth(130.0);
|
||||
fileOffsetColumn.setResizable(false);
|
||||
|
||||
fileSizeColumn.setMinWidth(120.0);
|
||||
fileSizeColumn.setPrefWidth(120.0);
|
||||
fileSizeColumn.setMaxWidth(120.0);
|
||||
fileSizeColumn.setResizable(false);
|
||||
|
||||
fileHashedRegionSizeColumn.setMinWidth(120.0);
|
||||
fileHashedRegionSizeColumn.setPrefWidth(120.0);
|
||||
fileHashedRegionSizeColumn.setMaxWidth(120.0);
|
||||
fileHashedRegionSizeColumn.setResizable(false);
|
||||
|
||||
filePaddingColumn.setMinWidth(80.0);
|
||||
filePaddingColumn.setPrefWidth(80.0);
|
||||
filePaddingColumn.setMaxWidth(80.0);
|
||||
filePaddingColumn.setResizable(false);
|
||||
|
||||
fileSHA256HashColumn.setMinWidth(600.0);
|
||||
fileSHA256HashColumn.setPrefWidth(600.0);
|
||||
fileSHA256HashColumn.setMaxWidth(600.0);
|
||||
fileSHA256HashColumn.setResizable(false);
|
||||
|
||||
uploadColumn.setMinWidth(120.0);
|
||||
uploadColumn.setPrefWidth(120.0);
|
||||
uploadColumn.setMaxWidth(120.0);
|
||||
uploadColumn.setResizable(false);
|
||||
|
||||
numberColumn.setCellValueFactory(new PropertyValueFactory<>("number"));
|
||||
fileNameColumn.setCellValueFactory(new PropertyValueFactory<>("fileName"));
|
||||
fileSizeColumn.setCellValueFactory(new PropertyValueFactory<>("fileSize"));
|
||||
fileOffsetColumn.setCellValueFactory(new PropertyValueFactory<>("fileOffset"));
|
||||
filePaddingColumn.setCellValueFactory(new PropertyValueFactory<>("padding"));
|
||||
fileSHA256HashColumn.setCellValueFactory(new PropertyValueFactory<>("SHA256Hash"));
|
||||
fileHashedRegionSizeColumn.setCellValueFactory(new PropertyValueFactory<>("hashedRegionSize"));
|
||||
// ><
|
||||
uploadColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Hfs0RowModel, Boolean>, ObservableValue<Boolean>>() {
|
||||
@Override
|
||||
public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Hfs0RowModel, Boolean> paramFeatures) {
|
||||
Hfs0RowModel model = paramFeatures.getValue();
|
||||
|
||||
SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(model.isMarkSelected());
|
||||
|
||||
booleanProperty.addListener(new ChangeListener<Boolean>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldValue, Boolean newValue) {
|
||||
model.setMarkSelected(newValue);
|
||||
table.refresh();
|
||||
}
|
||||
});
|
||||
return booleanProperty;
|
||||
}
|
||||
});
|
||||
|
||||
uploadColumn.setCellFactory(new Callback<TableColumn<Hfs0RowModel, Boolean>, TableCell<Hfs0RowModel, Boolean>>() {
|
||||
@Override
|
||||
public TableCell<Hfs0RowModel, Boolean> call(TableColumn<Hfs0RowModel, Boolean> paramFeatures) {
|
||||
CheckBoxTableCell<Hfs0RowModel, Boolean> cell = new CheckBoxTableCell<>();
|
||||
return cell;
|
||||
}
|
||||
});
|
||||
table.setRowFactory( // this shit is made to implement context menu. It's such a pain..
|
||||
new Callback<TableView<Hfs0RowModel>, TableRow<Hfs0RowModel>>() {
|
||||
@Override
|
||||
public TableRow<Hfs0RowModel> call(TableView<Hfs0RowModel> nslHfs0RowModelTableView) {
|
||||
final TableRow<Hfs0RowModel> row = new TableRow<>();
|
||||
row.setOnMouseClicked(new EventHandler<MouseEvent>() { // Just.. don't ask..
|
||||
@Override
|
||||
public void handle(MouseEvent mouseEvent) {
|
||||
if (!row.isEmpty() && mouseEvent.getButton() == MouseButton.PRIMARY){
|
||||
Hfs0RowModel thisItem = row.getItem();
|
||||
thisItem.setMarkSelected(!thisItem.isMarkSelected());
|
||||
table.refresh();
|
||||
}
|
||||
mouseEvent.consume();
|
||||
}
|
||||
});
|
||||
return row;
|
||||
}
|
||||
}
|
||||
);
|
||||
table.setItems(rowsObsLst);
|
||||
table.getColumns().addAll(numberColumn, fileNameColumn, fileOffsetColumn, fileSizeColumn, fileHashedRegionSizeColumn, filePaddingColumn, fileSHA256HashColumn, uploadColumn);
|
||||
}
|
||||
/**
|
||||
* Add files when user selected them
|
||||
* */
|
||||
public void setContentToTable(HFS0Provider hfs0){
|
||||
rowsObsLst.clear();
|
||||
Hfs0RowModel.resetNumCnt();
|
||||
if (hfs0 == null) {
|
||||
table.refresh();
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < hfs0.getFilesCnt(); i++){
|
||||
rowsObsLst.add(new Hfs0RowModel(
|
||||
hfs0.getHfs0Files()[i].getName(),
|
||||
hfs0.getHfs0Files()[i].getSize(),
|
||||
hfs0.getHfs0Files()[i].getOffset(),
|
||||
hfs0.getHfs0Files()[i].getHashedRegionSize(),
|
||||
hfs0.getHfs0Files()[i].isPadding(),
|
||||
hfs0.getHfs0Files()[i].getSHA256Hash()
|
||||
));
|
||||
}
|
||||
|
||||
table.refresh();
|
||||
}
|
||||
/**
|
||||
* Return files ready for upload. Requested from NSLMainController only -> uploadBtnAction() //TODO: set undefined
|
||||
* @return null if no files marked for upload
|
||||
* List<File> if there are files
|
||||
* */
|
||||
public List<IRowModel> getFilesForDump(){
|
||||
List<IRowModel> models = new ArrayList<>();
|
||||
if (rowsObsLst.isEmpty())
|
||||
return null;
|
||||
for (Hfs0RowModel model: rowsObsLst) {
|
||||
if (model.isMarkSelected()) {
|
||||
models.add(model);
|
||||
}
|
||||
}
|
||||
return models;
|
||||
}
|
||||
}
|
273
src/main/java/konogonka/Controllers/XCI/XCIController.java
Normal file
|
@ -0,0 +1,273 @@
|
|||
package konogonka.Controllers.XCI;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import konogonka.AppPreferences;
|
||||
import konogonka.Controllers.TabController;
|
||||
import konogonka.Tools.XCI.XCIProvider;
|
||||
import konogonka.Workers.AnalyzerXCI;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static konogonka.LoperConverter.byteArrToHexString;
|
||||
|
||||
public class XCIController implements TabController {
|
||||
|
||||
/* Header */
|
||||
@FXML
|
||||
private TextField rsa2048pkcs1TF,
|
||||
secureAreaStartAddrTF,
|
||||
pkgIdTF,
|
||||
gcInfoIVTF,
|
||||
Hfs0headerSHA256Lbl,
|
||||
Hfs0initDataSHA256Lbl,
|
||||
normAreaEndAddrTF;
|
||||
@FXML
|
||||
private Label headLbl,
|
||||
bkupAreaStartAddrLbl,
|
||||
titleKEKIndexLbl,
|
||||
gcSizeLbl,
|
||||
gcHdrVersLbl,
|
||||
gcFlags,
|
||||
vDataEndAddrLbl,
|
||||
hfs0partOffLbl,
|
||||
hfs0hdrSizeLbl,
|
||||
secureModeFlagLbl,
|
||||
titleKeyFlagLbl,
|
||||
keyFlagLbl;
|
||||
/* GC Info */
|
||||
@FXML
|
||||
private TextField fwModeTF,
|
||||
cupVersionTF,
|
||||
emptyPadding1TF,
|
||||
updPartHashTF,
|
||||
cupIDTF,
|
||||
emptyPadding2TF;
|
||||
@FXML
|
||||
private Label fwVersionLbl,
|
||||
accessCtrlFlagsLbl,
|
||||
readWaitTime1Lbl,
|
||||
readWaitTime2Lbl,
|
||||
writeWaitTime1,
|
||||
writeWaitTime2,
|
||||
emptyPadding1Lbl,
|
||||
emptyPadding2Lbl;
|
||||
/* GC Cert */
|
||||
@FXML
|
||||
private TextField rsa2048PKCS1sigCertTF,
|
||||
magicCertCertTF,
|
||||
unknown1CertTF,
|
||||
unknown2CertTF,
|
||||
deviceIDCertTF,
|
||||
unknown3CertTF,
|
||||
encryptedDataCertTF;
|
||||
@FXML
|
||||
private Label kekIndexCertLbl,
|
||||
magicCertCertOkLbl;
|
||||
|
||||
@FXML
|
||||
private HFSBlockController
|
||||
HFSBlockMainController,
|
||||
HFSBlockUpdateController,
|
||||
HFSBlockNormalController,
|
||||
HFSBlockSecureController,
|
||||
HFSBlockLogoController;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
HFSBlockMainController.setTitlePaneTypeName("main", "HFS0 (Primary): 0xF000");
|
||||
HFSBlockUpdateController.setTitlePaneTypeName("update", "HFS0 update");
|
||||
HFSBlockNormalController.setTitlePaneTypeName("normal", "HFS0 normal");
|
||||
HFSBlockSecureController.setTitlePaneTypeName("secure", "HFS0 secure");
|
||||
HFSBlockLogoController.setTitlePaneTypeName("logo", "HFS0 logo");
|
||||
}
|
||||
|
||||
/**
|
||||
* Start analyze XCI
|
||||
* */
|
||||
@Override
|
||||
public void analyze(File selectedFile){
|
||||
HFSBlockController.setSelectedFile(selectedFile);
|
||||
|
||||
AnalyzerXCI analyzerXCI = new AnalyzerXCI(selectedFile, AppPreferences.getInstance().getXciHeaderKey());
|
||||
analyzerXCI.setOnSucceeded(e->{
|
||||
populateFields(analyzerXCI.getValue());
|
||||
});
|
||||
Thread workThread = new Thread(analyzerXCI);
|
||||
workThread.setDaemon(true);
|
||||
workThread.start();
|
||||
}
|
||||
@Override
|
||||
public void resetTab(){
|
||||
HFSBlockController.setSelectedFile(null);
|
||||
/* Header */
|
||||
rsa2048pkcs1TF.setText("-");
|
||||
headLbl.setText("-");
|
||||
secureAreaStartAddrTF.setText("-");
|
||||
bkupAreaStartAddrLbl.setText("-");
|
||||
titleKEKIndexLbl.setText("-");
|
||||
gcSizeLbl.setText("-");
|
||||
gcHdrVersLbl.setText("-");
|
||||
gcFlags.setText("-");
|
||||
pkgIdTF.setText("-");
|
||||
vDataEndAddrLbl.setText("-");
|
||||
gcInfoIVTF.setText("-");
|
||||
hfs0partOffLbl.setText("-");
|
||||
hfs0hdrSizeLbl.setText("-");
|
||||
Hfs0headerSHA256Lbl.setText("-");
|
||||
Hfs0initDataSHA256Lbl.setText("-");
|
||||
secureModeFlagLbl.setText("-");
|
||||
titleKeyFlagLbl.setText("-");
|
||||
keyFlagLbl.setText("-");
|
||||
normAreaEndAddrTF.setText("-");
|
||||
/* GC Info */
|
||||
fwVersionLbl.setText("-");
|
||||
accessCtrlFlagsLbl.setText("-");
|
||||
readWaitTime1Lbl.setText("-");
|
||||
readWaitTime2Lbl.setText("-");
|
||||
writeWaitTime1.setText("-");
|
||||
writeWaitTime2.setText("-");
|
||||
fwModeTF.setText("-");
|
||||
cupVersionTF.setText("-");
|
||||
emptyPadding1TF.setText("-");
|
||||
updPartHashTF.setText("-");
|
||||
cupIDTF.setText("-");
|
||||
emptyPadding2TF.setText("-");
|
||||
emptyPadding1Lbl.setText("-");
|
||||
emptyPadding2Lbl.setText("-");
|
||||
|
||||
/* Certificate */
|
||||
rsa2048PKCS1sigCertTF.setText("-");
|
||||
magicCertCertTF.setText("-");
|
||||
magicCertCertOkLbl.setText("-");
|
||||
unknown1CertTF.setText("-");
|
||||
kekIndexCertLbl.setText("-");
|
||||
unknown2CertTF.setText("-");
|
||||
deviceIDCertTF.setText("-");
|
||||
unknown3CertTF.setText("-");
|
||||
encryptedDataCertTF.setText("-");
|
||||
|
||||
/* HFS0 */
|
||||
HFSBlockMainController.resetTab();
|
||||
HFSBlockUpdateController.resetTab();
|
||||
HFSBlockNormalController.resetTab();
|
||||
HFSBlockSecureController.resetTab();
|
||||
HFSBlockLogoController.resetTab();
|
||||
}
|
||||
private void populateFields(XCIProvider xci){
|
||||
if (xci != null){
|
||||
/* Header */
|
||||
rsa2048pkcs1TF.setText(byteArrToHexString(xci.getGCHeader().getRsa2048PKCS1sig()));
|
||||
//RainbowHexDump.hexDumpUTF8(xci.getGCHeader().getRsa2048PKCS1sig());
|
||||
headLbl.setText(Boolean.toString(xci.getGCHeader().isMagicHeadOk()));
|
||||
//System.out.println(xci.getGCHeader().isMagicHeadOk());
|
||||
secureAreaStartAddrTF.setText(byteArrToHexString(xci.getGCHeader().getSecureAreaStartAddr()));
|
||||
//System.out.println(xci.getGCHeader().isSecureAreaStartAddrOk());
|
||||
bkupAreaStartAddrLbl.setText(Boolean.toString(xci.getGCHeader().isBkupAreaStartAddrOk()));
|
||||
//System.out.println(xci.getGCHeader().isBkupAreaStartAddrOk());
|
||||
titleKEKIndexLbl.setText(String.format("%02x", xci.getGCHeader().getTitleKEKIndexBoth())+": "
|
||||
+String.format("%02x", xci.getGCHeader().getTitleKEKIndex())+" "
|
||||
+String.format("%02x", xci.getGCHeader().getKEKIndex())
|
||||
);
|
||||
//System.out.print(String.format("%02x", xci.getGCHeader().getTitleKEKIndexBoth())+" ");
|
||||
//System.out.print(String.format("%02x", xci.getGCHeader().getTitleKEKIndex())+" ");
|
||||
//System.out.println(String.format("%02x", xci.getGCHeader().getKEKIndex()));
|
||||
switch (xci.getGCHeader().getGcSize()){
|
||||
case (byte) 0xFA: // 1 GB
|
||||
gcSizeLbl.setText("1 GB");
|
||||
break;
|
||||
case (byte) 0xF8: // 2 GB
|
||||
gcSizeLbl.setText("2 GB");
|
||||
break;
|
||||
case (byte) 0xF0: // 4 GB
|
||||
gcSizeLbl.setText("4 GB");
|
||||
break;
|
||||
case (byte) 0xE0: // 8 GB
|
||||
gcSizeLbl.setText("8 GB");
|
||||
break;
|
||||
case (byte) 0xE1: // 16 GB
|
||||
gcSizeLbl.setText("16 GB");
|
||||
break;
|
||||
case (byte) 0xE2: // 32 GB
|
||||
gcSizeLbl.setText("32 GB");
|
||||
break;
|
||||
default:
|
||||
gcSizeLbl.setText("? "+String.format("%02x", xci.getGCHeader().getGcSize()));
|
||||
}
|
||||
//System.out.println(String.format("%02x", xci.getGCHeader().getGcSize()));
|
||||
gcHdrVersLbl.setText(String.format("%02x", xci.getGCHeader().getGcVersion()));
|
||||
//System.out.println(String.format("%02x", xci.getGCHeader().getGcVersion()));
|
||||
gcFlags.setText(String.format("%02x", xci.getGCHeader().getGcFlags()));
|
||||
//System.out.println(String.format("%02x", xci.getGCHeader().getGcFlags()));
|
||||
pkgIdTF.setText(byteArrToHexString(xci.getGCHeader().getPkgID()));
|
||||
//RainbowHexDump.hexDumpUTF8(xci.getGCHeader().getPkgID());
|
||||
vDataEndAddrLbl.setText(Long.toString(xci.getGCHeader().getValDataEndAddr()));
|
||||
//System.out.println(xci.getGCHeader().getValDataEndAddr());
|
||||
gcInfoIVTF.setText(byteArrToHexString(xci.getGCHeader().getGcInfoIV()));
|
||||
//RainbowHexDump.hexDumpUTF8(xci.getGCHeader().getGcInfoIV());
|
||||
hfs0partOffLbl.setText(Long.toString(xci.getGCHeader().getHfs0partOffset()));
|
||||
//System.out.println(xci.getGCHeader().getHfs0partOffset());
|
||||
hfs0hdrSizeLbl.setText(Long.toString(xci.getGCHeader().getHfs0headerSize()));
|
||||
//System.out.println(xci.getGCHeader().getHfs0headerSize());
|
||||
Hfs0headerSHA256Lbl.setText(byteArrToHexString(xci.getGCHeader().getHfs0headerSHA256()));
|
||||
//RainbowHexDump.hexDumpUTF8(xci.getGCHeader().getHfs0headerSHA256());
|
||||
Hfs0initDataSHA256Lbl.setText(byteArrToHexString(xci.getGCHeader().getHfs0initDataSHA256()));
|
||||
//RainbowHexDump.hexDumpUTF8(xci.getGCHeader().getHfs0initDataSHA256() );
|
||||
secureModeFlagLbl.setText(xci.getGCHeader().isSecureModeFlagOk()+" ("+xci.getGCHeader().getSecureModeFlag()+")");
|
||||
//System.out.print(xci.getGCHeader().getSecureModeFlag());
|
||||
//System.out.println(xci.getGCHeader().isSecureModeFlagOk());
|
||||
titleKeyFlagLbl.setText(xci.getGCHeader().istitleKeyFlagOk()+" ("+xci.getGCHeader().getTitleKeyFlag()+")");
|
||||
//System.out.print(xci.getGCHeader().getTitleKeyFlag());
|
||||
//System.out.println(xci.getGCHeader().istitleKeyFlagOk());
|
||||
keyFlagLbl.setText(xci.getGCHeader().iskeyFlagOk()+" ("+xci.getGCHeader().getKeyFlag()+")");
|
||||
//System.out.print(xci.getGCHeader().getKeyFlag());
|
||||
//System.out.println(xci.getGCHeader().iskeyFlagOk());
|
||||
normAreaEndAddrTF.setText(byteArrToHexString(xci.getGCHeader().getNormAreaEndAddr()));
|
||||
//System.out.println(xci.getGCHeader().isNormAreaEndAddrOk());
|
||||
|
||||
/* GC Info */
|
||||
fwVersionLbl.setText(Long.toString(xci.getGCInfo().getFwVersion()));
|
||||
String tempACF = byteArrToHexString(xci.getGCInfo().getAccessCtrlFlags());
|
||||
if (tempACF.equals("1100a100"))
|
||||
accessCtrlFlagsLbl.setText("25Mhz [0x1100a100]");
|
||||
else if(tempACF.equals("1000a100"))
|
||||
accessCtrlFlagsLbl.setText("50Mhz [0x1000a100]");
|
||||
else
|
||||
accessCtrlFlagsLbl.setText("??? ["+tempACF+"]");
|
||||
readWaitTime1Lbl.setText(Long.toString(xci.getGCInfo().getReadWaitTime1()));
|
||||
readWaitTime2Lbl.setText(Long.toString(xci.getGCInfo().getReadWaitTime2()));
|
||||
writeWaitTime1.setText(Long.toString(xci.getGCInfo().getWriteWaitTime1()));
|
||||
writeWaitTime2.setText(Long.toString(xci.getGCInfo().getWriteWaitTime2()));
|
||||
fwModeTF.setText(byteArrToHexString(xci.getGCInfo().getFwMode()));
|
||||
cupVersionTF.setText(byteArrToHexString(xci.getGCInfo().getCupVersion()));
|
||||
emptyPadding1Lbl.setText(Boolean.toString(xci.getGCInfo().isEmptyPadding1()));
|
||||
emptyPadding1TF.setText(byteArrToHexString(xci.getGCInfo().getEmptyPadding1()));
|
||||
updPartHashTF.setText(byteArrToHexString(xci.getGCInfo().getUpdPartHash()));
|
||||
cupIDTF.setText(byteArrToHexString(xci.getGCInfo().getCupID()));
|
||||
emptyPadding2Lbl.setText(Boolean.toString(xci.getGCInfo().isEmptyPadding2()));
|
||||
emptyPadding2TF.setText(byteArrToHexString(xci.getGCInfo().getEmptyPadding2()));
|
||||
|
||||
/* Certificate */
|
||||
rsa2048PKCS1sigCertTF.setText(byteArrToHexString(xci.getGCCert().getRsa2048PKCS1sig()));
|
||||
magicCertCertTF.setText(byteArrToHexString(xci.getGCCert().getMagicCert()));
|
||||
magicCertCertOkLbl.setText(Boolean.toString(xci.getGCCert().isMagicCertOk()));
|
||||
unknown1CertTF.setText(byteArrToHexString(xci.getGCCert().getUnknown1()));
|
||||
kekIndexCertLbl.setText(String.format("%02x", xci.getGCCert().getKekIndex()));
|
||||
unknown2CertTF.setText(byteArrToHexString(xci.getGCCert().getUnknown2()));
|
||||
deviceIDCertTF.setText(byteArrToHexString(xci.getGCCert().getDeviceID()));
|
||||
unknown3CertTF.setText(byteArrToHexString(xci.getGCCert().getUnknown3()));
|
||||
encryptedDataCertTF.setText(byteArrToHexString(xci.getGCCert().getEncryptedData()));
|
||||
|
||||
/* HFS0 */
|
||||
HFSBlockMainController.populateTab(xci.getHfs0ProviderMain());
|
||||
HFSBlockUpdateController.populateTab(xci.getHfs0ProviderUpdate());
|
||||
HFSBlockNormalController.populateTab(xci.getHfs0ProviderNormal());
|
||||
HFSBlockSecureController.populateTab(xci.getHfs0ProviderSecure());
|
||||
HFSBlockLogoController.populateTab(xci.getHfs0ProviderLogo());
|
||||
}
|
||||
}
|
||||
}
|
22
src/main/java/konogonka/LoperConverter.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
package konogonka;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class LoperConverter {
|
||||
public static int getLEint(byte[] bytes, int fromOffset){
|
||||
return ByteBuffer.wrap(bytes, fromOffset, 0x4).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
||||
}
|
||||
|
||||
public static long getLElong(byte[] bytes, int fromOffset){
|
||||
return ByteBuffer.wrap(bytes, fromOffset, 0x8).order(ByteOrder.LITTLE_ENDIAN).getLong();
|
||||
}
|
||||
public static String byteArrToHexString(byte[] bArr){
|
||||
if (bArr == null)
|
||||
return "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b: bArr)
|
||||
sb.append(String.format("%02x", b));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
5
src/main/java/konogonka/Main.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package konogonka;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args){ MainFx.main(args); }
|
||||
}
|
52
src/main/java/konogonka/MainFx.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
package konogonka;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.stage.Stage;
|
||||
import konogonka.Controllers.MainController;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class MainFx extends Application {
|
||||
public static final String appVersion = "v0.1-DEV";
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception{
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/landingPage.fxml"));
|
||||
|
||||
Locale userLocale = new Locale(Locale.getDefault().getISO3Language()); // NOTE: user locale based on ISO3 Language codes
|
||||
ResourceBundle rb = ResourceBundle.getBundle("locale", userLocale);
|
||||
|
||||
loader.setResources(rb);
|
||||
|
||||
Parent root = loader.load();
|
||||
|
||||
primaryStage.getIcons().addAll(
|
||||
new Image(getClass().getResourceAsStream("/res/app_icon32x32.png")),
|
||||
new Image(getClass().getResourceAsStream("/res/app_icon48x48.png")),
|
||||
new Image(getClass().getResourceAsStream("/res/app_icon64x64.png")),
|
||||
new Image(getClass().getResourceAsStream("/res/app_icon128x128.png"))
|
||||
);
|
||||
primaryStage.setTitle("konogonka "+appVersion);
|
||||
|
||||
Scene mainScene = new Scene(root, 1200, 800);
|
||||
mainScene.getStylesheets().add("/res/app_light.css");
|
||||
|
||||
primaryStage.setScene(mainScene);
|
||||
primaryStage.setMinWidth(1000.0);
|
||||
primaryStage.setMinHeight(750.0);
|
||||
primaryStage.show();
|
||||
|
||||
MainController controller = loader.getController();
|
||||
primaryStage.setOnHidden(e-> controller.exit());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
}
|
19
src/main/java/konogonka/MediatorControl.java
Normal file
|
@ -0,0 +1,19 @@
|
|||
package konogonka;
|
||||
|
||||
import konogonka.Controllers.MainController;
|
||||
|
||||
public class MediatorControl {
|
||||
private MainController applicationController;
|
||||
|
||||
public static MediatorControl getInstance(){
|
||||
return MediatorControlHold.INSTANCE;
|
||||
}
|
||||
|
||||
private static class MediatorControlHold {
|
||||
private static final MediatorControl INSTANCE = new MediatorControl();
|
||||
}
|
||||
public void setController(MainController controller){
|
||||
this.applicationController = controller;
|
||||
}
|
||||
public MainController getContoller(){ return this.applicationController; }
|
||||
}
|
5
src/main/java/konogonka/ModelControllers/EMsgType.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package konogonka.ModelControllers;
|
||||
|
||||
public enum EMsgType {
|
||||
PASS, FAIL, INFO, WARNING
|
||||
}
|
54
src/main/java/konogonka/ModelControllers/LogPrinter.java
Normal file
|
@ -0,0 +1,54 @@
|
|||
package konogonka.ModelControllers;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class LogPrinter {
|
||||
private MessagesConsumer msgConsumer;
|
||||
private BlockingQueue<String> msgQueue;
|
||||
private BlockingQueue<Double> progressQueue;
|
||||
|
||||
public LogPrinter(){
|
||||
this.msgQueue = new LinkedBlockingQueue<>();
|
||||
this.progressQueue = new LinkedBlockingQueue<>();
|
||||
this.msgConsumer = new MessagesConsumer(this.msgQueue, this.progressQueue);
|
||||
this.msgConsumer.start();
|
||||
}
|
||||
/**
|
||||
* This is what will print to textArea of the application.
|
||||
* */
|
||||
public void print(String message, EMsgType type){
|
||||
try {
|
||||
switch (type){
|
||||
case PASS:
|
||||
msgQueue.put("[ PASS ] "+message+"\n");
|
||||
break;
|
||||
case FAIL:
|
||||
msgQueue.put("[ FAIL ] "+message+"\n");
|
||||
break;
|
||||
case INFO:
|
||||
msgQueue.put("[ INFO ] "+message+"\n");
|
||||
break;
|
||||
case WARNING:
|
||||
msgQueue.put("[ WARN ] "+message+"\n");
|
||||
break;
|
||||
default:
|
||||
msgQueue.put(message);
|
||||
}
|
||||
}catch (InterruptedException ie){
|
||||
ie.printStackTrace();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Update progress for progress bar
|
||||
* */
|
||||
public void updateProgress(Double value) throws InterruptedException{
|
||||
progressQueue.put(value);
|
||||
}
|
||||
/**
|
||||
* When we're done - close it
|
||||
* */
|
||||
public void close(){
|
||||
msgConsumer.interrupt();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package konogonka.ModelControllers;
|
||||
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.scene.control.ProgressBar;
|
||||
import javafx.scene.control.ProgressIndicator;
|
||||
import javafx.scene.control.TextArea;
|
||||
import konogonka.MediatorControl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
public class MessagesConsumer extends AnimationTimer {
|
||||
private final BlockingQueue<String> msgQueue;
|
||||
private final TextArea logsArea;
|
||||
|
||||
private final BlockingQueue<Double> progressQueue;
|
||||
private final ProgressBar progressBar;
|
||||
|
||||
private boolean isInterrupted;
|
||||
|
||||
MessagesConsumer(BlockingQueue<String> msgQueue, BlockingQueue<Double> progressQueue){
|
||||
this.isInterrupted = false;
|
||||
|
||||
this.msgQueue = msgQueue;
|
||||
this.logsArea = MediatorControl.getInstance().getContoller().logArea;
|
||||
|
||||
this.progressQueue = progressQueue;
|
||||
this.progressBar = MediatorControl.getInstance().getContoller().progressBar;
|
||||
|
||||
progressBar.setProgress(0.0);
|
||||
|
||||
progressBar.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(long l) {
|
||||
ArrayList<String> messages = new ArrayList<>();
|
||||
int msgRecieved = msgQueue.drainTo(messages);
|
||||
if (msgRecieved > 0)
|
||||
messages.forEach(msg -> logsArea.appendText(msg));
|
||||
|
||||
ArrayList<Double> progress = new ArrayList<>();
|
||||
int progressRecieved = progressQueue.drainTo(progress);
|
||||
if (progressRecieved > 0) {
|
||||
progress.forEach(prg -> {
|
||||
if (prg != 1.0)
|
||||
progressBar.setProgress(prg);
|
||||
else
|
||||
progressBar.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
|
||||
});
|
||||
}
|
||||
|
||||
if (isInterrupted) {
|
||||
progressBar.setProgress(0.0);
|
||||
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void interrupt(){
|
||||
this.isInterrupted = true;
|
||||
}
|
||||
}
|
32
src/main/java/konogonka/RainbowHexDump.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
package konogonka;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Debug tool like hexdump <3
|
||||
*/
|
||||
public class RainbowHexDump {
|
||||
private static final String ANSI_RESET = "\u001B[0m";
|
||||
private static final String ANSI_BLACK = "\u001B[30m";
|
||||
private static final String ANSI_RED = "\u001B[31m";
|
||||
private static final String ANSI_GREEN = "\u001B[32m";
|
||||
private static final String ANSI_YELLOW = "\u001B[33m";
|
||||
private static final String ANSI_BLUE = "\u001B[34m";
|
||||
private static final String ANSI_PURPLE = "\u001B[35m";
|
||||
private static final String ANSI_CYAN = "\u001B[36m";
|
||||
private static final String ANSI_WHITE = "\u001B[37m";
|
||||
|
||||
|
||||
public static void hexDumpUTF8(byte[] byteArray){
|
||||
if (byteArray == null || byteArray.length == 0)
|
||||
return;
|
||||
System.out.print(ANSI_BLUE);
|
||||
for (int i=0; i < byteArray.length; i++)
|
||||
System.out.print(String.format("%02d-", i%100));
|
||||
System.out.println(">"+ANSI_RED+byteArray.length+ANSI_RESET);
|
||||
for (byte b: byteArray)
|
||||
System.out.print(String.format("%02x ", b));
|
||||
System.out.println();
|
||||
System.out.print(new String(byteArray, StandardCharsets.UTF_8)+"\n");
|
||||
}
|
||||
}
|
52
src/main/java/konogonka/ServiceWindow.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
package konogonka;
|
||||
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class ServiceWindow {
|
||||
/** Create window with error notification */
|
||||
public static void getErrorNotification(String title, String body){
|
||||
getNotification(title, body, Alert.AlertType.ERROR);
|
||||
}
|
||||
/** Create window with information notification */
|
||||
public static void getInfoNotification(String title, String body){
|
||||
getNotification(title, body, Alert.AlertType.INFORMATION);
|
||||
}
|
||||
/** Real window creator */
|
||||
private static void getNotification(String title, String body, Alert.AlertType type){
|
||||
Alert alertBox = new Alert(type);
|
||||
alertBox.setTitle(title);
|
||||
alertBox.setHeaderText(null);
|
||||
alertBox.setContentText(body);
|
||||
alertBox.getDialogPane().setMinWidth(Region.USE_PREF_SIZE);
|
||||
alertBox.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
alertBox.setResizable(true); // Java bug workaround for JDR11/OpenJFX. TODO: nothing. really.
|
||||
alertBox.getDialogPane().getStylesheets().add("/res/app_light.css");
|
||||
|
||||
Stage dialogStage = (Stage) alertBox.getDialogPane().getScene().getWindow();
|
||||
dialogStage.setAlwaysOnTop(true);
|
||||
dialogStage.toFront();
|
||||
|
||||
alertBox.show();
|
||||
}
|
||||
/**
|
||||
* Create notification window with confirm/deny
|
||||
* */
|
||||
public static boolean getConfirmationWindow(String title, String body){
|
||||
Alert alertBox = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alertBox.setTitle(title);
|
||||
alertBox.setHeaderText(null);
|
||||
alertBox.setContentText(body);
|
||||
alertBox.getDialogPane().setMinWidth(Region.USE_PREF_SIZE);
|
||||
alertBox.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
alertBox.setResizable(true); // Java bug workaround for JDR11/OpenJFX. TODO: nothing. really.
|
||||
alertBox.getDialogPane().getStylesheets().add("/res/app_light.css");
|
||||
Optional<ButtonType> result = alertBox.showAndWait();
|
||||
|
||||
return (result.isPresent() && result.get() == ButtonType.OK);
|
||||
}
|
||||
}
|
183
src/main/java/konogonka/Settings/SettingsController.java
Normal file
|
@ -0,0 +1,183 @@
|
|||
package konogonka.Settings;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.TextFormatter;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import konogonka.AppPreferences;
|
||||
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class SettingsController implements Initializable {
|
||||
@FXML
|
||||
private Button okBtn, cancelBtn, importBtn;
|
||||
@FXML
|
||||
private TextField
|
||||
xciHdrKeyTF,
|
||||
hdrKeyTF,
|
||||
keyApp0TF,
|
||||
keyApp1TF,
|
||||
keyApp2TF,
|
||||
keyApp3TF,
|
||||
keyApp4TF,
|
||||
keyApp5TF,
|
||||
keyOcean0TF,
|
||||
keyOcean1TF,
|
||||
keyOcean2TF,
|
||||
keyOcean3TF,
|
||||
keyOcean4TF,
|
||||
keyOcean5TF,
|
||||
keySys0TF,
|
||||
keySys1TF,
|
||||
keySys2TF,
|
||||
keySys3TF,
|
||||
keySys4TF,
|
||||
keySys5TF;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
xciHdrKeyTF.setText(AppPreferences.getInstance().getXciHeaderKey());
|
||||
hdrKeyTF.setText(AppPreferences.getInstance().getHeaderKey());
|
||||
keyApp0TF.setText(AppPreferences.getInstance().getApplicationKey(0));
|
||||
keyApp1TF.setText(AppPreferences.getInstance().getApplicationKey(1));
|
||||
keyApp2TF.setText(AppPreferences.getInstance().getApplicationKey(2));
|
||||
keyApp3TF.setText(AppPreferences.getInstance().getApplicationKey(3));
|
||||
keyApp4TF.setText(AppPreferences.getInstance().getApplicationKey(4));
|
||||
keyApp5TF.setText(AppPreferences.getInstance().getApplicationKey(5));
|
||||
keyOcean0TF.setText(AppPreferences.getInstance().getOceanKey(0));
|
||||
keyOcean1TF.setText(AppPreferences.getInstance().getOceanKey(1));
|
||||
keyOcean2TF.setText(AppPreferences.getInstance().getOceanKey(2));
|
||||
keyOcean3TF.setText(AppPreferences.getInstance().getOceanKey(3));
|
||||
keyOcean4TF.setText(AppPreferences.getInstance().getOceanKey(4));
|
||||
keyOcean5TF.setText(AppPreferences.getInstance().getOceanKey(5));
|
||||
keySys0TF.setText(AppPreferences.getInstance().getSystemKey(0));
|
||||
keySys1TF.setText(AppPreferences.getInstance().getSystemKey(1));
|
||||
keySys2TF.setText(AppPreferences.getInstance().getSystemKey(2));
|
||||
keySys3TF.setText(AppPreferences.getInstance().getSystemKey(3));
|
||||
keySys4TF.setText(AppPreferences.getInstance().getSystemKey(4));
|
||||
keySys5TF.setText(AppPreferences.getInstance().getSystemKey(5));
|
||||
|
||||
setTextValidation(xciHdrKeyTF);
|
||||
setTextValidation(hdrKeyTF);
|
||||
setTextValidation(keyApp0TF);
|
||||
setTextValidation(keyApp1TF);
|
||||
setTextValidation(keyApp2TF);
|
||||
setTextValidation(keyApp3TF);
|
||||
setTextValidation(keyApp4TF);
|
||||
setTextValidation(keyApp5TF);
|
||||
setTextValidation(keyOcean0TF);
|
||||
setTextValidation(keyOcean1TF);
|
||||
setTextValidation(keyOcean2TF);
|
||||
setTextValidation(keyOcean3TF);
|
||||
setTextValidation(keyOcean4TF);
|
||||
setTextValidation(keyOcean5TF);
|
||||
setTextValidation(keySys0TF);
|
||||
setTextValidation(keySys1TF);
|
||||
setTextValidation(keySys2TF);
|
||||
setTextValidation(keySys3TF);
|
||||
setTextValidation(keySys4TF);
|
||||
setTextValidation(keySys5TF);
|
||||
|
||||
importBtn.setOnAction(e->{
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("prod.keys");
|
||||
fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("prod.keys", "prod.keys"));
|
||||
|
||||
File prodKeysFile = fileChooser.showOpenDialog(importBtn.getScene().getWindow());
|
||||
|
||||
if (prodKeysFile != null && prodKeysFile.exists()) {
|
||||
HashMap<String, String > fileMap = new HashMap<>();
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(
|
||||
new FileReader(prodKeysFile)
|
||||
);
|
||||
|
||||
String fileLine;
|
||||
String[] keyValue;
|
||||
while ((fileLine = br.readLine()) != null){
|
||||
keyValue = fileLine.trim().split("\\s+?=\\s+?", 2);
|
||||
if (keyValue.length == 2)
|
||||
fileMap.put(keyValue[0], keyValue[1]);
|
||||
}
|
||||
hdrKeyTF.setText(fileMap.get("header_key"));
|
||||
keyApp0TF.setText(fileMap.get("key_area_key_application_00"));
|
||||
keyApp1TF.setText(fileMap.get("key_area_key_application_01"));
|
||||
keyApp2TF.setText(fileMap.get("key_area_key_application_02"));
|
||||
keyApp3TF.setText(fileMap.get("key_area_key_application_03"));
|
||||
keyApp4TF.setText(fileMap.get("key_area_key_application_04"));
|
||||
keyApp5TF.setText(fileMap.get("key_area_key_application_05"));
|
||||
keyOcean0TF.setText(fileMap.get("key_area_key_ocean_00"));
|
||||
keyOcean1TF.setText(fileMap.get("key_area_key_ocean_01"));
|
||||
keyOcean2TF.setText(fileMap.get("key_area_key_ocean_02"));
|
||||
keyOcean3TF.setText(fileMap.get("key_area_key_ocean_03"));
|
||||
keyOcean4TF.setText(fileMap.get("key_area_key_ocean_04"));
|
||||
keyOcean5TF.setText(fileMap.get("key_area_key_ocean_05"));
|
||||
keySys0TF.setText(fileMap.get("key_area_key_system_00"));
|
||||
keySys1TF.setText(fileMap.get("key_area_key_system_01"));
|
||||
keySys2TF.setText(fileMap.get("key_area_key_system_02"));
|
||||
keySys3TF.setText(fileMap.get("key_area_key_system_03"));
|
||||
keySys4TF.setText(fileMap.get("key_area_key_system_04"));
|
||||
keySys5TF.setText(fileMap.get("key_area_key_system_05"));
|
||||
}
|
||||
catch (IOException ioe){
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
/*
|
||||
for (String key: fileMap.keySet()){
|
||||
System.out.print(key+ " - ");
|
||||
System.out.println(fileMap.get(key));
|
||||
}
|
||||
//*/
|
||||
}
|
||||
});
|
||||
|
||||
cancelBtn.setOnAction(e->{
|
||||
Stage thisStage = (Stage)cancelBtn.getScene().getWindow();
|
||||
thisStage.close();
|
||||
});
|
||||
|
||||
okBtn.setOnAction(e->{
|
||||
Stage thisStage = (Stage)cancelBtn.getScene().getWindow();
|
||||
AppPreferences.getInstance().setAll(
|
||||
xciHdrKeyTF.getText(),
|
||||
hdrKeyTF.getText(),
|
||||
keyApp0TF.getText(),
|
||||
keyApp1TF.getText(),
|
||||
keyApp2TF.getText(),
|
||||
keyApp3TF.getText(),
|
||||
keyApp4TF.getText(),
|
||||
keyApp5TF.getText(),
|
||||
keyOcean0TF.getText(),
|
||||
keyOcean1TF.getText(),
|
||||
keyOcean2TF.getText(),
|
||||
keyOcean3TF.getText(),
|
||||
keyOcean4TF.getText(),
|
||||
keyOcean5TF.getText(),
|
||||
keySys0TF.getText(),
|
||||
keySys1TF.getText(),
|
||||
keySys2TF.getText(),
|
||||
keySys3TF.getText(),
|
||||
keySys4TF.getText(),
|
||||
keySys5TF.getText()
|
||||
);
|
||||
thisStage.close();
|
||||
});
|
||||
}
|
||||
|
||||
private void setTextValidation(TextField tf){
|
||||
tf.setTextFormatter(new TextFormatter<Object>(change -> {
|
||||
if (change.getControlNewText().contains(" ") | change.getControlNewText().contains("\t"))
|
||||
return null;
|
||||
else
|
||||
return change;
|
||||
}));
|
||||
}
|
||||
}
|
50
src/main/java/konogonka/Settings/SettingsWindow.java
Normal file
|
@ -0,0 +1,50 @@
|
|||
package konogonka.Settings;
|
||||
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.stage.Stage;
|
||||
import konogonka.MainFx;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class SettingsWindow {
|
||||
public SettingsWindow(){
|
||||
Stage stageSettings = new Stage();
|
||||
|
||||
stageSettings.setMinWidth(570);
|
||||
stageSettings.setMinHeight(500);
|
||||
|
||||
FXMLLoader loaderSettings = new FXMLLoader(getClass().getResource("/FXML/Settings/SettingsLayout.fxml"));
|
||||
|
||||
Locale userLocale = new Locale(Locale.getDefault().getISO3Language());
|
||||
|
||||
ResourceBundle resourceBundle = ResourceBundle.getBundle("locale", userLocale);
|
||||
|
||||
loaderSettings.setResources(resourceBundle);
|
||||
|
||||
try {
|
||||
Parent parentAbout = loaderSettings.load();
|
||||
|
||||
stageSettings.setTitle(resourceBundle.getString("settings_SettingsName"));
|
||||
|
||||
stageSettings.getIcons().addAll(
|
||||
new Image(MainFx.class.getResourceAsStream("/res/settings_icon32x32.png")),
|
||||
new Image(MainFx.class.getResourceAsStream("/res/settings_icon48x48.png")),
|
||||
new Image(MainFx.class.getResourceAsStream("/res/settings_icon64x64.png")),
|
||||
new Image(MainFx.class.getResourceAsStream("/res/settings_icon128x128.png"))
|
||||
);
|
||||
|
||||
stageSettings.setScene(new Scene(parentAbout, 570, 500));
|
||||
stageSettings.setMinWidth(550.0);
|
||||
stageSettings.setMinHeight(550.0);
|
||||
stageSettings.show();
|
||||
|
||||
} catch (IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
126
src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java
Normal file
|
@ -0,0 +1,126 @@
|
|||
package konogonka.Tools.NCA;
|
||||
|
||||
import konogonka.RainbowHexDump;
|
||||
import konogonka.Tools.NCA.NCASectionTableBlock.NCASectionBlock;
|
||||
import konogonka.Tools.PFS0.PFS0Provider;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.security.Security;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class NCAContentPFS0 {
|
||||
private LinkedList<byte[]> SHA256hashes;
|
||||
private PFS0Provider pfs0;
|
||||
|
||||
public NCAContentPFS0(File file, long offsetPosition, NCASectionBlock ncaSectionBlock, NCAHeaderTableEntry ncaHeaderTableEntry, byte[] decryptedKey){
|
||||
SHA256hashes = new LinkedList<>();
|
||||
try {
|
||||
RandomAccessFile raf = new RandomAccessFile(file, "r");
|
||||
// If it's PFS0Provider
|
||||
if (ncaSectionBlock.getSuperBlockPFS0() != null){
|
||||
// IF NO ENCRYPTION
|
||||
if (ncaSectionBlock.getCryptoType() == 0x1) {
|
||||
long thisMediaLocation = offsetPosition + (ncaHeaderTableEntry.getMediaStartOffset() * 0x200);
|
||||
long hashTableLocation = thisMediaLocation + ncaSectionBlock.getSuperBlockPFS0().getHashTableOffset();
|
||||
long pfs0Location = thisMediaLocation + ncaSectionBlock.getSuperBlockPFS0().getPfs0offset();
|
||||
|
||||
raf.seek(hashTableLocation);
|
||||
|
||||
byte[] rawData;
|
||||
long sha256recordsNumber = ncaSectionBlock.getSuperBlockPFS0().getHashTableSize() / 0x20;
|
||||
// Collect hashes
|
||||
for (int i = 0; i < sha256recordsNumber; i++){
|
||||
rawData = new byte[0x20]; // 32 bytes - size of SHA256 hash
|
||||
if (raf.read(rawData) != -1)
|
||||
SHA256hashes.add(rawData);
|
||||
else
|
||||
break; // TODO: fix
|
||||
}
|
||||
// Get pfs0
|
||||
raf.seek(pfs0Location);
|
||||
pfs0 = new PFS0Provider(file, pfs0Location);
|
||||
|
||||
raf.close();
|
||||
}
|
||||
// If encrypted (regular)
|
||||
else if (ncaSectionBlock.getCryptoType() == 0x3){
|
||||
long thisMediaLocation = offsetPosition + (ncaHeaderTableEntry.getMediaStartOffset() * 0x200); // todo: use this location for CTR
|
||||
long hashTableLocation = thisMediaLocation + ncaSectionBlock.getSuperBlockPFS0().getHashTableOffset();
|
||||
long pfs0Location = thisMediaLocation + ncaSectionBlock.getSuperBlockPFS0().getPfs0offset();
|
||||
|
||||
raf.seek(hashTableLocation);
|
||||
|
||||
byte[] rawData;
|
||||
long sha256recordsNumber = ncaSectionBlock.getSuperBlockPFS0().getHashTableSize() / 0x20;
|
||||
// Collect hashes
|
||||
for (int i = 0; i < sha256recordsNumber; i++){
|
||||
rawData = new byte[0x20]; // 32 bytes - size of SHA256 hash
|
||||
if (raf.read(rawData) != -1)
|
||||
SHA256hashes.add(rawData);
|
||||
else
|
||||
break; // TODO: fix
|
||||
}
|
||||
// Get pfs0
|
||||
raf.seek(pfs0Location);
|
||||
|
||||
rawData = new byte[0x20]; // 32 bytes - size of SHA256 hash
|
||||
|
||||
if (raf.read(rawData) != -1) {
|
||||
System.out.println("Encrypted");
|
||||
RainbowHexDump.hexDumpUTF8(rawData);
|
||||
}
|
||||
try {
|
||||
/*
|
||||
System.out.println("Decrypted?");
|
||||
Security.addProvider(new BouncyCastleProvider()); // TODO: DO FUCKING REMEMBER THIS SHIT FOR CTR
|
||||
IvParameterSpec iv = new IvParameterSpec(new byte[10]);
|
||||
SecretKeySpec key = new SecretKeySpec(decryptedKey, "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC");
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, iv);
|
||||
byte[] decr = cipher.doFinal(rawData);
|
||||
RainbowHexDump.hexDumpUTF8(decr);
|
||||
|
||||
*/
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
raf.close();
|
||||
}
|
||||
}
|
||||
else if (ncaSectionBlock.getSuperBlockIVFC() != null){
|
||||
|
||||
}
|
||||
else {
|
||||
return; // TODO: FIX THIS STUFF
|
||||
}
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public LinkedList<byte[]> getSHA256hashes() { return SHA256hashes; }
|
||||
public PFS0Provider getPfs0() { return pfs0; }
|
||||
}
|
35
src/main/java/konogonka/Tools/NCA/NCAHeaderTableEntry.java
Normal file
|
@ -0,0 +1,35 @@
|
|||
package konogonka.Tools.NCA;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class NCAHeaderTableEntry {
|
||||
|
||||
private long mediaStartOffset;
|
||||
private long mediaEndOffset;
|
||||
private byte[] unknwn1;
|
||||
private byte[] unknwn2;
|
||||
|
||||
public NCAHeaderTableEntry(byte[] table) throws Exception{
|
||||
if (table.length < 0x10)
|
||||
throw new Exception("Section Table size is too small.");
|
||||
|
||||
this.mediaStartOffset = convertUnsignedIntBytesToLong(Arrays.copyOfRange(table, 0x0, 0x4));
|
||||
this.mediaEndOffset = convertUnsignedIntBytesToLong(Arrays.copyOfRange(table, 0x4, 0x8));
|
||||
this.unknwn1 = Arrays.copyOfRange(table, 0x8, 0xC);
|
||||
this.unknwn2 = Arrays.copyOfRange(table, 0xC, 0x10);
|
||||
}
|
||||
|
||||
private long convertUnsignedIntBytesToLong(byte[] intBytes){
|
||||
if (intBytes.length == 4)
|
||||
return ByteBuffer.wrap(Arrays.copyOf(intBytes, 8)).order(ByteOrder.LITTLE_ENDIAN).getLong();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
public long getMediaStartOffset() { return mediaStartOffset; }
|
||||
public long getMediaEndOffset() { return mediaEndOffset; }
|
||||
public byte[] getUnknwn1() { return unknwn1; }
|
||||
public byte[] getUnknwn2() { return unknwn2; }
|
||||
}
|
282
src/main/java/konogonka/Tools/NCA/NCAProvider.java
Normal file
|
@ -0,0 +1,282 @@
|
|||
package konogonka.Tools.NCA;
|
||||
|
||||
import konogonka.Tools.NCA.NCASectionTableBlock.NCASectionBlock;
|
||||
import konogonka.xtsaes.XTSAESCipher;
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static konogonka.LoperConverter.getLElong;
|
||||
|
||||
// TODO: check file size
|
||||
public class NCAProvider {
|
||||
private File file; // File that contains NCA
|
||||
private long offset; // Offset where NCA actually located
|
||||
private HashMap<String, String> keys; // hashmap with keys using _0x naming (where x number 0-N)
|
||||
// Header
|
||||
private byte[] rsa2048one;
|
||||
private byte[] rsa2048two;
|
||||
private String magicnum;
|
||||
private byte systemOrGcIndicator;
|
||||
private byte contentType;
|
||||
private byte cryptoType1; // keyblob index. Considering as number within application/ocean/system
|
||||
private byte keyIndex; // application/ocean/system (kaek index?)
|
||||
private long ncaSize; // Size of this NCA (bytes)
|
||||
private byte[] titleId;
|
||||
private byte[] sdkVersion; // version ver_revision.ver_micro.vev_minor.ver_major
|
||||
private byte cryptoType2; // keyblob index. Considering as number within application/ocean/system
|
||||
private byte[] rightsId;
|
||||
|
||||
private byte[] sha256hash0;
|
||||
private byte[] sha256hash1;
|
||||
private byte[] sha256hash2;
|
||||
private byte[] sha256hash3;
|
||||
|
||||
private byte[] encryptedKey0;
|
||||
private byte[] encryptedKey1;
|
||||
private byte[] encryptedKey2;
|
||||
private byte[] encryptedKey3;
|
||||
|
||||
private byte[] decryptedKey0;
|
||||
private byte[] decryptedKey1;
|
||||
private byte[] decryptedKey2;
|
||||
private byte[] decryptedKey3;
|
||||
|
||||
private NCAHeaderTableEntry tableEntry0;
|
||||
private NCAHeaderTableEntry tableEntry1;
|
||||
private NCAHeaderTableEntry tableEntry2;
|
||||
private NCAHeaderTableEntry tableEntry3;
|
||||
|
||||
private NCASectionBlock sectionBlock0;
|
||||
private NCASectionBlock sectionBlock1;
|
||||
private NCASectionBlock sectionBlock2;
|
||||
private NCASectionBlock sectionBlock3;
|
||||
|
||||
public NCAProvider(File file, HashMap<String, String> keys) throws Exception{
|
||||
this(file, keys, 0);
|
||||
}
|
||||
|
||||
public NCAProvider (File file, HashMap<String, String> keys, long offsetPosition) throws Exception{
|
||||
this.keys = keys;
|
||||
String header_key = keys.get("header_key");
|
||||
if (header_key == null )
|
||||
throw new Exception("header_key is not found within key set provided.");
|
||||
if (header_key.length() != 64)
|
||||
throw new Exception("header_key is too small or too big. Must be 64 symbols.");
|
||||
|
||||
this.file = file;
|
||||
this.offset = offsetPosition;
|
||||
|
||||
KeyParameter key1 = new KeyParameter(
|
||||
hexStrToByteArray(header_key.substring(0, 32))
|
||||
);
|
||||
KeyParameter key2 = new KeyParameter(
|
||||
hexStrToByteArray(header_key.substring(32, 64))
|
||||
);
|
||||
|
||||
XTSAESCipher xtsaesCipher = new XTSAESCipher(false);
|
||||
xtsaesCipher.init(false, key1, key2);
|
||||
//-------------------------------------------------------------------------------------------------------------------------
|
||||
byte[] decryptedHeader = new byte[0xC00];
|
||||
|
||||
RandomAccessFile raf = new RandomAccessFile(file, "r");
|
||||
byte[] encryptedSequence = new byte[0x200];
|
||||
byte[] decryptedSequence;
|
||||
|
||||
raf.seek(offsetPosition);
|
||||
|
||||
for (int i = 0; i < 6; i++){
|
||||
if (raf.read(encryptedSequence) != 0x200)
|
||||
throw new Exception("Read error "+i);
|
||||
decryptedSequence = new byte[0x200];
|
||||
xtsaesCipher.processDataUnit(encryptedSequence, 0, 0x200, decryptedSequence, 0, i);
|
||||
System.arraycopy(decryptedSequence, 0, decryptedHeader, i * 0x200, 0x200);
|
||||
}
|
||||
|
||||
getHeader(decryptedHeader);
|
||||
|
||||
raf.close();
|
||||
|
||||
/*
|
||||
//---------------------------------------------------------------------
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("/tmp/decrypted.nca"));
|
||||
int i = 0;
|
||||
byte[] block = new byte[0x200];
|
||||
while (fis.read(block) != -1){
|
||||
decryptedSequence = new byte[0x200];
|
||||
xtsaesCipher.processDataUnit(block, 0, 0x200, decryptedSequence, 0, i++);
|
||||
bos.write(decryptedSequence);
|
||||
}
|
||||
bos.close();
|
||||
//---------------------------------------------------------------------*/
|
||||
}
|
||||
|
||||
private byte[] hexStrToByteArray(String s) {
|
||||
int len = s.length();
|
||||
byte[] data = new byte[len / 2];
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
||||
+ Character.digit(s.charAt(i+1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
private void getHeader(byte[] decryptedData) throws Exception{
|
||||
rsa2048one = Arrays.copyOfRange(decryptedData, 0, 0x100);
|
||||
rsa2048two = Arrays.copyOfRange(decryptedData, 0x100, 0x200);
|
||||
magicnum = new String(decryptedData, 0x200, 0x4, StandardCharsets.US_ASCII);
|
||||
systemOrGcIndicator = decryptedData[0x204];
|
||||
contentType = decryptedData[0x205];
|
||||
cryptoType1 = decryptedData[0x206];
|
||||
keyIndex = decryptedData[0x207];
|
||||
ncaSize = getLElong(decryptedData, 0x208);
|
||||
titleId = Arrays.copyOfRange(decryptedData, 0x210, 0x21C); // 0x218 ?
|
||||
sdkVersion = Arrays.copyOfRange(decryptedData, 0x21c, 0x220);
|
||||
cryptoType2 = decryptedData[0x220];
|
||||
rightsId = Arrays.copyOfRange(decryptedData, 0x230, 0x240);
|
||||
byte[] tableBytes = Arrays.copyOfRange(decryptedData, 0x240, 0x280);
|
||||
byte[] sha256tableBytes = Arrays.copyOfRange(decryptedData, 0x280, 0x300);
|
||||
sha256hash0 = Arrays.copyOfRange(sha256tableBytes, 0, 0x20);
|
||||
sha256hash1 = Arrays.copyOfRange(sha256tableBytes, 0x20, 0x40);
|
||||
sha256hash2 = Arrays.copyOfRange(sha256tableBytes, 0x40, 0x60);
|
||||
sha256hash3 = Arrays.copyOfRange(sha256tableBytes, 0x60, 0x80);
|
||||
byte [] encryptedKeysArea = Arrays.copyOfRange(decryptedData, 0x300, 0x340);
|
||||
|
||||
encryptedKey0 = Arrays.copyOfRange(encryptedKeysArea, 0, 0x10);
|
||||
encryptedKey1 = Arrays.copyOfRange(encryptedKeysArea, 0x10, 0x20);
|
||||
encryptedKey2 = Arrays.copyOfRange(encryptedKeysArea, 0x20, 0x30);
|
||||
encryptedKey3 = Arrays.copyOfRange(encryptedKeysArea, 0x30, 0x40);
|
||||
|
||||
//todo: if nca3 proceed
|
||||
// If no rights ID (ticket?) exists
|
||||
if (Arrays.equals(rightsId, new byte[0x10])) {
|
||||
byte realCryptoType;
|
||||
if (cryptoType1 < cryptoType2)
|
||||
realCryptoType = cryptoType2;
|
||||
else
|
||||
realCryptoType = cryptoType1;
|
||||
|
||||
if (realCryptoType > 0) // TODO: CLARIFY WHY THEH FUCK IS IT FAIR????
|
||||
realCryptoType -= 1;
|
||||
|
||||
|
||||
String keyAreaKey;
|
||||
switch (keyIndex){
|
||||
case 0:
|
||||
keyAreaKey = keys.get("key_area_key_application_0"+realCryptoType);
|
||||
System.out.println("Using key_area_key_application_0"+realCryptoType);
|
||||
break;
|
||||
case 1:
|
||||
keyAreaKey = keys.get("key_area_key_ocean_0"+realCryptoType);
|
||||
System.out.println("Using key_area_key_ocean_0"+realCryptoType);
|
||||
break;
|
||||
case 2:
|
||||
keyAreaKey = keys.get("key_area_key_system_0"+realCryptoType);
|
||||
System.out.println("Using key_area_key_system_0"+realCryptoType);
|
||||
break;
|
||||
default:
|
||||
keyAreaKey = null;
|
||||
}
|
||||
|
||||
if (keyAreaKey != null){
|
||||
SecretKeySpec skSpec = new SecretKeySpec(hexStrToByteArray(keyAreaKey), "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, skSpec);
|
||||
decryptedKey0 = cipher.doFinal(encryptedKey0);
|
||||
decryptedKey1 = cipher.doFinal(encryptedKey1);
|
||||
decryptedKey2 = cipher.doFinal(encryptedKey2);
|
||||
decryptedKey3 = cipher.doFinal(encryptedKey3);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
}
|
||||
|
||||
tableEntry0 = new NCAHeaderTableEntry(tableBytes);
|
||||
tableEntry1 = new NCAHeaderTableEntry(Arrays.copyOfRange(tableBytes, 0x10, 0x20));
|
||||
tableEntry2 = new NCAHeaderTableEntry(Arrays.copyOfRange(tableBytes, 0x20, 0x30));
|
||||
tableEntry3 = new NCAHeaderTableEntry(Arrays.copyOfRange(tableBytes, 0x30, 0x40));
|
||||
|
||||
sectionBlock0 = new NCASectionBlock(Arrays.copyOfRange(decryptedData, 0x400, 0x600));
|
||||
sectionBlock1 = new NCASectionBlock(Arrays.copyOfRange(decryptedData, 0x600, 0x800));
|
||||
sectionBlock2 = new NCASectionBlock(Arrays.copyOfRange(decryptedData, 0x800, 0xa00));
|
||||
sectionBlock3 = new NCASectionBlock(Arrays.copyOfRange(decryptedData, 0xa00, 0xc00));
|
||||
}
|
||||
|
||||
public byte[] getRsa2048one() { return rsa2048one; }
|
||||
public byte[] getRsa2048two() { return rsa2048two; }
|
||||
public String getMagicnum() { return magicnum; }
|
||||
public byte getSystemOrGcIndicator() { return systemOrGcIndicator; }
|
||||
public byte getContentType() { return contentType; }
|
||||
public byte getCryptoType1() { return cryptoType1; }
|
||||
public byte getKeyIndex() { return keyIndex; }
|
||||
public long getNcaSize() { return ncaSize; }
|
||||
public byte[] getTitleId() { return titleId; }
|
||||
public byte[] getSdkVersion() { return sdkVersion; }
|
||||
public byte getCryptoType2() { return cryptoType2; }
|
||||
public byte[] getRightsId() { return rightsId; }
|
||||
|
||||
public byte[] getSha256hash0() { return sha256hash0; }
|
||||
public byte[] getSha256hash1() { return sha256hash1; }
|
||||
public byte[] getSha256hash2() { return sha256hash2; }
|
||||
public byte[] getSha256hash3() { return sha256hash3; }
|
||||
|
||||
public byte[] getEncryptedKey0() { return encryptedKey0; }
|
||||
public byte[] getEncryptedKey1() { return encryptedKey1; }
|
||||
public byte[] getEncryptedKey2() { return encryptedKey2; }
|
||||
public byte[] getEncryptedKey3() { return encryptedKey3; }
|
||||
|
||||
public byte[] getDecryptedKey0() { return decryptedKey0; }
|
||||
public byte[] getDecryptedKey1() { return decryptedKey1; }
|
||||
public byte[] getDecryptedKey2() { return decryptedKey2; }
|
||||
public byte[] getDecryptedKey3() { return decryptedKey3; }
|
||||
|
||||
public NCAHeaderTableEntry getTableEntry0() { return tableEntry0; }
|
||||
public NCAHeaderTableEntry getTableEntry1() { return tableEntry1; }
|
||||
public NCAHeaderTableEntry getTableEntry2() { return tableEntry2; }
|
||||
public NCAHeaderTableEntry getTableEntry3() { return tableEntry3; }
|
||||
|
||||
public NCASectionBlock getSectionBlock0() { return sectionBlock0; }
|
||||
public NCASectionBlock getSectionBlock1() { return sectionBlock1; }
|
||||
public NCASectionBlock getSectionBlock2() { return sectionBlock2; }
|
||||
public NCASectionBlock getSectionBlock3() { return sectionBlock3; }
|
||||
|
||||
/**
|
||||
* Get content for the selected section
|
||||
* @param sectionNumber should be 1-4
|
||||
* */
|
||||
public NCAContentPFS0 getNCAContentPFS0(int sectionNumber){
|
||||
switch (sectionNumber){
|
||||
case 0:
|
||||
return new NCAContentPFS0(file, offset, sectionBlock0, tableEntry0, decryptedKey2); // TODO: remove decryptedKey2
|
||||
case 1:
|
||||
return new NCAContentPFS0(file, offset, sectionBlock1, tableEntry1, decryptedKey2);
|
||||
case 2:
|
||||
return new NCAContentPFS0(file, offset, sectionBlock2, tableEntry2, decryptedKey2);
|
||||
case 3:
|
||||
return new NCAContentPFS0(file, offset, sectionBlock3, tableEntry3, decryptedKey2);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 0 OR 2 crypto type
|
||||
// 0,1,2 kaek index
|
||||
//settings.keyset.key_area_keys[ctx->crypto_type][ctx->header.kaek_ind]
|
||||
/*
|
||||
0x207 =
|
||||
0: key_area_key_application_ 0x206 range:[0-6]; usually used 0 or 2
|
||||
1: key_area_key_ocean [0-6]
|
||||
2: key_area_key_system [0-6]
|
||||
|
||||
if(ncahdr_x206 < ncahdr_x220){ret = ncahdr_x220; } else { ret = ncahdr_x206; } return ret;
|
||||
|
||||
ret > 0? ret--
|
||||
|
||||
*/
|
|
@ -0,0 +1,96 @@
|
|||
package konogonka.Tools.NCA.NCASectionTableBlock;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static konogonka.LoperConverter.getLEint;
|
||||
import static konogonka.LoperConverter.getLElong;
|
||||
|
||||
public class NCASectionBlock {
|
||||
private byte[] version;
|
||||
private byte fsType;
|
||||
private byte hashType;
|
||||
private byte cryptoType;
|
||||
private byte padding;
|
||||
private SuperBlockIVFC superBlockIVFC;
|
||||
private SuperBlockPFS0 superBlockPFS0;
|
||||
private byte[] BKTRfullHeader;
|
||||
// BKTR extended
|
||||
private long BKTRoffsetSection1;
|
||||
private long BKTRsizeSection1;
|
||||
private String BKTRmagicSection1;
|
||||
private int BKTRu32Section1;
|
||||
private int BKTRs32Section1;
|
||||
private byte[] BKTRunknownSection1;
|
||||
|
||||
private long BKTRoffsetSection2;
|
||||
private long BKTRsizeSection2;
|
||||
private String BKTRmagicSection2;
|
||||
private int BKTRu32Section2;
|
||||
private int BKTRs32Section2;
|
||||
private byte[] BKTRunknownSection2;
|
||||
|
||||
private byte[] BKTRunknown1;
|
||||
private byte[] BKTRunknown2;
|
||||
|
||||
public NCASectionBlock(byte[] tableBlockBytes) throws Exception{
|
||||
if (tableBlockBytes.length != 0x200)
|
||||
throw new Exception("Table Block Section size is incorrect.");
|
||||
version = Arrays.copyOfRange(tableBlockBytes, 0, 0x2);
|
||||
fsType = tableBlockBytes[0x2];
|
||||
hashType = tableBlockBytes[0x3];
|
||||
cryptoType = tableBlockBytes[0x4];
|
||||
padding = tableBlockBytes[0x5];
|
||||
byte[] superBlockBytes = Arrays.copyOfRange(tableBlockBytes, 0x8, 0xf8);
|
||||
|
||||
if ((fsType == 0) && (hashType == 0x3))
|
||||
superBlockIVFC = new SuperBlockIVFC(superBlockBytes);
|
||||
else if ((fsType == 0x1) && (hashType == 0x2))
|
||||
superBlockPFS0 = new SuperBlockPFS0(superBlockBytes);
|
||||
|
||||
BKTRfullHeader = Arrays.copyOfRange(tableBlockBytes, 0x100, 0x200);
|
||||
|
||||
BKTRoffsetSection1 = getLElong(BKTRfullHeader, 0);
|
||||
BKTRsizeSection1 = getLElong(BKTRfullHeader, 0x8);
|
||||
BKTRmagicSection1 = new String(Arrays.copyOfRange(BKTRfullHeader, 0x10, 0x14), StandardCharsets.US_ASCII);
|
||||
BKTRu32Section1 = getLEint(BKTRfullHeader, 0x14);
|
||||
BKTRs32Section1 = getLEint(BKTRfullHeader, 0x18);
|
||||
BKTRunknownSection1 = Arrays.copyOfRange(tableBlockBytes, 0x1c, 0x20);
|
||||
|
||||
BKTRoffsetSection2 = getLElong(BKTRfullHeader, 0x20);
|
||||
BKTRsizeSection2 = getLElong(BKTRfullHeader, 0x28);
|
||||
BKTRmagicSection2 = new String(Arrays.copyOfRange(BKTRfullHeader, 0x30, 0x34), StandardCharsets.US_ASCII);
|
||||
BKTRu32Section2 = getLEint(BKTRfullHeader, 0x34);
|
||||
BKTRs32Section2 = getLEint(BKTRfullHeader, 0x38);
|
||||
BKTRunknownSection2 = Arrays.copyOfRange(tableBlockBytes, 0x3c, 0x40);
|
||||
|
||||
BKTRunknown1 = Arrays.copyOfRange(tableBlockBytes, 0x40, 0x44);
|
||||
BKTRunknown2 = Arrays.copyOfRange(tableBlockBytes, 0x44, 0x48);
|
||||
}
|
||||
|
||||
public byte[] getVersion() { return version; }
|
||||
public byte getFsType() { return fsType; }
|
||||
public byte getHashType() { return hashType; }
|
||||
public byte getCryptoType() { return cryptoType; }
|
||||
public byte getPadding() { return padding; }
|
||||
public SuperBlockIVFC getSuperBlockIVFC() { return superBlockIVFC; }
|
||||
public SuperBlockPFS0 getSuperBlockPFS0() { return superBlockPFS0; }
|
||||
public byte[] getBKTRfullHeader() { return BKTRfullHeader; }
|
||||
|
||||
public long getBKTRoffsetSection1() { return BKTRoffsetSection1; }
|
||||
public long getBKTRsizeSection1() { return BKTRsizeSection1; }
|
||||
public String getBKTRmagicSection1() { return BKTRmagicSection1; }
|
||||
public int getBKTRu32Section1() { return BKTRu32Section1; }
|
||||
public int getBKTRs32Section1() { return BKTRs32Section1; }
|
||||
public byte[] getBKTRunknownSection1() { return BKTRunknownSection1; }
|
||||
public long getBKTRoffsetSection2() { return BKTRoffsetSection2; }
|
||||
public long getBKTRsizeSection2() { return BKTRsizeSection2; }
|
||||
public String getBKTRmagicSection2() { return BKTRmagicSection2; }
|
||||
public int getBKTRu32Section2() { return BKTRu32Section2; }
|
||||
public int getBKTRs32Section2() { return BKTRs32Section2; }
|
||||
public byte[] getBKTRunknownSection2() { return BKTRunknownSection2; }
|
||||
public byte[] getBKTRunknown1() { return BKTRunknown1; }
|
||||
public byte[] getBKTRunknown2() { return BKTRunknown2; }
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
package konogonka.Tools.NCA.NCASectionTableBlock;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static konogonka.LoperConverter.getLEint;
|
||||
import static konogonka.LoperConverter.getLElong;
|
||||
|
||||
public class SuperBlockIVFC {
|
||||
private String magic;
|
||||
private int magicNumber;
|
||||
private int masterHashSize;
|
||||
private int totalNumberOfLevels;
|
||||
private long lvl1Offset;
|
||||
private long lvl1Size;
|
||||
private int lvl1SBlockSize;
|
||||
private byte[] reserved1;
|
||||
|
||||
private long lvl2Offset;
|
||||
private long lvl2Size;
|
||||
private int lvl2SBlockSize;
|
||||
private byte[] reserved2;
|
||||
|
||||
private long lvl3Offset;
|
||||
private long lvl3Size;
|
||||
private int lvl3SBlockSize;
|
||||
private byte[] reserved3;
|
||||
|
||||
private long lvl4Offset;
|
||||
private long lvl4Size;
|
||||
private int lvl4SBlockSize;
|
||||
private byte[] reserved4;
|
||||
|
||||
private long lvl5Offset;
|
||||
private long lvl5Size;
|
||||
private int lvl5SBlockSize;
|
||||
private byte[] reserved5;
|
||||
|
||||
private long lvl6Offset;
|
||||
private long lvl6Size;
|
||||
private int lvl6SBlockSize;
|
||||
private byte[] reserved6;
|
||||
|
||||
private byte[] unknown;
|
||||
private byte[] hash;
|
||||
|
||||
SuperBlockIVFC(byte[] sbBytes){
|
||||
this.magic = new String(Arrays.copyOfRange(sbBytes, 0, 4), StandardCharsets.US_ASCII);
|
||||
this.magicNumber = getLEint(sbBytes, 0x4);
|
||||
this.masterHashSize = getLEint(sbBytes, 0x8);
|
||||
this.totalNumberOfLevels = getLEint(sbBytes, 0xc);
|
||||
|
||||
this.lvl1Offset = getLElong(sbBytes, 0x10);
|
||||
this.lvl1Size = getLElong(sbBytes, 0x18);
|
||||
this.lvl1SBlockSize = getLEint(sbBytes, 0x20);
|
||||
this.reserved1 = Arrays.copyOfRange(sbBytes, 0x24, 0x28);
|
||||
|
||||
this.lvl2Offset = getLElong(sbBytes, 0x28);
|
||||
this.lvl2Size = getLElong(sbBytes, 0x30);
|
||||
this.lvl2SBlockSize = getLEint(sbBytes, 0x38);
|
||||
this.reserved2 = Arrays.copyOfRange(sbBytes, 0x3c, 0x40);
|
||||
|
||||
this.lvl3Offset = getLElong(sbBytes, 0x40);
|
||||
this.lvl3Size = getLElong(sbBytes, 0x48);
|
||||
this.lvl3SBlockSize = getLEint(sbBytes, 0x50);
|
||||
this.reserved3 = Arrays.copyOfRange(sbBytes, 0x54, 0x58);
|
||||
|
||||
this.lvl4Offset = getLElong(sbBytes, 0x58);
|
||||
this.lvl4Size = getLElong(sbBytes, 0x60);
|
||||
this.lvl4SBlockSize = getLEint(sbBytes, 0x68);
|
||||
this.reserved4 = Arrays.copyOfRange(sbBytes, 0x6c, 0x70);
|
||||
|
||||
this.lvl5Offset = getLElong(sbBytes, 0x70);
|
||||
this.lvl5Size = getLElong(sbBytes, 0x78);
|
||||
this.lvl5SBlockSize = getLEint(sbBytes, 0x80);
|
||||
this.reserved5 = Arrays.copyOfRange(sbBytes, 0x84, 0x88);
|
||||
|
||||
this.lvl6Offset = getLElong(sbBytes, 0x88);
|
||||
this.lvl6Size = getLElong(sbBytes, 0x90);
|
||||
this.lvl6SBlockSize = getLEint(sbBytes, 0x98);
|
||||
this.reserved6 = Arrays.copyOfRange(sbBytes, 0x9c, 0xa0);
|
||||
|
||||
this.unknown = Arrays.copyOfRange(sbBytes, 0xa0, 0xc0);
|
||||
this.hash = Arrays.copyOfRange(sbBytes, 0xc0, 0xe0);
|
||||
/*
|
||||
System.out.println(magic);
|
||||
System.out.println(magicNumber);
|
||||
System.out.println(masterHashSize);
|
||||
System.out.println(totalNumberOfLevels);
|
||||
System.out.println(lvl1Offset);
|
||||
System.out.println(lvl1Size);
|
||||
System.out.println(lvl1SBlockSize);
|
||||
RainbowHexDump.hexDumpUTF8(reserved1);
|
||||
|
||||
System.out.println(lvl2Offset);
|
||||
System.out.println(lvl2Size);
|
||||
System.out.println(lvl2SBlockSize);
|
||||
RainbowHexDump.hexDumpUTF8(reserved2);
|
||||
|
||||
System.out.println(lvl3Offset);
|
||||
System.out.println(lvl3Size);
|
||||
System.out.println(lvl3SBlockSize);
|
||||
RainbowHexDump.hexDumpUTF8(reserved3);
|
||||
|
||||
System.out.println(lvl4Offset);
|
||||
System.out.println(lvl4Size);
|
||||
System.out.println(lvl4SBlockSize);
|
||||
RainbowHexDump.hexDumpUTF8(reserved4);
|
||||
|
||||
System.out.println(lvl5Offset);
|
||||
System.out.println(lvl5Size);
|
||||
System.out.println(lvl5SBlockSize);
|
||||
RainbowHexDump.hexDumpUTF8(reserved5);
|
||||
|
||||
System.out.println(lvl6Offset);
|
||||
System.out.println(lvl6Size);
|
||||
System.out.println(lvl6SBlockSize);
|
||||
RainbowHexDump.hexDumpUTF8(reserved6);
|
||||
|
||||
RainbowHexDump.hexDumpUTF8(unknown);
|
||||
RainbowHexDump.hexDumpUTF8(hash);
|
||||
// */
|
||||
}
|
||||
|
||||
public String getMagic() { return magic; }
|
||||
public int getMagicNumber() { return magicNumber; }
|
||||
public int getMasterHashSize() { return masterHashSize; }
|
||||
public int getTotalNumberOfLevels() { return totalNumberOfLevels; }
|
||||
public long getLvl1Offset() { return lvl1Offset; }
|
||||
public long getLvl1Size() { return lvl1Size; }
|
||||
public int getLvl1SBlockSize() { return lvl1SBlockSize; }
|
||||
public byte[] getReserved1() { return reserved1; }
|
||||
public long getLvl2Offset() { return lvl2Offset; }
|
||||
public long getLvl2Size() { return lvl2Size; }
|
||||
public int getLvl2SBlockSize() { return lvl2SBlockSize; }
|
||||
public byte[] getReserved2() { return reserved2; }
|
||||
public long getLvl3Offset() { return lvl3Offset; }
|
||||
public long getLvl3Size() { return lvl3Size; }
|
||||
public int getLvl3SBlockSize() { return lvl3SBlockSize; }
|
||||
public byte[] getReserved3() { return reserved3; }
|
||||
public long getLvl4Offset() { return lvl4Offset; }
|
||||
public long getLvl4Size() { return lvl4Size; }
|
||||
public int getLvl4SBlockSize() { return lvl4SBlockSize; }
|
||||
public byte[] getReserved4() { return reserved4; }
|
||||
public long getLvl5Offset() { return lvl5Offset; }
|
||||
public long getLvl5Size() { return lvl5Size; }
|
||||
public int getLvl5SBlockSize() { return lvl5SBlockSize; }
|
||||
public byte[] getReserved5() { return reserved5; }
|
||||
public long getLvl6Offset() { return lvl6Offset; }
|
||||
public long getLvl6Size() { return lvl6Size; }
|
||||
public int getLvl6SBlockSize() { return lvl6SBlockSize; }
|
||||
public byte[] getReserved6() { return reserved6; }
|
||||
public byte[] getUnknown() { return unknown; }
|
||||
public byte[] getHash() { return hash; }
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package konogonka.Tools.NCA.NCASectionTableBlock;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static konogonka.LoperConverter.getLEint;
|
||||
import static konogonka.LoperConverter.getLElong;
|
||||
|
||||
public class SuperBlockPFS0 {
|
||||
private byte[] SHA256hash;
|
||||
private int blockSize;
|
||||
private int unknownNumberTwo;
|
||||
private long hashTableOffset;
|
||||
private long hashTableSize;
|
||||
private long pfs0offset;
|
||||
private long pfs0size;
|
||||
private byte[] zeroes;
|
||||
|
||||
SuperBlockPFS0(byte[] sbBytes){
|
||||
SHA256hash = Arrays.copyOfRange(sbBytes, 0, 0x20);
|
||||
blockSize = getLEint(sbBytes, 0x20);
|
||||
unknownNumberTwo = getLEint(sbBytes, 0x24);
|
||||
hashTableOffset = getLElong(sbBytes, 0x28);
|
||||
hashTableSize = getLElong(sbBytes, 0x30);
|
||||
pfs0offset = getLElong(sbBytes, 0x38);
|
||||
pfs0size = getLElong(sbBytes, 0x40);
|
||||
zeroes = Arrays.copyOfRange(sbBytes, 0x48, 0xf8);
|
||||
/*
|
||||
RainbowHexDump.hexDumpUTF8(SHA256hash);
|
||||
System.out.println(blockSize);
|
||||
System.out.println(unknownNumberTwo);
|
||||
System.out.println(hashTableOffset);
|
||||
System.out.println(hashTableSize);
|
||||
System.out.println(pfs0offset);
|
||||
System.out.println(pfs0size);
|
||||
RainbowHexDump.hexDumpUTF8(zeroes);
|
||||
*/
|
||||
}
|
||||
|
||||
public byte[] getSHA256hash() { return SHA256hash; }
|
||||
public int getBlockSize() { return blockSize; }
|
||||
public int getUnknownNumberTwo() { return unknownNumberTwo; }
|
||||
public long getHashTableOffset() { return hashTableOffset; }
|
||||
public long getHashTableSize() { return hashTableSize; }
|
||||
public long getPfs0offset() { return pfs0offset; }
|
||||
public long getPfs0size() { return pfs0size; }
|
||||
public byte[] getZeroes() { return zeroes; }
|
||||
}
|
112
src/main/java/konogonka/Tools/PFS0/PFS0Provider.java
Normal file
|
@ -0,0 +1,112 @@
|
|||
package konogonka.Tools.PFS0;
|
||||
|
||||
import konogonka.RainbowHexDump;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static konogonka.LoperConverter.*;
|
||||
|
||||
public class PFS0Provider {
|
||||
private long pfs0offsetPosition;
|
||||
private long rawFileDataStart;
|
||||
|
||||
private String magic;
|
||||
private int filesCount;
|
||||
private int stringTableSize;
|
||||
private byte[] padding;
|
||||
private PFS0subFile[] pfs0subFiles;
|
||||
|
||||
public PFS0Provider(File fileWithPfs0) throws Exception{ this(fileWithPfs0, 0); }
|
||||
|
||||
public PFS0Provider(File fileWithPfs0, long pfs0offsetPosition) throws Exception{
|
||||
this.pfs0offsetPosition = pfs0offsetPosition;
|
||||
|
||||
try {
|
||||
RandomAccessFile raf = new RandomAccessFile(fileWithPfs0, "r");
|
||||
|
||||
raf.seek(pfs0offsetPosition);
|
||||
byte[] fileStartingBytes = new byte[0x10];
|
||||
// Read PFS0Provider, files count, header, padding (4 zero bytes)
|
||||
if (raf.read(fileStartingBytes) != 0x10){
|
||||
raf.close();
|
||||
throw new Exception("PFS0Provider: Unable to read starting bytes");
|
||||
}
|
||||
// Check PFS0Provider
|
||||
magic = new String(fileStartingBytes, 0x0, 0x4, StandardCharsets.US_ASCII);
|
||||
if (! magic.equals("PFS0")){
|
||||
raf.close();
|
||||
throw new Exception("PFS0Provider: Bad magic");
|
||||
}
|
||||
// Get files count
|
||||
filesCount = getLEint(fileStartingBytes, 0x4);
|
||||
if (filesCount <= 0 ) {
|
||||
raf.close();
|
||||
throw new Exception("PFS0Provider: Files count is too small");
|
||||
}
|
||||
// Get string table
|
||||
stringTableSize = getLEint(fileStartingBytes, 0x8);
|
||||
if (stringTableSize <= 0 ){
|
||||
raf.close();
|
||||
throw new Exception("PFS0Provider: String table is too small");
|
||||
}
|
||||
padding = Arrays.copyOfRange(fileStartingBytes, 0xc, 0x10);
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
pfs0subFiles = new PFS0subFile[filesCount];
|
||||
|
||||
long[] offsetsSubFiles = new long[filesCount];
|
||||
long[] sizesSubFiles = new long[filesCount];
|
||||
int[] strTableOffsets = new int[filesCount];
|
||||
byte[][] zeroBytes = new byte[filesCount][];
|
||||
|
||||
byte[] fileEntryTable = new byte[0x18];
|
||||
for (int i=0; i<filesCount; i++){
|
||||
if (raf.read(fileEntryTable) != 0x18)
|
||||
throw new Exception("PFS0Provider: String table is too small");
|
||||
offsetsSubFiles[i] = getLElong(fileEntryTable, 0);
|
||||
sizesSubFiles[i] = getLElong(fileEntryTable, 0x8);
|
||||
strTableOffsets[i] = getLEint(fileEntryTable, 0x10);
|
||||
zeroBytes[i] = Arrays.copyOfRange(fileEntryTable, 0x14, 0x18);
|
||||
}
|
||||
//**********************************************************************************************************
|
||||
// In here pointer in front of String table
|
||||
String[] subFileNames = new String[filesCount];
|
||||
byte[] stringTbl = new byte[stringTableSize];
|
||||
if (raf.read(stringTbl) != stringTableSize){
|
||||
throw new Exception("Read PFS0Provider String table failure. Can't read requested string table size ("+stringTableSize+")");
|
||||
}
|
||||
|
||||
for (int i=0; i < filesCount; i++){
|
||||
int j = 0;
|
||||
while (stringTbl[strTableOffsets[i]+j] != (byte)0x00)
|
||||
j++;
|
||||
subFileNames[i] = new String(stringTbl, strTableOffsets[i], j, StandardCharsets.UTF_8);
|
||||
}
|
||||
for (int i = 0; i < filesCount; i++){
|
||||
pfs0subFiles[i] = new PFS0subFile(
|
||||
subFileNames[i],
|
||||
offsetsSubFiles[i],
|
||||
sizesSubFiles[i],
|
||||
zeroBytes[i]
|
||||
);
|
||||
}
|
||||
rawFileDataStart = raf.getFilePointer();
|
||||
raf.close();
|
||||
}
|
||||
catch (IOException ioe){
|
||||
throw new IOException("PFS0Provider: "+ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public long getPfs0offsetPosition() { return pfs0offsetPosition; }
|
||||
public String getMagic() { return magic; }
|
||||
public int getFilesCount() { return filesCount; }
|
||||
public int getStringTableSize() { return stringTableSize; }
|
||||
public byte[] getPadding() { return padding; }
|
||||
|
||||
public long getRawFileDataStart() { return rawFileDataStart; }
|
||||
public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; }
|
||||
}
|
20
src/main/java/konogonka/Tools/PFS0/PFS0subFile.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
package konogonka.Tools.PFS0;
|
||||
|
||||
public class PFS0subFile {
|
||||
private String name;
|
||||
private long offset; // REAL in file (including offset in NCA/NSP file)
|
||||
private long size;
|
||||
private byte[] zeroes;
|
||||
|
||||
public PFS0subFile(String name, long offset, long size, byte[] zeroesInTable){
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
this.size = size;
|
||||
this.zeroes = zeroesInTable;
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
public long getOffset() { return offset; }
|
||||
public long getSize() { return size; }
|
||||
public byte[] getZeroes() { return zeroes; }
|
||||
}
|
27
src/main/java/konogonka/Tools/XCI/HFS0File.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
package konogonka.Tools.XCI;
|
||||
|
||||
public class HFS0File {
|
||||
private String name;
|
||||
private long offset;
|
||||
private long size;
|
||||
private long hashedRegionSize;
|
||||
private boolean padding;
|
||||
private byte[] SHA256Hash;
|
||||
|
||||
public HFS0File(String name, long offset, long size, long hashedRegionSize, boolean padding, byte[] SHA256Hash){
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
this.size = size;
|
||||
this.hashedRegionSize = hashedRegionSize;
|
||||
this.padding = padding;
|
||||
this.SHA256Hash = SHA256Hash;
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
public long getOffset() { return offset; }
|
||||
public long getSize() { return size; }
|
||||
public long getHashedRegionSize() { return hashedRegionSize; }
|
||||
public boolean isPadding() { return padding; }
|
||||
public byte[] getSHA256Hash() { return SHA256Hash; }
|
||||
|
||||
}
|
109
src/main/java/konogonka/Tools/XCI/HFS0Provider.java
Normal file
|
@ -0,0 +1,109 @@
|
|||
package konogonka.Tools.XCI;
|
||||
|
||||
import konogonka.RainbowHexDump;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import static konogonka.LoperConverter.*;
|
||||
|
||||
/**
|
||||
* HFS0
|
||||
* */
|
||||
public class HFS0Provider {
|
||||
|
||||
private boolean magicHFS0;
|
||||
private int filesCnt;
|
||||
private boolean paddingHfs0;
|
||||
private int stringTableSize;
|
||||
private long rawFileDataStart;
|
||||
|
||||
private HFS0File[] hfs0Files;
|
||||
|
||||
HFS0Provider(long hfsOffsetPosition, RandomAccessFile raf) throws Exception{
|
||||
byte[] hfs0bytes = new byte[16];
|
||||
try{
|
||||
raf.seek(hfsOffsetPosition);
|
||||
if (raf.read(hfs0bytes) != 16){
|
||||
throw new Exception("Read HFS0 structure failure. Can't read first 16 bytes on requested offset.");
|
||||
}
|
||||
}
|
||||
catch (IOException ioe){
|
||||
throw new Exception("Read HFS0 structure failure. Can't read first 16 bytes on requested offset: "+ioe.getMessage());
|
||||
}
|
||||
magicHFS0 = Arrays.equals(Arrays.copyOfRange(hfs0bytes, 0, 4),new byte[]{0x48, 0x46, 0x53, 0x30});
|
||||
filesCnt = getLEint(hfs0bytes, 0x4);
|
||||
stringTableSize = getLEint(hfs0bytes, 8);
|
||||
paddingHfs0 = Arrays.equals(Arrays.copyOfRange(hfs0bytes, 12, 16),new byte[4]);
|
||||
|
||||
hfs0Files = new HFS0File[filesCnt];
|
||||
|
||||
// TODO: IF NOT EMPTY TABLE:
|
||||
|
||||
long[] offsetHfs0files = new long[filesCnt];
|
||||
long[] sizeHfs0files = new long[filesCnt];
|
||||
int[] hashedRegionSizeHfs0Files = new int[filesCnt];
|
||||
boolean[] paddingHfs0Files = new boolean[filesCnt];
|
||||
byte[][] SHA256HashHfs0Files = new byte[filesCnt][];
|
||||
int[] strTableOffsets = new int[filesCnt];
|
||||
|
||||
try {
|
||||
// Populate meta information regarding each file inside (?) HFS0
|
||||
byte[] metaInfoBytes = new byte[64];
|
||||
for (int i=0; i < filesCnt; i++){
|
||||
if (raf.read(metaInfoBytes) != 64) {
|
||||
throw new Exception("Read HFS0 File Entry Table failure for file # "+i);
|
||||
}
|
||||
offsetHfs0files[i] = getLElong(metaInfoBytes, 0);
|
||||
sizeHfs0files[i] = getLElong(metaInfoBytes, 8);
|
||||
hashedRegionSizeHfs0Files[i] = getLEint(metaInfoBytes, 20);
|
||||
paddingHfs0Files[i] = Arrays.equals(Arrays.copyOfRange(metaInfoBytes, 24, 32), new byte[8]);
|
||||
SHA256HashHfs0Files[i] = Arrays.copyOfRange(metaInfoBytes, 32, 64);
|
||||
|
||||
strTableOffsets[i] = getLEint(metaInfoBytes, 16);
|
||||
}
|
||||
// Define location of actual data for this HFS0
|
||||
rawFileDataStart = raf.getFilePointer()+stringTableSize;
|
||||
if (stringTableSize <= 0)
|
||||
throw new Exception("String table size of HFS0 less or equal to zero");
|
||||
byte[] stringTbl = new byte[stringTableSize];
|
||||
if (raf.read(stringTbl) != stringTableSize){
|
||||
throw new Exception("Read HFS0 String table failure. Can't read requested string table size ("+stringTableSize+")");
|
||||
}
|
||||
String[] namesHfs0files = new String[filesCnt];
|
||||
// Parse string table
|
||||
for (int i=0; i < filesCnt; i++){
|
||||
int j = 0;
|
||||
while (stringTbl[strTableOffsets[i]+j] != (byte)0x00)
|
||||
j++;
|
||||
namesHfs0files[i] = new String(stringTbl, strTableOffsets[i], j, StandardCharsets.UTF_8);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------
|
||||
// Set files
|
||||
for (int i=0; i < filesCnt; i++){
|
||||
hfs0Files[i] = new HFS0File(
|
||||
namesHfs0files[i],
|
||||
offsetHfs0files[i],
|
||||
sizeHfs0files[i],
|
||||
hashedRegionSizeHfs0Files[i],
|
||||
paddingHfs0Files[i],
|
||||
SHA256HashHfs0Files[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (IOException ioe){
|
||||
throw new Exception("Read HFS0 structure failure: "+ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMagicHFS0() { return magicHFS0; }
|
||||
public int getFilesCnt() { return filesCnt; }
|
||||
public boolean isPaddingHfs0() { return paddingHfs0; }
|
||||
public int getStringTableSize() { return stringTableSize; }
|
||||
|
||||
public long getRawFileDataStart() { return rawFileDataStart; }
|
||||
public HFS0File[] getHfs0Files() { return hfs0Files; }
|
||||
}
|
49
src/main/java/konogonka/Tools/XCI/XCIGamecardCert.java
Normal file
|
@ -0,0 +1,49 @@
|
|||
package konogonka.Tools.XCI;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Gamecard Cert
|
||||
* */
|
||||
public class XCIGamecardCert {
|
||||
private byte[] rsa2048PKCS1sig;
|
||||
private byte[] magicCert;
|
||||
private byte[] unknown1;
|
||||
private byte kekIndex;
|
||||
private byte[] unknown2;
|
||||
private byte[] deviceID;
|
||||
private byte[] unknown3;
|
||||
private byte[] encryptedData;
|
||||
|
||||
XCIGamecardCert(byte[] certBytes) throws Exception{
|
||||
if (certBytes.length != 512)
|
||||
throw new Exception("XCIGamecardCert Incorrect array size. Expected 512 bytes while received "+certBytes.length);
|
||||
rsa2048PKCS1sig = Arrays.copyOfRange(certBytes, 0, 256);
|
||||
magicCert = Arrays.copyOfRange(certBytes, 256, 260);
|
||||
unknown1 = Arrays.copyOfRange(certBytes, 260, 264);
|
||||
kekIndex = certBytes[264];
|
||||
unknown2 = Arrays.copyOfRange(certBytes, 265, 272);
|
||||
deviceID = Arrays.copyOfRange(certBytes, 272, 288);
|
||||
unknown3 = Arrays.copyOfRange(certBytes, 288, 298);
|
||||
encryptedData = Arrays.copyOfRange(certBytes, 298, 512);
|
||||
/*
|
||||
RainbowHexDump.hexDumpUTF8(rsa2048PKCS1sig);
|
||||
RainbowHexDump.hexDumpUTF8(magicCert);
|
||||
RainbowHexDump.hexDumpUTF8(unknown1);
|
||||
System.out.println(kekIndex);
|
||||
RainbowHexDump.hexDumpUTF8(unknown2);
|
||||
RainbowHexDump.hexDumpUTF8(deviceID);
|
||||
RainbowHexDump.hexDumpUTF8(unknown3);
|
||||
RainbowHexDump.hexDumpUTF8(encryptedData);
|
||||
*/
|
||||
}
|
||||
public byte[] getRsa2048PKCS1sig() { return rsa2048PKCS1sig; }
|
||||
public byte[] getMagicCert() { return magicCert; }
|
||||
public boolean isMagicCertOk(){ return Arrays.equals(magicCert, new byte[]{0x48, 0x45, 0x41, 0x44}); }
|
||||
public byte[] getUnknown1() { return unknown1; }
|
||||
public byte getKekIndex() { return kekIndex; }
|
||||
public byte[] getUnknown2() { return unknown2; }
|
||||
public byte[] getDeviceID() { return deviceID; }
|
||||
public byte[] getUnknown3() { return unknown3; }
|
||||
public byte[] getEncryptedData() { return encryptedData; }
|
||||
}
|
131
src/main/java/konogonka/Tools/XCI/XCIGamecardHeader.java
Normal file
|
@ -0,0 +1,131 @@
|
|||
package konogonka.Tools.XCI;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static konogonka.LoperConverter.getLEint;
|
||||
import static konogonka.LoperConverter.getLElong;
|
||||
/**
|
||||
* Header information
|
||||
* */
|
||||
public class XCIGamecardHeader{
|
||||
private byte[] rsa2048PKCS1sig;
|
||||
private boolean magicHead;
|
||||
private byte[] SecureAreaStartAddr;
|
||||
private boolean bkupAreaStartAddr;
|
||||
private byte titleKEKIndexBoth;
|
||||
private byte titleKEKIndex;
|
||||
private byte KEKIndex;
|
||||
private byte gcSize;
|
||||
private byte gcVersion;
|
||||
private byte gcFlags;
|
||||
private byte[] pkgID;
|
||||
private long valDataEndAddr;
|
||||
private byte[] gcInfoIV;
|
||||
private long hfs0partOffset;
|
||||
private long hfs0headerSize;
|
||||
private byte[] hfs0headerSHA256;
|
||||
private byte[] hfs0initDataSHA256 ;
|
||||
private int secureModeFlag;
|
||||
private int titleKeyFlag;
|
||||
private int keyFlag;
|
||||
private byte[] normAreaEndAddr;
|
||||
|
||||
XCIGamecardHeader(byte[] headerBytes) throws Exception{
|
||||
if (headerBytes.length != 400)
|
||||
throw new Exception("XCIGamecardHeader Incorrect array size. Expected 400 bytes while received "+headerBytes.length);
|
||||
rsa2048PKCS1sig = Arrays.copyOfRange(headerBytes, 0, 256);
|
||||
magicHead = Arrays.equals(Arrays.copyOfRange(headerBytes, 256, 260), new byte[]{0x48, 0x45, 0x41, 0x44});
|
||||
SecureAreaStartAddr = Arrays.copyOfRange(headerBytes, 260, 264);
|
||||
bkupAreaStartAddr = Arrays.equals(Arrays.copyOfRange(headerBytes, 264, 268), new byte[]{(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff});
|
||||
titleKEKIndexBoth = headerBytes[268];
|
||||
titleKEKIndex = (byte) ((titleKEKIndexBoth >> 4) & (byte) 0x0F);
|
||||
KEKIndex = (byte) (titleKEKIndexBoth & 0x0F);
|
||||
gcSize = headerBytes[269];
|
||||
gcVersion = headerBytes[270];
|
||||
gcFlags = headerBytes[271];
|
||||
pkgID = Arrays.copyOfRange(headerBytes, 272, 280);
|
||||
valDataEndAddr = getLElong(headerBytes, 280); //TODO: FIX/simplify //
|
||||
gcInfoIV = reverseBytes(Arrays.copyOfRange(headerBytes, 288, 304));
|
||||
hfs0partOffset = getLElong(headerBytes, 304);
|
||||
hfs0headerSize = getLElong(headerBytes, 312);
|
||||
hfs0headerSHA256 = Arrays.copyOfRange(headerBytes, 320, 352);
|
||||
hfs0initDataSHA256 = Arrays.copyOfRange(headerBytes, 352, 384);
|
||||
secureModeFlag = getLEint(headerBytes, 384);
|
||||
titleKeyFlag = getLEint(headerBytes, 388);
|
||||
keyFlag = getLEint(headerBytes, 392);
|
||||
normAreaEndAddr = Arrays.copyOfRange(headerBytes, 396, 400);
|
||||
}
|
||||
|
||||
public byte[] getRsa2048PKCS1sig() { return rsa2048PKCS1sig; }
|
||||
public boolean isMagicHeadOk() { return magicHead; }
|
||||
public byte[] getSecureAreaStartAddr() { return SecureAreaStartAddr; }
|
||||
public boolean isBkupAreaStartAddrOk() { return bkupAreaStartAddr; }
|
||||
public byte getTitleKEKIndexBoth() { return titleKEKIndexBoth; }
|
||||
public byte getTitleKEKIndex() { return titleKEKIndex; }
|
||||
public byte getKEKIndex() { return KEKIndex; }
|
||||
|
||||
public byte getGcSize() {
|
||||
return gcSize;
|
||||
}
|
||||
public byte getGcVersion() {
|
||||
return gcVersion;
|
||||
}
|
||||
public byte getGcFlags() {
|
||||
return gcFlags;
|
||||
}
|
||||
public byte[] getPkgID() {
|
||||
return pkgID;
|
||||
}
|
||||
public long getValDataEndAddr() {
|
||||
return valDataEndAddr;
|
||||
}
|
||||
public byte[] getGcInfoIV() {
|
||||
return gcInfoIV;
|
||||
}
|
||||
public long getHfs0partOffset() {
|
||||
return hfs0partOffset;
|
||||
}
|
||||
public long getHfs0headerSize() {
|
||||
return hfs0headerSize;
|
||||
}
|
||||
public byte[] getHfs0headerSHA256() {
|
||||
return hfs0headerSHA256;
|
||||
}
|
||||
public byte[] getHfs0initDataSHA256() {
|
||||
return hfs0initDataSHA256;
|
||||
}
|
||||
public int getSecureModeFlag() {
|
||||
return secureModeFlag;
|
||||
}
|
||||
public boolean isSecureModeFlagOk(){
|
||||
return secureModeFlag == 1;
|
||||
}
|
||||
public int getTitleKeyFlag() {
|
||||
return titleKeyFlag;
|
||||
}
|
||||
public boolean istitleKeyFlagOk(){
|
||||
return titleKeyFlag == 2;
|
||||
}
|
||||
public int getKeyFlag() {
|
||||
return keyFlag;
|
||||
}
|
||||
public boolean iskeyFlagOk(){
|
||||
return keyFlag == 0;
|
||||
}
|
||||
public byte[] getNormAreaEndAddr() {
|
||||
return normAreaEndAddr;
|
||||
}
|
||||
|
||||
private byte[] reverseBytes(byte[] bArr){
|
||||
Byte[] objArr = new Byte[bArr.length];
|
||||
for (int i=0;i < bArr.length; i++)
|
||||
objArr[i] = bArr[i];
|
||||
List<Byte> bytesList = Arrays.asList(objArr);
|
||||
Collections.reverse(bytesList);
|
||||
for (int i=0;i < bArr.length; i++)
|
||||
bArr[i] = objArr[i];
|
||||
return bArr;
|
||||
}
|
||||
}
|
101
src/main/java/konogonka/Tools/XCI/XCIGamecardInfo.java
Normal file
|
@ -0,0 +1,101 @@
|
|||
package konogonka.Tools.XCI;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static konogonka.LoperConverter.getLEint;
|
||||
import static konogonka.LoperConverter.getLElong;
|
||||
|
||||
/**
|
||||
* Gamecard Info
|
||||
* */
|
||||
public class XCIGamecardInfo{
|
||||
|
||||
private long fwVersion;
|
||||
private byte[] accessCtrlFlags; // 0x00A10011 for 25MHz access or 0x00A10010 for 50MHz access
|
||||
private int readWaitTime1;
|
||||
private int readWaitTime2;
|
||||
private int writeWaitTime1;
|
||||
private int writeWaitTime2;
|
||||
private byte[] fwMode;
|
||||
private byte[] cupVersion;
|
||||
private byte[] emptyPadding1;
|
||||
private byte[] updPartHash;
|
||||
private byte[] cupID;
|
||||
private byte[] emptyPadding2;
|
||||
// todo: Add factory function instead
|
||||
XCIGamecardInfo(byte[] infoBytes, byte[] IV, String XCI_HEADER_KEY) throws Exception {
|
||||
if (XCI_HEADER_KEY.trim().isEmpty())
|
||||
return;
|
||||
if (infoBytes.length != 112)
|
||||
throw new Exception("XCIGamecardInfo Incorrect array size. Expected 112 bytes while received "+infoBytes.length);
|
||||
|
||||
IvParameterSpec gciIV = new IvParameterSpec(IV);
|
||||
SecretKeySpec skSpec = new SecretKeySpec(hexStrToByteArray(XCI_HEADER_KEY), "AES");
|
||||
|
||||
try {
|
||||
// NOTE: CBC
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, skSpec, gciIV);
|
||||
|
||||
byte[] decrypted = cipher.doFinal(infoBytes);
|
||||
|
||||
fwVersion = getLElong(decrypted, 0);
|
||||
accessCtrlFlags = Arrays.copyOfRange(decrypted, 8, 12);
|
||||
readWaitTime1 = getLEint(decrypted, 12);
|
||||
readWaitTime2 = getLEint(decrypted, 16);
|
||||
writeWaitTime1 = getLEint(decrypted, 20);
|
||||
writeWaitTime2 = getLEint(decrypted, 24);
|
||||
fwMode = Arrays.copyOfRange(decrypted, 28, 32);
|
||||
cupVersion = Arrays.copyOfRange(decrypted, 32, 36);
|
||||
emptyPadding1 = Arrays.copyOfRange(decrypted, 36, 40);
|
||||
updPartHash = Arrays.copyOfRange(decrypted, 40, 48);
|
||||
cupID = Arrays.copyOfRange(decrypted, 48, 56);
|
||||
emptyPadding2 = Arrays.copyOfRange(decrypted, 56, 112);
|
||||
/*
|
||||
System.out.println(fwVersion);
|
||||
RainbowHexDump.hexDumpUTF8(accessCtrlFlags);
|
||||
System.out.println(readWaitTime1);
|
||||
System.out.println(readWaitTime2);
|
||||
System.out.println(writeWaitTime1);
|
||||
System.out.println(writeWaitTime2);
|
||||
RainbowHexDump.hexDumpUTF8(fwMode);
|
||||
RainbowHexDump.hexDumpUTF8(cupVersion);
|
||||
RainbowHexDump.hexDumpUTF8(emptyPadding1);
|
||||
RainbowHexDump.hexDumpUTF8(updPartHash);
|
||||
RainbowHexDump.hexDumpUTF8(cupID);
|
||||
RainbowHexDump.hexDumpUTF8(emptyPadding2);
|
||||
*/
|
||||
} catch (Exception e) {
|
||||
throw new Exception("XCIGamecardInfo Decryption failed: \n "+e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
private byte[] hexStrToByteArray(String s) { // thanks stackoverflow
|
||||
int len = s.length();
|
||||
byte[] data = new byte[len / 2];
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
||||
+ Character.digit(s.charAt(i+1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public long getFwVersion() { return fwVersion; }
|
||||
public byte[] getAccessCtrlFlags() { return accessCtrlFlags; }
|
||||
public int getReadWaitTime1() { return readWaitTime1; }
|
||||
public int getReadWaitTime2() { return readWaitTime2; }
|
||||
public int getWriteWaitTime1() { return writeWaitTime1; }
|
||||
public int getWriteWaitTime2() { return writeWaitTime2; }
|
||||
|
||||
public byte[] getFwMode() { return fwMode; }
|
||||
public byte[] getCupVersion() { return cupVersion; }
|
||||
public boolean isEmptyPadding1() { return Arrays.equals(emptyPadding1, new byte[4]); }
|
||||
public byte[] getEmptyPadding1() { return emptyPadding1; }
|
||||
public byte[] getUpdPartHash() { return updPartHash; }
|
||||
public byte[] getCupID() { return cupID; }
|
||||
public boolean isEmptyPadding2() { return Arrays.equals(emptyPadding2, new byte[56]); }
|
||||
public byte[] getEmptyPadding2() { return emptyPadding2; }
|
||||
}
|
100
src/main/java/konogonka/Tools/XCI/XCIProvider.java
Normal file
|
@ -0,0 +1,100 @@
|
|||
package konogonka.Tools.XCI;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class XCIProvider{
|
||||
// TODO: Since LOGO partition added, we have to handle it properly. Is it works??
|
||||
|
||||
//private BufferedInputStream xciBIS;
|
||||
private XCIGamecardHeader xciGamecardHeader;
|
||||
private XCIGamecardInfo xciGamecardInfo;
|
||||
private XCIGamecardCert xciGamecardCert;
|
||||
private HFS0Provider hfs0ProviderMain,
|
||||
hfs0ProviderUpdate,
|
||||
hfs0ProviderNormal,
|
||||
hfs0ProviderSecure,
|
||||
hfs0ProviderLogo;
|
||||
|
||||
public XCIProvider(File file, String XCI_HEADER_KEY) throws Exception{ // TODO: ADD FILE SIZE CHECK !!! Check xciHdrKey
|
||||
RandomAccessFile raf;
|
||||
|
||||
try {
|
||||
//xciBIS = new BufferedInputStream(new FileInputStream(file));
|
||||
raf = new RandomAccessFile(file, "r");
|
||||
}
|
||||
catch (FileNotFoundException fnfe){
|
||||
throw new Exception("XCI File not found: \n "+fnfe.getMessage());
|
||||
}
|
||||
|
||||
if (file.length() < 0xf010)
|
||||
throw new Exception("XCI File is too small.");
|
||||
|
||||
try{
|
||||
byte[] gamecardHeaderBytes = new byte[400];
|
||||
byte[] gamecardInfoBytes = new byte[112];
|
||||
byte[] gamecardCertBytes = new byte[512];
|
||||
|
||||
// Creating GC Header class
|
||||
if (raf.read(gamecardHeaderBytes) != 400) {
|
||||
raf.close();
|
||||
throw new Exception("XCI Can't read Gamecard Header bytes.");
|
||||
}
|
||||
xciGamecardHeader = new XCIGamecardHeader(gamecardHeaderBytes); // throws exception
|
||||
// Creating GC Info class
|
||||
if (raf.read(gamecardInfoBytes) != 112) {
|
||||
raf.close();
|
||||
throw new Exception("XCI Can't read Gamecard Header bytes.");
|
||||
}
|
||||
xciGamecardInfo = new XCIGamecardInfo(gamecardInfoBytes, xciGamecardHeader.getGcInfoIV(), XCI_HEADER_KEY);
|
||||
// Creating GC Cerfificate class
|
||||
raf.seek(0x7000);
|
||||
if (raf.read(gamecardCertBytes) != 512) {
|
||||
raf.close();
|
||||
throw new Exception("XCI Can't read Gamecard certificate bytes.");
|
||||
}
|
||||
xciGamecardCert = new XCIGamecardCert(gamecardCertBytes);
|
||||
|
||||
hfs0ProviderMain = new HFS0Provider(0xf000, raf);
|
||||
if (hfs0ProviderMain.getFilesCnt() < 3){
|
||||
raf.close();
|
||||
throw new Exception("XCI Can't read Gamecard certificate bytes.");
|
||||
}
|
||||
// Get all partitions from the main HFS0 file
|
||||
String partition;
|
||||
for (HFS0File hfs0File: hfs0ProviderMain.getHfs0Files()){
|
||||
partition = hfs0File.getName();
|
||||
if (partition.equals("update")) {
|
||||
hfs0ProviderUpdate = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf);
|
||||
continue;
|
||||
}
|
||||
if (partition.equals("normal")) {
|
||||
hfs0ProviderNormal = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf);
|
||||
continue;
|
||||
}
|
||||
if (partition.equals("secure")) {
|
||||
hfs0ProviderSecure = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf);
|
||||
continue;
|
||||
}
|
||||
if (partition.equals("logo")) {
|
||||
hfs0ProviderLogo = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf);
|
||||
}
|
||||
}
|
||||
raf.close();
|
||||
}
|
||||
catch (IOException ioe){
|
||||
throw new Exception("XCI Failed file analyze for ["+file.getName()+"]\n "+ioe.getMessage());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Getters
|
||||
* */
|
||||
public XCIGamecardHeader getGCHeader(){ return this.xciGamecardHeader; }
|
||||
public XCIGamecardInfo getGCInfo(){ return this.xciGamecardInfo; }
|
||||
public XCIGamecardCert getGCCert(){ return this.xciGamecardCert; }
|
||||
public HFS0Provider getHfs0ProviderMain() { return this.hfs0ProviderMain; }
|
||||
public HFS0Provider getHfs0ProviderUpdate() { return this.hfs0ProviderUpdate; }
|
||||
public HFS0Provider getHfs0ProviderNormal() { return this.hfs0ProviderNormal; }
|
||||
public HFS0Provider getHfs0ProviderSecure() { return this.hfs0ProviderSecure; }
|
||||
public HFS0Provider getHfs0ProviderLogo() { return this.hfs0ProviderLogo; }
|
||||
}
|
40
src/main/java/konogonka/Workers/AnalyzerNCA.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package konogonka.Workers;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import konogonka.ModelControllers.EMsgType;
|
||||
import konogonka.ModelControllers.LogPrinter;
|
||||
import konogonka.Tools.NCA.NCAProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class AnalyzerNCA extends Task<NCAProvider> {
|
||||
|
||||
private File file;
|
||||
private LogPrinter logPrinter;
|
||||
private HashMap<String, String> keysMap;
|
||||
|
||||
public AnalyzerNCA(File file, HashMap<String, String> keysMap){
|
||||
this.file = file;
|
||||
this.logPrinter = new LogPrinter();
|
||||
this.keysMap = keysMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NCAProvider call() {
|
||||
logPrinter.print("\tStart chain: NCA", EMsgType.INFO);
|
||||
|
||||
NCAProvider ncaProvider;
|
||||
|
||||
try {
|
||||
ncaProvider = new NCAProvider(file, keysMap);
|
||||
}catch (Exception e){
|
||||
logPrinter.print(e.getMessage(), EMsgType.FAIL);
|
||||
ncaProvider = null;
|
||||
}finally {
|
||||
logPrinter.print("\tEnd chain: NCA", EMsgType.INFO);
|
||||
logPrinter.close();
|
||||
}
|
||||
return ncaProvider;
|
||||
}
|
||||
}
|
40
src/main/java/konogonka/Workers/AnalyzerNSP.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package konogonka.Workers;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import konogonka.ModelControllers.EMsgType;
|
||||
import konogonka.ModelControllers.LogPrinter;
|
||||
import konogonka.Tools.PFS0.PFS0Provider;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class AnalyzerNSP extends Task<PFS0Provider> {
|
||||
|
||||
private File file;
|
||||
private LogPrinter logPrinter;
|
||||
|
||||
public AnalyzerNSP(File file){
|
||||
this.file = file;
|
||||
this.logPrinter = new LogPrinter();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PFS0Provider call() {
|
||||
logPrinter.print("\tStart chain: NSP", EMsgType.INFO);
|
||||
try{
|
||||
return new PFS0Provider(file);
|
||||
}
|
||||
catch (Exception e){
|
||||
logPrinter.print("\tException: "+e.getMessage(), EMsgType.FAIL);
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
private void close(){
|
||||
logPrinter.print("\tEnd chain: NSP", EMsgType.INFO);
|
||||
logPrinter.close();
|
||||
}
|
||||
}
|
39
src/main/java/konogonka/Workers/AnalyzerXCI.java
Normal file
|
@ -0,0 +1,39 @@
|
|||
package konogonka.Workers;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import konogonka.ModelControllers.EMsgType;
|
||||
import konogonka.ModelControllers.LogPrinter;
|
||||
import konogonka.Tools.XCI.XCIProvider;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class AnalyzerXCI extends Task<XCIProvider> {
|
||||
|
||||
private File file;
|
||||
private LogPrinter logPrinter;
|
||||
private String xciHdrKey;
|
||||
|
||||
public AnalyzerXCI(File file, String xciHdrKey){
|
||||
this.file = file;
|
||||
this.logPrinter = new LogPrinter();
|
||||
this.xciHdrKey = xciHdrKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XCIProvider call() {
|
||||
logPrinter.print("\tStart chain: XCI", EMsgType.INFO);
|
||||
|
||||
XCIProvider xciProvider;
|
||||
|
||||
try {
|
||||
xciProvider = new XCIProvider(file, xciHdrKey);
|
||||
}catch (Exception e){
|
||||
logPrinter.print(e.getMessage(), EMsgType.FAIL);
|
||||
xciProvider = null;
|
||||
}finally {
|
||||
logPrinter.print("\tEnd chain: XCI", EMsgType.INFO);
|
||||
logPrinter.close();
|
||||
}
|
||||
return xciProvider;
|
||||
}
|
||||
}
|
99
src/main/java/konogonka/Workers/NspXciExtractor.java
Normal file
|
@ -0,0 +1,99 @@
|
|||
package konogonka.Workers;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import konogonka.Controllers.IRowModel;
|
||||
import konogonka.ModelControllers.EMsgType;
|
||||
import konogonka.ModelControllers.LogPrinter;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
|
||||
public class NspXciExtractor extends Task<Void> {
|
||||
|
||||
private long rawDataStartPos;
|
||||
private List<IRowModel> models;
|
||||
private String filesDestPath;
|
||||
private LogPrinter logPrinter;
|
||||
private File NspXciFile;
|
||||
|
||||
public NspXciExtractor(long rawDataStartPos, List<IRowModel> models, String filesDestPath, File NspXciFile){
|
||||
this.rawDataStartPos = rawDataStartPos;
|
||||
this.models = models;
|
||||
this.filesDestPath = filesDestPath;
|
||||
this.NspXciFile = NspXciFile;
|
||||
this.logPrinter = new LogPrinter();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void call() {
|
||||
logPrinter.print("\tStart extracting", EMsgType.INFO);
|
||||
for (IRowModel model: models){
|
||||
logPrinter.print(filesDestPath+model.getFileName(), EMsgType.INFO);
|
||||
|
||||
File contentFile = new File(filesDestPath+model.getFileName());
|
||||
|
||||
long realFileOffset = rawDataStartPos + model.getFileOffset();
|
||||
long realFileSize = model.getFileSize();
|
||||
|
||||
long readFrom = 0;
|
||||
|
||||
int readPice = 8388608; // 8mb NOTE: consider switching to 1mb 1048576
|
||||
byte[] readBuf;
|
||||
|
||||
try{
|
||||
BufferedOutputStream extractedFileOS = new BufferedOutputStream(new FileOutputStream(contentFile));
|
||||
|
||||
BufferedInputStream bufferedInStream = new BufferedInputStream(new FileInputStream(NspXciFile)); // TODO: refactor?
|
||||
if (bufferedInStream.skip(realFileOffset) != realFileOffset) {
|
||||
logPrinter.print("File length is less than offset noted", EMsgType.FAIL);
|
||||
return null;
|
||||
}
|
||||
|
||||
while (readFrom < realFileSize){
|
||||
/*
|
||||
if (isCancelled()) // Check if user interrupted process.
|
||||
return false;
|
||||
*/
|
||||
if (realFileSize - readFrom < readPice)
|
||||
readPice = Math.toIntExact(realFileSize - readFrom); // it's safe, I guarantee
|
||||
readBuf = new byte[readPice];
|
||||
if (bufferedInStream.read(readBuf) != readPice) {
|
||||
logPrinter.print("Can't read required chunk from file", EMsgType.FAIL);
|
||||
return null;
|
||||
}
|
||||
|
||||
extractedFileOS.write(readBuf, 0, readPice);
|
||||
//-----------------------------------------/
|
||||
try {
|
||||
logPrinter.updateProgress((readFrom+readPice)/(realFileSize/100.0) / 100.0);
|
||||
}catch (InterruptedException ie){
|
||||
getException().printStackTrace(); // TODO: Do something with this
|
||||
}
|
||||
//-----------------------------------------/
|
||||
readFrom += readPice;
|
||||
}
|
||||
bufferedInStream.close();
|
||||
extractedFileOS.close();
|
||||
//-----------------------------------------/
|
||||
try{
|
||||
logPrinter.updateProgress(1.0);
|
||||
}
|
||||
catch (InterruptedException ie){
|
||||
getException().printStackTrace(); // TODO: Do something with this
|
||||
}
|
||||
//-----------------------------------------/
|
||||
}
|
||||
catch (IOException ioe){
|
||||
logPrinter.print("\tRead/Write error\n\t"+ioe.getMessage(), EMsgType.INFO);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
close();
|
||||
return null;
|
||||
}
|
||||
|
||||
private void close(){
|
||||
logPrinter.print("\tEnd extracting", EMsgType.INFO);
|
||||
logPrinter.close();
|
||||
}
|
||||
}
|
116
src/main/java/konogonka/xtsaes/XTSAESBlockCipher.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright 2016 Ahseya.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package konogonka.xtsaes;
|
||||
|
||||
import net.jcip.annotations.NotThreadSafe;
|
||||
import org.bouncycastle.crypto.BlockCipher;
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
import org.bouncycastle.crypto.DataLengthException;
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.LongFunction;
|
||||
|
||||
/**
|
||||
* XTS-AES implemented as a BlockCipher.
|
||||
*
|
||||
* @author Ahseya
|
||||
*/
|
||||
@NotThreadSafe
|
||||
public class XTSAESBlockCipher implements BlockCipher {
|
||||
|
||||
private final XTSCore core;
|
||||
private final int blockSize;
|
||||
private final int dataUnitSize;
|
||||
private long dataUnit;
|
||||
private int index;
|
||||
|
||||
XTSAESBlockCipher(
|
||||
XTSCore core,
|
||||
int blockSize,
|
||||
int dataUnitSize,
|
||||
long dataUnit,
|
||||
int index) {
|
||||
|
||||
this.core = Objects.requireNonNull(core, "core");
|
||||
this.blockSize = blockSize;
|
||||
this.dataUnitSize = dataUnitSize;
|
||||
this.dataUnit = dataUnit;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
XTSAESBlockCipher(XTSCore core, LongFunction<byte[]> tweakValueFunction, int dataUnitSize) {
|
||||
this(new XTSCore(new XTSTweak(tweakValueFunction)), core.getBlockSize(), dataUnitSize, 0, 0);
|
||||
}
|
||||
|
||||
public XTSAESBlockCipher(boolean isDefault, LongFunction<byte[]> tweakValueFunction, int dataUnitSize) {
|
||||
this(new XTSCore(isDefault), tweakValueFunction, dataUnitSize);
|
||||
}
|
||||
|
||||
public XTSAESBlockCipher(boolean isDefault, int dataUnitSize) {
|
||||
this(new XTSCore(isDefault), isDefault?XTSTweak::defaultTweakFunction:XTSTweak::nintTweakFunction, dataUnitSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException {
|
||||
if (params instanceof KeyParameter) {
|
||||
core.init(forEncryption, (KeyParameter) params);
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("invalid params: " + params.getClass().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlgorithmName() {
|
||||
return core.getAlgorithmName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockSize() {
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
|
||||
throws DataLengthException, IllegalStateException {
|
||||
|
||||
if (index == 0) {
|
||||
core.reset(dataUnit);
|
||||
}
|
||||
|
||||
if ((index += blockSize) == dataUnitSize) {
|
||||
dataUnit++;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
return core.processBlock(in, inOff, out, outOff);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
index = 0;
|
||||
dataUnit = 0;
|
||||
}
|
||||
}
|
||||
// TODO consider passing initial data unit sequence number in addition to key via CipherParameters subclass
|
114
src/main/java/konogonka/xtsaes/XTSAESCipher.java
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright 2016 Ahseya.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package konogonka.xtsaes;
|
||||
|
||||
import net.jcip.annotations.NotThreadSafe;
|
||||
import org.bouncycastle.crypto.DataLengthException;
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.LongFunction;
|
||||
|
||||
/**
|
||||
* XTS-AES cipher with arbitrary (non 128-bit aligned) data unit lengths.
|
||||
*
|
||||
* @author Ahseya
|
||||
* @author Dmitry Isaenko (updates for special usage)
|
||||
*/
|
||||
@NotThreadSafe
|
||||
public class XTSAESCipher {
|
||||
|
||||
private final XTSCore core;
|
||||
private final int blockSize;
|
||||
|
||||
XTSAESCipher(XTSCore core) {
|
||||
this.core = Objects.requireNonNull(core, "core");
|
||||
blockSize = core.getBlockSize();
|
||||
}
|
||||
|
||||
public XTSAESCipher(LongFunction<byte[]> tweakFunction) {
|
||||
this(new XTSCore(new XTSTweak(tweakFunction)));
|
||||
}
|
||||
|
||||
public XTSAESCipher(boolean isDefault) {
|
||||
this(new XTSCore(isDefault));
|
||||
}
|
||||
|
||||
String getAlgorithmName() {
|
||||
return core.getAlgorithmName();
|
||||
}
|
||||
|
||||
int getBlockSize() {
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
public XTSAESCipher init(boolean forEncryption, KeyParameter key) throws IllegalArgumentException {
|
||||
core.init(forEncryption, key);
|
||||
return this;
|
||||
}
|
||||
|
||||
public XTSAESCipher init(boolean forEncryption, KeyParameter key1, KeyParameter key2)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
core.init(forEncryption, key1, key2);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int processDataUnit(byte[] in, int inOff, int length, byte[] out, int outOff, long sequenceNumber)
|
||||
throws DataLengthException, IllegalStateException {
|
||||
|
||||
core.reset(sequenceNumber);
|
||||
return process(in, inOff, length, out, outOff);
|
||||
}
|
||||
|
||||
int process(byte[] in, int inOff, int length, byte[] out, int outOff)
|
||||
throws DataLengthException, IllegalStateException {
|
||||
|
||||
if (length < blockSize) {
|
||||
throw new DataLengthException("data unit size too small: " + length);
|
||||
}
|
||||
|
||||
if (inOff + length > in.length) {
|
||||
throw new DataLengthException("input buffer too small for data unit size: " + length);
|
||||
}
|
||||
|
||||
if (outOff + length > out.length) {
|
||||
throw new DataLengthException("output buffer too small for data unit size: " + length);
|
||||
}
|
||||
|
||||
int to = length % blockSize == 0
|
||||
? length
|
||||
: length - (blockSize * 2);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < to; i += blockSize) {
|
||||
core.processBlock(in, inOff + i, out, outOff + i);
|
||||
}
|
||||
|
||||
if (length > i) {
|
||||
core.processPartial(in, inOff + i, out, outOff + i, length - i);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
151
src/main/java/konogonka/xtsaes/XTSCore.java
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright 2016 Ahseya.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package konogonka.xtsaes;
|
||||
|
||||
import net.jcip.annotations.NotThreadSafe;
|
||||
import org.bouncycastle.crypto.BlockCipher;
|
||||
import org.bouncycastle.crypto.DataLengthException;
|
||||
import org.bouncycastle.crypto.engines.AESFastEngine;
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* XTS core functions.
|
||||
*
|
||||
* @author Ahseya
|
||||
* @author Dmitry Isaenko (updates for special usage)
|
||||
*/
|
||||
@NotThreadSafe
|
||||
class XTSCore {
|
||||
|
||||
private static final int BLOCK_SIZE = 16;
|
||||
|
||||
private final BlockCipher cipher;
|
||||
private final XTSTweak tweak;
|
||||
private boolean forEncryption;
|
||||
|
||||
XTSCore(BlockCipher cipher, XTSTweak tweak) {
|
||||
this.cipher = Objects.requireNonNull(cipher, "cipher");
|
||||
this.tweak = Objects.requireNonNull(tweak, "tweak");
|
||||
}
|
||||
|
||||
XTSCore(XTSTweak tweak) {
|
||||
this(new AESFastEngine(), tweak);
|
||||
}
|
||||
|
||||
XTSCore(boolean isDefault) {
|
||||
this(new XTSTweak(isDefault));
|
||||
}
|
||||
|
||||
XTSCore init(boolean forEncryption, KeyParameter key) throws IllegalArgumentException {
|
||||
byte[] k = ((KeyParameter) key).getKey();
|
||||
if (k.length != 32 && k.length != 64) {
|
||||
throw new IllegalArgumentException("bad key length: " + k.length);
|
||||
}
|
||||
|
||||
byte[] key1 = Arrays.copyOfRange(k, 0, k.length / 2);
|
||||
byte[] key2 = Arrays.copyOfRange(k, k.length / 2, k.length);
|
||||
|
||||
return init(forEncryption, new KeyParameter(key1), new KeyParameter(key2));
|
||||
}
|
||||
|
||||
XTSCore init(boolean forEncryption, KeyParameter key1, KeyParameter key2) throws IllegalArgumentException {
|
||||
cipher.init(forEncryption, key1);
|
||||
tweak.init(key2);
|
||||
this.forEncryption = forEncryption;
|
||||
return this;
|
||||
}
|
||||
|
||||
XTSCore reset(long tweakValue) throws DataLengthException, IllegalStateException {
|
||||
tweak.reset(tweakValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
String getAlgorithmName() {
|
||||
return cipher.getAlgorithmName();
|
||||
}
|
||||
|
||||
int getBlockSize() {
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
|
||||
int processBlock(byte[] in, int inOff, byte[] out, int outOff) throws DataLengthException, IllegalStateException {
|
||||
byte[] tweakValue = tweak.value();
|
||||
doProcessBlock(in, inOff, out, outOff, tweakValue);
|
||||
tweak.next();
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
|
||||
int doProcessBlock(byte[] in, int inOff, byte[] out, int outOff, byte[] tweakValue)
|
||||
throws DataLengthException, IllegalStateException {
|
||||
|
||||
merge(in, inOff, out, outOff, tweakValue);
|
||||
cipher.processBlock(out, outOff, out, outOff);
|
||||
merge(out, outOff, out, outOff, tweakValue);
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
|
||||
void merge(byte[] in, int inOff, byte[] out, int outOff, byte[] tweak) {
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
out[i + outOff] = (byte) (in[i + inOff] ^ tweak[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int processPartial(byte[] in, int inOff, byte[] out, int outOff, int length) {
|
||||
if (length <= BLOCK_SIZE) {
|
||||
throw new DataLengthException("input buffer too small/ missing last two blocks: " + length);
|
||||
}
|
||||
|
||||
if (length >= BLOCK_SIZE * 2) {
|
||||
throw new DataLengthException("input buffer too large/ non-partial final block: " + length);
|
||||
}
|
||||
|
||||
byte[] tweakA = tweak.value();
|
||||
byte[] tweakB = tweak.next().value();
|
||||
|
||||
return forEncryption
|
||||
? XTSCore.this.doProcessPartial(in, inOff, out, outOff, length, tweakA, tweakB)
|
||||
: XTSCore.this.doProcessPartial(in, inOff, out, outOff, length, tweakB, tweakA);
|
||||
}
|
||||
|
||||
int doProcessPartial(byte[] in, int inOff, byte[] out, int outOff, int length, byte[] tweakA, byte[] tweakB)
|
||||
throws DataLengthException, IllegalStateException {
|
||||
// M-1 block
|
||||
doProcessBlock(in, inOff, out, outOff, tweakA);
|
||||
|
||||
// Cipher stealing
|
||||
byte[] buffer = Arrays.copyOfRange(out, outOff, outOff + BLOCK_SIZE);
|
||||
System.arraycopy(in, inOff + BLOCK_SIZE, buffer, 0, length - BLOCK_SIZE);
|
||||
|
||||
// M block
|
||||
doProcessBlock(buffer, 0, buffer, 0, tweakB);
|
||||
|
||||
// Copy over final block pair
|
||||
System.arraycopy(out, outOff, out, outOff + BLOCK_SIZE, length - BLOCK_SIZE);
|
||||
System.arraycopy(buffer, 0, out, outOff, BLOCK_SIZE);
|
||||
return length;
|
||||
}
|
||||
}
|
126
src/main/java/konogonka/xtsaes/XTSTweak.java
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright 2016 Ahseya.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package konogonka.xtsaes;
|
||||
|
||||
import net.jcip.annotations.NotThreadSafe;
|
||||
import org.bouncycastle.crypto.BlockCipher;
|
||||
import org.bouncycastle.crypto.DataLengthException;
|
||||
import org.bouncycastle.crypto.engines.AESFastEngine;
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
import org.bouncycastle.util.Pack;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.function.LongFunction;
|
||||
|
||||
/**
|
||||
* XTS tweak with pluggable tweak function.
|
||||
*
|
||||
* @author Ahseya
|
||||
* @author Dmitry Isaenko (updates for special usage)
|
||||
*/
|
||||
@NotThreadSafe
|
||||
class XTSTweak {
|
||||
static byte[] nintTweakFunction(long tweakValue) {
|
||||
byte[] bs = new byte[BLOCK_SIZE];
|
||||
byte[] twk = Pack.longToBigEndian(tweakValue);
|
||||
int j = BLOCK_SIZE-twk.length;
|
||||
for (byte b: twk){
|
||||
bs[j++] = b;
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
static byte[] defaultTweakFunction(long tweakValue) {
|
||||
byte[] bs = Pack.longToLittleEndian(tweakValue);
|
||||
bs = Arrays.copyOfRange(bs, 0, BLOCK_SIZE);
|
||||
return bs;
|
||||
}
|
||||
|
||||
private static final long FDBK = 0x87;
|
||||
private static final long MSB = 0x8000000000000000L;
|
||||
private static final int BLOCK_SIZE = 16;
|
||||
|
||||
private final BlockCipher cipher;
|
||||
private final LongFunction<byte[]> tweakFunction;
|
||||
private final byte[] tweak;
|
||||
|
||||
XTSTweak(BlockCipher cipher, LongFunction<byte[]> tweakFunction, byte[] tweak) {
|
||||
this.cipher = Objects.requireNonNull(cipher, "cipher");
|
||||
this.tweakFunction = Objects.requireNonNull(tweakFunction, "tweakFunction");
|
||||
this.tweak = Objects.requireNonNull(tweak, "tweak");
|
||||
|
||||
if (cipher.getBlockSize() != BLOCK_SIZE) {
|
||||
throw new IllegalArgumentException("bad block size: " + cipher.getBlockSize());
|
||||
}
|
||||
}
|
||||
|
||||
XTSTweak(BlockCipher cipher, LongFunction<byte[]> tweakFunction) {
|
||||
this(cipher, tweakFunction, new byte[cipher.getBlockSize()]);
|
||||
}
|
||||
|
||||
XTSTweak(LongFunction<byte[]> tweakFunction) {
|
||||
this(new AESFastEngine(), tweakFunction);
|
||||
}
|
||||
|
||||
XTSTweak(boolean isDefault) {
|
||||
this(isDefault
|
||||
? XTSTweak::defaultTweakFunction
|
||||
: XTSTweak::nintTweakFunction);
|
||||
}
|
||||
|
||||
XTSTweak init(KeyParameter key) throws IllegalArgumentException {
|
||||
cipher.init(true, key);
|
||||
return this;
|
||||
}
|
||||
|
||||
XTSTweak reset(long tweakValue) throws DataLengthException, IllegalStateException {
|
||||
return reset(tweakFunction.apply(tweakValue));
|
||||
}
|
||||
|
||||
XTSTweak reset(byte[] tweakBytes) throws DataLengthException, IllegalStateException {
|
||||
cipher.processBlock(tweakBytes, 0, tweak, 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
byte[] value() {
|
||||
return Arrays.copyOf(tweak, tweak.length);
|
||||
}
|
||||
|
||||
XTSTweak next() {
|
||||
long lo = Pack.littleEndianToLong(tweak, 0);
|
||||
long hi = Pack.littleEndianToLong(tweak, 8);
|
||||
|
||||
long fdbk = (hi & MSB) == 0
|
||||
? 0L
|
||||
: FDBK;
|
||||
|
||||
hi = (hi << 1) | (lo >>> 63);
|
||||
lo = (lo << 1) ^ fdbk;
|
||||
|
||||
Pack.longToLittleEndian(lo, tweak, 0);
|
||||
Pack.longToLittleEndian(hi, tweak, 8);
|
||||
return this;
|
||||
}
|
||||
}
|
42
src/main/resources/FXML/NCA/NCASectionContent.fxml
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.Separator?>
|
||||
<?import javafx.scene.control.TitledPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<VBox spacing="5.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.NCA.NCASectionContentController">
|
||||
<children>
|
||||
<TitledPane text="PFS0">
|
||||
<content>
|
||||
<VBox spacing="5.0">
|
||||
<HBox VBox.vgrow="ALWAYS">
|
||||
<children>
|
||||
<Label text=" #">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label text="SHA256 Hash">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
</HBox>
|
||||
<VBox fx:id="sha256pane" VBox.vgrow="ALWAYS" />
|
||||
<Separator prefWidth="200.0" />
|
||||
<fx:include fx:id="SectionPFS0" source="../NSP/NSPTab.fxml" />
|
||||
</VBox>
|
||||
</content></TitledPane>
|
||||
</children>
|
||||
</VBox>
|
1618
src/main/resources/FXML/NCA/NCASectionHeaderBlock.fxml
Normal file
717
src/main/resources/FXML/NCA/NCATab.fxml
Normal file
|
@ -0,0 +1,717 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.control.TitledPane?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<ScrollPane fitToWidth="true" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.NCA.NCAController">
|
||||
<VBox spacing="5.0">
|
||||
<children>
|
||||
<TitledPane animated="false" expanded="false" text="Header">
|
||||
<content>
|
||||
<VBox spacing="5.0">
|
||||
<children>
|
||||
<GridPane>
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="60.0" minWidth="55.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="130.0" minWidth="125.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="450.0" prefWidth="500.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="2">
|
||||
<children>
|
||||
<Label text="0x100" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="5">
|
||||
<children>
|
||||
<Label text="0x205" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="9">
|
||||
<children>
|
||||
<Label text="0x210" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="13">
|
||||
<children>
|
||||
<Label text="0x240" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="3">
|
||||
<children>
|
||||
<Label text="0x200" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="6">
|
||||
<children>
|
||||
<Label text="0x206" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="8">
|
||||
<children>
|
||||
<Label text="0x208" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="11">
|
||||
<children>
|
||||
<Label text="0x220" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="4">
|
||||
<children>
|
||||
<Label text="0x204" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="7">
|
||||
<children>
|
||||
<Label text="0x207" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="10">
|
||||
<children>
|
||||
<Label text="0x21C" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="12">
|
||||
<children>
|
||||
<Label text="0x230" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="1">
|
||||
<children>
|
||||
<Label text="0x0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="14">
|
||||
<children>
|
||||
<Label text="0x280" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.rowIndex="15">
|
||||
<children>
|
||||
<Label text="0x300" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="3">
|
||||
<children>
|
||||
<Label text="0x4" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="2">
|
||||
<children>
|
||||
<Label text="0x100" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="1">
|
||||
<children>
|
||||
<Label text="0x100" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="1">
|
||||
<children>
|
||||
<Label text="RSA-2048 signature over the 0x200-bytes starting at offset 0x200 using fixed key. " AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="2">
|
||||
<children>
|
||||
<Label text="RSA-2048 signature over the 0x200-bytes starting at offset 0x200 using key from NPDM, or zeroes if not a program. " AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="3">
|
||||
<children>
|
||||
<Label text="Magicnum" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="4">
|
||||
<children>
|
||||
<Label text="Distribution type (0 = system NCAs; 1 = gamecard)" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="15">
|
||||
<children>
|
||||
<Label text="0x10*0x4(0x40)" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="14">
|
||||
<children>
|
||||
<Label text="0x20*0x4(0x80)" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="13">
|
||||
<children>
|
||||
<Label text="0x10*0x4(0x40)" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="4">
|
||||
<children>
|
||||
<Label text="0x1" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="5">
|
||||
<children>
|
||||
<Label text="0x1" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="6">
|
||||
<children>
|
||||
<Label text="0x1" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="7">
|
||||
<children>
|
||||
<Label text="0x1" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="8">
|
||||
<children>
|
||||
<Label text="0x8" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="9">
|
||||
<children>
|
||||
<Label text="0x8" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="10">
|
||||
<children>
|
||||
<Label text="0x4" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="11">
|
||||
<children>
|
||||
<Label text="0x1" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="12">
|
||||
<children>
|
||||
<Label text="0x10" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="5">
|
||||
<children>
|
||||
<Label text="Content Type (0=Program, 1=Meta, 2=Control, 3=Manual, 4=Data, 5=PublicData)" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="6">
|
||||
<children>
|
||||
<Label text="Crypto Type. Only used stating with 3.0.0. Normally 0. 2 = Crypto supported starting with 3.0.0." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="7">
|
||||
<children>
|
||||
<Label text="Key area encryption key (kaek), must be 0-2 (0=app, 1=ocean, 2=system)." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="8">
|
||||
<children>
|
||||
<Label text="Size of the entire NCA." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="10">
|
||||
<children>
|
||||
<Label text="sdk_version. byte0 usually 0? Known minimum-value(0x000B0000). Calc: byte3.byte2.byte1.byte0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="11">
|
||||
<children>
|
||||
<Label text="Crypto-Type2. Selects which crypto-sysver to use. 0x3 = 3.0.1, 0x4 = 4.0.0, 0x5 = 5.0.0." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="12">
|
||||
<children>
|
||||
<Label text="Rights ID (Ticket)" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.columnSpan="2" GridPane.rowIndex="13">
|
||||
<children>
|
||||
<VBox spacing="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
<TitledPane animated="false" expanded="false" text="Table for each section">
|
||||
<content>
|
||||
<VBox spacing="5.0">
|
||||
<children>
|
||||
<fx:include fx:id="NCATable1" source="NCATable.fxml" />
|
||||
<fx:include fx:id="NCATable2" source="NCATable.fxml" />
|
||||
<fx:include fx:id="NCATable3" source="NCATable.fxml" />
|
||||
<fx:include fx:id="NCATable4" source="NCATable.fxml" />
|
||||
</children>
|
||||
</VBox>
|
||||
</content>
|
||||
</TitledPane>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="14">
|
||||
<children>
|
||||
<Label text="Table of SHA256 hashes, over each 0x200-byte Section Header Block." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="15">
|
||||
<children>
|
||||
<Label text="Key area" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="3">
|
||||
<children>
|
||||
<Label fx:id="magicnumLbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="4">
|
||||
<children>
|
||||
<Label fx:id="systemOrGcIndLbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="5">
|
||||
<children>
|
||||
<Label fx:id="contentTypeLbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="6">
|
||||
<children>
|
||||
<Label fx:id="cryptoType1Lbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="7">
|
||||
<children>
|
||||
<Label fx:id="keyIndexLbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="8">
|
||||
<children>
|
||||
<Label fx:id="ncaSizeLbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="9">
|
||||
<children>
|
||||
<Label fx:id="titleIdLbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="10">
|
||||
<children>
|
||||
<Label fx:id="sdkVersionLbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="11">
|
||||
<children>
|
||||
<Label fx:id="cryptoType2Lbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="12">
|
||||
<children>
|
||||
<Label fx:id="ticketLbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="9">
|
||||
<children>
|
||||
<Label text="titleID" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="1">
|
||||
<children>
|
||||
<TextField fx:id="rsa2048oneTF" editable="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="2">
|
||||
<children>
|
||||
<TextField fx:id="rsa2048twoTF" editable="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="14">
|
||||
<children>
|
||||
<VBox spacing="3.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
<TextField fx:id="sha256section1TF" editable="false" />
|
||||
<TextField fx:id="sha256section2TF" editable="false" />
|
||||
<TextField fx:id="sha256section3TF" editable="false" />
|
||||
<TextField fx:id="sha256section4TF" editable="false" />
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="3.0" top="3.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="15">
|
||||
<children>
|
||||
<VBox spacing="3.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<padding>
|
||||
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
|
||||
</padding>
|
||||
<children>
|
||||
<Label text="Encrypted" />
|
||||
<TextField fx:id="keyAreaEnKey0TF" editable="false" />
|
||||
<TextField fx:id="keyAreaEnKey1TF" editable="false" />
|
||||
<TextField fx:id="keyAreaEnKey2TF" editable="false" />
|
||||
<TextField fx:id="keyAreaEnKey3TF" editable="false" />
|
||||
<Label text="Decrypted" />
|
||||
<TextField fx:id="keyAreaDecKey0TF" editable="false" />
|
||||
<TextField fx:id="keyAreaDecKey1TF" editable="false" />
|
||||
<TextField fx:id="keyAreaDecKey2TF" editable="false" />
|
||||
<TextField fx:id="keyAreaDecKey3TF" editable="false" />
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="1">
|
||||
<children>
|
||||
<Label layoutX="38.0" layoutY="6.0" text="Size" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="2">
|
||||
<children>
|
||||
<Label layoutX="14.0" layoutY="7.0" text="Description" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="3">
|
||||
<children>
|
||||
<Label layoutY="6.0" text="Value" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid">
|
||||
<children>
|
||||
<Label layoutX="2.0" layoutY="7.0" text="Offset" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</children>
|
||||
</GridPane>
|
||||
</children>
|
||||
</VBox>
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane expanded="false" text="Section Header Block (0x400 - 0xC00)">
|
||||
<content>
|
||||
<VBox spacing="5.0">
|
||||
<children>
|
||||
<TitledPane expanded="false" text="Section 0">
|
||||
<content>
|
||||
<fx:include fx:id="NCASectionHeaderFirst" source="NCASectionHeaderBlock.fxml" />
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane expanded="false" text="Section 1">
|
||||
<content>
|
||||
<fx:include fx:id="NCASectionHeaderSecond" source="NCASectionHeaderBlock.fxml" />
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane expanded="false" text="Section 2">
|
||||
<content>
|
||||
<fx:include fx:id="NCASectionHeaderThird" source="NCASectionHeaderBlock.fxml" />
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane expanded="false" text="Section 3">
|
||||
<content>
|
||||
<fx:include fx:id="NCASectionHeaderFourth" source="NCASectionHeaderBlock.fxml" />
|
||||
</content>
|
||||
</TitledPane>
|
||||
</children>
|
||||
</VBox>
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane text="Sections content">
|
||||
<content>
|
||||
<VBox spacing="5.0">
|
||||
<children>
|
||||
<TitledPane expanded="false" text="Section 0">
|
||||
<content>
|
||||
<fx:include fx:id="NCASectionContentFirst" source="../NCA/NCASectionContent.fxml" />
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane expanded="false" text="Section 1">
|
||||
<content>
|
||||
<fx:include fx:id="NCASectionContentSecond" source="../NCA/NCASectionContent.fxml" />
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane text="Section 2">
|
||||
<content>
|
||||
<fx:include fx:id="NCASectionContentThird" source="../NCA/NCASectionContent.fxml" />
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane text="Section 3">
|
||||
<content>
|
||||
<fx:include fx:id="NCASectionContentFourth" source="../NCA/NCASectionContent.fxml" />
|
||||
</content>
|
||||
</TitledPane>
|
||||
</children>
|
||||
</VBox>
|
||||
</content></TitledPane>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
</ScrollPane>
|
155
src/main/resources/FXML/NCA/NCATable.fxml
Normal file
|
@ -0,0 +1,155 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<GridPane gridLinesVisible="true" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.NCA.NCATableController">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="60.0" minWidth="55.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="60.0" minWidth="55.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="150.0" minWidth="100.0" prefWidth="150.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0" minWidth="100.0" prefWidth="110.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<AnchorPane prefHeight="200.0" styleClass="customTitleGrid">
|
||||
<children>
|
||||
<Label text="Offset" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<Label text="0x0" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x8" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0xC" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Unknown" GridPane.columnIndex="2" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Unknown" GridPane.columnIndex="2" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Media end-offset" GridPane.columnIndex="2" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Media offset " GridPane.columnIndex="2" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="unknwn2Lbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="unknwn1Lbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="mediaEndOffsetLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="mediaStartOffsetLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="1">
|
||||
<children>
|
||||
<Label layoutX="-6.0" layoutY="6.0" text="Size" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="2">
|
||||
<children>
|
||||
<Label layoutX="3.0" layoutY="8.0" text="Description" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="3">
|
||||
<children>
|
||||
<Label layoutX="24.0" layoutY="8.0" text="Value" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</children>
|
||||
</GridPane>
|
293
src/main/resources/FXML/NSP/NSPTab.fxml
Normal file
|
@ -0,0 +1,293 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.Separator?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.SVGPath?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<VBox spacing="5.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.NSP.NSPController">
|
||||
<children>
|
||||
<GridPane gridLinesVisible="true">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="90.0" minWidth="85.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="60.0" minWidth="55.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="180.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<AnchorPane styleClass="customTitleGrid">
|
||||
<children>
|
||||
<Label layoutX="10.0" layoutY="7.0" text="Offset" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="1">
|
||||
<children>
|
||||
<Label layoutX="-4.0" layoutY="6.0" text="Size" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="2">
|
||||
<children>
|
||||
<Label layoutX="14.0" layoutY="8.0" text="Description" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="3">
|
||||
<children>
|
||||
<Label layoutX="-4.0" layoutY="8.0" text="Value" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<Label text="0x0" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Magic "PFS0"" GridPane.columnIndex="2" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Number of files" GridPane.columnIndex="2" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="magicLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x8" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0xC" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Size of the string table" GridPane.columnIndex="2" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Zero/Reserved" GridPane.columnIndex="2" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="stringTableSizeLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="paddingLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="filesCountLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding></Label>
|
||||
<Label text="0x10" GridPane.rowIndex="5">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="fileEntryTableSizeLbl" text="X" GridPane.columnIndex="1" GridPane.rowIndex="5">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="stringsTableOffsetLbl" text="0x10+X" GridPane.rowIndex="6">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="stringsTableSizeLbl" text="Y" GridPane.columnIndex="1" GridPane.rowIndex="6">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="rawFileDataOffsetLbl" text="0x10+X+Y" GridPane.rowIndex="7">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="..." GridPane.columnIndex="1" GridPane.rowIndex="7">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="File Entry Table" GridPane.columnIndex="2" GridPane.rowIndex="5">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="String Table" GridPane.columnIndex="2" GridPane.rowIndex="6">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Raw File Data" GridPane.columnIndex="2" GridPane.rowIndex="7">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="..." GridPane.columnIndex="3" GridPane.rowIndex="5">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="..." GridPane.columnIndex="3" GridPane.rowIndex="6">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="..." GridPane.columnIndex="3" GridPane.rowIndex="7">
|
||||
<GridPane.margin>
|
||||
<Insets />
|
||||
</GridPane.margin>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</GridPane>
|
||||
<HBox />
|
||||
<HBox>
|
||||
<children>
|
||||
<Label text="Raw data start position: " />
|
||||
<Label fx:id="RawDataStartLbl" text="-" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox>
|
||||
<children>
|
||||
<Label text="File size: " />
|
||||
<Label fx:id="NSPSizeLbl" text="-" />
|
||||
</children>
|
||||
</HBox>
|
||||
<Separator prefWidth="200.0" />
|
||||
<fx:include fx:id="tableFilesList" source="TableView.fxml" />
|
||||
<BorderPane>
|
||||
<center>
|
||||
<Button fx:id="extractBtn" disable="true" mnemonicParsing="false" text="%btnExtract" BorderPane.alignment="CENTER">
|
||||
<graphic>
|
||||
<SVGPath content="M2,10.96C1.5,10.68 1.35,10.07 1.63,9.59L3.13,7C3.24,6.8 3.41,6.66 3.6,6.58L11.43,2.18C11.59,2.06 11.79,2 12,2C12.21,2 12.41,2.06 12.57,2.18L20.47,6.62C20.66,6.72 20.82,6.88 20.91,7.08L22.36,9.6C22.64,10.08 22.47,10.69 22,10.96L21,11.54V16.5C21,16.88 20.79,17.21 20.47,17.38L12.57,21.82C12.41,21.94 12.21,22 12,22C11.79,22 11.59,21.94 11.43,21.82L3.53,17.38C3.21,17.21 3,16.88 3,16.5V10.96C2.7,11.13 2.32,11.14 2,10.96M12,4.15V4.15L12,10.85V10.85L17.96,7.5L12,4.15M5,15.91L11,19.29V12.58L5,9.21V15.91M19,15.91V12.69L14,15.59C13.67,15.77 13.3,15.76 13,15.6V19.29L19,15.91M13.85,13.36L20.13,9.73L19.55,8.72L13.27,12.35L13.85,13.36Z" />
|
||||
</graphic>
|
||||
</Button>
|
||||
</center>
|
||||
<opaqueInsets>
|
||||
<Insets />
|
||||
</opaqueInsets>
|
||||
</BorderPane>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
</VBox>
|
10
src/main/resources/FXML/NSP/TableView.fxml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
|
||||
<AnchorPane xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.NSP.Pfs0TableViewController">
|
||||
<children>
|
||||
<TableView fx:id="table" editable="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
176
src/main/resources/FXML/Settings/SettingsLayout.fxml
Normal file
|
@ -0,0 +1,176 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<?import javafx.scene.control.Separator?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.SVGPath?>
|
||||
|
||||
<AnchorPane prefHeight="600.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Settings.SettingsController">
|
||||
<children>
|
||||
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
<ScrollPane fitToWidth="true" VBox.vgrow="ALWAYS">
|
||||
<content>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="5.0">
|
||||
<children>
|
||||
<Label text="Used for XCI" />
|
||||
<HBox alignment="CENTER_LEFT" spacing="5.0">
|
||||
<children>
|
||||
<Label text="xci_header_key" wrapText="true" />
|
||||
<TextField HBox.hgrow="ALWAYS" fx:id="xciHdrKeyTF" />
|
||||
</children>
|
||||
</HBox>
|
||||
<Label disable="true" text="Length should be 32 symbols" wrapText="true" />
|
||||
<Separator prefWidth="200.0" />
|
||||
<Label text="Used for NCA" />
|
||||
<Button fx:id="importBtn" contentDisplay="TOP" mnemonicParsing="false" text="Import from prod.keys">
|
||||
<graphic>
|
||||
<SVGPath content="M1,12H10.76L8.26,9.5L9.67,8.08L14.59,13L9.67,17.92L8.26,16.5L10.76,14H1V12M19,3C20.11,3 21,3.9 21,5V19A2,2 0 0,1 19,21H5C3.89,21 3,20.1 3,19V16H5V19H19V7H5V10H3V5A2,2 0 0,1 5,3H19Z" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<HBox alignment="CENTER_LEFT" spacing="5.0">
|
||||
<children>
|
||||
<Label text="header_key" wrapText="true" />
|
||||
<TextField fx:id="hdrKeyTF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<Label disable="true" text="Length should be 64 symbols" wrapText="true" />
|
||||
<Pane VBox.vgrow="ALWAYS" />
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_application_00" />
|
||||
<TextField fx:id="keyApp0TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_application_01" />
|
||||
<TextField fx:id="keyApp1TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_application_02" />
|
||||
<TextField fx:id="keyApp2TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_application_03" />
|
||||
<TextField fx:id="keyApp3TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_application_04" />
|
||||
<TextField fx:id="keyApp4TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_application_05" />
|
||||
<TextField fx:id="keyApp5TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_ocean_00" />
|
||||
<TextField fx:id="keyOcean0TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_ocean_01" />
|
||||
<TextField fx:id="keyOcean1TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_ocean_02" />
|
||||
<TextField fx:id="keyOcean2TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_ocean_03" />
|
||||
<TextField fx:id="keyOcean3TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_ocean_04" />
|
||||
<TextField fx:id="keyOcean4TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_ocean_05" />
|
||||
<TextField fx:id="keyOcean5TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_system_00" />
|
||||
<TextField fx:id="keySys0TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_system_01" />
|
||||
<TextField fx:id="keySys1TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_system_02" />
|
||||
<TextField fx:id="keySys2TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_system_03" />
|
||||
<TextField fx:id="keySys3TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_system_04" />
|
||||
<TextField fx:id="keySys4TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox spacing="5.0">
|
||||
<children>
|
||||
<Label text="key_area_key_system_05" />
|
||||
<TextField fx:id="keySys5TF" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
</HBox>
|
||||
<Separator prefWidth="200.0" />
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
</content>
|
||||
</ScrollPane>
|
||||
<ButtonBar>
|
||||
<buttons>
|
||||
|
||||
<Button fx:id="okBtn" mnemonicParsing="false" text="Ok" />
|
||||
<Button fx:id="cancelBtn" mnemonicParsing="false" text="Cancel" />
|
||||
</buttons>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
</ButtonBar>
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
</AnchorPane>
|
185
src/main/resources/FXML/XCI/HFSBlock.fxml
Normal file
|
@ -0,0 +1,185 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TitledPane?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.SVGPath?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<TitledPane fx:id="currentTitledPane" expanded="false" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.XCI.HFSBlockController">
|
||||
<content>
|
||||
<VBox spacing="5.0">
|
||||
<children>
|
||||
<GridPane gridLinesVisible="true">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="60.0" minWidth="55.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="60.0" minWidth="55.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="170.0" prefWidth="180.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="80.0" prefWidth="80.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<Label text="0x0" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x8" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Magicnum "HFS0" " GridPane.columnIndex="2" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Number of files" GridPane.columnIndex="2" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Size of the string table" GridPane.columnIndex="2" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="hfs0mainMagicNumLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="1">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="hfs0mainFileCntLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="2">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="hfs0mainStrTblSizeLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="3">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0xC" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="Zero/Reserved" GridPane.columnIndex="2" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Label fx:id="hfs0mainPaddingLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="4">
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<AnchorPane styleClass="customTitleGrid">
|
||||
<children>
|
||||
<Label layoutY="6.0" text="Offset" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="1">
|
||||
<children>
|
||||
<Label layoutX="21.0" layoutY="6.0" text="Size" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="2">
|
||||
<children>
|
||||
<Label layoutX="26.0" layoutY="6.0" text="Description" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="3">
|
||||
<children>
|
||||
<Label layoutY="6.0" text="Value" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
<padding>
|
||||
<Insets left="5.0" right="5.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</children>
|
||||
</GridPane>
|
||||
<HBox>
|
||||
<children>
|
||||
<Label text="Raw data starting position: " />
|
||||
<Label fx:id="hfs0mainRawFileDataStartLbl" text="-" />
|
||||
</children>
|
||||
</HBox>
|
||||
<fx:include fx:id="hfs0tableFilesListMain" source="Hfs0TableView.fxml" />
|
||||
<BorderPane>
|
||||
<center>
|
||||
<Button fx:id="extractMainBtn" disable="true" mnemonicParsing="false" text="%btnExtract" BorderPane.alignment="CENTER">
|
||||
<graphic>
|
||||
<SVGPath content="M2,10.96C1.5,10.68 1.35,10.07 1.63,9.59L3.13,7C3.24,6.8 3.41,6.66 3.6,6.58L11.43,2.18C11.59,2.06 11.79,2 12,2C12.21,2 12.41,2.06 12.57,2.18L20.47,6.62C20.66,6.72 20.82,6.88 20.91,7.08L22.36,9.6C22.64,10.08 22.47,10.69 22,10.96L21,11.54V16.5C21,16.88 20.79,17.21 20.47,17.38L12.57,21.82C12.41,21.94 12.21,22 12,22C11.79,22 11.59,21.94 11.43,21.82L3.53,17.38C3.21,17.21 3,16.88 3,16.5V10.96C2.7,11.13 2.32,11.14 2,10.96M12,4.15V4.15L12,10.85V10.85L17.96,7.5L12,4.15M5,15.91L11,19.29V12.58L5,9.21V15.91M19,15.91V12.69L14,15.59C13.67,15.77 13.3,15.76 13,15.6V19.29L19,15.91M13.85,13.36L20.13,9.73L19.55,8.72L13.27,12.35L13.85,13.36Z" />
|
||||
</graphic>
|
||||
</Button>
|
||||
</center>
|
||||
</BorderPane>
|
||||
</children>
|
||||
</VBox>
|
||||
</content>
|
||||
</TitledPane>
|
10
src/main/resources/FXML/XCI/Hfs0TableView.fxml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
|
||||
<AnchorPane xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.XCI.Hfs0TableViewController">
|
||||
<children>
|
||||
<TableView fx:id="table" editable="true" minHeight="250.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
1205
src/main/resources/FXML/XCI/XCITab.fxml
Normal file
91
src/main/resources/FXML/landingPage.fxml
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.ProgressBar?>
|
||||
<?import javafx.scene.control.SplitPane?>
|
||||
<?import javafx.scene.control.Tab?>
|
||||
<?import javafx.scene.control.TabPane?>
|
||||
<?import javafx.scene.control.TextArea?>
|
||||
<?import javafx.scene.control.ToolBar?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.SVGPath?>
|
||||
|
||||
<AnchorPane xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.MainController">
|
||||
<children>
|
||||
<VBox layoutX="10.0" layoutY="10.0" spacing="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
<ToolBar prefHeight="40.0" prefWidth="200.0">
|
||||
<items>
|
||||
<Button contentDisplay="TOP" mnemonicParsing="false" onAction="#selectFilesBtnAction" text="%btnFileOpen">
|
||||
<graphic>
|
||||
<SVGPath content="M12,10L8,14H11V20H13V14H16M19,4H5C3.89,4 3,4.9 3,6V18A2,2 0 0,0 5,20H9V18H5V8H19V18H15V20H19A2,2 0 0,0 21,18V6A2,2 0 0,0 19,4Z" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="analyzeBtn" contentDisplay="TOP" disable="true" mnemonicParsing="false" text="%btnAnalyze">
|
||||
<graphic>
|
||||
<SVGPath content="M7,2V13H10V22L17,10H13L17,2H7Z" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<Pane prefWidth="15.0" />
|
||||
<Button fx:id="settingsBtn" contentDisplay="TOP" mnemonicParsing="false" text="%btnSettings">
|
||||
<graphic>
|
||||
<SVGPath content="M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button contentDisplay="TOP" mnemonicParsing="false" onAction="#showHideLogs" text="%btnLogShow">
|
||||
<graphic>
|
||||
<SVGPath content="M17,11H15V9H17M13,11H11V9H13M9,11H7V9H9M20,2H4A2,2 0 0,0 2,4V22L6,18H20A2,2 0 0,0 22,16V4C22,2.89 21.1,2 20,2Z" />
|
||||
</graphic>
|
||||
</Button>
|
||||
</items>
|
||||
</ToolBar>
|
||||
<SplitPane fx:id="splitPane" dividerPositions="0.5" VBox.vgrow="ALWAYS">
|
||||
<items>
|
||||
<TabPane fx:id="tabPane" side="LEFT" tabClosingPolicy="UNAVAILABLE">
|
||||
<tabs>
|
||||
<Tab closable="false">
|
||||
<content>
|
||||
<fx:include fx:id="NSPTab" source="NSP/NSPTab.fxml" />
|
||||
</content>
|
||||
<graphic>
|
||||
<Label text="NSP" />
|
||||
</graphic>
|
||||
</Tab>
|
||||
<Tab closable="false">
|
||||
<content>
|
||||
<fx:include fx:id="XCITab" source="XCI/XCITab.fxml" />
|
||||
</content>
|
||||
<graphic>
|
||||
<Label text="XCI" />
|
||||
</graphic>
|
||||
</Tab>
|
||||
<Tab closable="false">
|
||||
<content>
|
||||
<fx:include fx:id="NCATab" source="NCA/NCATab.fxml" />
|
||||
</content>
|
||||
<graphic>
|
||||
<Label text="NCA" />
|
||||
</graphic>
|
||||
</Tab>
|
||||
</tabs>
|
||||
</TabPane>
|
||||
<AnchorPane fx:id="logPane" prefHeight="200.0" prefWidth="200.0">
|
||||
<children>
|
||||
<TextArea fx:id="logArea" editable="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</items>
|
||||
</SplitPane>
|
||||
<ProgressBar fx:id="progressBar" minHeight="7.0" progress="0.0" />
|
||||
<Label fx:id="filenameSelected" text="%lblNoFileSelected" />
|
||||
</children>
|
||||
</VBox>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
</AnchorPane>
|
12
src/main/resources/locale.properties
Normal file
|
@ -0,0 +1,12 @@
|
|||
btnFileOpen=Select NSP/XCI/NCA
|
||||
btnAnalyze=Analyze
|
||||
lblNoFileSelected=No files selected.
|
||||
tableNumberLbl=#
|
||||
tableFileNameLbl=File name
|
||||
tableSizeLbl=Size (kB)
|
||||
tableUploadLbl=Extract?
|
||||
tableOffsetLbl=Offset (kB)
|
||||
btnExtract=Extract files
|
||||
btnLogShow=Log
|
||||
settings_SettingsName=Settings
|
||||
btnSettings=Settings
|
13
src/main/resources/locale_fra.properties
Normal file
|
@ -0,0 +1,13 @@
|
|||
btnFileOpen=Selectionner NSP/XCI/NCA
|
||||
btnAnalyze=Analyser
|
||||
lblNoFileSelected=Aucuns fichiers s\u00E9lectionn\u00E9s.
|
||||
tableUploadLbl=Extraire ?
|
||||
tableSizeLbl=Taille (kB)
|
||||
tableFileNameLbl=Nom de fichier
|
||||
tableNumberLbl=#
|
||||
tableOffsetLbl=D\u00E9calage (kB)
|
||||
btnExtract=Extraire les fichiers
|
||||
btnLogShow=B\u00FBche
|
||||
settings_SettingsName=R\u00E9glages
|
||||
btnSettings=R\u00E9glages
|
||||
|
13
src/main/resources/locale_rus.properties
Normal file
|
@ -0,0 +1,13 @@
|
|||
btnFileOpen=\u0412\u044B\u0431\u0440\u0430\u0442\u044C NSP/XCI/NCA
|
||||
btnAnalyze=\u0410\u043D\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C
|
||||
lblNoFileSelected=\u0424\u0430\u0439\u043B\u044B \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u044B.
|
||||
tableUploadLbl=\u0420\u0430\u0441\u043F\u0430\u043A\u043E\u0432\u0430\u0442\u044C?
|
||||
tableSizeLbl=\u0420\u0430\u0437\u043C\u0435\u0440 (\u043A\u0411)
|
||||
tableFileNameLbl=\u0418\u043C\u044F \u0444\u0430\u0439\u043B\u0430
|
||||
tableNumberLbl=\u2116
|
||||
tableOffsetLbl=\u0421\u043C\u0435\u0449\u0435\u043D\u0438\u0435 (\u043A\u0411)
|
||||
btnExtract=\u0420\u0430\u0441\u043F\u0430\u043A\u043E\u0432\u0430\u0442\u044C \u0444\u0430\u0439\u043B\u044B
|
||||
btnLogShow=\u041B\u043E\u0433
|
||||
settings_SettingsName=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438
|
||||
btnSettings=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438
|
||||
|
12
src/main/resources/locale_ukr.properties
Normal file
|
@ -0,0 +1,12 @@
|
|||
btnFileOpen=\u0412\u0438\u0431\u0440\u0430\u0442\u0438 NSP/XCI/NCA
|
||||
btnAnalyze=\u0410\u043D\u0430\u043B\u0456\u0437\u0443\u0432\u0430\u0442\u0438
|
||||
lblNoFileSelected=\u0424\u0430\u0439\u043B\u0438 \u043D\u0435 \u0432\u0438\u0431\u0440\u0430\u043D\u0456.
|
||||
tableNumberLbl=\u2116
|
||||
tableFileNameLbl=\u0406\u043C'\u044F \u0444\u0430\u0439\u043B\u0443
|
||||
tableSizeLbl=\u0420\u043E\u0437\u043C\u0456\u0440 (\u043A\u0411)
|
||||
tableUploadLbl=\u0420\u043E\u0437\u043F\u0430\u043A\u043E\u0432\u0443\u0432\u0430\u0442\u0438?
|
||||
tableOffsetLbl=\u0417\u043C\u0456\u0449\u0435\u043D\u043D\u044F (\u043A\u0411)
|
||||
btnExtract=\u0420\u043E\u0437\u043F\u0430\u043A\u0443\u0432\u0430\u0442\u0438 \u0444\u0430\u0439\u043B\u0438
|
||||
btnLogShow=\u041B\u043E\u0433
|
||||
settings_SettingsName=\u041D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u043D\u044F
|
||||
btnSettings=\u041D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u043D\u044F
|
BIN
src/main/resources/res/NotoMono-Regular.ttf
Normal file
BIN
src/main/resources/res/app_icon128x128.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
src/main/resources/res/app_icon32x32.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src/main/resources/res/app_icon48x48.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src/main/resources/res/app_icon64x64.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
290
src/main/resources/res/app_light.css
Normal file
|
@ -0,0 +1,290 @@
|
|||
@font-face {
|
||||
src: url("NotoMono-Regular.ttf");
|
||||
}
|
||||
.root{
|
||||
-fx-background: #ebebeb;
|
||||
}
|
||||
|
||||
.button, .buttonUp, .buttonStop, .buttonSelect{
|
||||
-fx-background-color: #fefefe;
|
||||
-fx-border-color: #fefefe;
|
||||
-fx-border-radius: 3;
|
||||
-fx-border-width: 2;
|
||||
-fx-text-fill: #2c2c2c;
|
||||
-fx-effect: dropshadow(three-pass-box, #b4b4b4, 2, 0, 0, 0);
|
||||
|
||||
}
|
||||
.button:hover, .buttonStop:hover, .buttonUp:hover, .choice-box:hover, .button:focused:hover, .buttonStop:focused:hover, .buttonUp:focused:hover, .buttonSelect:focused:hover, .choice-box:focused:hover{
|
||||
-fx-background-color: #fefefe;
|
||||
-fx-border-color: #00caca;
|
||||
-fx-border-radius: 3;
|
||||
-fx-border-width: 2;
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
.button:focused, .buttonStop:focused, .buttonUp:focused, .buttonSelect:focused, .choice-box:focused{
|
||||
-fx-background-color: #cccccc;
|
||||
-fx-border-color: #cccccc;
|
||||
}
|
||||
|
||||
.button:pressed, .button:pressed:hover{
|
||||
-fx-background-color: #fefefe;
|
||||
-fx-border-color: #e82382;
|
||||
-fx-border-radius: 3;
|
||||
-fx-border-width: 2;
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
.buttonSelect:pressed, .buttonSelect:pressed:hover{
|
||||
-fx-background-color: #fefefe;
|
||||
-fx-border-color: #289de8;
|
||||
-fx-border-radius: 3;
|
||||
-fx-border-width: 2;
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
.buttonUp:pressed, .buttonUp:pressed:hover{
|
||||
-fx-background-color: #fefefe;
|
||||
-fx-border-color: #a2e019;
|
||||
-fx-border-radius: 3;
|
||||
-fx-border-width: 2;
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
.buttonStop:pressed, .buttonStop:pressed:hover{
|
||||
-fx-background-color: #fefefe;
|
||||
-fx-border-color: #fb582c;
|
||||
-fx-border-radius: 3;
|
||||
-fx-border-width: 2;
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
// -========================+ TextArea =====================-
|
||||
.text-area{
|
||||
-fx-background-color: transparent;
|
||||
-fx-control-inner-background: #fefefe;
|
||||
-fx-font-family: "Noto Mono";
|
||||
-fx-border-color: #06b9bb;
|
||||
-fx-border-radius: 3;
|
||||
-fx-border-width: 2;
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
-fx-fit-to-width: true;
|
||||
-fx-background-color: transparent;
|
||||
-fx-box-border: transparent;
|
||||
}
|
||||
.progress-bar > .track {
|
||||
-fx-background-color: transparent;
|
||||
-fx-box-border: transparent;
|
||||
}
|
||||
.progress-bar > .bar {
|
||||
-fx-background-color: linear-gradient(to right, #00bce4, #ff5f53);
|
||||
-fx-background-radius: 2;
|
||||
-fx-background-insets: 1 1 2 1;
|
||||
-fx-padding: 0.23em;
|
||||
}
|
||||
|
||||
.dialog-pane {
|
||||
-fx-background-color: #fefefe;
|
||||
}
|
||||
.dialog-pane > .button-bar > .container{
|
||||
-fx-background-color: #ebebeb;
|
||||
}
|
||||
|
||||
.dialog-pane > .label{
|
||||
-fx-padding: 10 5 10 5;
|
||||
}
|
||||
|
||||
.tool-bar{
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.special-pane-as-border{
|
||||
-fx-background-color: #2c2c2c;
|
||||
-fx-min-height: 1;
|
||||
}
|
||||
// -======================== Choice box =========================-
|
||||
.choice-box {
|
||||
-fx-background-color: #fefefe;
|
||||
-fx-border-color: #fefefe;
|
||||
-fx-border-radius: 3;
|
||||
-fx-border-width: 2;
|
||||
-fx-mark-color: #eea11e;
|
||||
-fx-effect: dropshadow(three-pass-box, #b4b4b4, 2, 0, 0, 0);
|
||||
}
|
||||
.choice-box > .label {
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
|
||||
.choice-box:pressed, .choice-box:pressed:hover{
|
||||
-fx-background-color: #fefefe;
|
||||
-fx-border-color: #eea11e;
|
||||
-fx-border-radius: 3;
|
||||
-fx-border-width: 2;
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
|
||||
// Background color of the whole context menu
|
||||
.choice-box .context-menu {
|
||||
-fx-background-color: #fefefe;
|
||||
}
|
||||
|
||||
// Focused item background color in the list
|
||||
.choice-box .context-menu .menu-item:focused {
|
||||
-fx-background-color: #eea11e;
|
||||
|
||||
}
|
||||
.choice-box .context-menu .menu-item:focused .label {
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
|
||||
// -======================== TAB PANE =========================-
|
||||
.tab-pane .tab SVGPath{
|
||||
-fx-fill: #2c2c2c; // OK
|
||||
}
|
||||
.tab-pane .tab:selected SVGPath{
|
||||
-fx-fill: #289de8; // OK
|
||||
}
|
||||
.tab-pane .tab{
|
||||
-fx-background-color: #fefefe; //ok
|
||||
-fx-focus-color: transparent;
|
||||
-fx-faint-focus-color: transparent;
|
||||
-fx-border-radius: 0 0 0 0;
|
||||
-fx-border-width: 3 0 0 0;
|
||||
-fx-border-color: #fefefe; //OK
|
||||
}
|
||||
|
||||
.tab-pane .tab:selected{
|
||||
-fx-background-color: #ebebeb; // OK
|
||||
-fx-focus-color: transparent;
|
||||
-fx-faint-focus-color: transparent;
|
||||
-fx-border-radius: 0 0 0 0;
|
||||
-fx-border-width: 3 0 0 0;
|
||||
-fx-border-color: #289de8; // OK
|
||||
}
|
||||
|
||||
.tab-pane > .tab-header-area {
|
||||
-fx-background-insets: 0.0;
|
||||
-fx-padding: 5 5 5 5;
|
||||
}
|
||||
|
||||
.tab-pane > .tab-header-area > .tab-header-background
|
||||
{
|
||||
-fx-background-color: #fefefe; // OK
|
||||
|
||||
}
|
||||
.tab-pane > .tab-header-area > .headers-region > .tab {
|
||||
-fx-padding: 10;
|
||||
}
|
||||
// -=========================== TABLE ======================-
|
||||
.table-view {
|
||||
-fx-background-color: #fefefe;
|
||||
-fx-background-image: url(app_logo.png);
|
||||
-fx-background-position: center;
|
||||
-fx-background-repeat: no-repeat;
|
||||
-fx-border-color: #06b9bb;
|
||||
-fx-border-radius: 3;
|
||||
-fx-border-width: 2;
|
||||
}
|
||||
.table-view .arrow {
|
||||
-fx-mark-color: #2c2c2c ;
|
||||
}
|
||||
.table-view .column-header {
|
||||
-fx-background-color: transparent;
|
||||
-fx-border-width: 0 1 2 0;
|
||||
-fx-border-color: #b0b0b0;
|
||||
}
|
||||
.table-view .column-header-background .label{
|
||||
-fx-background-color: transparent;
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
.table-view .column-header-background, .table-view .filler{
|
||||
-fx-background-color: #fefefe;
|
||||
}
|
||||
|
||||
.table-view .table-cell{
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
.table-row-cell, .table-row-cell:filled:selected, .table-row-cell:selected{
|
||||
-fx-background-color: -fx-table-cell-border-color, #d3fffd;
|
||||
-fx-background-insets: 0, 0 0 1 0;
|
||||
-fx-padding: 0.0em; /* 0 */
|
||||
-fx-table-cell-border-color: #b0b0b0;
|
||||
}
|
||||
.table-row-cell .text, .table-row-cell:odd .text {
|
||||
-fx-fill: #2c2c2c;
|
||||
}
|
||||
.table-row-cell:filled:selected .text, .table-row-cell:odd:filled:selected .text{
|
||||
-fx-fill: #2c2c2c;
|
||||
-fx-font-weight: bold
|
||||
}
|
||||
.table-row-cell:odd, .table-row-cell:odd:filled:selected, .table-row-cell:odd:selected{
|
||||
-fx-background-color: -fx-table-cell-border-color, #fefefe;
|
||||
-fx-background-insets: 0, 0 0 1 0;
|
||||
-fx-padding: 0.0em; /* 0 */
|
||||
-fx-table-cell-border-color: #b0b0b0;
|
||||
}
|
||||
// -========================== Context menu =====================-
|
||||
.context-menu {
|
||||
-fx-background-color: #fefefe;
|
||||
-fx-cursor: hand;
|
||||
}
|
||||
.context-menu .menu-item .label {
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
.context-menu .menu-item:focused .label {
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
// -========================== Text Field =====================-
|
||||
.text-field {
|
||||
-fx-border-color: #289de8;
|
||||
-fx-border-width: 0 0 1 0;
|
||||
-fx-background-color: transparent;
|
||||
-fx-text-fill: #2c2c2c;
|
||||
}
|
||||
.text-field:focused {
|
||||
-fx-border-color: #e82382;
|
||||
-fx-border-width: 0 0 1 0;
|
||||
-fx-background-color: transparent;
|
||||
-fx-text-fill: #e82382;
|
||||
}
|
||||
|
||||
.customMainGrid {
|
||||
-fx-border-color: #191919;
|
||||
-fx-border-width: 1;
|
||||
}
|
||||
.customTitleGrid {
|
||||
-fx-background-color: #191919, #d3fffd;
|
||||
-fx-background-insets: 0, 1;
|
||||
}
|
||||
.customGrid {
|
||||
-fx-background-color: #191919, #f0f0f0;
|
||||
-fx-background-insets: 0, 1;
|
||||
}
|
||||
|
||||
.regionUpload{
|
||||
-fx-shape: "M8,21V19H16V21H8M8,17V15H16V17H8M8,13V11H16V13H8M19,9H5L12,2L19,9Z";
|
||||
-fx-background-color: #a2e019;
|
||||
-size: 24;
|
||||
-fx-min-height: -size;
|
||||
-fx-min-width: 20;
|
||||
}
|
||||
|
||||
.regionStop{
|
||||
-fx-shape: "M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z";
|
||||
-fx-background-color: #fb582c;
|
||||
-size: 24;
|
||||
-fx-min-height: -size;
|
||||
-fx-min-width: -size;
|
||||
}
|
||||
|
||||
.regionLamp {
|
||||
-fx-shape: "M12,2A7,7 0 0,0 5,9C5,11.38 6.19,13.47 8,14.74V17A1,1 0 0,0 9,18H15A1,1 0 0,0 16,17V14.74C17.81,13.47 19,11.38 19,9A7,7 0 0,0 12,2M9,21A1,1 0 0,0 10,22H14A1,1 0 0,0 15,21V20H9V21Z";
|
||||
-fx-background-color: #2c2c2c;
|
||||
-size: 17.5;
|
||||
-fx-min-height: -size;
|
||||
-fx-min-width: 12.5;
|
||||
}
|
||||
.regionUpdatesCheck {
|
||||
-fx-shape: "M19,8L15,12H18A6,6 0 0,1 12,18C11,18 10.03,17.75 9.2,17.3L7.74,18.76C8.97,19.54 10.43,20 12,20A8,8 0 0,0 20,12H23M6,12A6,6 0 0,1 12,6C13,6 13.97,6.25 14.8,6.7L16.26,5.24C15.03,4.46 13.57,4 12,4A8,8 0 0,0 4,12H1L5,16L9,12";
|
||||
-fx-background-color: #2c2c2c;
|
||||
-size: 17.5;
|
||||
-fx-min-width: -size;
|
||||
}
|
BIN
src/main/resources/res/app_logo.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
src/main/resources/res/settings_icon128x128.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
src/main/resources/res/settings_icon32x32.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src/main/resources/res/settings_icon48x48.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
src/main/resources/res/settings_icon64x64.png
Normal file
After Width: | Height: | Size: 3.1 KiB |