initial commit

This commit is contained in:
maxmoon 2023-01-10 18:13:25 +01:00
commit d7e870010d
97 changed files with 15413 additions and 0 deletions

18
CMakeLists.txt Normal file
View File

@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 2.8.4)
set(CMAKE_MODULE_PATH
${CMAKE_SOURCE_DIR}/cmake
${CMAKE_MODULE_PATH})
project(Heimdall)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
option(DISABLE_FRONTEND "Disable GUI frontend" OFF)
add_subdirectory(libpit)
add_subdirectory(heimdall)
if(NOT DISABLE_FRONTEND)
add_subdirectory(heimdall-frontend)
add_dependencies(heimdall-frontend heimdall)
endif()

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.

492
Linux/README Normal file
View File

@ -0,0 +1,492 @@
Heimdall (c) 2010-2017 Benjamin Dobell, Glass Echidna
http://www.glassechidna.com.au/products/heimdall/
DISCLAIMER:
This software attempts to flash your Galaxy S device. The very nature of
flashing is dangerous. As with all flashing software, Heimdall has the
potential to damage (brick) your device if not used carefully. If you're
concerned, don't use this software. Flashing ROMs onto your phone may also
void your warranty. Benjamin Dobell and Glass Echidna are not responsible
for the result of your actions.
These instructions are for Linux operating systems.
Flashing Heimdall Firmware Package with Heimdall Frontend:
As of Heimdall Frontend 1.3 there are now two main ways to flash a ROM from
Heimdall Frontend. The simpler and preferred option is to download a
Heimdall Firmware Package and follow the following steps.
1. Fully charge your device (use the wall charger as it's faster).
2. Open the a terminal and run Heimdall Frontend by typing:
heimdall-frontend
3. From the "Load Package" tab, under the "Heimdall Firmware Package"
section click the "Browse" button.
4. Use the dialogue that appears to navigate to, and select, the Heimdall
firmware package that you wish to flash.
5. You will see progress bars appear as the package is decompressed and
extracted.
When the package has finished being decompressed you should see
information about the particular firmware package that has been
selected.
6. Verify that your device is listed under "Supported Devices". If it's not
then STOP immediately! DO NOT flash this firmware to your device!
Instead search for an appropriate firmware package for your device.
If you believe there is a mistake and your device is actually
supported please get in contact with the firmware developer (not Glass
Echidna!) and ask them to rectify the issue. If the developer provided
a URL you may be able to contact them by pressing the "Homepage" button.
7. If you've verified your device is supported you may continue to press
the "Load / Customise" button.
8. You should now be looking at the "Flash" tab. If not verify that you did
in fact push the "Load / Customise" button.
Generally, you won't NEED or WANT to customise a firmware package! In
which case you can safely move on to step 9.
Nonetheless, the "Flash" tab provides you with a means to customise the
firmware package before flashing it to your device. See "Performing a
Custom Flash with Heimdall Frontend" for more details.
9. Put your Galaxy S device into download mode and plug it in to your PC.
Download mode can be accessed several different ways depending on your
particular device model. If you're unsure how to do this please search
online for the appropriate method.
10. Press the "Start" button.
11. Heimdall Frontend will display the progress and inform you when the
flash is complete.
If something went wrong i.e. your device wasn't detected because it
wasn't in download mode, then the status section will let you know the
cause of the problem.
Performing a Custom Flash with Heimdall Frontend:
This is the advanced means of flashing firmware to your device.
If you're not an advanced user or a developer, in the event that a Heimdall
Firmware Package doesn't exist for the particular firmware (or files) that
you wish to flash, then I strongly recommend you get in touch with the
developer of the firmware (or files) and politely ask them to create a
Heimdall Firmware Package for you. In doing so, you avoid the risk of
making mistakes due to inexperience.
If you're looking to customise an existing Heimdall Firmware Package then
follow steps 1-8 of "Flashing Heimdall Firmware Package with Heimdall
Frontend" then start from below with step 5.
1. Fully charge your device (use the wall charger as it's faster).
2. Download a decrypted device ROM or a Heimdall Firmware Package
and extract everything to the one directory.
3. If the ROM is not a Heimdall Firmware Package it may instead be provided
as multiple archives (nested or otherwise), extract them all to the same
location.
NOTE: If you want to use the CSC then extract it last. If you're asked
to overwrite files then do so.
3. Open the a terminal and run Heimdall Frontend by typing:
heimdall-frontend
4. Select the "Flash" tab. From the "Flash" tab you're able to completely
customise a flash.
5. Before you can chose which partitions you want to flash with particular
files you MUST first select a PIT file. To do this click the "Browse"
button in the "PIT" section. This will open a dialogue allowing you to
navigate to and select a valid PIT (.pit) file.
If you do not already have a valid PIT file stored on your computer you
can download your device's PIT file from the "Utilities" tab.
6. If a valid PIT file has been selected then the "Add" button below the
"Partitions (Files)" list-box will be enabled. Press this button to add
a partition to your flash.
7. When you first add a partition you will see the "Partition Name" and
"Partition ID" be populated with information. Use the "Partition Name"
drop down to select which partition you wish to flash. "Partition ID"
will automatically update and is never directly editable.
8. You must then select a file to flash to the partition that you just
specified using the "Browse" button under the "File / Partition". You
will not be able to flash, create a firmware package or add another
partition until you have selected a file. However, you're still able to
press the "Remove" button if you've decided not to flash the partition
you've just specified.
9. When you've specified a file name then you'll be able to see the updated
information in the partition list to the right. You can select any
partition from this list and customise it as you see fit.
You can also remove a partition from the list by selecting it and
clicking the "Remove" button. Removing a partition from the list doesn't
remove it from your device, it simply means it will not be flashed.
10. Repeat steps 7-9 as often as needed to specify all the partitions/files
that you wish to flash.
11. Now you can chose whether you would like to repartition your device as
well as whether you would like to prevent the device rebooting once a
flash has been completed. These options can be enabled or disabled by
toggling the "Repartition" and "No Reboot" check-boxes.
In the general case you will only need to enable repartition if you wish
to change the PIT file on your device. Keep in mind that repartitioning
will wipe your device!
The "No Reboot" option is rarely required. It's mostly in place so you
can manually boot straight into recovery mode after a flash (rather than
booting up normally).
12. If you've added at least one partition to your flash (and selected a
file for that partition) then the "Start" button will be enabled. Press
the "Start" button to begin the flashing process.
You may notice that the "Create Package" tab becomes available at the
whenever the "Start" button becomes available. From this tab you're able
to create a reusable, redistributable Heimdall Firmware Package with the
files and partitions you just selected. See "How to Create a Heimdall
Firmware Package" for details.
13. Heimdall Frontend will display the progress and inform you when the
flash is complete.
If something went wrong i.e. your device wasn't detected because it
wasn't in download mode, then the status section will let you know the
cause of the problem.
Flashing Firmware from Command Line:
1. Fully charge your phone (use the wall charger as it's faster).
2. Download a decrypted device ROM or a Heimdall Firmware Package
and extract everything to the one directory.
3. If the ROM is not a Heimdall Firmware Package it may instead be provided
as multiple archives (nested or otherwise), extract them all to the same
location.
NOTE: If you want to use the CSC then extract it last.
4. Put your Galaxy S device into download mode and plug it in..
5. Open a terminal and navigate to the directory where you extracted
the ROM/firmware files.
6. Type the following to list all the functionality Heimdall supports:
heimdall help
7. Before flashing, you must first know the names of the partitions you
wish to flash. These can be obtained by executing:
heimdall print-pit --no-reboot
The inclusion of --no-reboot ensures the phone will not reboot after PIT
file has been downloaded and displayed. After executing a command with
the --no-reboot argument, the next command should include the --resume
argument.
NOTE: You can still safely reboot your phone manually (with the power
button) after executing --no-reboot commands.
8. Use the help and print-pit output to construct a command with all the
files you want to flash.
Here is an example that does a full flash and repartition on a GT-I9000:
heimdall flash --repartition --resume --pit s1_odin_20100512.pit --FACTORYFS factoryfs.rfs --CACHE cache.rfs --DBDATA dbdata.rfs --IBL+PBL boot.bin --SBL Sbl.bin --PARAM param.lfs --KERNEL zImage --MODEM modem.bin
9. Heimdall will display the progress as it flashes so that you know things
are working as they should.
How to Create a Heimdall Firmware Package:
Firstly, Heimdall's firmware package format is just a regular TAR archive
compressed with gzip. The only two real requirements are that a valid
firmware.xml must be included (refer to Appendix A) and you can only
include files (no directories, links etc.) As such if you'd like there is
nothing preventing you from creating Heimdall packages manually. Of course
Heimdall Frontend provides a simple user interface that takes care of all
the hard work for you.
There are two ways in which you can create a firmware package. You can
create a package from scratch, or you can load an existing package, apply
modifications and then save the package. Creating a package from scratch
is the preferred approach, by taking this approach you're far less likely
to run into file name length limitations.
Before you can access Heimdall Frontend's firmware creation functionality
(available from the "Create Package" tab) you must first specify which
files will be included in your package, as well as a few flashing options
i.e. Whether or not users should repartition when flashing. This
information must be filled out from the "Flash" tab in exactly the same
fashion you would provide information to flash your device (see "Performing
a Custom Flash with Heimdall Frontend"). As mentioned above, it's not the
preferred means, but you're able to load an existing package as a starting
point for this information.
Once you've specified the files/partitions you wish to include in your
firmware package the "Create Package" tab will become available. Clicking
this tab will display additional information that you can include in your
package. In order to continue you must fill out all sections except for the
URLs section, which is optional. The following is a break-down of what all
these options mean.
- General Firmware Information: -
Firmware Name - This is the name of your particular firmware. An
example would be "Cyanogenmod".
Firmware Version - This is the version identifier for your package. Any
valid string will be accepted, although the inclusion of decimal
point version number is preferred i.e. "7.1". If it makes sense
then feel free to append a text string like "RC1" or "Beta 1" to
the decimal point version.
Platform Name - This is the name of platform (or operating system) that
your firmware is based on. In most cases this will simply be
"Android".
Platform Version - This is the operating system version that your
firmware is based on. Again decimal point version numbers are
preferred over text, i.e. "2.3.4" is preferred over "Gingerbread".
- Developers -
URLs (Optional):
Homepage - Here you can enter your personal URL or a URL particularly
pertaining to the firmware being packaged. The URL must be well
formed for it to work. An example of a well formed URL is
"http://www.glassechidna.com.au/products/heimdall/". It is
important to include "http://" in order to specify the protocol as
other protocols such as "ftp://" are equally valid although
unlikely to be used.
Donate - Here you can enter a URL that will link users to a page to
make donations for the effort you've put into developing your
firmware. Once again the URL must be well formed but there is no
requirement on how your donation page should work. For instance
both "http://www.glassechidna.com.au/donate/" and
"http://forum.xda-developers.com/donatetome.php?u=2710388" are
equally valid.
Developer Info:
Name - Here you can enter in the name of individual team members or a
team name. Click "Add" and the developer will be added to the list
on the right. If you make a mistake you can select a developer from
the list and click "Remove". You can list as many developers as you
like, however visual constraints of the "Load Package" tab means
only a few names will be visible. Where possible you may want to
opt for team names over listing individual team members.
- Supported Devices -
This section allows you to create a list of devices that are supported by
your particular firmware. Although Heimdall isn't capable of enforcing this
we strongly recommend you take this section seriously. If filled out
correctly you could help save a number of accidental bricks!
Device Info:
Manufacturer - This is where you can enter the name of the manufacturer
for a particular device. For now this will most likely be
"Samsung".
Name - This is the human readable name for a particular device.
"Galaxy S", "Galaxy S II", "Droid Charge", "Vibrant" and
"Galaxy S (Telstra)" are all valid names. There are a lot of
possible variations here so be as specific as you think is
necessary.
Product Code - This is by far the most important bit of device
information. Device names tend to be region specific and further
subject to the whims of telecommunication companies and resellers.
Product Codes (or product IDs) are designated by manufacturers and
are generally the definitive means of referring to a particular
device. Examples are "GT-I9000", "GT-I9100" and "SCH-I897". If
you're unsure of a particular product code then both Google and
GSMArena are your friends!
After filling out all the necessary information the "Build" button will be
enabled. If it's still disabled then you know you're missing some required
information. In particular you must specify at least one developer and at
least one supported device. Pressing the "Build" button will bring up a
save dialogue where you must chose a file name for your particular package.
Don't worry about specifying the ".tar.gz" extension Heimdall Frontend will
take care of this automatically.
Once you've chosen a file name Heimdall Frontend will begin the process of
building the firmware package. In doing so a valid firmware.xml file will
be generated from the information entered. All files will be archived in a
single TAR file then the TAR archive will be compressed via gzip
compression. Compression will take a little while but you will see progress
bars so you know the application hasn't hung. When the progress bars
disappear you're finished making your package.
Congratulations! You're now ready to redistribute your firmware package
online or by any means you see fit.
Appendix A - firmware.xml
The following details a part of the Heimdall Firmware Package format. This
is only relevant to developers or advanced users who wish to create Heimdall
Firmware Packages outside of Heimdall Frontend or in some way integrate support
for the format in their own software.
All Heimdall Firmware Packages must contain a file called firmware.xml. This
file stores flash information and meta-data for the package as well as
information about other files contained within the package.
The format is fairly straight-forward so it won't be explained in great detail.
Nonetheless the following is an example of a valid firmware.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<firmware version="1">
<name>Test Firmware</name>
<version>1.1</version>
<platform>
<name>Android</name>
<version>2.3.4</version>
</platform>
<developers>
<name>Benjamin Dobell</name>
<name>Hedonism Bot</name>
</developers>
<url>http://www.glassechidna.com.au/</url>
<donateurl>http://www.glassechidna.com.au/donate/</donateurl>
<devices>
<device>
<manufacturer>Samsung</manufacturer>
<product>GT-I9000</product>
<name>Galaxy S</name>
</device>
<device>
<manufacturer>Samsung</manufacturer>
<product>GT-I9000T</product>
<name>Galaxy S (Telstra)</name>
</device>
<device>
<manufacturer>Samsung</manufacturer>
<product>GT-I9000M</product>
<name>Vibrant</name>
</device>
</devices>
<pit>Nl3276-I9000 s1_odin_20100512.pit</pit>
<repartition>0</repartition>
<noreboot>0</noreboot>
<files>
<file>
<id>0</id>
<filename>gq3276-boot.bin</filename>
</file>
<file>
<id>24</id>
<filename>Uh3276-cache.rfs</filename>
</file>
<file>
<id>22</id>
<filename>em3276-factoryfs.rfs</filename>
</file>
<file>
<id>11</id>
<filename>fl3276-modem.bin</filename>
</file>
<file>
<id>21</id>
<filename>Xd3276-param.lfs</filename>
</file>
<file>
<id>3</id>
<filename>if3276-Sbl.bin</filename>
</file>
<file>
<id>6</id>
<filename>cr3276-zImage</filename>
</file>
</files>
</firmware>
New lines need not be included and the order in which elements are specified
does not need to match that of the above example.
One and only one <firmware> element must be included. The <firmware> element
must also have a version attribute specified. The version must be parsable as
an integer and indicates what version of the Heimdall Firmware Package
specification the package adheres to.
All data is stored as strings, however a <file>'s <id> element must be parsable
as an integer. The <id> value represents the partition ID (according to the
specified PIT file) that the file should be flashed to.
A <firmware>'s <repartition> and <noreboot> elements must also be parsable as
an integer. However, as they represent boolean values, a value of zero ("0")
means false (or disabled) where as a non-zero value (typically "1") means true
(or enabled).
File names are specified relative to the TAR archive in which firmware.xml and
all other files are to be stored. Heimdall Firmware Packages do not support
directories or links, as such file names should only be a name and not a path.
<url> and <donateurl> are the only optional elements, all other elements must
be included.
Appendix B - Installing Heimdall Suite from Source:
1. First make sure you have installed build-essential, cmake, zlib1g-dev,
qt5-default, libusb-1.0-0-dev and OpenGL (e.g libgl1-mesa-glx and
libgl1-mesa-dev).
NOTE: Package names may not be absolutely identical to those above.
2. Open a terminal and navigate to the directory you downloaded,
or extracted, Heimdall to.
3. Enter the following commands to compile Heimdall Suite:
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make

491
OSX/README.txt Normal file
View File

@ -0,0 +1,491 @@
Heimdall (c) 2010-2017 Benjamin Dobell, Glass Echidna
http://www.glassechidna.com.au/products/heimdall/
DISCLAIMER:
This software attempts to flash your Galaxy S device. The very nature of
flashing is dangerous. As with all flashing software, Heimdall has the
potential to damage (brick) your device if not used carefully. If you're
concerned, don't use this software. Flashing ROMs onto your phone may also
void your warranty. Benjamin Dobell and Glass Echidna are not responsible
for the result of your actions.
These instructions are for OS X operating systems.
Installing Heimdall and Heimdall Frontend Binaries:
1. Run "Heimdall Suite.pkg" and follow the instructions.
2. Reboot your system.
3. Done
Flashing Heimdall Firmware Package with Heimdall Frontend:
As of Heimdall Frontend 1.3 there are now two main ways to flash a ROM from
Heimdall Frontend. The simpler and preferred option is to download a
Heimdall Firmware Package and follow the following steps.
1. Fully charge your device (use the wall charger as it's faster).
2. Open the Heimdall Frontend (heimdall-frontend) application.
3. From the "Load Package" tab, under the "Heimdall Firmware Package"
section click the "Browse" button.
4. Use the dialogue that appears to navigate to, and select, the Heimdall
firmware package that you wish to flash.
5. You will see progress bars appear as the package is decompressed and
extracted.
When the package has finished being decompressed you should see
information about the particular firmware package that has been
selected.
6. Verify that your device is listed under "Supported Devices". If it's not
then STOP immediately! DO NOT flash this firmware to your device!
Instead search for an appropriate firmware package for your device.
If you believe there is a mistake and your device is actually
supported please get in contact with the firmware developer (not Glass
Echidna!) and ask them to rectify the issue. If the developer provided
a URL you may be able to contact them by pressing the "Homepage" button.
7. If you've verified your device is supported you may continue to press
the "Load / Customise" button.
8. You should now be looking at the "Flash" tab. If not verify that you did
in fact push the "Load / Customise" button.
Generally, you won't NEED or WANT to customise a firmware package! In
which case you can safely move on to step 9.
Nonetheless, the "Flash" tab provides you with a means to customise the
firmware package before flashing it to your device. See "Performing a
Custom Flash with Heimdall Frontend" for more details.
9. Put your Galaxy S device into download mode and plug it in to your PC.
Download mode can be accessed several different ways depending on your
particular device model. If you're unsure how to do this please search
online for the appropriate method.
10. Press the "Start" button.
11. Heimdall Frontend will display the progress and inform you when the
flash is complete.
If something went wrong i.e. your device wasn't detected because it
wasn't in download mode, then the status section will let you know the
cause of the problem.
Performing a Custom Flash with Heimdall Frontend:
This is the advanced means of flashing firmware to your device.
If you're not an advanced user or a developer, in the event that a Heimdall
Firmware Package doesn't exist for the particular firmware (or files) that
you wish to flash, then I strongly recommend you get in touch with developer
of the firmware (or files) and politely ask them to create a Heimdall
Firmware Package for you. In doing so then you don't have to worry about
making mistakes due to inexperience.
If you're looking to customise an existing Heimdall Firmware Package then
follow steps 1-8 of "Flashing Heimdall Firmware Package with Heimdall
Frontend" then start from below with step 5.
1. Fully charge your device (use the wall charger as it's faster).
2. Download a decrypted device ROM or a Heimdall Firmware Package
and extract everything to the one directory.
3. If the ROM is not a Heimdall Firmware Package it may instead be provided
as multiple archives (nested or otherwise), extract them all to the same
location.
NOTE: If you want to use the CSC then extract it last.
3. Open the Heimdall Frontend (heimdall-frontend) application.
4. Select the "Flash" tab. From the "Flash" tab you're able to completely
customise a flash.
5. Before you can chose which partitions you want to flash with particular
files you MUST first select a PIT file. To do this click the "Browse"
button in the "PIT" section. This will open a dialogue allowing you to
navigate to and select a valid PIT (.pit) file.
If you do not already have a valid PIT file stored on your computer you
can download your device's PIT file from the "Utilities" tab.
6. If a valid PIT file has been selected then "Add" button below the
"Partitions (Files)" list-box will become enabled. Press this button to
add a partition to your flash.
7. When you first add a partition you will see the "Partition Name" and
"Partition ID" be populated with information. Use the "Partition Name"
drop down to select which partition you wish to flash. "Partition ID"
will automatically update and is never directly editable.
8. You must then select a file to flash to the partition that you just
specified using the "Browse" button under the "File / Partition". You
will not be able to flash, create a firmware package or add another
partition until you have selected a file. However, you're still able to
press the "Remove" button if you've decided not to flash the partition
you've just specified.
9. When you've specified a file name then you'll be able to see the updated
information in the partition list to the right. You can select any
partition from this list and customise it as you see fit.
You can also remove a partition from the list by selecting it and
clicking the "Remove" button. Removing a partition from the list doesn't
remove it from your device, it simply means it will not be flashed.
10. Repeat steps 7-9 as often as needed to specify all the partitions/files
that you wish to flash.
11. Now you can chose whether you would like to repartition your device as
well as whether you would like to prevent the device rebooting once a
flash has been completed. These options can be enabled or disabled by
toggling the "Repartition" and "No Reboot" check-boxes.
In the general case you will only need to enable repartition if you wish
to change the PIT file on your device. Keep in mind that repartitioning
will wipe your device!
The "No Reboot" option is rarely required. It's mostly in place so you
can manually boot straight into recovery mode after a flash (rather than
booting up normally).
12. If you've added at least one partition to your flash (and selected a
file for that partition) then the "Start" button will be enabled. Press
the "Start" button to begin the flashing process.
You may notice that the "Create Package" tab becomes available at the
whenever the "Start" button becomes available. From this tab you're able
to create a reusable, redistributable Heimdall Firmware Package with the
files and partitions you just selected. See "How to Create a Heimdall
Firmware Package" for details.
13. Heimdall Frontend will display the progress and inform you when the
flash is complete.
If something went wrong i.e. your device wasn't detected because it
wasn't in download mode, then the status section will let you know the
cause of the problem.
Flashing Firmware from Command Line:
1. Fully charge your phone (use the wall charger as it's faster).
2. Download a decrypted device ROM or a Heimdall Firmware Package
and extract everything to the one directory.
3. If the ROM is not a Heimdall Firmware Package it may instead be provided
as multiple archives (nested or otherwise), extract them all to the same
location.
NOTE: If you want to use the CSC then extract it last. If you're asked
to overwrite files then do so.
4. Put your Galaxy S device into download mode and plug it in..
5. Open a terminal and navigate to the directory where you extracted
the ROM/firmware files.
6. Type the following to list all the functionality Heimdall supports:
heimdall help
7. Before flashing, you must first know the names of the partitions you
wish to flash. These can be obtained by executing:
heimdall print-pit --no-reboot
The inclusion of --no-reboot ensures the phone will not reboot after PIT
file has been downloaded and displayed. After executing a command with
the --no-reboot argument, the next command should include the --resume
argument.
NOTE: You can still safely reboot your phone manually (with the power
button) after executing --no-reboot commands.
8. Use the help and print-pit output to construct a command with all the
file you want to flash.
Here is an example that does a full flash and repartition on a GT-I9000:
heimdall flash --repartition --resume --pit s1_odin_20100512.pit --FACTORYFS factoryfs.rfs --CACHE cache.rfs --DBDATA dbdata.rfs --IBL+PBL boot.bin --SBL Sbl.bin --PARAM param.lfs --KERNEL zImage --MODEM modem.bin
9. Heimdall will display the progress as it flashes so that you know things
are working as they should.
How to Create a Heimdall Firmware Package:
Firstly, Heimdall's firmware package format is just a regular TAR archive
compressed with gzip. The only two real requirements are that a valid
firmware.xml must be included (refer to Appendix A) and you can only
include files (no directories, links etc.) As such if you'd like there is
nothing preventing you from creating Heimdall packages manually. Of course
Heimdall Frontend provides a simple user interface that takes care of all
the hard work for you.
There are two ways in which you can create a firmware package. You can
create a package from scratch, or you can load an existing package, apply
modifications and then save the package. Creating a package from scratch
is the preferred approach, by taking this approach you're far less likely
to run into file name length limitations. These are not Heimdall's own
limitation but rather a limitation of the TAR archive format.
Before you can access Heimdall Frontend's firmware creation functionality
(available from the "Create Package" tab) you must first specify which
files will be included in your package, as well as a few flashing options
i.e. Whether or not users should repartition when flashing. This
information must be filled out from the "Flash" tab in exactly the same
fashion you would provide information to flash your device (see "Performing
a Custom Flash with Heimdall Frontend"). As mentioned above, it's not the
preferred means, but you're able to load an existing package as a starting
point for this information.
Once you've specified the files/partitions you wish to include in your
firmware package the "Create Package" tab will become available. Clicking
this tab will display additional information that you can include in your
package. In order to continue you must fill out all sections except for the
URLs section, which is optional. The following is a break-down of what all
these options mean.
- General Firmware Information: -
Firmware Name - This is the name of your particular firmware. An
example would be "Cyanogenmod".
Firmware Version - This is the version identifier for your package. Any
valid string will be accepted although a the inclusion of decimal
point version number is preferred i.e. "7.1". If it makes sense
then feel free to append a text string like "RC1" or "Beta 1" to
the decimal point version.
Platform Name - This is the name of the platform (or operating system)
that your firmware is based on. In most cases this will simply be
"Android".
Platform Version - This is the operating system version that your
firmware is based on. Again decimal point version numbers are
preferred over text, i.e. "2.3.4" is preferred over "Gingerbread".
- Developers -
URLs (Optional):
Homepage - Here you can enter your personal URL or a URL particularly
pertaining to the firmware being packaged. The URL must be well
formed for it to work. An example of a well formed URL is
"http://www.glassechidna.com.au/products/heimdall/". It is
important to include "http://" in order to specify the protocol as
other protocols such as "ftp://" are equally valid although
unlikely to be used.
Donate - Here you can enter a URL that will link users to a page to
make donations for the effort you've put into developing your
firmware. Once again the URL must be well formed but there is no
requirement on how your donation page should work. For instance
both "http://www.glassechidna.com.au/donate/" and
"http://forum.xda-developers.com/donatetome.php?u=2710388" are
equally valid.
Developer Info:
Name - Here you can enter in the name of individual team members or a
team name. Click "Add" and the developer will be added to the list
on the right. If you make a mistake you can select a developer from
the list and click "Remove". You can list as many developers as you
like however visual constraints of the "Load Package" tab means
only a few names will be visible. Where possible you may want to
opt for team names over listing individual team members.
- Supported Devices -
This section allows you to create a list of devices that are supported by
your particular firmware. Although Heimdall isn't capable of enforcing this
we strongly recommend you take this section seriously. If filled out
correctly you could help save a number of accidental bricks!
Device Info:
Manufacturer - This is where you can enter the name of the manufacturer
for a particular device. For now this will most likely be
"Samsung".
Name - This is the human readable name for a particular device.
"Galaxy S", "Galaxy S II", "Droid Charge", "Vibrant" and
"Galaxy S (Telstra)" are all valid names. There are a lot of
possible variations here so be as specific as you think is
necessary.
Product Code - This is by far the most important bit of device
information. Device names tend to be region specific and further
subject to the whims of telecommunication companies and resellers.
Product Codes (or product IDs) are designated by manufacturers and
are generally the definitive means of referring to a particular
device. Examples are "GT-I9000", "GT-I9100" and "SCH-I897". If
you're unsure of a particular product code then both Google and
GSMArena are your friends!
After filling out all the necessary information the "Build" button will be
enabled. If it's still disabled then you know you're missing some required
information. In particular you must specify at least one developer and at
least one supported device. Pressing the "Build" button will bring up a
save dialogue where you must chose a file name for your particular package.
Don't worry about specifying the ".tar.gz" extension Heimdall Frontend will
take care of this automatically.
Once you've chosen a file name Heimdall Frontend will begin the process of
building the firmware package. In doing so a valid firmware.xml file will
be generated from the information entered. All files will be archived in a
single TAR file then the TAR archive will be compressed via gzip
compression. Compression will take a little while but you will see progress
bars so you know the application hasn't hung. When the progress bars
disappear you're finished making your package.
Congratulations! You're now ready to redistribute your firmware package
online or by any means you see fit.
Appendix A - firmware.xml
The following details a part of the Heimdall Firmware Package format. This
is only relevant to developers or advanced users who wish to create Heimdall
Firmware Packages outside of Heimdall Frontend or in some way integrate support
for the format in their own software.
All Heimdall Firmware Packages must contain a file called firmware.xml. This
file stores flash information and meta-data for the package as well as
information about other files contained within the package.
The format is fairly straight-forward so it won't be explained in great detail.
Nonetheless the following is an example of a valid firmware.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<firmware version="1">
<name>Test Firmware</name>
<version>1.1</version>
<platform>
<name>Android</name>
<version>2.3.4</version>
</platform>
<developers>
<name>Benjamin Dobell</name>
<name>Hedonism Bot</name>
</developers>
<url>http://www.glassechidna.com.au/</url>
<donateurl>http://www.glassechidna.com.au/donate/</donateurl>
<devices>
<device>
<manufacturer>Samsung</manufacturer>
<product>GT-I9000</product>
<name>Galaxy S</name>
</device>
<device>
<manufacturer>Samsung</manufacturer>
<product>GT-I9000T</product>
<name>Galaxy S (Telstra)</name>
</device>
<device>
<manufacturer>Samsung</manufacturer>
<product>GT-I9000M</product>
<name>Vibrant</name>
</device>
</devices>
<pit>Nl3276-I9000 s1_odin_20100512.pit</pit>
<repartition>0</repartition>
<noreboot>0</noreboot>
<files>
<file>
<id>0</id>
<filename>gq3276-boot.bin</filename>
</file>
<file>
<id>24</id>
<filename>Uh3276-cache.rfs</filename>
</file>
<file>
<id>22</id>
<filename>em3276-factoryfs.rfs</filename>
</file>
<file>
<id>11</id>
<filename>fl3276-modem.bin</filename>
</file>
<file>
<id>21</id>
<filename>Xd3276-param.lfs</filename>
</file>
<file>
<id>3</id>
<filename>if3276-Sbl.bin</filename>
</file>
<file>
<id>6</id>
<filename>cr3276-zImage</filename>
</file>
</files>
</firmware>
New lines need not be included and the order in which elements are specified
does not need to match that of the above example.
One and only one <firmware> element must be included. The <firmware> element
must also have a version attribute specified. The version must be parsable as
an integer and indicates what version of the Heimdall Firmware Package
specification the package adheres to.
All data is stored as strings, however a <file>'s <id> element must be parsable
as an integer. The <id> value represents the partition ID (according to the
specified PIT file) that the file should be flashed to.
A <firmware>'s <repartition> and <noreboot> elements must also be parsable as
an integer. However, as they represent boolean values, a value of zero ("0")
means false (or disabled) where as a non-zero value (typically "1") means true
(or enabled).
File names are specified relative to the TAR archive in which firmware.xml and
all other files are to be stored. Heimdall Firmware Packages do not support
directories or links, as such file names should only be a name and not a path.
<url> and <donateurl> are the only optional elements, all other elements must
be included.
Appendix B - Installing Heimdall Suite from Source
1. Open Terminal and install dependencies using Homebrew (http://brew.sh)
brew install libusb qt5 cmake
2. Build Heimdall & Heimdall Frontend
mkdir build
cd build
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DQt5Widgets_DIR=/usr/local/opt/qt5/lib/cmake/Qt5Widgets ..
make

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd";>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key> <string>English</string>
<key>CFBundleGetInfoString</key> <string>Heimdall Download Mode</string>
<key>CFBundleIdentifier</key> <string>au.com.glassechidna.heimdall.usb_shield</string>
<key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
<key>CFBundleName</key> <string>Heimdall Download Mode</string>
<key>CFBundlePackageType</key> <string>KEXT</string>
<key>CFBundleSignature</key> <string>????</string>
<key>CFBundleVersion</key> <string>6.0</string>
<key>IOKitPersonalities</key>
<dict>
<key>0x6001</key>
<dict>
<key>CFBundleIdentifier</key> <string>com.apple.driver.AppleUSBComposite</string>
<key>IOClass</key> <string>AppleUSBComposite</string>
<key>IOProbeScore</key> <integer>300000</integer>
<key>IOProviderClass</key> <string>IOUSBDevice</string>
<key>idVendor</key> <integer>1256</integer>
<key>idProduct</key> <integer>26113</integer>
<key>bcdDevice</key> <integer>256</integer>
</dict>
<key>0x685D</key>
<dict>
<key>CFBundleIdentifier</key> <string>com.apple.driver.AppleUSBComposite</string>
<key>IOClass</key> <string>AppleUSBComposite</string>
<key>IOProbeScore</key> <integer>300000</integer>
<key>IOProviderClass</key> <string>IOUSBDevice</string>
<key>idVendor</key> <integer>1256</integer>
<key>idProduct</key> <integer>26717</integer>
<key>bcdDevice</key> <integer>256</integer>
</dict>
<key>0x68C3</key>
<dict>
<key>CFBundleIdentifier</key> <string>com.apple.driver.AppleUSBComposite</string>
<key>IOClass</key> <string>AppleUSBComposite</string>
<key>IOProbeScore</key> <integer>300000</integer>
<key>IOProviderClass</key> <string>IOUSBDevice</string>
<key>idVendor</key> <integer>1256</integer>
<key>idProduct</key> <integer>26819</integer>
<key>bcdDevice</key> <integer>256</integer>
</dict>
</dict>
<key>OSBundleCompatibleVersion</key> <string>1.8</string>
<key>OSBundleLibraries</key>
<dict>
<key>com.apple.kpi.iokit</key> <string>8.0.0</string>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>files</key>
<dict/>
<key>files2</key>
<dict/>
<key>rules</key>
<dict>
<key>^Resources/</key>
<true/>
<key>^Resources/.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^Resources/.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^version.plist$</key>
<true/>
</dict>
<key>rules2</key>
<dict>
<key>.*\.dSYM($|/)</key>
<dict>
<key>weight</key>
<real>11</real>
</dict>
<key>^(.*/)?\.DS_Store$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>2000</real>
</dict>
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
<dict>
<key>nested</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^.*</key>
<true/>
<key>^Info\.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^PkgInfo$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^Resources/</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
<key>^Resources/.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^Resources/.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^[^/]+$</key>
<dict>
<key>nested</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^embedded\.provisionprofile$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
<key>^version\.plist$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
</dict>
</dict>
</plist>

8
OSX/install-kext.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
BASEDIR=$(dirname $0)
echo 'Installing Driver...'
sudo cp -R "$BASEDIR/heimdall.kext" /System/Library/Extensions
sudo chmod -R 755 /System/Library/Extensions/heimdall.kext
sudo chown -R root:wheel /System/Library/Extensions/heimdall.kext
sudo kextload /System/Library/Extensions/heimdall.kext
echo 'Installation complete. If Heimdall cannot recognise your device a reboot may be required.'

60
README.md Normal file
View File

@ -0,0 +1,60 @@
[Original source](https://github.com/Benjamin-Dobell/Heimdall) by Benjamin Dobell
UPDATE: It was modified by maxmoon in 2022 to flash custom firmware like [LineageOS](https://download.lineageos.org) on old devices (there was a bug).
[Here](https://publish.ministryofinternet.eu/utopify-org/flashing-old-smartphones-with-custom-firmware) is a step by step guide on how to flash old smartphones with it, like a **Samsung Galaxy S5 (SM-G900F)**.
---
**The following lines are from the original README.md**
---
# Heimdall
Heimdall is a cross-platform open-source tool suite used to flash firmware (aka ROMs) onto Samsung mobile devices.
## Supported Platforms
Officially, AMD64/x86-64 (64-bit) or x86 (32-bit) computers running:
* Linux
* macOS
* Windows (XP, Vista, 7 etc.)
However, several third-parties have reported success running Heimdall on ARM chipsets
(in particular Raspberry Pi), as well as additional operating systems such as FreeBSD.
## How does Heimdall work?
Heimdall connects to a mobile device over USB and interacts with low-level software
running on the device, known as Loke. Loke and Heimdall communicate via the custom
Samsung-developed protocol typically referred to as the 'Odin 3 protocol'.
USB communication in Heimdall is handled by the popular open-source USB library, [libusb](http://libusb.info).
## Free & Open Source
Heimdall is both free and open source. It is licensed under the MIT license (see LICENSE).
Heimdall is maintained and predominantly developed by [Glass Echidna](http://glassechidna.com.au/),
a _tiny_ independent software development company. If you appreciate our work and would like
to support future development please consider making a [donation](http://glassechidna.com.au/donate/).
## Documentation
For more details about how to compile and install Heimdall please refer to the
appropriate platform specific README:
#### Linux
- Linux/README ([online](https://raw.githubusercontent.com/Benjamin-Dobell/Heimdall/master/Linux/README))
#### OS X
- OSX/README.txt ([online](https://raw.githubusercontent.com/Benjamin-Dobell/Heimdall/master/OSX/README.txt))
#### Windows
- Win32/README.txt ([online](https://raw.githubusercontent.com/Benjamin-Dobell/Heimdall/master/Win32/README.txt))

BIN
Win32/Drivers/zadig.exe Normal file

Binary file not shown.

547
Win32/README.txt Normal file
View File

@ -0,0 +1,547 @@
Heimdall (c) 2010-2017 Benjamin Dobell, Glass Echidna
http://www.glassechidna.com.au/products/heimdall/
DISCLAIMER:
This software attempts to flash your Galaxy S device. The very nature of
flashing is dangerous. As with all flashing software, Heimdall has the
potential to damage (brick) your device if not used carefully. If you're
concerned, don't use this software. Flashing ROMs onto your device may also
void your warranty. Benjamin Dobell and Glass Echidna are not responsible
for the result of your actions.
These instructions were written for Windows 7 / Vista / Server 2008 however the
procedure should be essentially the same for all supported versions of
Windows (XP onwards).
Driver Installation Instructions:
1. Put your device into download mode and plug it in.
2. Run zadig.exe included in the Drivers subdirectory.
3. From the menu chose Options -> List All Devices.
4. From the USB Device list chose "Samsung USB Composite DEvice".
5. Press "Install Driver", click "Yes" to the prompt and if you receive
a message about being unable to verify the publisher of the driver
click "Install this driver software anyway".
6. Done
Driver Uninstallation Instructions:
1. Put your device into download mode by holding Volume Down + Home + Power.
2. Plug your phone into your PC.
3. Open up Device Manager on your PC (Control Panel -> System -> Device Manager).
4. Under "Libusb (WinUSB) devices" right click on "Samsung USB Composite Device" and chose Properties.
5. Go to the Driver tab and select Update Driver.
6. Chose to browse your computer for the driver.
7. Chose to pick from a list of devices drivers on your computer.
8. Pick the original Samsung Composite driver, press next and then follow the prompts.
9. Done
Flashing Heimdall Firmware Package with Heimdall Frontend:
As of Heimdall Frontend 1.3 there are now two main ways to flash a ROM from
Heimdall Frontend. The simpler and preferred option is to download a
Heimdall Firmware Package and follow the following steps.
1. Fully charge your device (use the wall charger as it's faster).
2. Open the Heimdall Frontend (heimdall-frontend) executable.
3. From the "Load Package" tab, under the "Heimdall Firmware Package"
section click the "Browse" button.
4. Use the dialogue that appears to navigate to, and select, the Heimdall
firmware package that you wish to flash.
5. You will see progress bars appear as the package is decompressed and
extracted.
When the package has finished being decompressed you should see
information about the particular firmware package that has been
selected.
6. Verify that your device is listed under "Supported Devices". If it's not
then STOP immediately! DO NOT flash this firmware to your device!
Instead search for an appropriate firmware package for your device.
If you believe there is a mistake and your device is actually
supported please get in contact with the firmware developer (not Glass
Echidna!) and ask them to rectify the issue. If the developer provided
a URL you may be able to contact them by pressing the "Homepage" button.
7. If you've verified your device is supported you may continue to press
the "Load / Customise" button.
8. You should now be looking at the "Flash" tab. If not verify that you did
in fact push the "Load / Customise" button.
Generally, you won't NEED or WANT to customise a firmware package! In
which case you can safely move on to step 9.
Nonetheless, the "Flash" tab provides you with a means to customise the
firmware package before flashing it to your device. See "Performing a
Custom Flash with Heimdall Frontend" for more details.
9. Put your Galaxy S device into download mode and plug it in to your PC.
Download mode can be accessed several different ways depending on your
particular device model. If you're unsure how to do this please search
online for the appropriate method.
10. Press the "Start" button.
11. Heimdall Frontend will display the progress and inform you when the
flash is complete.
If something went wrong i.e. your device wasn't detected because it
wasn't in download mode, then the status section will let you know the
cause of the problem.
Performing a Custom Flash with Heimdall Frontend:
This is the advanced means of flashing firmware to your device.
If you're not an advanced user or a developer, in the event that a Heimdall
Firmware Package doesn't exist for the particular firmware (or files) that
you wish to flash, then I strongly recommend you get in touch with developer
of the firmware (or files) and politely ask them to create a Heimdall
Firmware Package for you. In doing so then you don't have to worry about
making mistakes due to inexperience.
If you're looking to customise an existing Heimdall Firmware Package then
follow steps 1-8 of "Flashing Heimdall Firmware Package with Heimdall
Frontend" then start from below with step 5.
1. Fully charge your device (use the wall charger as it's faster).
2. Download a decrypted device ROM or a Heimdall Firmware Package
and extract everything to the one directory.
3. If the ROM is not a Heimdall Firmware Package it may instead be provided
as multiple archives (nested or otherwise), extract them all to the same
location.
NOTE: If you want to use the CSC then extract it last.
3. Open the Heimdall Frontend (heimdall-frontend) executable.
4. Select the "Flash" tab. From the "Flash" tab you're able to completely
customise a flash.
5. Before you can chose which partitions you want to flash with particular
files you MUST first select a PIT file. To do this click the "Browse"
button in the "PIT" section. This will open a dialogue allowing you to
navigate to and select a valid PIT (.pit) file.
If you do not already have a valid PIT file stored on your computer you
can download your device's PIT file from the "Utilities" tab.
6. If a valid PIT file has been selected then "Add" button below the
"Partitions (Files)" list-box will become enabled. Press this button to
add a partition to your flash.
7. When you first add a partition you will see the "Partition Name" and
"Partition ID" be populated with information. Use the "Partition Name"
drop down to select which partition you wish to flash. "Partition ID"
will automatically update and is never directly editable.
8. You must then select a file to flash to the partition that you just
specified using the "Browse" button under the "File / Partition". You
will not be able to flash, create a firmware package or add another
partition until you have selected a file. However, you're still able to
press the "Remove" button if you've decided not to flash the partition
you've just specified.
9. When you've specified a file name then you'll be able to see the updated
information in the partition list to the right. You can select any
partition from this list and customise it as you see fit.
You can also remove a partition from the list by selecting it and
clicking the "Remove" button. Removing a partition from the list doesn't
remove it from your device, it simply means it will not be flashed.
10. Repeat steps 7-9 as often as needed to specify all the partitions/files
that you wish to flash.
11. Now you can chose whether you would like to repartition your device as
well as whether you would like to prevent the device rebooting once a
flash has been completed. These options can be enabled or disabled by
toggling the "Repartition" and "No Reboot" check-boxes.
In the general case you will only need to enable repartition if you wish
to change the PIT file on your device. Keep in mind that repartitioning
will wipe your device!
The "No Reboot" option is rarely required. It's mostly in place so you
can manually boot straight into recovery mode after a flash (rather than
booting up normally).
12. If you've added at least one partition to your flash (and selected a
file for that partition) then the "Start" button will be enabled. Press
the "Start" button to begin the flashing process.
You may notice that the "Create Package" tab becomes available at the
whenever the "Start" button becomes available. From this tab you're able
to create a reusable, redistributable Heimdall Firmware Package with the
files and partitions you just selected. See "How to Create a Heimdall
Firmware Package" for details.
13. Heimdall Frontend will display the progress and inform you when the
flash is complete.
If something went wrong i.e. your device wasn't detected because it
wasn't in download mode, then the status section will let you know the
cause of the problem.
Flashing Firmware from Command Line:
1. Fully charge your phone (use the wall charger as it's faster).
2. Download a decrypted device ROM or a Heimdall Firmware Package
and extract everything to the one directory.
3. If the ROM is not a Heimdall Firmware Package it may instead be provided
as multiple archives (nested or otherwise), extract them all to the same
location.
NOTE: If you want to use the CSC then extract it last. If you're asked
to overwrite files then do so.
4. Put your Galaxy S device into download mode and plug it in..
5. Open command prompt and navigate to the directory where you installed
heimdall.
NOTE: Adding Heimdall to your PATH variable will allow you to run
Heimdall from any directory.
6. Type the following to list all the functionality Heimdall supports:
heimdall help
7. Before flashing, you must first know the names of the partitions you
wish to flash. These can be obtained by executing:
heimdall print-pit --no-reboot
The inclusion of --no-reboot ensures the phone will not reboot after PIT
file has been downloaded and displayed. After executing a command with
the --no-reboot argument, the next command should include the --resume
argument.
NOTE: You can still safely reboot your phone manually (with the power
button) after executing --no-reboot commands.
8. Use the help and print-pit output to construct a command with all the
file you want to flash.
Here is an example that does a full flash and repartition on a GT-I9000:
heimdall flash --repartition --resume --pit s1_odin_20100512.pit --FACTORYFS factoryfs.rfs --CACHE cache.rfs --DBDATA dbdata.rfs --IBL+PBL boot.bin --SBL Sbl.bin --PARAM param.lfs --KERNEL zImage --MODEM modem.bin
NOTE: The above command assumes the files specified are installed in the
same directory as Heimdall.
9. Heimdall will display the progress as it flashes so that you know things
are working as they should.
How to Create a Heimdall Firmware Package:
Firstly, Heimdall's firmware package format is just a regular TAR archive
compressed with gzip. The only two real requirements are that a valid
firmware.xml must be included (refer to Appendix A) and you can only
include files (no directories, links etc.) As such if you'd like there is
nothing preventing you from creating Heimdall packages manually. Of course
Heimdall Frontend provides a simple user interface that takes care of all
the hard work for you.
There are two ways in which you can create a firmware package. You can
create a package from scratch, or you can load an existing package, apply
modifications and then save the package. Creating a package from scratch
is the preferred approach, by taking this approach you're far less likely
to run into file name length limitations. These are not Heimdall's own
limitation but rather a limitation of the TAR archive format.
Before you can access Heimdall Frontend's firmware creation functionality
(available from the "Create Package" tab) you must first specify which
files will be included in your package, as well as a few flashing options
i.e. Whether or not users should repartition when flashing. This
information must be filled out from the "Flash" tab in exactly the same
fashion you would provide information to flash your device (see "Performing
a Custom Flash with Heimdall Frontend"). As mentioned above, it's not the
preferred means, but you're able to load an existing package as a starting
point for this information.
Once you've specified the files/partitions you wish to include in your
firmware package the "Create Package" tab will become available. Clicking
this tab will display additional information that you can include in your
package. In order to continue you must fill out all sections except for the
URLs section, which is optional. The following is a break-down of what all
these options mean.
- General Firmware Information: -
Firmware Name - This is the name of your particular firmware. An
example would be "Cyanogenmod".
Firmware Version - This is the version identifier for your package. Any
valid string will be accepted although a the inclusion of decimal
point version number is preferred i.e. "7.1". If it makes sense
then feel free to append a text string like "RC1" or "Beta 1" to
the decimal point version.
Platform Name - This is the name of the platform (or operating system)
that your firmware is based on. In most cases this will simply be
"Android".
Platform Version - This is the operating system version that your
firmware is based on. Again decimal point version numbers are
preferred over text, i.e. "2.3.4" is preferred over "Gingerbread".
- Developers -
URLs (Optional):
Homepage - Here you can enter your personal URL or a URL particularly
pertaining to the firmware being packaged. The URL must be well
formed for it to work. An example of a well formed URL is
"http://www.glassechidna.com.au/products/heimdall/". It is
important to include "http://" in order to specify the protocol as
other protocols such as "ftp://" are equally valid although
unlikely to be used.
Donate - Here you can enter a URL that will link users to a page to
make donations for the effort you've put into developing your
firmware. Once again the URL must be well formed but there is no
requirement on how your donation page should work. For instance
both "http://www.glassechidna.com.au/donate/" and
"http://forum.xda-developers.com/donatetome.php?u=2710388" are
equally valid.
Developer Info:
Name - Here you can enter in the name of individual team members or a
team name. Click "Add" and the developer will be added to the list
on the right. If you make a mistake you can select a developer from
the list and click "Remove". You can list as many developers as you
like however visual constraints of the "Load Package" tab means
only a few names will be visible. Where possible you may want to
opt for team names over listing individual team members.
- Supported Devices -
This section allows you to create a list of devices that are supported by
your particular firmware. Although Heimdall isn't capable of enforcing this
we strongly recommend you take this section seriously. If filled out
correctly you could help save a number of accidental bricks!
Device Info:
Manufacturer - This is where you can enter the name of the manufacturer
for a particular device. For now this will most likely be
"Samsung".
Name - This is the human readable name for a particular device.
"Galaxy S", "Galaxy S II", "Droid Charge", "Vibrant" and
"Galaxy S (Telstra)" are all valid names. There are a lot of
possible variations here so be as specific as you think is
necessary.
Product Code - This is by far the most important bit of device
information. Device names tend to be region specific and further
subject to the whims of telecommunication companies and resellers.
Product Codes (or product IDs) are designated by manufacturers and
are generally the definitive means of referring to a particular
device. Examples are "GT-I9000", "GT-I9100" and "SCH-I897". If
you're unsure of a particular product code then both Google and
GSMArena are your friends!
After filling out all the necessary information the "Build" button will be
enabled. If it's still disabled then you know you're missing some required
information. In particular you must specify at least one developer and at
least one supported device. Pressing the "Build" button will bring up a
save dialogue where you must chose a file name for your particular package.
Don't worry about specifying the ".tar.gz" extension Heimdall Frontend will
take care of this automatically.
Once you've chosen a file name Heimdall Frontend will begin the process of
building the firmware package. In doing so a valid firmware.xml file will
be generated from the information entered. All files will be archived in a
single TAR file then the TAR archive will be compressed via gzip
compression. Compression will take a little while but you will see progress
bars so you know the application hasn't hung. When the progress bars
disappear you're finished making your package.
Congratulations! You're now ready to redistribute your firmware package
online or by any means you see fit.
Appendix A - firmware.xml
The following details a part of the Heimdall Firmware Package format. This
is only relevant to developers or advanced users who wish to create Heimdall
Firmware Packages outside of Heimdall Frontend or in some way integrate support
for the format in their own software.
All Heimdall Firmware Packages must contain a file called firmware.xml. This
file stores flash information and meta-data for the package as well as
information about other files contained within the package.
The format is fairly straight-forward so it won't be explained in great detail.
Nonetheless the following is an example of a valid firmware.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<firmware version="1">
<name>Test Firmware</name>
<version>1.1</version>
<platform>
<name>Android</name>
<version>2.3.4</version>
</platform>
<developers>
<name>Benjamin Dobell</name>
<name>Hedonism Bot</name>
</developers>
<url>http://www.glassechidna.com.au/</url>
<donateurl>http://www.glassechidna.com.au/donate/</donateurl>
<devices>
<device>
<manufacturer>Samsung</manufacturer>
<product>GT-I9000</product>
<name>Galaxy S</name>
</device>
<device>
<manufacturer>Samsung</manufacturer>
<product>GT-I9000T</product>
<name>Galaxy S (Telstra)</name>
</device>
<device>
<manufacturer>Samsung</manufacturer>
<product>GT-I9000M</product>
<name>Vibrant</name>
</device>
</devices>
<pit>Nl3276-I9000 s1_odin_20100512.pit</pit>
<repartition>0</repartition>
<noreboot>0</noreboot>
<files>
<file>
<id>0</id>
<filename>gq3276-boot.bin</filename>
</file>
<file>
<id>24</id>
<filename>Uh3276-cache.rfs</filename>
</file>
<file>
<id>22</id>
<filename>em3276-factoryfs.rfs</filename>
</file>
<file>
<id>11</id>
<filename>fl3276-modem.bin</filename>
</file>
<file>
<id>21</id>
<filename>Xd3276-param.lfs</filename>
</file>
<file>
<id>3</id>
<filename>if3276-Sbl.bin</filename>
</file>
<file>
<id>6</id>
<filename>cr3276-zImage</filename>
</file>
</files>
</firmware>
New lines need not be included and the order in which elements are specified
does not need to match that of the above example.
One and only one <firmware> element must be included. The <firmware> element
must also have a version attribute specified. The version must be parsable as
an integer and indicates what version of the Heimdall Firmware Package
specification the package adheres to.
All data is stored as strings, however a <file>'s <id> element must be parsable
as an integer. The <id> value represents the partition ID (according to the
specified PIT file) that the file should be flashed to.
A <firmware>'s <repartition> and <noreboot> elements must also be parsable as
an integer. However, as they represent boolean values, a value of zero ("0")
means false (or disabled) where as a non-zero value (typically "1") means true
(or enabled).
File names are specified relative to the TAR archive in which firmware.xml and
all other files are to be stored. Heimdall Firmware Packages do not support
directories or links, as such file names should only be a name and not a path.
<url> and <donateurl> are the only optional elements, all other elements must
be included.
Appendix B - Installing Heimdall Suite from Source
Heimdall and Heimdall Frontend both utilise CMake for managing the build
process. CMake can generate files for various build systems including GNU
Make and Visual Studio. However, official packages are compiled with GNU
Make and MinGW-W64 GCC/G++.
NOTE: Official builds use MinGW-W64 simply because on-going cross-platform
development is simpler when using just the one IDE (Jetbrain's CLion)
and similar toolchains.
1. Setup a MinGW-W64 build environment by utilising MSYS2:
http://msys2.github.io/
2. After installing MSYS2 a command prompt will launch, enter:
Pacman -Syu
Pacman -S mingw-w64-x86_64 mingw-w64-x86_64-clang mingw-w64-x86_64-cmake mingw-w64-x86_64-libusb mingw-w64-x86_64-qt5-static make
3. Add the MinGW-W64 binaries to your PATH environment variable:
export PATH="/mingw64/bin:$PATH"
4. Build Heimdall & Heimdall Frontend
mkdir build
cd build
cmake -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release -DQt5Widgets_DIR=/c/msys64/mingw64/qt5-static/lib/cmake/Qt5Widgets ..
make

36
cmake/Findlibusb.cmake Normal file
View File

@ -0,0 +1,36 @@
find_path(LIBUSB_INCLUDE_DIR
NAMES
libusb.h
PATHS
/usr/local/include
/opt/local/include
/usr/include
PATH_SUFFIXES
libusb-1.0
)
if (libusb_USE_STATIC_LIBS AND NOT MSVC)
set (LIBUSB_LIB_PREFIX "lib" CACHE INTERNAL "libusb library name prefix passed to find_library")
set (LIBUSB_LIB_SUFFIX ".a" CACHE INTERNAL "libusb library name suffix passed to find_library")
else (libusb_USE_STATIC_LIBS AND NOT MSVC)
set (LIBUSB_LIB_PREFIX "" CACHE INTERNAL "libusb library name prefix passed to find_library")
set (LIBUSB_LIB_SUFFIX "" CACHE INTERNAL "libusb library name suffix passed to find_library")
endif (libusb_USE_STATIC_LIBS AND NOT MSVC)
find_library(LIBUSB_LIBRARY
NAMES
${LIBUSB_LIB_PREFIX}usb-1.0${LIBUSB_LIB_SUFFIX} ${LIBUSB_LIB_PREFIX}usb${LIBUSB_LIB_SUFFIX}
PATHS
/usr/local/lib
/opt/local/lib
/usr/lib
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(libusb REQUIRED_VARS LIBUSB_LIBRARY LIBUSB_INCLUDE_DIR)
if (LIBUSB_FOUND)
set(LIBUSB_INCLUDE_DIRS ${LIBUSB_INCLUDE_DIR})
set(LIBUSB_LIBRARIES ${LIBUSB_LIBRARY})
mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARY)
endif (LIBUSB_FOUND)

15
cmake/LargeFiles.c Normal file
View File

@ -0,0 +1,15 @@
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
#define VALID_ARRAY_LENGTH 1
#define INVALID_ARRAY_LENGTH -1
int main(int argc, const char **argv)
{
int a[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? VALID_ARRAY_LENGTH : INVALID_ARRAY_LENGTH];
off_t offset = ftello(NULL);
fseeko(NULL, offset, SEEK_SET);
return 0;
}

107
cmake/LargeFiles.cmake Normal file
View File

@ -0,0 +1,107 @@
macro(test_large_files VARIABLE USE_64_SUFFIX)
if(NOT DEFINED ${VARIABLE})
message(STATUS "Checking if large (64-bit) file support is available...")
if(USE_64_SUFFIX)
set(SUFFIX_64 "64")
else(USE_64_SUFFIX)
set(SUFFIX_64 "")
endif(USE_64_SUFFIX)
# First try without any macros defined
try_compile(LARGE_FILES_SUPPORTED "${CMAKE_BINARY_DIR}"
"${CMAKE_MODULE_PATH}/LargeFiles${SUFFIX_64}.c"
OUTPUT_VARIABLE TRY_LARGE_FILES_OUTPUT)
if(VERBOSE_LARGE_FILES)
message(STATUS "Large file output (no special flags):\n${TRY_LARGE_FILES_OUTPUT}")
endif(VERBOSE_LARGE_FILES)
if(NOT LARGE_FILES_SUPPORTED)
# Try with C macro _FILE_OFFSET_BITS=64
try_compile(LARGE_FILES_SUPPORTED "${CMAKE_BINARY_DIR}"
"${CMAKE_MODULE_PATH}/LargeFiles${SUFFIX_64}.c"
COMPILE_DEFINITIONS "-D_FILE_OFFSET_BITS=64"
OUTPUT_VARIABLE TRY_LARGE_FILES_OUTPUT)
if(VERBOSE_LARGE_FILES)
message(STATUS "Large file output (_FILE_OFFSET_BITS=64):\n${TRY_LARGE_FILES_OUTPUT}")
endif(VERBOSE_LARGE_FILES)
if(LARGE_FILES_SUPPORTED)
set(_FILE_OFFSET_BITS=64 CACHE INTERNAL "C macro _FILE_OFFSET_BITS=64 is required for 64-bit file support")
endif(LARGE_FILES_SUPPORTED)
endif(NOT LARGE_FILES_SUPPORTED)
if(NOT LARGE_FILES_SUPPORTED)
# Try with C macro _LARGEFILE_SOURCE
try_compile(LARGE_FILES_SUPPORTED "${CMAKE_BINARY_DIR}"
"${CMAKE_MODULE_PATH}/LargeFiles${SUFFIX_64}.c"
COMPILE_DEFINITIONS "-D_LARGEFILE${SUFFIX_64}_SOURCE"
OUTPUT_VARIABLE TRY_LARGE_FILES_OUTPUT)
if(VERBOSE_LARGE_FILES)
message(STATUS "Large file output (_LARGEFILE${SUFFIX_64}_SOURCE):\n${TRY_LARGE_FILES_OUTPUT}")
endif(VERBOSE_LARGE_FILES)
if(LARGE_FILES_SUPPORTED)
set(_LARGEFILE${SUFFIX_64}_SOURCE=1 CACHE INTERNAL "C macro _LARGEFILE${SUFFIX_64}_SOURCE is required for 64-bit file support")
endif(LARGE_FILES_SUPPORTED)
endif(NOT LARGE_FILES_SUPPORTED)
if(NOT LARGE_FILES_SUPPORTED)
# Try with both C macro _FILE_OFFSET_BITS=64 and _LARGEFILE_SOURCE
try_compile(LARGE_FILES_SUPPORTED "${CMAKE_BINARY_DIR}"
"${CMAKE_MODULE_PATH}/LargeFiles${SUFFIX_64}.c"
COMPILE_DEFINITIONS "-D_FILE_OFFSET_BITS=64" "-D_LARGEFILE${SUFFIX_64}_SOURCE"
OUTPUT_VARIABLE TRY_LARGE_FILES_OUTPUT)
if(VERBOSE_LARGE_FILES)
message(STATUS "Large file output (_FILE_OFFSET_BITS=64 and _LARGEFILE${SUFFIX_64}_SOURCE):\n${TRY_LARGE_FILES_OUTPUT}")
endif(VERBOSE_LARGE_FILES)
if(LARGE_FILES_SUPPORTED)
set(_FILE_OFFSET_BITS=64 CACHE INTERNAL "C macro _FILE_OFFSET_BITS=64 is required for 64-bit file support")
set(_LARGEFILE${SUFFIX_64}_SOURCE=1 CACHE INTERNAL "C macro _LARGEFILE${SUFFIX_64}_SOURCE is required for 64-bit file support")
endif(LARGE_FILES_SUPPORTED)
endif(NOT LARGE_FILES_SUPPORTED)
if(NOT LARGE_FILES_SUPPORTED)
# Maybe we are using the Windows C standard library
try_compile(LARGE_FILES_SUPPORTED "${CMAKE_BINARY_DIR}"
"${CMAKE_MODULE_PATH}/LargeFilesWindows.c")
endif(NOT LARGE_FILES_SUPPORTED)
if(LARGE_FILES_SUPPORTED)
message(STATUS "Checking if large (64-bit) file support is available - yes")
set(${VARIABLE} 1 CACHE INTERNAL "Is large file support available?")
else(LARGE_FILES_SUPPORTED)
message(STATUS "Checking if large (64-bit) file support is available - no")
set(${VARIABLE} 0 CACHE INTERNAL "Is large file support available?")
endif(LARGE_FILES_SUPPORTED)
endif(NOT DEFINED ${VARIABLE})
endmacro(test_large_files VARIABLE USE_64_SUFFIX)
macro(use_large_files TARGET USE_64_SUFFIX)
test_large_files(USING_LARGE_FILES ${USE_64_SUFFIX})
if(USING_LARGE_FILES)
if(DEFINED _FILE_OFFSET_BITS)
set_property(TARGET ${TARGET}
APPEND PROPERTY COMPILE_DEFINITIONS "-D_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}")
endif(DEFINED _FILE_OFFSET_BITS)
if(DEFINED _LARGEFILE_SOURCE)
set_property(TARGET ${TARGET}
APPEND PROPERTY COMPILE_DEFINITIONS "-D_LARGEFILE_SOURCE")
endif(DEFINED _LARGEFILE_SOURCE)
if(DEFINED _LARGEFILE64_SOURCE)
set_property(TARGET ${TARGET}
APPEND PROPERTY COMPILE_DEFINITIONS "-D_LARGEFILE64_SOURCE")
endif(DEFINED _LARGEFILE64_SOURCE)
else(USING_LARGE_FILES)
message(FATAL_ERROR "Large file support not available")
endif(USING_LARGE_FILES)
endmacro(use_large_files TARGET USE_64_SUFFIX)

16
cmake/LargeFiles64.c Normal file
View File

@ -0,0 +1,16 @@
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
#define VALID_ARRAY_LENGTH 1
#define INVALID_ARRAY_LENGTH -1
int main(int argc, const char **argv)
{
int a[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? VALID_ARRAY_LENGTH : INVALID_ARRAY_LENGTH];
off64_t offset = ftello64(NULL);
fseeko64(NULL, offset, SEEK_SET);
return 0;
}

View File

@ -0,0 +1,8 @@
#include <stdio.h>
int main()
{
__int64 off = 0;
_fseeki64(NULL, off, SEEK_SET);
return 0;
}

View File

@ -0,0 +1,56 @@
cmake_minimum_required(VERSION 2.8.4)
project(heimdall-frontend)
set(LIBPIT_INCLUDE_DIRS
../libpit/source)
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON) # moc files are generated in build (current) directory
find_package(Qt5Widgets REQUIRED)
find_package(ZLIB REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
if(MINGW)
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
endif(MINGW)
include_directories(${LIBPIT_INCLUDE_DIRS})
set(HEIMDALL_FRONTEND_SOURCE_FILES
source/aboutform.cpp
source/Alerts.cpp
source/FirmwareInfo.cpp
source/main.cpp
source/mainwindow.cpp
source/PackageData.cpp
source/Packaging.cpp)
qt5_wrap_ui(HEIMDALL_FRONTEND_FORMS
mainwindow.ui
aboutform.ui)
qt5_add_resources(HEIMDALL_FRONTEND_RESOURCES
mainwindow.qrc)
add_executable(heimdall-frontend WIN32
MACOSX_BUNDLE
${HEIMDALL_FRONTEND_SOURCE_FILES}
${HEIMDALL_FRONTEND_FORMS}
${HEIMDALL_FRONTEND_RESOURCES})
include(LargeFiles)
use_large_files(heimdall-frontend YES)
set_property(TARGET heimdall-frontend
APPEND PROPERTY COMPILE_DEFINITIONS "QT_LARGEFILE_SUPPORT")
target_link_libraries(heimdall-frontend pit)
target_link_libraries(heimdall-frontend Qt5::Widgets)
target_link_libraries(heimdall-frontend z)
install (TARGETS heimdall-frontend
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

View File

@ -0,0 +1,455 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutForm</class>
<widget class="QWidget" name="AboutForm">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>581</width>
<height>491</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>581</width>
<height>491</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>581</width>
<height>491</height>
</size>
</property>
<property name="windowTitle">
<string>About Heimdall Frontend</string>
</property>
<widget class="QPushButton" name="okPushButton">
<property name="geometry">
<rect>
<x>250</x>
<y>460</y>
<width>75</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>OK</string>
</property>
</widget>
<widget class="QScrollArea" name="scrollArea">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>561</width>
<height>441</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>-701</y>
<width>542</width>
<height>1140</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="versionCopyrightLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Heimdall Frontend&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Version 1.4.2&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Copyright © 2010-2017 Benjamin Dobell, Glass Echidna&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Heimdall (command line)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;%HEIMDALL-VERSION%Copyright © 2010-2017 Benjamin Dobell, Glass Echidna&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;If you appreciate this software and you would like to support future development please consider donating:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.glassechidna.com.au/donate/&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;http://www.glassechidna.com.au/donate/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>15</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:600;&quot;&gt;Glass Echidna Homepage:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.glassechidna.com.au/&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;http://www.glassechidna.com.au/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:600;&quot;&gt;Heimdall Homepage:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.glassechidna.com.au/products/heimdall/&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;http://www.glassechidna.com.au/products/heimdall/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>9</pointsize>
<kerning>true</kerning>
</font>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:600;&quot;&gt;Heimdall and Heimdall Frontend are licensed under the following license:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &amp;quot;Software&amp;quot;), 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:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;THE SOFTWARE IS PROVIDED &amp;quot;AS IS&amp;quot;, 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.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>0</number>
</property>
<property name="indent">
<number>2</number>
</property>
<property name="openExternalLinks">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>15</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:600;&quot;&gt;Heimdall Frontend's user interface is powered by the Qt Framework:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;Copyright © 2008-2011 Nokia Corporation&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;Qt is licensed under the &lt;/span&gt;&lt;a href=&quot;http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Lesser General Public License v2.1.&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>15</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:600;&quot;&gt;Heimdall Frontend utilises zlib for package compression:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;zlib is licensed under the following license:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;Copyright © 1995-2010 Jean-loup Gailly and Mark Adler&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:10pt;&quot;&gt;3. This notice may not be removed or altered from any source distribution.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>15</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt; font-weight:600;&quot;&gt;Heimdall (command line) utilises libusbx for all USB communication:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;libusbx is licensed under the &lt;/span&gt;&lt;a href=&quot;http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Lesser General Public License v2.1.&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>okPushButton</sender>
<signal>clicked()</signal>
<receiver>AboutForm</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>287</x>
<y>470</y>
</hint>
<hint type="destinationlabel">
<x>290</x>
<y>245</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,4 @@
<RCC>
<qresource prefix="MainWindow">
</qresource>
</RCC>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// Qt
#include <QMessageBox>
// Heimdall Frontend
#include "Alerts.h"
using namespace HeimdallFrontend;
void Alerts::DisplayError(const QString& errorMessage)
{
QMessageBox messageBox;
messageBox.setModal(true);
messageBox.setText(errorMessage);
messageBox.setIcon(QMessageBox::Critical);
messageBox.exec();
}
void Alerts::DisplayWarning(const QString& warningMessage)
{
QMessageBox messageBox;
messageBox.setModal(true);
messageBox.setText(warningMessage);
messageBox.setIcon(QMessageBox::Warning);
messageBox.exec();
}

View File

@ -0,0 +1,38 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef ALERTS_H
#define ALERTS_H
// Qt
#include <QString>
namespace HeimdallFrontend
{
class Alerts
{
public:
static void DisplayError(const QString& errorMessage);
static void DisplayWarning(const QString& warningMessage);
};
}
#endif

View File

@ -0,0 +1,783 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// Qt
#include "QRegExp"
// Heimdall Frontend
#include "Alerts.h"
#include "FirmwareInfo.h"
#include "Packaging.h"
using namespace HeimdallFrontend;
DeviceInfo::DeviceInfo()
{
}
DeviceInfo::DeviceInfo(const QString& manufacturer, const QString& product, const QString& name)
{
this->manufacturer = manufacturer;
this->product = product;
this->name = name;
}
bool DeviceInfo::ParseXml(QXmlStreamReader& xml)
{
bool foundManufacturer = false;
bool foundProduct = false;
bool foundName = false;
while (!xml.atEnd())
{
QXmlStreamReader::TokenType nextToken = xml.readNext();
if (nextToken == QXmlStreamReader::StartElement)
{
if (xml.name() == "manufacturer")
{
if (foundManufacturer)
{
Alerts::DisplayError("Found multiple <manufacturer> elements in <device>.");
return (false);
}
foundManufacturer = true;
manufacturer = xml.readElementText();
}
else if (xml.name() == "product")
{
if (foundProduct)
{
Alerts::DisplayError("Found multiple <product> elements in <device>.");
return (false);
}
foundProduct = true;
product = xml.readElementText();
}
else if (xml.name() == "name")
{
if (foundName)
{
Alerts::DisplayError("Found multiple <name> elements in <device>.");
return (false);
}
foundName = true;
name = xml.readElementText();
}
else
{
Alerts::DisplayError(QString("<%1> is not a valid child of <device>.").arg(xml.name().toString()));
return (false);
}
}
else if (nextToken == QXmlStreamReader::EndElement)
{
if (xml.name() == "device")
{
if (foundManufacturer && foundProduct && foundName)
{
return (true);
}
else
{
Alerts::DisplayError("Required elements are missing from <device>.");
return (false);
}
}
}
else
{
if (!(nextToken == QXmlStreamReader::Characters && xml.isWhitespace()))
{
Alerts::DisplayError("Unexpected token found in <device>.");
return (false);
}
}
}
return (false);
}
void DeviceInfo::WriteXml(QXmlStreamWriter& xml) const
{
xml.writeStartElement("device");
xml.writeStartElement("manufacturer");
xml.writeCharacters(manufacturer);
xml.writeEndElement();
xml.writeStartElement("product");
xml.writeCharacters(product);
xml.writeEndElement();
xml.writeStartElement("name");
xml.writeCharacters(name);
xml.writeEndElement();
xml.writeEndElement();
}
PlatformInfo::PlatformInfo()
{
}
void PlatformInfo::Clear(void)
{
name.clear();
version.clear();
}
bool PlatformInfo::IsCleared(void) const
{
return (name.isEmpty() && version.isEmpty());
}
bool PlatformInfo::ParseXml(QXmlStreamReader& xml)
{
Clear();
bool foundName = false;
bool foundVersion = false;
while (!xml.atEnd())
{
QXmlStreamReader::TokenType nextToken = xml.readNext();
if (nextToken == QXmlStreamReader::StartElement)
{
if (xml.name() == "name")
{
if (foundName)
{
Alerts::DisplayError("Found multiple <name> elements in <platform>.");
return (false);
}
foundName = true;
name = xml.readElementText();
}
else if (xml.name() == "version")
{
if (foundVersion)
{
Alerts::DisplayError("Found multiple <version> elements in <platform>.");
return (false);
}
foundVersion = true;
version = xml.readElementText();
}
else
{
Alerts::DisplayError(QString("<%1> is not a valid child of <platform>.").arg(xml.name().toString()));
return (false);
}
}
else if (nextToken == QXmlStreamReader::EndElement)
{
if (xml.name() == "platform")
{
if (foundName && foundVersion)
{
return (true);
}
else
{
Alerts::DisplayError("Required elements are missing from <platform>.");
return (false);
}
}
}
else
{
if (!(nextToken == QXmlStreamReader::Characters && xml.isWhitespace()))
{
Alerts::DisplayError("Unexpected token found in <platform>.");
return (false);
}
}
}
return (false);
}
void PlatformInfo::WriteXml(QXmlStreamWriter& xml) const
{
xml.writeStartElement("platform");
xml.writeStartElement("name");
xml.writeCharacters(name);
xml.writeEndElement();
xml.writeStartElement("version");
xml.writeCharacters(version);
xml.writeEndElement();
xml.writeEndElement();
}
FileInfo::FileInfo()
{
}
FileInfo::FileInfo(unsigned int partitionId, const QString& filename)
{
this->partitionId = partitionId;
this->filename = filename;
}
bool FileInfo::ParseXml(QXmlStreamReader& xml)
{
bool foundId = false;
bool foundFilename = false;
while (!xml.atEnd())
{
QXmlStreamReader::TokenType nextToken = xml.readNext();
if (nextToken == QXmlStreamReader::StartElement)
{
if (xml.name() == "id")
{
if (foundId)
{
Alerts::DisplayError("Found multiple <id> elements in <file>.");
return (false);
}
foundId = true;
partitionId = xml.readElementText().toInt();
}
else if (xml.name() == "filename")
{
if (foundFilename)
{
Alerts::DisplayError("Found multiple <filename> elements in <file>.");
return (false);
}
foundFilename = true;
filename = xml.readElementText();
}
else
{
Alerts::DisplayError(QString("<%1> is not a valid child of <file>.").arg(xml.name().toString()));
return (false);
}
}
else if (nextToken == QXmlStreamReader::EndElement)
{
if (xml.name() == "file")
{
if (foundId && foundFilename)
{
return (true);
}
else
{
Alerts::DisplayError("Required elements are missing from <file>.");
return (false);
}
}
}
else
{
if (!(nextToken == QXmlStreamReader::Characters && xml.isWhitespace()))
{
Alerts::DisplayError("Unexpected token found in <file>.");
return (false);
}
}
}
return (false);
}
void FileInfo::WriteXml(QXmlStreamWriter& xml, const QString& filename) const
{
xml.writeStartElement("file");
xml.writeStartElement("id");
xml.writeCharacters(QString::number(partitionId));
xml.writeEndElement();
xml.writeStartElement("filename");
xml.writeCharacters(filename);
xml.writeEndElement();
xml.writeEndElement();
}
FirmwareInfo::FirmwareInfo()
{
repartition = false;
noReboot = false;
}
void FirmwareInfo::Clear(void)
{
name = "";
version = "";
platformInfo.Clear();
developers.clear();
url.clear();
donateUrl.clear();
deviceInfos.clear();
pitFilename.clear();
repartition = false;
noReboot = false;
fileInfos.clear();
}
bool FirmwareInfo::IsCleared(void) const
{
return (name.isEmpty() && version.isEmpty() && platformInfo.IsCleared() && developers.isEmpty() && url.isEmpty() && url.isEmpty() && donateUrl.isEmpty()
&& deviceInfos.isEmpty() && pitFilename.isEmpty() && !repartition && !noReboot && fileInfos.isEmpty());
}
bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
{
Clear();
bool foundName = false;
bool foundVersion = false;
bool foundPlatform = false;
bool foundDevelopers = false;
bool foundUrl = false;
bool foundDonateUrl = false;
bool foundDevices = false;
bool foundPit = false;
bool foundRepartition = false;
bool foundNoReboot = false;
bool foundFiles = false;
if (!xml.readNextStartElement())
{
Alerts::DisplayError("Failed to find <firmware> element.");
return (false);
}
if (xml.name() != "firmware")
{
Alerts::DisplayError(QString("Expected <firmware> element but found <%1>.").arg(xml.name().toString()));
return (false);
}
QString formatVersionString;
formatVersionString += xml.attributes().value("version");
if (formatVersionString.isEmpty())
{
Alerts::DisplayError("<firmware> is missing the version attribute.");
return (false);
}
bool parsedVersion = false;
int formatVersion = formatVersionString.toInt(&parsedVersion);
if (!parsedVersion)
{
Alerts::DisplayError("<firmware> contains a malformed version.");
return (false);
}
if (formatVersion > kVersion)
{
Alerts::DisplayError("Package is for a newer version of Heimdall Frontend.\nPlease download the latest version of Heimdall Frontend.");
return (false);
}
while (!xml.atEnd())
{
QXmlStreamReader::TokenType nextToken = xml.readNext();
if (nextToken == QXmlStreamReader::StartElement)
{
if (xml.name() == "name")
{
if (foundName)
{
Alerts::DisplayError("Found multiple <name> elements in <firmware>.");
return (false);
}
foundName = true;
name = xml.readElementText();
}
else if (xml.name() == "version")
{
if (foundVersion)
{
Alerts::DisplayError("Found multiple <version> elements in <firmware>.");
return (false);
}
foundVersion = true;
version = xml.readElementText();
}
else if (xml.name() == "platform")
{
if (foundPlatform)
{
Alerts::DisplayError("Found multiple <platform> elements in <firmware>.");
return (false);
}
foundPlatform = true;
if (!platformInfo.ParseXml(xml))
return (false);
}
else if (xml.name() == "developers")
{
if (foundDevelopers)
{
Alerts::DisplayError("Found multiple <developers> elements in <firmware>.");
return (false);
}
foundDevelopers = true;
while (!xml.atEnd())
{
nextToken = xml.readNext();
if (nextToken == QXmlStreamReader::StartElement)
{
if (xml.name() == "name")
{
developers.append(xml.readElementText());
}
else
{
Alerts::DisplayError(QString("<%1> is not a valid child of <developers>.").arg(xml.name().toString()));
return (false);
}
}
else if (nextToken == QXmlStreamReader::EndElement)
{
if (xml.name() == "developers")
break;
}
else
{
if (!(nextToken == QXmlStreamReader::Characters && xml.isWhitespace()))
{
Alerts::DisplayError("Unexpected token found in <developers>.");
return (false);
}
}
}
}
else if (xml.name() == "url")
{
if (foundUrl)
{
Alerts::DisplayError("Found multiple <url> elements in <firmware>.");
return (false);
}
foundUrl = true;
url = xml.readElementText();
}
else if (xml.name() == "donateurl")
{
if (foundDonateUrl)
{
Alerts::DisplayError("Found multiple <donateurl> elements in <firmware>.");
return (false);
}
foundDonateUrl = true;
donateUrl = xml.readElementText();
}
else if (xml.name() == "devices")
{
if (foundDevices)
{
Alerts::DisplayError("Found multiple <devices> elements in <firmware>.");
return (false);
}
foundDevices = true;
while (!xml.atEnd())
{
nextToken = xml.readNext();
if (nextToken == QXmlStreamReader::StartElement)
{
if (xml.name() == "device")
{
DeviceInfo deviceInfo;
if (!deviceInfo.ParseXml(xml))
return (false);
deviceInfos.append(deviceInfo);
}
else
{
Alerts::DisplayError(QString("<%1> is not a valid child of <devices>.").arg(xml.name().toString()));
return (false);
}
}
else if (nextToken == QXmlStreamReader::EndElement)
{
if (xml.name() == "devices")
break;
}
else
{
if (!(nextToken == QXmlStreamReader::Characters && xml.isWhitespace()))
{
Alerts::DisplayError("Unexpected token found in <devices>.");
return (false);
}
}
}
}
else if (xml.name() == "pit")
{
if (foundPit)
{
Alerts::DisplayError("Found multiple <pit> elements in <firmware>.");
return (false);
}
foundPit = true;
pitFilename = xml.readElementText();
}
else if (xml.name() == "repartition")
{
if (foundRepartition)
{
Alerts::DisplayError("Found multiple <repartition> elements in <firmware>.");
return (false);
}
foundRepartition = true;
repartition = (xml.readElementText().toInt() != 0);
}
else if (xml.name() == "noreboot")
{
if (foundNoReboot)
{
Alerts::DisplayError("Found multiple <noreboot> elements in <firmware>.");
return (false);
}
foundNoReboot = true;
noReboot = (xml.readElementText().toInt() != 0);
}
else if (xml.name() == "files")
{
if (foundFiles)
{
Alerts::DisplayError("Found multiple <files> elements in <firmware>.");
return (false);
}
foundFiles = true;
while (!xml.atEnd())
{
nextToken = xml.readNext();
if (nextToken == QXmlStreamReader::StartElement)
{
if (xml.name() == "file")
{
FileInfo fileInfo;
if (!fileInfo.ParseXml(xml))
return (false);
fileInfos.append(fileInfo);
}
else
{
Alerts::DisplayError(QString("<%1> is not a valid child of <files>.").arg(xml.name().toString()));
return (false);
}
}
else if (nextToken == QXmlStreamReader::EndElement)
{
if (xml.name() == "files")
break;
}
else
{
if (!(nextToken == QXmlStreamReader::Characters && xml.isWhitespace()))
{
Alerts::DisplayError("Unexpected token found in <devices>.");
return (false);
}
}
}
}
else
{
Alerts::DisplayError(QString("<%1> is not a valid child of <firmware>.").arg(xml.name().toString()));
return (false);
}
}
else if (nextToken == QXmlStreamReader::EndElement)
{
if (xml.name() == "firmware")
{
if (!(foundName && foundVersion && foundPlatform && foundDevelopers && foundDevices && foundPit && foundRepartition && foundNoReboot && foundFiles))
{
Alerts::DisplayError("Required elements are missing from <firmware>.");
return (false);
}
else
{
break;
}
}
}
else
{
if (!(nextToken == QXmlStreamReader::Characters && xml.isWhitespace()))
{
Alerts::DisplayError("Unexpected token found in <firmware>.");
return (false);
}
}
}
// Read whitespaces at the end of the file (if there are any)
xml.readNext();
if (!xml.atEnd())
{
Alerts::DisplayError("Found data after </firmware>.");
return (false);
}
return (true);
}
void FirmwareInfo::WriteXml(QXmlStreamWriter& xml) const
{
xml.writeStartDocument();
xml.writeStartElement("firmware");
xml.writeAttribute("version", QString::number(FirmwareInfo::kVersion));
xml.writeStartElement("name");
xml.writeCharacters(name);
xml.writeEndElement();
xml.writeStartElement("version");
xml.writeCharacters(version);
xml.writeEndElement();
platformInfo.WriteXml(xml);
xml.writeStartElement("developers");
for (int i = 0; i < developers.length(); i++)
{
xml.writeStartElement("name");
xml.writeCharacters(developers[i]);
xml.writeEndElement();
}
xml.writeEndElement();
if (!url.isEmpty())
{
xml.writeStartElement("url");
xml.writeCharacters(url);
xml.writeEndElement();
}
if (!donateUrl.isEmpty())
{
xml.writeStartElement("donateurl");
xml.writeCharacters(donateUrl);
xml.writeEndElement();
}
xml.writeStartElement("devices");
for (int i = 0; i < deviceInfos.length(); i++)
deviceInfos[i].WriteXml(xml);
xml.writeEndElement();
xml.writeStartElement("pit");
int lastSlash = pitFilename.lastIndexOf('/');
if (lastSlash < 0)
lastSlash = pitFilename.lastIndexOf('\\');
xml.writeCharacters(pitFilename.mid(lastSlash + 1));
xml.writeEndElement();
xml.writeStartElement("repartition");
xml.writeCharacters((repartition) ? "1" : "0");
xml.writeEndElement();
xml.writeStartElement("noreboot");
xml.writeCharacters((noReboot) ? "1" : "0");
xml.writeEndElement();
xml.writeStartElement("files");
for (int i = 0; i < fileInfos.length(); i++)
{
fileInfos[i].WriteXml(xml, Packaging::ClashlessFilename(fileInfos, i));
}
xml.writeEndElement();
xml.writeEndElement();
xml.writeEndDocument();
}

View File

@ -0,0 +1,302 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef FIRMWAREINFO_H
#define FIRMWAREINFO_H
// Qt
#include <QFile>
#include <QString>
#include <QXmlStreamReader>
namespace HeimdallFrontend
{
class DeviceInfo
{
private:
QString manufacturer;
QString product;
QString name;
public:
DeviceInfo();
DeviceInfo(const QString& manufacturer, const QString& product, const QString& name);
bool ParseXml(QXmlStreamReader& xml);
void WriteXml(QXmlStreamWriter& xml) const;
const QString& GetManufacturer(void) const
{
return (manufacturer);
}
void SetManufacturer(const QString& manufacturer)
{
this->manufacturer = manufacturer;
}
const QString& GetProduct(void) const
{
return (product);
}
void SetProduct(const QString& product)
{
this->product = product;
}
const QString& GetName(void) const
{
return (name);
}
void SetName(const QString& name)
{
this->name = name;
}
};
class PlatformInfo
{
private:
QString name;
QString version;
public:
PlatformInfo();
void Clear(void);
bool IsCleared(void) const;
bool ParseXml(QXmlStreamReader& xml);
void WriteXml(QXmlStreamWriter& xml) const;
const QString& GetName(void) const
{
return (name);
}
void SetName(const QString& name)
{
this->name = name;
}
const QString& GetVersion(void) const
{
return (version);
}
void SetVersion(const QString& version)
{
this->version = version;
}
};
class FileInfo
{
private:
unsigned int partitionId;
QString filename;
public:
FileInfo();
FileInfo(unsigned int partitionId, const QString& filename);
bool ParseXml(QXmlStreamReader& xml);
void WriteXml(QXmlStreamWriter& xml, const QString& filename) const;
unsigned int GetPartitionId(void) const
{
return (partitionId);
}
void SetPartitionId(unsigned int partitionId)
{
this->partitionId = partitionId;
}
const QString& GetFilename(void) const
{
return (filename);
}
void SetFilename(const QString& filename)
{
this->filename = filename;
}
};
class FirmwareInfo
{
public:
enum
{
kVersion = 1
};
private:
QString name;
QString version;
PlatformInfo platformInfo;
QList<QString> developers;
QString url;
QString donateUrl;
QList<DeviceInfo> deviceInfos;
QString pitFilename;
bool repartition;
bool noReboot;
QList<FileInfo> fileInfos;
public:
FirmwareInfo();
void Clear(void);
bool IsCleared(void) const;
bool ParseXml(QXmlStreamReader& xml);
void WriteXml(QXmlStreamWriter& xml) const;
const QString& GetName(void) const
{
return (name);
}
void SetName(const QString& name)
{
this->name = name;
}
const QString& GetVersion(void) const
{
return (version);
}
void SetVersion(const QString& version)
{
this->version = version;
}
const PlatformInfo& GetPlatformInfo(void) const
{
return (platformInfo);
}
PlatformInfo& GetPlatformInfo(void)
{
return (platformInfo);
}
const QList<QString>& GetDevelopers(void) const
{
return (developers);
}
QList<QString>& GetDevelopers(void)
{
return (developers);
}
const QString& GetUrl(void) const
{
return (url);
}
void SetUrl(const QString& url)
{
this->url = url;
}
const QString& GetDonateUrl(void) const
{
return (donateUrl);
}
void SetDonateUrl(const QString& donateUrl)
{
this->donateUrl = donateUrl;
}
const QList<DeviceInfo>& GetDeviceInfos(void) const
{
return (deviceInfos);
}
QList<DeviceInfo>& GetDeviceInfos(void)
{
return (deviceInfos);
}
const QString& GetPitFilename(void) const
{
return (pitFilename);
}
void SetPitFilename(const QString& pitFilename)
{
this->pitFilename = pitFilename;
}
bool GetRepartition(void) const
{
return (repartition);
}
void SetRepartition(bool repartition)
{
this->repartition = repartition;
}
bool GetNoReboot(void) const
{
return (noReboot);
}
void SetNoReboot(bool noReboot)
{
this->noReboot = noReboot;
}
const QList<FileInfo>& GetFileInfos(void) const
{
return (fileInfos);
}
QList<FileInfo>& GetFileInfos(void)
{
return (fileInfos);
}
};
}
#endif

View File

@ -0,0 +1,66 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// Heimdall Frontend
#include "Alerts.h"
#include "PackageData.h"
using namespace HeimdallFrontend;
PackageData::PackageData()
{
}
PackageData::~PackageData()
{
for (int i = 0; i < files.length(); i++)
delete files[i];
}
void PackageData::Clear(void)
{
firmwareInfo.Clear();
for (int i = 0; i < files.length(); i++)
delete files[i];
files.clear();
}
bool PackageData::ReadFirmwareInfo(QFile *file)
{
if (!file->open(QFile::ReadOnly))
{
Alerts::DisplayError(QString("Failed to open file: \1%s").arg(file->fileName()));
return (false);
}
QXmlStreamReader xml(file);
bool success = firmwareInfo.ParseXml(xml);
file->close();
return (success);
}
bool PackageData::IsCleared(void) const
{
return (firmwareInfo.IsCleared() && files.isEmpty());
}

View File

@ -0,0 +1,77 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef PACKAGEDATA_H
#define PACKAGEDATA_H
// Qt
#include <QTemporaryFile>
// Heimdall Frontend
#include "FirmwareInfo.h"
namespace HeimdallFrontend
{
class PackageData
{
private:
FirmwareInfo firmwareInfo;
QList<QTemporaryFile *> files;
public:
PackageData();
~PackageData();
void Clear(void);
bool ReadFirmwareInfo(QFile *file);
bool IsCleared(void) const;
const FirmwareInfo& GetFirmwareInfo(void) const
{
return (firmwareInfo);
}
FirmwareInfo& GetFirmwareInfo(void)
{
return (firmwareInfo);
}
const QList<QTemporaryFile *>& GetFiles(void) const
{
return (files);
}
QList<QTemporaryFile *>& GetFiles(void)
{
return (files);
}
// Simply clears the files list, it does delete/close any files.
void RemoveAllFiles(void)
{
files.clear();
}
};
}
#endif

View File

@ -0,0 +1,934 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifdef WIN32
#pragma warning(disable : 4996)
#endif
// C/C++ Standard Library
#include <stdio.h>
// zlib
#include "zlib.h"
// Qt
#include <QDateTime>
#include <QDir>
#include <QProgressDialog>
// Heimdall Frontend
#include "Alerts.h"
#include "Packaging.h"
using namespace HeimdallFrontend;
const qint64 Packaging::kMaxFileSize = 8589934592ll;
const char *Packaging::ustarMagic = "ustar";
bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData)
{
TarHeader tarHeader;
if (!tarFile.open())
{
Alerts::DisplayError(QString("Error opening temporary TAR archive:\n%1").arg(tarFile.fileName()));
return (false);
}
bool previousEmpty = false;
QProgressDialog progressDialog("Extracting files...", "Cancel", 0, tarFile.size());
progressDialog.setWindowModality(Qt::ApplicationModal);
progressDialog.setWindowTitle("Heimdall Frontend");
while (!tarFile.atEnd())
{
qint64 dataRead = tarFile.read(tarHeader.buffer, TarHeader::kBlockLength);
if (dataRead != TarHeader::kBlockLength)
{
progressDialog.close();
Alerts::DisplayError("Package's TAR archive is malformed.");
tarFile.close();
return (false);
}
progressDialog.setValue(tarFile.pos());
if (progressDialog.wasCanceled())
{
tarFile.close();
progressDialog.close();
return (false);
}
//bool ustarFormat = strcmp(tarHeader.fields.magic, ustarMagic) == 0;
bool empty = true;
for (int i = 0; i < TarHeader::kBlockLength; i++)
{
if (tarHeader.buffer[i] != 0)
{
empty = false;
break;
}
}
if (empty)
{
if (previousEmpty)
{
// Two empty blocks in a row means we've reached the end of the archive.
break;
}
}
else
{
int checksum = 0;
for (char *bufferIndex = tarHeader.buffer; bufferIndex < tarHeader.fields.checksum; bufferIndex++)
checksum += static_cast<unsigned char>(*bufferIndex);
checksum += 8 * ' ';
checksum += static_cast<unsigned char>(tarHeader.fields.typeFlag);
// Both the TAR and USTAR formats have terrible documentation, it's not clear if the following code is required.
/*if (ustarFormat)
{
for (char *bufferIndex = tarHeader.fields.linkName; bufferIndex < tarHeader.fields.prefix + 155; bufferIndex++)
checksum += static_cast<unsigned char>(*bufferIndex);
}*/
bool parsed = false;
// The size field is not always null terminated, so we must create a copy and null terminate it for parsing.
char fileSizeString[13];
memcpy(fileSizeString, tarHeader.fields.size, 12);
fileSizeString[12] = '\0';
qulonglong fileSize = QString(fileSizeString).toULongLong(&parsed, 8);
if (!parsed)
{
progressDialog.close();
Alerts::DisplayError("Tar header contained an invalid file size.");
tarFile.close();
return (false);
}
if (fileSize > 0 && tarHeader.fields.typeFlag == '0')
{
// We're working with a file.
QString filename = QString::fromUtf8(tarHeader.fields.name);
QTemporaryFile *outputFile = new QTemporaryFile("XXXXXX-" + filename);
packageData->GetFiles().append(outputFile);
if (!outputFile->open())
{
progressDialog.close();
Alerts::DisplayError(QString("Failed to open output file: \n%1").arg(outputFile->fileName()));
tarFile.close();
return (false);
}
qulonglong dataRemaining = fileSize;
char readBuffer[TarHeader::kBlockReadCount * TarHeader::kBlockLength];
// Copy the file contents from tarFile to outputFile
while (dataRemaining > 0)
{
qint64 fileDataToRead = (dataRemaining < TarHeader::kBlockReadCount * TarHeader::kBlockLength)
? dataRemaining : TarHeader::kBlockReadCount * TarHeader::kBlockLength;
qint64 dataRead = tarFile.read(readBuffer, fileDataToRead + (TarHeader::kBlockLength - fileDataToRead % TarHeader::kBlockLength) % TarHeader::kBlockLength);
if (dataRead < fileDataToRead || dataRead % TarHeader::kBlockLength != 0)
{
progressDialog.close();
Alerts::DisplayError("Unexpected read error whilst extracting package files.");
tarFile.close();
outputFile->close();
remove(outputFile->fileName().toStdString().c_str());
return (false);
}
outputFile->write(readBuffer, fileDataToRead);
dataRemaining -= fileDataToRead;
progressDialog.setValue(tarFile.pos());
if (progressDialog.wasCanceled())
{
tarFile.close();
outputFile->close();
remove(outputFile->fileName().toStdString().c_str());
progressDialog.close();
return (false);
}
}
outputFile->close();
}
else
{
progressDialog.close();
Alerts::DisplayError("Heimdall packages shouldn't contain links or directories.");
tarFile.close();
return (false);
}
}
previousEmpty = empty;
}
progressDialog.close();
tarFile.close();
return (true);
}
bool Packaging::WriteTarEntry(const QString& filePath, QTemporaryFile *tarFile, const QString& entryFilename)
{
TarHeader tarHeader;
memset(tarHeader.buffer, 0, TarHeader::kBlockLength);
QFile file(filePath);
if (!file.open(QFile::ReadOnly))
{
Alerts::DisplayError(QString("Failed to open file: \n%1").arg(file.fileName()));
return (false);
}
if (file.size() > Packaging::kMaxFileSize)
{
Alerts::DisplayError(QString("File is too large to be packaged:\n%1").arg(file.fileName()));
return (false);
}
QFileInfo qtFileInfo(file);
QByteArray utfFilename;
utfFilename = entryFilename.toUtf8();
if (utfFilename.length() > 100)
{
Alerts::DisplayError(QString("File name is too long:\n%1").arg(qtFileInfo.fileName()));
return (false);
}
strcpy(tarHeader.fields.name, utfFilename.constData());
unsigned int mode = 0;
QFile::Permissions permissions = file.permissions();
// Other
if (permissions.testFlag(QFile::ExeOther))
mode |= TarHeader::kModeOtherExecute;
if (permissions.testFlag(QFile::WriteOther))
mode |= TarHeader::kModeOtherWrite;
if (permissions.testFlag(QFile::ReadOther))
mode |= TarHeader::kModeOtherRead;
// Group
if (permissions.testFlag(QFile::ExeGroup))
mode |= TarHeader::kModeGroupExecute;
if (permissions.testFlag(QFile::WriteGroup))
mode |= TarHeader::kModeGroupWrite;
if (permissions.testFlag(QFile::ReadGroup))
mode |= TarHeader::kModeGroupRead;
// Owner
if (permissions.testFlag(QFile::ExeOwner))
mode |= TarHeader::kModeOwnerExecute;
if (permissions.testFlag(QFile::WriteOwner))
mode |= TarHeader::kModeOwnerWrite;
if (permissions.testFlag(QFile::ReadOwner))
mode |= TarHeader::kModeOwnerRead;
sprintf(tarHeader.fields.mode, "%07o", mode);
// Owner id
uint id = qtFileInfo.ownerId();
if (id < 2097151)
sprintf(tarHeader.fields.userId, "%07o", id);
else
sprintf(tarHeader.fields.userId, "%07o", 0);
// Group id
id = qtFileInfo.groupId();
if (id < 2097151)
sprintf(tarHeader.fields.groupId, "%07o", id);
else
sprintf(tarHeader.fields.groupId, "%07o", 0);
// Note: We don't support base-256 encoding. Support could be added later.
sprintf(tarHeader.fields.size, "%011llo", file.size());
sprintf(tarHeader.fields.modifiedTime, "%u", qtFileInfo.lastModified().toTime_t());
// Regular File
tarHeader.fields.typeFlag = '0';
// Calculate checksum
int checksum = 0;
memset(tarHeader.fields.checksum, ' ', 8);
for (int i = 0; i < TarHeader::kTarHeaderLength; i++)
checksum += static_cast<unsigned char>(tarHeader.buffer[i]);
sprintf(tarHeader.fields.checksum, "%07o", checksum);
// Write the header to the TAR file.
tarFile->write(tarHeader.buffer, TarHeader::kBlockLength);
char buffer[TarHeader::kBlockWriteCount * TarHeader::kBlockLength];
qint64 offset = 0;
while (offset < file.size())
{
qint64 dataRead = file.read(buffer, TarHeader::kBlockWriteCount * TarHeader::kBlockLength);
if (tarFile->write(buffer, dataRead) != dataRead)
{
Alerts::DisplayError("Failed to write data to the temporary TAR file.");
return (false);
}
if (dataRead % TarHeader::kBlockLength != 0)
{
int remainingBlockLength = TarHeader::kBlockLength - dataRead % TarHeader::kBlockLength;
memset(buffer, 0, remainingBlockLength);
if (tarFile->write(buffer, remainingBlockLength) != remainingBlockLength)
{
Alerts::DisplayError("Failed to write data to the temporary TAR file.");
return (false);
}
}
offset += dataRead;
}
return (true);
}
bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarFile)
{
const QList<FileInfo>& fileInfos = firmwareInfo.GetFileInfos();
QProgressDialog progressDialog("Packaging files...", "Cancel", 0, fileInfos.length() + 2);
progressDialog.setWindowModality(Qt::ApplicationModal);
progressDialog.setWindowTitle("Heimdall Frontend");
QTemporaryFile firmwareXmlFile("XXXXXX-firmware.xml");
if (!firmwareXmlFile.open())
{
progressDialog.close();
Alerts::DisplayError(QString("Failed to create temporary file: \n%1").arg(firmwareXmlFile.fileName()));
return (false);
}
QXmlStreamWriter xml(&firmwareXmlFile);
firmwareInfo.WriteXml(xml);
firmwareXmlFile.close();
if (!tarFile->open())
{
progressDialog.close();
Alerts::DisplayError(QString("Failed to open file: \n%1").arg(tarFile->fileName()));
return (false);
}
for (int i = 0; i < fileInfos.length(); i++)
{
// If the file was already compressed we don't compress it again.
bool skip = false;
for (int j = 0; j < i; j++)
{
if (fileInfos[i].GetFilename() == fileInfos[j].GetFilename())
{
skip = true;
break;
}
}
if (skip)
{
progressDialog.setValue(i);
continue;
}
QString filename = ClashlessFilename(fileInfos, i);
if (filename == "firmware.xml")
{
Alerts::DisplayError("You cannot name your partition files \"firmware.xml\".\nIt is a reserved name.");
return (false);
}
if (!WriteTarEntry(fileInfos[i].GetFilename(), tarFile, filename))
{
tarFile->resize(0);
tarFile->close();
progressDialog.close();
return (false);
}
progressDialog.setValue(i);
if (progressDialog.wasCanceled())
{
tarFile->resize(0);
tarFile->close();
progressDialog.close();
return (false);
}
}
int lastSlash = firmwareInfo.GetPitFilename().lastIndexOf('/');
if (lastSlash < 0)
lastSlash = firmwareInfo.GetPitFilename().lastIndexOf('\\');
QString pitFilename = ClashlessFilename(fileInfos, firmwareInfo.GetPitFilename().mid(lastSlash + 1));
if (pitFilename == "firmware.xml")
{
Alerts::DisplayError("You cannot name your PIT file \"firmware.xml\".\nIt is a reserved name.");
return (false);
}
if (!WriteTarEntry(firmwareInfo.GetPitFilename(), tarFile, pitFilename))
{
tarFile->resize(0);
tarFile->close();
return (false);
}
progressDialog.setValue(progressDialog.value() + 1);
if (progressDialog.wasCanceled())
{
tarFile->resize(0);
tarFile->close();
progressDialog.close();
return (false);
}
if (!WriteTarEntry(firmwareXmlFile.fileName(), tarFile, "firmware.xml"))
{
tarFile->resize(0);
tarFile->close();
return (false);
}
progressDialog.setValue(progressDialog.value() + 1);
progressDialog.close();
// Write two empty blocks to signify the end of the archive.
char emptyEntry[TarHeader::kBlockLength];
memset(emptyEntry, 0, TarHeader::kBlockLength);
tarFile->write(emptyEntry, TarHeader::kBlockLength);
tarFile->write(emptyEntry, TarHeader::kBlockLength);
tarFile->close();
return (true);
}
bool Packaging::ExtractPackage(const QString& packagePath, PackageData *packageData)
{
FILE *compressedPackageFile = fopen(packagePath.toStdString().c_str(), "rb");
if (!compressedPackageFile)
{
Alerts::DisplayError(QString("Failed to open package:\n%1").arg(packagePath));
return (false);
}
fseek(compressedPackageFile, 0, SEEK_END);
quint64 compressedFileSize = ftell(compressedPackageFile);
rewind(compressedPackageFile);
gzFile packageFile = gzdopen(fileno(compressedPackageFile), "rb");
QTemporaryFile outputTar("XXXXXX.tar");
if (!outputTar.open())
{
Alerts::DisplayError("Failed to open temporary TAR archive.");
gzclose(packageFile);
return (false);
}
char buffer[kExtractBufferLength];
int bytesRead;
quint64 totalBytesRead = 0;
QProgressDialog progressDialog("Decompressing package...", "Cancel", 0, compressedFileSize);
progressDialog.setWindowModality(Qt::ApplicationModal);
progressDialog.setWindowTitle("Heimdall Frontend");
do
{
bytesRead = gzread(packageFile, buffer, kExtractBufferLength);
if (bytesRead == -1)
{
progressDialog.close();
Alerts::DisplayError("Error decompressing archive.");
gzclose(packageFile);
return (false);
}
outputTar.write(buffer, bytesRead);
totalBytesRead += bytesRead;
progressDialog.setValue(totalBytesRead);
if (progressDialog.wasCanceled())
{
gzclose(packageFile);
progressDialog.close();
return (false);
}
} while (bytesRead > 0);
progressDialog.close();
outputTar.close();
gzclose(packageFile); // Closes packageFile and compressedPackageFile
if (!ExtractTar(outputTar, packageData))
return (false);
// Find and read firmware.xml
for (int i = 0; i < packageData->GetFiles().length(); i++)
{
QTemporaryFile *file = packageData->GetFiles()[i];
if (file->fileTemplate() == "XXXXXX-firmware.xml")
{
if (!packageData->ReadFirmwareInfo(file))
{
packageData->Clear();
return (false);
}
return (true);
}
}
Alerts::DisplayError("firmware.xml is missing from the package.");
return (false);
}
bool Packaging::BuildPackage(const QString& packagePath, const FirmwareInfo& firmwareInfo)
{
FILE *compressedPackageFile = fopen(packagePath.toStdString().c_str(), "wb");
if (!compressedPackageFile)
{
Alerts::DisplayError(QString("Failed to create package:\n%1").arg(packagePath));
return (false);
}
QTemporaryFile tar("XXXXXX.tar");
if (!CreateTar(firmwareInfo, &tar))
{
fclose(compressedPackageFile);
remove(packagePath.toStdString().c_str());
return (false);
}
if (!tar.open())
{
Alerts::DisplayError(QString("Failed to open temporary file: \n%1").arg(tar.fileName()));
fclose(compressedPackageFile);
remove(packagePath.toStdString().c_str());
return (false);
}
gzFile packageFile = gzdopen(fileno(compressedPackageFile), "wb");
char buffer[kCompressBufferLength];
qint64 totalBytesRead = 0;
int bytesRead;
QProgressDialog progressDialog("Compressing package...", "Cancel", 0, tar.size());
progressDialog.setWindowModality(Qt::ApplicationModal);
progressDialog.setWindowTitle("Heimdall Frontend");
do
{
bytesRead = tar.read(buffer, kCompressBufferLength);
if (bytesRead == -1)
{
progressDialog.close();
Alerts::DisplayError("Error reading temporary TAR file.");
gzclose(packageFile);
remove(packagePath.toStdString().c_str());
return (false);
}
if (gzwrite(packageFile, buffer, bytesRead) != bytesRead)
{
progressDialog.close();
Alerts::DisplayError("Error compressing package.");
gzclose(packageFile);
remove(packagePath.toStdString().c_str());
return (false);
}
totalBytesRead += bytesRead;
progressDialog.setValue(totalBytesRead);
if (progressDialog.wasCanceled())
{
gzclose(packageFile);
remove(packagePath.toStdString().c_str());
progressDialog.close();
return (false);
}
} while (bytesRead > 0);
progressDialog.close();
gzclose(packageFile); // Closes packageFile and compressedPackageFile
return (true);
}
QString Packaging::ClashlessFilename(const QList<FileInfo>& fileInfos, int fileInfoIndex)
{
int lastSlash = fileInfos[fileInfoIndex].GetFilename().lastIndexOf('/');
if (lastSlash < 0)
lastSlash = fileInfos[fileInfoIndex].GetFilename().lastIndexOf('\\');
QString filename = fileInfos[fileInfoIndex].GetFilename().mid(lastSlash + 1);
unsigned int renameIndex = 0;
// Check for name clashes
for (int i = 0; i < fileInfoIndex; i++)
{
lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
if (lastSlash < 0)
lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1);
// If the filenames are the same, but the files themselves aren't the same (i.e. not the same path), then rename.
if (filename == otherFilename && fileInfos[i].GetFilename() != fileInfos[fileInfoIndex].GetFilename())
renameIndex++;
}
if (renameIndex > 0)
{
int lastPeriodIndex = filename.lastIndexOf(QChar('.'));
QString shortFilename;
QString fileType;
if (lastPeriodIndex >= 0)
{
shortFilename = filename.left(lastPeriodIndex);
fileType = filename.mid(lastPeriodIndex);
}
else
{
shortFilename = filename;
}
unsigned int renameIndexOffset = 0;
bool validIndexOffset = true;
// Before we append a rename index we must ensure it doesn't produce further collisions.
for (int i = 0; i < fileInfos.length(); i++)
{
int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
if (lastSlash < 0)
lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1);
if (otherFilename.length() > filename.length() + 1)
{
QString trimmedOtherFilename = otherFilename.left(shortFilename.length());
if (shortFilename == trimmedOtherFilename)
{
lastPeriodIndex = otherFilename.lastIndexOf(QChar('.'));
QString shortOtherFilename;
if (lastPeriodIndex >= 0)
shortOtherFilename = otherFilename.left(lastPeriodIndex);
else
shortOtherFilename = otherFilename;
QRegExp renameExp("-[0-9]+");
if (renameExp.lastIndexIn(shortOtherFilename) == shortFilename.length())
{
unsigned int trailingInteger = shortOtherFilename.mid(shortFilename.length() + 1).toUInt(&validIndexOffset);
if (!validIndexOffset)
break;
if (trailingInteger > renameIndexOffset)
renameIndexOffset = trailingInteger;
}
}
}
}
if (validIndexOffset)
{
// Ensure renaming won't involve integer overflow!
if (renameIndex > static_cast<unsigned int>(-1) - renameIndexOffset)
validIndexOffset = false;
}
if (validIndexOffset)
{
shortFilename.append(QChar('-'));
shortFilename.append(QString::number(renameIndexOffset + renameIndex));
return (shortFilename + fileType);
}
else
{
// Fallback behaviour... an absolutely terrible brute force implementation!
QString filename;
QString renamePrefix;
for (;;)
{
renamePrefix.append(QChar('+'));
for (unsigned int i = 0; i < static_cast<unsigned int>(-1); i++)
{
filename = shortFilename + renamePrefix + QString::number(i) + fileType;
bool valid = true;
for (int i = 0; i < fileInfos.length(); i++)
{
int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
if (lastSlash < 0)
lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
if (filename == fileInfos[i].GetFilename().mid(lastSlash + 1))
{
valid = false;
break;
}
}
if (valid)
return (filename);
}
}
}
}
else
{
return (filename);
}
}
QString Packaging::ClashlessFilename(const QList<FileInfo>& fileInfos, const QString& filename)
{
unsigned int renameIndex = 0;
// Check for name clashes
for (int i = 0; i < fileInfos.length(); i++)
{
int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
if (lastSlash < 0)
lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1);
if (filename == otherFilename)
renameIndex++;
}
if (renameIndex > 0)
{
int lastPeriodIndex = filename.lastIndexOf(QChar('.'));
QString shortFilename;
QString fileType;
if (lastPeriodIndex >= 0)
{
shortFilename = filename.left(lastPeriodIndex);
fileType = filename.mid(lastPeriodIndex);
}
else
{
shortFilename = filename;
}
unsigned int renameIndexOffset = 0;
bool validIndexOffset = true;
// Before we append a rename index we must ensure it doesn't produce further collisions.
for (int i = 0; i < fileInfos.length(); i++)
{
int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
if (lastSlash < 0)
lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1);
if (otherFilename.length() > filename.length() + 1)
{
QString trimmedOtherFilename = otherFilename.left(filename.length());
if (filename == trimmedOtherFilename)
{
lastPeriodIndex = otherFilename.lastIndexOf(QChar('.'));
QString shortOtherFilename;
if (lastPeriodIndex >= 0)
shortOtherFilename = otherFilename.left(lastPeriodIndex);
else
shortOtherFilename = otherFilename;
QRegExp renameExp("-[0-9]+");
if (renameExp.lastIndexIn(shortOtherFilename) == shortFilename.length())
{
unsigned int trailingInteger = shortOtherFilename.mid(shortFilename.length() + 1).toUInt(&validIndexOffset);
if (!validIndexOffset)
break;
if (trailingInteger > renameIndexOffset)
renameIndexOffset = trailingInteger;
}
}
}
}
if (validIndexOffset)
{
// Ensure renaming won't involve integer overflow!
if (renameIndex > static_cast<unsigned int>(-1) - renameIndexOffset)
validIndexOffset = false;
}
if (validIndexOffset)
{
shortFilename.append(QChar('-'));
shortFilename.append(QString::number(renameIndexOffset + renameIndex));
return (shortFilename + fileType);
}
else
{
// Fallback behaviour, brute-force/semi-random.
bool valid;
QString filename;
do
{
valid = true;
filename = shortFilename + "-";
for (int i = 0; i < 8; i++)
filename.append(QChar(qrand() % ('Z' - 'A' + 1) + 'A'));
for (int i = 0; i < fileInfos.length(); i++)
{
int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
if (lastSlash < 0)
lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
if (filename == fileInfos[i].GetFilename().mid(lastSlash + 1))
{
valid = false;
break;
}
}
} while (!valid);
return (filename);
}
}
else
{
return (filename);
}
}

View File

@ -0,0 +1,121 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef PACKAGING_H
#define PACKAGING_H
// Qt
#include <QList>
#include <QString>
#include <QTemporaryFile>
// Heimdall Frontend
#include "PackageData.h"
namespace HeimdallFrontend
{
union TarHeader
{
enum
{
kBlockLength = 512,
kBlockReadCount = 8,
kBlockWriteCount = 8,
kTarHeaderLength = 257,
kUstarHeaderLength = 500,
};
enum
{
kModeOtherExecute = 1,
kModeOtherWrite = 1 << 1,
kModeOtherRead = 1 << 2,
kModeGroupExecute = 1 << 3,
kModeGroupWrite = 1 << 4,
kModeGroupRead = 1 << 5,
kModeOwnerExecute = 1 << 6,
kModeOwnerWrite = 1 << 7,
kModeOwnerRead = 1 << 8,
kModeReserved = 2 << 9,
kModeSetGid = 2 << 10,
kModeSetUid = 2 << 11
};
struct
{
char name[100];
char mode[8];
char userId[8];
char groupId[8];
char size[12];
char modifiedTime[12];
char checksum[8];
char typeFlag;
char linkName[100];
char magic[6];
char version[2];
char userName[32];
char groupName[32];
char devMajor[8];
char devMinor[8];
char prefix[155];
} fields;
char buffer[kBlockLength];
};
class Packaging
{
public:
// Would definitely prefer to use an enum but VC++ and GCC give conflicting warnings about C++0x or type overflow.
static const qint64 kMaxFileSize;
private:
enum
{
kExtractBufferLength = 262144,
kCompressBufferLength = 262144
};
// TODO: Add support for sparse files to both methods?
static bool ExtractTar(QTemporaryFile& tarFile, PackageData *packageData);
static bool WriteTarEntry(const QString& filePath, QTemporaryFile *tarFile, const QString& entryFilename);
static bool CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarFile); // Uses original TAR format.
public:
static const char *ustarMagic;
static bool ExtractPackage(const QString& packagePath, PackageData *packageData);
static bool BuildPackage(const QString& packagePath, const FirmwareInfo& firmwareInfo);
static QString ClashlessFilename(const QList<FileInfo>& fileInfos, int fileInfoIndex);
static QString ClashlessFilename(const QList<FileInfo>& fileInfos, const QString& filename);
};
}
#endif

View File

@ -0,0 +1,126 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// Qt
#include <QDir>
#include <QProcess>
// Heimdall Frontend
#include "aboutform.h"
#include <QStringList>
#define UNUSED(x) (void)(x)
using namespace HeimdallFrontend;
AboutForm::AboutForm(QWidget *parent) : QWidget(parent)
{
setupUi(this);
// Heimdall Command Line
QObject::connect(&heimdallProcess, SIGNAL(readyRead()), this, SLOT(HandleHeimdallStdout()));
QObject::connect(&heimdallProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(HandleHeimdallReturned(int, QProcess::ExitStatus)));
QObject::connect(&heimdallProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(HandleHeimdallError(QProcess::ProcessError)));
heimdallFailed = false;
RetrieveHeimdallVersion();
}
void AboutForm::RetrieveHeimdallVersion(void)
{
heimdallProcess.setReadChannel(QProcess::StandardOutput);
heimdallProcess.start("heimdall", QStringList("version"));
heimdallProcess.waitForFinished(350);
// OS X was playing up and not finding heimdall, so we're manually checking the PATH.
if (heimdallFailed)
{
QStringList environment = QProcess::systemEnvironment();
QStringList paths;
// Ensure /usr/bin is in PATH
for (int i = 0; i < environment.length(); i++)
{
if (environment[i].left(5) == "PATH=")
{
paths = environment[i].mid(5).split(':');
paths.prepend("/usr/bin");
break;
}
}
int pathIndex = -1;
while (heimdallFailed && ++pathIndex < paths.length())
{
QString heimdallPath = paths[pathIndex];
if (heimdallPath.length() > 0)
{
heimdallFailed = false;
if (heimdallPath[heimdallPath.length() - 1] != QDir::separator())
heimdallPath += QDir::separator();
heimdallPath += "heimdall";
heimdallProcess.start(heimdallPath, QStringList("version"));
heimdallProcess.waitForFinished(350);
}
}
if (heimdallFailed)
versionCopyrightLabel->setText(versionCopyrightLabel->text().replace("%HEIMDALL-VERSION%", ""));
}
}
void AboutForm::HandleHeimdallStdout(void)
{
QString version = heimdallProcess.readAll();
if (version.length() > 0)
{
if (version.at(0) == QChar('v'))
version = version.mid(1);
versionCopyrightLabel->setText(versionCopyrightLabel->text().replace("%HEIMDALL-VERSION%", "Version " + version + "<br />"));
}
}
void AboutForm::HandleHeimdallReturned(int exitCode, QProcess::ExitStatus exitStatus)
{
UNUSED(exitCode);
UNUSED(exitStatus);
// If for some reason %HEIMDALL-VERSION% hasn't been replaced yet, we'll replace it with an empty string.
versionCopyrightLabel->setText(versionCopyrightLabel->text().replace("%HEIMDALL-VERSION%", ""));
}
void AboutForm::HandleHeimdallError(QProcess::ProcessError error)
{
UNUSED(error);
heimdallFailed = true;
}

View File

@ -0,0 +1,58 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef ABOUTFORM_H
#define ABOUTFORM_H
// Qt
#include <QProcess>
#include <QWidget>
// Heimdall Frontend
#include "ui_aboutform.h"
namespace HeimdallFrontend
{
class AboutForm : public QWidget, public Ui::AboutForm
{
Q_OBJECT
private:
bool heimdallFailed;
QProcess heimdallProcess;
void RetrieveHeimdallVersion(void);
public:
explicit AboutForm(QWidget *parent = 0);
public slots:
// Heimdall Command Line
void HandleHeimdallStdout(void);
void HandleHeimdallReturned(int exitCode, QProcess::ExitStatus exitStatus);
void HandleHeimdallError(QProcess::ProcessError error);
};
}
#endif

View File

@ -0,0 +1,42 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// Qt
#include <QApplication>
#include <QtPlugin>
// Heimdall Frontend
#include "mainwindow.h"
#if defined(QT_STATIC)
Q_IMPORT_PLUGIN (QWindowsIntegrationPlugin);
#endif
using namespace HeimdallFrontend;
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
MainWindow window;
window.show();
return (application.exec());
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,206 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
// Qt
#include <QList>
#include <QMainWindow>
#include <QProcess>
#include <QTemporaryFile>
// libpit
#include "libpit.h"
// Heimdall Frontend
#include "aboutform.h"
#include "ui_mainwindow.h"
#include "PackageData.h"
using namespace libpit;
namespace HeimdallFrontend
{
enum class HeimdallState : int
{
Stopped = 1,
Flashing = (int)Stopped << 1,
DetectingDevice = (int)Flashing << 1,
ClosingPcScreen = (int)DetectingDevice << 1,
PrintingPit = (int)ClosingPcScreen << 1,
DownloadingPit = (int)PrintingPit << 1,
NoReboot = (int)DownloadingPit << 1
};
inline HeimdallState operator|(HeimdallState lhs, HeimdallState rhs)
{
return (HeimdallState)((int)lhs | (int)rhs);
}
inline HeimdallState& operator|=(HeimdallState& lhs, HeimdallState rhs)
{
lhs = lhs | rhs;
return lhs;
}
inline HeimdallState operator&(HeimdallState lhs, HeimdallState rhs)
{
lhs = (HeimdallState)((int)lhs & (int)rhs);
return lhs;
}
inline bool operator!(HeimdallState state)
{
return (int)state == 0;
}
class MainWindow : public QMainWindow, public Ui::MainWindow
{
Q_OBJECT
private:
enum
{
kPrintPitSourceDevice = 0,
kPrintPitSourceLocalFile
};
AboutForm aboutForm;
QString lastDirectory;
int tabIndex;
bool heimdallFailed;
HeimdallState heimdallState;
QProcess heimdallProcess;
PackageData loadedPackageData;
PitData currentPitData;
PackageData workingPackageData;
bool populatingPartitionNames;
QList<unsigned int> unusedPartitionIds;
bool verboseOutput;
bool resume;
void StartHeimdall(const QStringList& arguments);
void UpdateUnusedPartitionIds(void);
bool ReadPit(QFile *file);
void UpdatePackageUserInterface(void);
bool IsArchive(QString path);
QString PromptFileSelection(const QString& caption = QString("Select File"), const QString& filter = QString());
QString PromptFileCreation(const QString& caption = QString("Save File"), const QString& filter = QString());
void UpdateLoadPackageInterfaceAvailability(void);
void UpdateFlashInterfaceAvailability(void);
void UpdateCreatePackageInterfaceAvailability(void);
void UpdateUtilitiesInterfaceAvailability(void);
void UpdateInterfaceAvailability(void);
void UpdatePartitionNamesInterface(void);
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void OpenDonationWebpage(void);
void SetVerboseOutput(bool enabled);
void ShowAbout(void);
void FunctionTabChanged(int index);
// Load Package Tab
void SelectFirmwarePackage(void);
void OpenDeveloperHomepage(void);
void OpenDeveloperDonationWebpage(void);
void LoadFirmwarePackage(void);
// Flash Tab
void SelectPartitionName(int index);
void SelectPartitionFile(void);
void SelectPartition(int row);
void AddPartition(void);
void RemovePartition(void);
void SelectPit(void);
void SetRepartition(int enabled);
void SetNoReboot(int enabled);
void SetResume(bool enabled);
void SetResume(int enabled);
void StartFlash(void);
// Create Package Tab
void FirmwareNameChanged(const QString& text);
void FirmwareVersionChanged(const QString& text);
void PlatformNameChanged(const QString& text);
void PlatformVersionChanged(const QString& text);
void HomepageUrlChanged(const QString& text);
void DonateUrlChanged(const QString& text);
void DeveloperNameChanged(const QString& text);
void SelectDeveloper(int row);
void AddDeveloper(void);
void RemoveDeveloper(void);
void DeviceInfoChanged(const QString& text);
void SelectDevice(int row);
void AddDevice(void);
void RemoveDevice(void);
void BuildPackage(void);
// Utilities Tab
void DetectDevice(void);
void ClosePcScreen(void);
void SelectPitDestination(void);
void DownloadPit(void);
void DevicePrintPitToggled(bool checked);
void LocalFilePrintPitToggled(bool checked);
void SelectPrintPitFile(void);
void PrintPit(void);
// Heimdall Command Line
void HandleHeimdallStdout(void);
void HandleHeimdallReturned(int exitCode, QProcess::ExitStatus exitStatus);
void HandleHeimdallError(QProcess::ProcessError error);
};
}
#endif // MAINWINDOW_H

View File

@ -0,0 +1,3 @@
SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", ATTR{idProduct}=="6601", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", ATTR{idProduct}=="685d", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", ATTR{idProduct}=="68c3", MODE="0666"

52
heimdall/CMakeLists.txt Normal file
View File

@ -0,0 +1,52 @@
cmake_minimum_required(VERSION 2.8.4)
project(heimdall)
if((NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux") AND (NOT DEFINED libusb_USE_STATIC_LIBS))
set(libusb_USE_STATIC_LIBS YES)
endif((NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux") AND (NOT DEFINED libusb_USE_STATIC_LIBS))
find_package(libusb REQUIRED)
set(LIBPIT_INCLUDE_DIRS
../libpit/source)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
if(MINGW)
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
endif(MINGW)
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
add_definitions(-DOS_LINUX)
endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
include_directories(SYSTEM ${LIBUSB_INCLUDE_DIRS})
include_directories(${LIBPIT_INCLUDE_DIRS})
set(HEIMDALL_SOURCE_FILES
source/Arguments.cpp
source/BridgeManager.cpp
source/ClosePcScreenAction.cpp
source/DetectAction.cpp
source/DownloadPitAction.cpp
source/FlashAction.cpp
source/HelpAction.cpp
source/InfoAction.cpp
source/Interface.cpp
source/main.cpp
source/PrintPitAction.cpp
source/Utility.cpp
source/VersionAction.cpp)
include(LargeFiles)
use_large_files(heimdall YES)
add_executable(heimdall ${HEIMDALL_SOURCE_FILES})
target_link_libraries(heimdall PRIVATE pit)
target_link_libraries(heimdall PRIVATE ${LIBUSB_LIBRARY})
install (TARGETS heimdall
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

View File

@ -0,0 +1,215 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// Heimdall
#include "Arguments.h"
#include "Heimdall.h"
#include "Interface.h"
#include "Utility.h"
using namespace std;
using namespace Heimdall;
FlagArgument *FlagArgument::ParseArgument(const std::string& name, int argc, char **argv, int& argi)
{
return new FlagArgument(name);
}
StringArgument *StringArgument::ParseArgument(const std::string& name, int argc, char **argv, int& argi)
{
if (++argi < argc)
{
return (new StringArgument(name, argv[argi]));
}
else
{
Interface::Print("Missing parameter for argument: %s\n\n", argv[argi - 1]);
return (nullptr);
}
}
UnsignedIntegerArgument *UnsignedIntegerArgument::ParseArgument(const std::string& name, int argc, char **argv, int& argi)
{
UnsignedIntegerArgument *unsignedIntegerArgument = nullptr;
if (++argi < argc)
{
unsigned int value;
if (Utility::ParseUnsignedInt(value, argv[argi]) == kNumberParsingStatusSuccess)
unsignedIntegerArgument = new UnsignedIntegerArgument(name, value);
else
Interface::Print("%s must be a positive integer.", argv[argi - 1]);
}
else
{
Interface::Print("Missing parameter for argument: %s\n\n", argv[argi - 1]);
}
return (unsignedIntegerArgument);
}
Arguments::Arguments(const map<string, ArgumentType>& argumentTypes, const map<string, string>& shortArgumentAliases,
const map<string, string>& argumentAliases) :
argumentTypes(argumentTypes),
shortArgumentAliases(shortArgumentAliases),
argumentAliases(argumentAliases)
{
}
Arguments::~Arguments()
{
for (vector<const Argument *>::const_iterator it = argumentVector.begin(); it != argumentVector.end(); it++)
delete *it;
}
bool Arguments::ParseArguments(int argc, char **argv, int argi)
{
for (; argi < argc; ++argi)
{
string argumentName = argv[argi];
string nonwildcardArgumentName;
if (argumentName.find_first_of("--") == 0)
{
// Regular argument
argumentName = argumentName.substr(2);
nonwildcardArgumentName = argumentName;
}
else if (argumentName.find_first_of("-") == 0)
{
// Short argument alias
string shortArgumentAlias = argumentName.substr(1);
map<string, string>::const_iterator shortAliasIt = shortArgumentAliases.find(shortArgumentAlias);
if (shortAliasIt != shortArgumentAliases.end())
{
argumentName = shortAliasIt->second;
nonwildcardArgumentName = argumentName;
}
else
{
Interface::Print("Unknown argument: %s\n\n", argv[argi]);
return (false);
}
}
else
{
Interface::Print("Invalid argument: %s\n\n", argv[argi]);
return (false);
}
map<string, ArgumentType>::const_iterator argumentTypeIt = argumentTypes.find(argumentName);
if (argumentTypeIt == argumentTypes.end())
{
// No argument with that name, maybe it's an alias...
map<string, string>::const_iterator aliasIt = argumentAliases.find(argumentName);
if (aliasIt != argumentAliases.end())
{
argumentName = aliasIt->second;
nonwildcardArgumentName = argumentName;
argumentTypeIt = argumentTypes.find(argumentName);
}
}
// Handle wilcards
unsigned int unsignedIntName;
if (argumentTypeIt == argumentTypes.end())
{
// Look for the unsigned integer wildcard "%d".
if (Utility::ParseUnsignedInt(unsignedIntName, argumentName.c_str()) == kNumberParsingStatusSuccess)
{
argumentTypeIt = argumentTypes.find("%d");
argumentName = "%d";
}
// Look for the string wildcard "%s"
if (argumentTypeIt == argumentTypes.end())
{
argumentTypeIt = argumentTypes.find("%s");
argumentName = "%s";
}
}
// We don't want to insert wild-cards into our argument map.
if (argumentName == "%d" || argumentName == "%s")
argumentName = nonwildcardArgumentName;
Argument *argument = nullptr;
if (argumentTypeIt != argumentTypes.end())
{
switch (argumentTypeIt->second)
{
case kArgumentTypeFlag:
argument = FlagArgument::ParseArgument(argumentName, argc, argv, argi);
break;
case kArgumentTypeString:
argument = StringArgument::ParseArgument(argumentName, argc, argv, argi);
break;
case kArgumentTypeUnsignedInteger:
argument = UnsignedIntegerArgument::ParseArgument(argumentName, argc, argv, argi);
break;
default:
Interface::Print("Unknown argument type: %s\n\n", argv[argi]);
break;
}
}
else
{
Interface::Print("Unknown argument: %s\n\n", argv[argi]);
}
if (argument)
{
pair<map<string, const Argument *>::iterator, bool> insertResult = argumentMap.insert(pair<string, const Argument *>(argumentName, argument));
if (!insertResult.second)
{
Interface::Print("Duplicate argument: %s (%s)\n\n", argv[argi], argumentName.c_str());
delete argument;
return (false);
}
argumentVector.push_back(argument);
}
else
{
return (false);
}
}
return (true);
}

168
heimdall/source/Arguments.h Normal file
View File

@ -0,0 +1,168 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef ARGUMENTS_H
#define ARGUMENTS_H
// C/C++ Standard Library
#include <map>
#include <string>
#include <vector>
// Heimdall
#include "Heimdall.h"
namespace Heimdall
{
typedef enum
{
kArgumentTypeFlag = 0,
kArgumentTypeString,
kArgumentTypeUnsignedInteger
} ArgumentType;
class Argument
{
private:
std::string name;
ArgumentType type;
protected:
Argument(const std::string& name, ArgumentType type)
{
this->name = name;
this->type = type;
}
public:
virtual ~Argument()
{
}
const std::string& GetName(void) const
{
return name;
}
ArgumentType GetType(void) const
{
return type;
}
};
class FlagArgument : public Argument
{
private:
FlagArgument(const std::string& name) : Argument(name, kArgumentTypeFlag)
{
}
public:
static FlagArgument *ParseArgument(const std::string& name, int argc, char **argv, int& argi);
};
class StringArgument : public Argument
{
private:
std::string value;
StringArgument(const std::string& name, const std::string& value) : Argument(name, kArgumentTypeString)
{
this->value = value;
}
public:
static StringArgument *ParseArgument(const std::string& name, int argc, char **argv, int& argi);
const std::string& GetValue(void) const
{
return (value);
}
};
class UnsignedIntegerArgument : public Argument
{
private:
unsigned int value;
UnsignedIntegerArgument(const std::string& name, unsigned int value) : Argument(name, kArgumentTypeUnsignedInteger)
{
this->value = value;
}
public:
static UnsignedIntegerArgument *ParseArgument(const std::string& name, int argc, char **argv, int& argi);
unsigned int GetValue(void) const
{
return (value);
}
};
class Arguments
{
private:
const std::map<std::string, ArgumentType> argumentTypes;
const std::map<std::string, std::string> shortArgumentAliases;
const std::map<std::string, std::string> argumentAliases;
std::vector<const Argument *> argumentVector;
std::map<std::string, const Argument *> argumentMap;
public:
Arguments(const std::map<std::string, ArgumentType>& argumentTypes,
const std::map<std::string, std::string>& shortArgumentAliases = (std::map<std::string, std::string>()),
const std::map<std::string, std::string>& argumentAliases = (std::map<std::string, std::string>()));
~Arguments();
// argi is the index of the first argument to parse.
bool ParseArguments(int argc, char **argv, int argi);
const Argument *GetArgument(std::string argumentName) const
{
std::map<std::string, const Argument *>::const_iterator it = argumentMap.find(argumentName);
return (it != argumentMap.end() ? it->second : nullptr);
}
const std::map<std::string, ArgumentType>& GetArgumentTypes(void) const
{
return (argumentTypes);
}
const std::vector<const Argument *>& GetArguments(void) const
{
return (argumentVector);
}
};
}
#endif

View File

@ -0,0 +1,72 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef BEGINDUMPPACKET_H
#define BEGINDUMPPACKET_H
// Heimdall
#include "FileTransferPacket.h"
namespace Heimdall
{
class BeginDumpPacket : public FileTransferPacket
{
public:
enum
{
kChipTypeRam = 0,
kChipTypeNand = 1
};
private:
unsigned int chipType;
unsigned int chipId;
public:
BeginDumpPacket(unsigned int chipType, unsigned int chipId) : FileTransferPacket(FileTransferPacket::kRequestDump)
{
this->chipType = chipType;
this->chipId = chipId;
}
unsigned int GetChipType(void) const
{
return (chipType);
}
unsigned int GetChipId(void) const
{
return (chipId);
}
virtual void Pack(void)
{
FileTransferPacket::Pack();
PackInteger(FileTransferPacket::kDataSize, chipType);
PackInteger(FileTransferPacket::kDataSize + 4, chipId);
}
};
}
#endif

View File

@ -0,0 +1,39 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef BEGINSESSIONPACKET_H
#define BEGINSESSIONPACKET_H
// Heimdall
#include "SessionSetupPacket.h"
namespace Heimdall
{
class BeginSessionPacket : public SessionSetupPacket
{
public:
BeginSessionPacket() : SessionSetupPacket(SessionSetupPacket::kBeginSession)
{
}
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,182 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef BRIDGEMANAGER_H
#define BRIDGEMANAGER_H
// libpit
#include "libpit.h"
// Heimdall
#include "Heimdall.h"
struct libusb_context;
struct libusb_device;
struct libusb_device_handle;
namespace Heimdall
{
class InboundPacket;
class OutboundPacket;
class DeviceIdentifier
{
public:
const int vendorId;
const int productId;
DeviceIdentifier(int vid, int pid) :
vendorId(vid),
productId(pid)
{
}
};
class BridgeManager
{
public:
enum
{
kSupportedDeviceCount = 3
};
enum
{
kInitialiseSucceeded = 0,
kInitialiseFailed,
kInitialiseDeviceNotDetected
};
enum
{
kVidSamsung = 0x04E8
};
enum
{
kPidGalaxyS = 0x6601,
kPidGalaxyS2 = 0x685D,
kPidDroidCharge = 0x68C3
};
enum
{
kDefaultTimeoutSend = 3000,
kDefaultTimeoutReceive = 3000,
kDefaultTimeoutEmptyTransfer = 100
};
enum class UsbLogLevel
{
None = 0,
Error,
Warning,
Info,
Debug,
Default = Error
};
enum
{
kEmptyTransferNone = 0,
kEmptyTransferBefore = 1,
kEmptyTransferAfter = 1 << 1,
kEmptyTransferBeforeAndAfter = kEmptyTransferBefore | kEmptyTransferAfter
};
private:
static const DeviceIdentifier supportedDevices[kSupportedDeviceCount];
bool verbose;
libusb_context *libusbContext;
libusb_device_handle *deviceHandle;
libusb_device *heimdallDevice;
int interfaceIndex;
int altSettingIndex;
int inEndpoint;
int outEndpoint;
bool interfaceClaimed;
#ifdef OS_LINUX
bool detachedDriver;
#endif
unsigned int fileTransferSequenceMaxLength;
unsigned int fileTransferPacketSize;
unsigned int fileTransferSequenceTimeout;
UsbLogLevel usbLogLevel;
int FindDeviceInterface(void);
bool ClaimDeviceInterface(void);
bool SetupDeviceInterface(void);
void ReleaseDeviceInterface(void);
bool InitialiseProtocol(void);
bool SendBulkTransfer(unsigned char *data, int length, int timeout, bool retry = true) const;
int ReceiveBulkTransfer(unsigned char *data, int length, int timeout, bool retry = true) const;
public:
BridgeManager(bool verbose);
~BridgeManager();
bool DetectDevice(void);
int Initialise(bool resume);
bool BeginSession(void);
bool EndSession(bool reboot) const;
bool SendPacket(OutboundPacket *packet, int timeout = kDefaultTimeoutSend, int emptyTransferFlags = kEmptyTransferAfter) const;
bool ReceivePacket(InboundPacket *packet, int timeout = kDefaultTimeoutReceive, int emptyTransferFlags = kEmptyTransferNone) const;
bool RequestDeviceType(unsigned int request, int *result) const;
bool SendPitData(const libpit::PitData *pitData) const;
int ReceivePitFile(unsigned char **pitBuffer) const;
int DownloadPitFile(unsigned char **pitBuffer) const; // Thin wrapper around ReceivePitFile() with additional logging.
bool SendFile(FILE *file, unsigned int destination, unsigned int deviceType, unsigned int fileIdentifier = 0xFFFFFFFF) const;
void SetUsbLogLevel(UsbLogLevel usbLogLevel);
UsbLogLevel GetUsbLogLevel(void) const
{
return usbLogLevel;
}
bool IsVerbose(void) const
{
return (verbose);
}
};
}
#endif

View File

@ -0,0 +1,130 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// Heimdall
#include "Arguments.h"
#include "BridgeManager.h"
#include "ClosePcScreenAction.h"
#include "Heimdall.h"
#include "Interface.h"
using namespace std;
using namespace Heimdall;
const char *ClosePcScreenAction::usage = "Action: close-pc-screen\n\
Arguments: [--verbose] [--no-reboot] [--resume] [--stdout-errors]\n\
[--usb-log-level <none/error/warning/debug>]\n\
Description: Attempts to get rid off the \"connect phone to PC\" screen.\n\
Note: --no-reboot causes the device to remain in download mode after the action\n\
is completed. If you wish to perform another action whilst remaining in\n\
download mode, then the following action must specify the --resume flag.\n";
int ClosePcScreenAction::Execute(int argc, char **argv)
{
// Handle arguments
map<string, ArgumentType> argumentTypes;
argumentTypes["no-reboot"] = kArgumentTypeFlag;
argumentTypes["resume"] = kArgumentTypeFlag;
argumentTypes["verbose"] = kArgumentTypeFlag;
argumentTypes["stdout-errors"] = kArgumentTypeFlag;
argumentTypes["usb-log-level"] = kArgumentTypeString;
Arguments arguments(argumentTypes);
if (!arguments.ParseArguments(argc, argv, 2))
{
Interface::Print(ClosePcScreenAction::usage);
return (0);
}
const StringArgument *usbLogLevelArgument = static_cast<const StringArgument *>(arguments.GetArgument("usb-log-level"));
BridgeManager::UsbLogLevel usbLogLevel = BridgeManager::UsbLogLevel::Default;
if (usbLogLevelArgument)
{
const string& usbLogLevelString = usbLogLevelArgument->GetValue();
if (usbLogLevelString.compare("none") == 0 || usbLogLevelString.compare("NONE") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::None;
}
else if (usbLogLevelString.compare("error") == 0 || usbLogLevelString.compare("ERROR") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Error;
}
else if (usbLogLevelString.compare("warning") == 0 || usbLogLevelString.compare("WARNING") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Warning;
}
else if (usbLogLevelString.compare("info") == 0 || usbLogLevelString.compare("INFO") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Info;
}
else if (usbLogLevelString.compare("debug") == 0 || usbLogLevelString.compare("DEBUG") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Debug;
}
else
{
Interface::Print("Unknown USB log level: %s\n\n", usbLogLevelString.c_str());
Interface::Print(ClosePcScreenAction::usage);
return (0);
}
}
bool reboot = arguments.GetArgument("no-reboot") == nullptr;
bool resume = arguments.GetArgument("resume") != nullptr;
bool verbose = arguments.GetArgument("verbose") != nullptr;
if (arguments.GetArgument("stdout-errors") != nullptr)
Interface::SetStdoutErrors(true);
// Info
Interface::PrintReleaseInfo();
Sleep(1000);
// Download PIT file from device.
BridgeManager *bridgeManager = new BridgeManager(verbose);
bridgeManager->SetUsbLogLevel(usbLogLevel);
if (bridgeManager->Initialise(resume) != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession())
{
delete bridgeManager;
return (1);
}
Interface::Print("Attempting to close connect to pc screen...\n");
bool success = bridgeManager->EndSession(reboot);
delete bridgeManager;
if (success)
{
Interface::Print("Attempt complete\n");
return (0);
}
else
{
return (1);
}
}

View File

@ -0,0 +1,34 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef CLOSEPCSCREENACTION_H
#define CLOSEPCSCREENACTION_H
namespace Heimdall
{
namespace ClosePcScreenAction
{
extern const char *usage;
int Execute(int argc, char **argv);
}
}
#endif

View File

@ -0,0 +1,71 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef CONTROLPACKET_H
#define CONTROLPACKET_H
// Heimdall
#include "OutboundPacket.h"
namespace Heimdall
{
class ControlPacket : public OutboundPacket
{
public:
enum
{
kControlTypeSession = 0x64,
kControlTypePitFile = 0x65,
kControlTypeFileTransfer = 0x66,
kControlTypeEndSession = 0x67
};
protected:
enum
{
kDataSize = 4
};
private:
unsigned int controlType;
public:
ControlPacket(unsigned int controlType) : OutboundPacket(1024)
{
this->controlType = controlType;
}
unsigned int GetControlType(void) const
{
return (controlType);
}
virtual void Pack(void)
{
PackInteger(0, controlType);
}
};
}
#endif

View File

@ -0,0 +1,104 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// Heimdall
#include "Arguments.h"
#include "BridgeManager.h"
#include "DetectAction.h"
#include "Heimdall.h"
#include "Interface.h"
using namespace std;
using namespace Heimdall;
const char *DetectAction::usage = "Action: detect\n\
Arguments: [--verbose] [--stdout-errors]\n\
[--usb-log-level <none/error/warning/debug>]\n\
Description: Indicates whether or not a download mode device can be detected.\n";
int DetectAction::Execute(int argc, char **argv)
{
// Handle arguments
map<string, ArgumentType> argumentTypes;
argumentTypes["verbose"] = kArgumentTypeFlag;
argumentTypes["stdout-errors"] = kArgumentTypeFlag;
argumentTypes["usb-log-level"] = kArgumentTypeString;
Arguments arguments(argumentTypes);
if (!arguments.ParseArguments(argc, argv, 2))
{
Interface::Print(DetectAction::usage);
return (0);
}
bool verbose = arguments.GetArgument("verbose") != nullptr;
if (arguments.GetArgument("stdout-errors") != nullptr)
Interface::SetStdoutErrors(true);
const StringArgument *usbLogLevelArgument = static_cast<const StringArgument *>(arguments.GetArgument("usb-log-level"));
BridgeManager::UsbLogLevel usbLogLevel = BridgeManager::UsbLogLevel::Default;
if (usbLogLevelArgument)
{
const string& usbLogLevelString = usbLogLevelArgument->GetValue();
if (usbLogLevelString.compare("none") == 0 || usbLogLevelString.compare("NONE") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::None;
}
else if (usbLogLevelString.compare("error") == 0 || usbLogLevelString.compare("ERROR") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Error;
}
else if (usbLogLevelString.compare("warning") == 0 || usbLogLevelString.compare("WARNING") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Warning;
}
else if (usbLogLevelString.compare("info") == 0 || usbLogLevelString.compare("INFO") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Info;
}
else if (usbLogLevelString.compare("debug") == 0 || usbLogLevelString.compare("DEBUG") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Debug;
}
else
{
Interface::Print("Unknown USB log level: %s\n\n", usbLogLevelString.c_str());
Interface::Print(DetectAction::usage);
return (0);
}
}
// Download PIT file from device.
BridgeManager *bridgeManager = new BridgeManager(verbose);
bridgeManager->SetUsbLogLevel(usbLogLevel);
bool detected = bridgeManager->DetectDevice();
delete bridgeManager;
return ((detected) ? 0 : 1);
}

View File

@ -0,0 +1,34 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef DETECTACTION_H
#define DETECTACTION_H
namespace Heimdall
{
namespace DetectAction
{
extern const char *usage;
int Execute(int argc, char **argv);
}
}
#endif

View File

@ -0,0 +1,39 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef DEVICETYPEPACKET_H
#define DEVICETYPEPACKET_H
// Heimdall
#include "SessionSetupPacket.h"
namespace Heimdall
{
class DeviceTypePacket : public SessionSetupPacket
{
public:
DeviceTypePacket() : SessionSetupPacket(SessionSetupPacket::kDeviceType)
{
}
};
}
#endif

View File

@ -0,0 +1,171 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// C Standard Library
#include <stdio.h>
// Heimdall
#include "Arguments.h"
#include "BridgeManager.h"
#include "DownloadPitAction.h"
#include "Heimdall.h"
#include "Interface.h"
using namespace std;
using namespace Heimdall;
const char *DownloadPitAction::usage = "Action: download-pit\n\
Arguments: --output <filename> [--verbose] [--no-reboot] [--stdout-errors]\n\
[--usb-log-level <none/error/warning/debug>]\n\
Description: Downloads the connected device's PIT file to the specified\n\
output file.\n\
Note: --no-reboot causes the device to remain in download mode after the action\n\
is completed. If you wish to perform another action whilst remaining in\n\
download mode, then the following action must specify the --resume flag.\n";
int DownloadPitAction::Execute(int argc, char **argv)
{
// Handle arguments
map<string, ArgumentType> argumentTypes;
argumentTypes["output"] = kArgumentTypeString;
argumentTypes["no-reboot"] = kArgumentTypeFlag;
argumentTypes["resume"] = kArgumentTypeFlag;
argumentTypes["verbose"] = kArgumentTypeFlag;
argumentTypes["stdout-errors"] = kArgumentTypeFlag;
argumentTypes["usb-log-level"] = kArgumentTypeString;
Arguments arguments(argumentTypes);
if (!arguments.ParseArguments(argc, argv, 2))
{
Interface::Print(DownloadPitAction::usage);
return (0);
}
const StringArgument *outputArgument = static_cast<const StringArgument *>(arguments.GetArgument("output"));
if (!outputArgument)
{
Interface::Print("Output file was not specified.\n\n");
Interface::Print(DownloadPitAction::usage);
return (0);
}
bool reboot = arguments.GetArgument("no-reboot") == nullptr;
bool resume = arguments.GetArgument("resume") != nullptr;
bool verbose = arguments.GetArgument("verbose") != nullptr;
if (arguments.GetArgument("stdout-errors") != nullptr)
Interface::SetStdoutErrors(true);
const StringArgument *usbLogLevelArgument = static_cast<const StringArgument *>(arguments.GetArgument("usb-log-level"));
BridgeManager::UsbLogLevel usbLogLevel = BridgeManager::UsbLogLevel::Default;
if (usbLogLevelArgument)
{
const string& usbLogLevelString = usbLogLevelArgument->GetValue();
if (usbLogLevelString.compare("none") == 0 || usbLogLevelString.compare("NONE") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::None;
}
else if (usbLogLevelString.compare("error") == 0 || usbLogLevelString.compare("ERROR") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Error;
}
else if (usbLogLevelString.compare("warning") == 0 || usbLogLevelString.compare("WARNING") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Warning;
}
else if (usbLogLevelString.compare("info") == 0 || usbLogLevelString.compare("INFO") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Info;
}
else if (usbLogLevelString.compare("debug") == 0 || usbLogLevelString.compare("DEBUG") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Debug;
}
else
{
Interface::Print("Unknown USB log level: %s\n\n", usbLogLevelString.c_str());
Interface::Print(DownloadPitAction::usage);
return (0);
}
}
// Info
Interface::PrintReleaseInfo();
Sleep(1000);
// Open output file
const char *outputFilename = outputArgument->GetValue().c_str();
FILE *outputPitFile = FileOpen(outputFilename, "wb");
if (!outputPitFile)
{
Interface::PrintError("Failed to open output file \"%s\"\n", outputFilename);
return (1);
}
// Download PIT file from device.
BridgeManager *bridgeManager = new BridgeManager(verbose);
bridgeManager->SetUsbLogLevel(usbLogLevel);
if (bridgeManager->Initialise(resume) != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession())
{
FileClose(outputPitFile);
delete bridgeManager;
return (1);
}
unsigned char *pitBuffer;
int fileSize = bridgeManager->DownloadPitFile(&pitBuffer);
bool success = true;
if (fileSize > 0)
{
if (fwrite(pitBuffer, 1, fileSize, outputPitFile) != fileSize)
{
Interface::PrintError("Failed to write PIT data to output file.\n");
success = false;
}
}
else
{
success = false;
}
if (!bridgeManager->EndSession(reboot))
success = false;
delete bridgeManager;
FileClose(outputPitFile);
delete [] pitBuffer;
return (success ? 0 : 1);
}

View File

@ -0,0 +1,34 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef DOWNLOADPITACTION_H
#define DOWNLOADPITACTION_H
namespace Heimdall
{
namespace DownloadPitAction
{
extern const char *usage;
int Execute(int argc, char **argv);
}
}
#endif

View File

@ -0,0 +1,56 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef DUMPPARTFILETRANSFERPACKET_H
#define DUMPPARTFILETRANSFERPACKET_H
// Heimdall
#include "FileTransferPacket.h"
namespace Heimdall
{
class DumpPartFileTransferPacket : public FileTransferPacket
{
private:
unsigned int partIndex;
public:
DumpPartFileTransferPacket(unsigned int partIndex) : FileTransferPacket(FileTransferPacket::kRequestPart)
{
this->partIndex = partIndex;
}
unsigned int GetPartIndex(void) const
{
return (partIndex);
}
virtual void Pack(void)
{
FileTransferPacket::Pack();
PackInteger(FileTransferPacket::kDataSize, partIndex);
}
};
}
#endif

View File

@ -0,0 +1,56 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef DUMPPARTPITFILEPACKET_H
#define DUMPPARTPITFILEPACKET_H
// Heimdall
#include "PitFilePacket.h"
namespace Heimdall
{
class DumpPartPitFilePacket : public PitFilePacket
{
private:
unsigned int partIndex;
public:
DumpPartPitFilePacket(unsigned int partIndex) : PitFilePacket(PitFilePacket::kRequestPart)
{
this->partIndex = partIndex;
}
unsigned int GetPartIndex(void) const
{
return (partIndex);
}
void Pack(void)
{
PitFilePacket::Pack();
PackInteger(PitFilePacket::kDataSize, partIndex);
}
};
}
#endif

View File

@ -0,0 +1,58 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef DUMPRESPONSE_H
#define DUMPRESPONSE_H
// Heimdall
#include "ResponsePacket.h"
namespace Heimdall
{
class DumpResponse : public ResponsePacket
{
private:
unsigned int dumpSize;
public:
DumpResponse() : ResponsePacket(kResponseTypeFileTransfer)
{
}
unsigned int GetDumpSize(void) const
{
return (dumpSize);
}
bool Unpack(void)
{
if (!ResponsePacket::Unpack())
return (false);
dumpSize = UnpackInteger(ResponsePacket::kDataSize);
return (true);
}
};
}
#endif

View File

@ -0,0 +1,39 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef ENABLETFLASHPACKET_H
#define ENABLETFLASHPACKET_H
// Heimdall
#include "SessionSetupPacket.h"
namespace Heimdall
{
class EnableTFlashPacket : public SessionSetupPacket
{
public:
EnableTFlashPacket() : SessionSetupPacket(SessionSetupPacket::kEnableTFlash)
{
}
};
}
#endif

View File

@ -0,0 +1,98 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef ENDFILETRANSFERPACKET_H
#define ENDFILETRANSFERPACKET_H
// Heimdall
#include "FileTransferPacket.h"
namespace Heimdall
{
class EndFileTransferPacket : public FileTransferPacket
{
public:
enum
{
kDestinationPhone = 0x00,
kDestinationModem = 0x01
};
protected:
enum
{
kDataSize = FileTransferPacket::kDataSize + 16
};
private:
unsigned int destination; // PDA / Modem
unsigned int sequenceByteCount;
unsigned int unknown1; // EFS?
unsigned int deviceType;
protected:
EndFileTransferPacket(unsigned int destination, unsigned int sequenceByteCount, unsigned int unknown1, unsigned int deviceType)
: FileTransferPacket(FileTransferPacket::kRequestEnd)
{
this->destination = destination;
this->sequenceByteCount = sequenceByteCount;
this->unknown1 = unknown1;
this->deviceType = deviceType;
}
public:
unsigned int GetDestination(void) const
{
return (destination);
}
unsigned int GetSequenceByteCount(void) const
{
return (sequenceByteCount);
}
unsigned int GetUnknown1(void) const
{
return (unknown1);
}
unsigned int GetDeviceType(void) const
{
return (deviceType);
}
virtual void Pack(void)
{
FileTransferPacket::Pack();
PackInteger(FileTransferPacket::kDataSize, destination);
PackInteger(FileTransferPacket::kDataSize + 4, sequenceByteCount);
PackInteger(FileTransferPacket::kDataSize + 8, unknown1);
PackInteger(FileTransferPacket::kDataSize + 12, deviceType);
}
};
}
#endif

View File

@ -0,0 +1,57 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef ENDMODEMFILETRANSFERPACKET_H
#define ENDMODEMFILETRANSFERPACKET_H
// Heimdall
#include "EndFileTransferPacket.h"
namespace Heimdall
{
class EndModemFileTransferPacket : public EndFileTransferPacket
{
private:
unsigned int endOfFile;
public:
EndModemFileTransferPacket(unsigned int sequenceByteCount, unsigned int unknown1, unsigned int chipIdentifier, bool endOfFile)
: EndFileTransferPacket(EndFileTransferPacket::kDestinationModem, sequenceByteCount, unknown1, chipIdentifier)
{
this->endOfFile = (endOfFile) ? 1 : 0;
}
bool IsEndOfFile(void) const
{
return (endOfFile == 1);
}
void Pack(void)
{
EndFileTransferPacket::Pack();
PackInteger(EndFileTransferPacket::kDataSize, endOfFile);
}
};
}
#endif

View File

@ -0,0 +1,88 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef ENDPHONEFILETRANSFERPACKET_H
#define ENDPHONEFILETRANSFERPACKET_H
// Heimdall
#include "EndFileTransferPacket.h"
namespace Heimdall
{
class EndPhoneFileTransferPacket : public EndFileTransferPacket
{
public:
/*enum
{
kFilePrimaryBootloader = 0x00,
kFilePit = 0x01, // New 1.1 - Don't flash the pit this way!
kFileSecondaryBootloader = 0x03,
kFileSecondaryBootloaderBackup = 0x04, // New 1.1
kFileKernel = 0x06,
kFileRecovery = 0x07, // New 1.1
kFileTabletModem = 0x08, // New 1.2
kFileEfs = 0x14, // New 1.1
kFileParamLfs = 0x15,
kFileFactoryFilesystem = 0x16,
kFileDatabaseData = 0x17,
kFileCache = 0x18,
kFileModem = 0x0B // New 1.1 - Kies flashes the modem this way rather than using the EndModemFileTransferPacket.
};*/
private:
unsigned int fileIdentifier;
unsigned int endOfFile;
public:
EndPhoneFileTransferPacket(unsigned int sequenceByteCount, unsigned int unknown1, unsigned int chipIdentifier,
unsigned int fileIdentifier, bool endOfFile)
: EndFileTransferPacket(EndFileTransferPacket::kDestinationPhone, sequenceByteCount, unknown1, chipIdentifier)
{
this->fileIdentifier = fileIdentifier;
this->endOfFile = (endOfFile) ? 1 : 0;
}
unsigned int GetFileIdentifier(void)
{
return (fileIdentifier);
}
bool IsEndOfFile(void) const
{
return (endOfFile == 1);
}
void Pack(void)
{
EndFileTransferPacket::Pack();
PackInteger(EndFileTransferPacket::kDataSize, fileIdentifier);
PackInteger(EndFileTransferPacket::kDataSize + 4, endOfFile);
}
};
}
#endif

View File

@ -0,0 +1,56 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef ENDPITFILETRANSFERPACKET_H
#define ENDPITFILETRANSFERPACKET_H
// Heimdall
#include "PitFilePacket.h"
namespace Heimdall
{
class EndPitFileTransferPacket : public PitFilePacket
{
private:
unsigned int fileSize;
public:
EndPitFileTransferPacket(unsigned int fileSize) : PitFilePacket(PitFilePacket::kRequestEndTransfer)
{
this->fileSize = fileSize;
}
unsigned int GetFileSize(void) const
{
return (fileSize);
}
void Pack(void)
{
PitFilePacket::Pack();
PackInteger(PitFilePacket::kDataSize, fileSize);
}
};
}
#endif

View File

@ -0,0 +1,64 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef ENDSESSIONPACKET_H
#define ENDSESSIONPACKET_H
// Heimdall
#include "ControlPacket.h"
namespace Heimdall
{
class EndSessionPacket : public ControlPacket
{
public:
enum
{
kRequestEndSession = 0,
kRequestRebootDevice = 1
};
private:
unsigned int request;
public:
EndSessionPacket(unsigned int request) : ControlPacket(ControlPacket::kControlTypeEndSession)
{
this->request = request;
}
unsigned int GetRequest(void) const
{
return (request);
}
void Pack(void)
{
ControlPacket::Pack();
PackInteger(ControlPacket::kDataSize, request);
}
};
}
#endif

View File

@ -0,0 +1,56 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef FILEPARTSIZEPACKET_H
#define FILEPARTSIZEPACKET_H
// Heimdall
#include "SessionSetupPacket.h"
namespace Heimdall
{
class FilePartSizePacket : public SessionSetupPacket
{
private:
unsigned int filePartSize;
public:
FilePartSizePacket(unsigned int filePartSize) : SessionSetupPacket(SessionSetupPacket::kFilePartSize)
{
this->filePartSize = filePartSize;
}
unsigned int GetFilePartSize(void) const
{
return filePartSize;
}
void Pack(void)
{
SessionSetupPacket::Pack();
PackInteger(SessionSetupPacket::kDataSize, filePartSize);
}
};
}
#endif

View File

@ -0,0 +1,73 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef FILETRANSFERPACKET_H
#define FILETRANSFERPACKET_H
// Heimdall
#include "ControlPacket.h"
namespace Heimdall
{
class FileTransferPacket : public ControlPacket
{
public:
enum
{
kRequestFlash = 0x00,
kRequestDump = 0x01,
kRequestPart = 0x02,
kRequestEnd = 0x03
};
protected:
enum
{
kDataSize = ControlPacket::kDataSize + 4
};
private:
unsigned int request;
public:
FileTransferPacket(unsigned int request) : ControlPacket(ControlPacket::kControlTypeFileTransfer)
{
this->request = request;
}
unsigned int GetRequest(void) const
{
return (request);
}
virtual void Pack(void)
{
ControlPacket::Pack();
PackInteger(ControlPacket::kDataSize, request);
}
};
}
#endif

View File

@ -0,0 +1,578 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// C Standard Library
#include <stdio.h>
// Heimdall
#include "Arguments.h"
#include "BridgeManager.h"
#include "EnableTFlashPacket.h"
#include "EndModemFileTransferPacket.h"
#include "EndPhoneFileTransferPacket.h"
#include "FlashAction.h"
#include "Heimdall.h"
#include "Interface.h"
#include "SessionSetupResponse.h"
#include "TotalBytesPacket.h"
#include "Utility.h"
using namespace std;
using namespace libpit;
using namespace Heimdall;
const char *FlashAction::usage = "Action: flash\n\
Arguments:\n\
[--<partition name> <filename> ...]\n\
[--<partition identifier> <filename> ...]\n\
[--pit <filename>] [--verbose] [--no-reboot] [--resume] [--stdout-errors]\n\
[--usb-log-level <none/error/warning/debug>]\n\
or:\n\
--repartition --pit <filename> [--<partition name> <filename> ...]\n\
[--<partition identifier> <filename> ...] [--verbose] [--no-reboot]\n\
[--resume] [--stdout-errors] [--usb-log-level <none/error/warning/debug>]\n\
[--tflash]\n\
Description: Flashes one or more firmware files to your phone. Partition names\n\
(or identifiers) can be obtained by executing the print-pit action.\n\
T-Flash mode allows to flash the inserted SD-card instead of the internal MMC.\n\
Note: --no-reboot causes the device to remain in download mode after the action\n\
is completed. If you wish to perform another action whilst remaining in\n\
download mode, then the following action must specify the --resume flag.\n\
WARNING: If you're repartitioning it's strongly recommended you specify\n\
all files at your disposal.\n";
struct PartitionFile
{
const char *argumentName;
FILE *file;
PartitionFile(const char *argumentName, FILE *file)
{
this->argumentName = argumentName;
this->file = file;
}
};
struct PartitionFlashInfo
{
const PitEntry *pitEntry;
FILE *file;
PartitionFlashInfo(const PitEntry *pitEntry, FILE *file)
{
this->pitEntry = pitEntry;
this->file = file;
}
};
static bool openFiles(Arguments& arguments, vector<PartitionFile>& partitionFiles, FILE *& pitFile)
{
// Open PIT file
const StringArgument *pitArgument = static_cast<const StringArgument *>(arguments.GetArgument("pit"));
if (pitArgument)
{
pitFile = FileOpen(pitArgument->GetValue().c_str(), "rb");
if (!pitFile)
{
Interface::PrintError("Failed to open file \"%s\"\n", pitArgument->GetValue().c_str());
return (false);
}
}
// Open partition files
for (vector<const Argument *>::const_iterator it = arguments.GetArguments().begin(); it != arguments.GetArguments().end(); it++)
{
const string& argumentName = (*it)->GetName();
// The only way an argument could exist without being in the argument types map is if it's a wild-card.
// The "%d" wild-card refers to a partition by identifier, where as the "%s" wild-card refers to a
// partition by name.
if (arguments.GetArgumentTypes().find(argumentName) == arguments.GetArgumentTypes().end())
{
const StringArgument *stringArgument = static_cast<const StringArgument *>(*it);
FILE *file = FileOpen(stringArgument->GetValue().c_str(), "rb");
if (!file)
{
Interface::PrintError("Failed to open file \"%s\"\n", stringArgument->GetValue().c_str());
return (false);
}
partitionFiles.push_back(PartitionFile(argumentName.c_str(), file));
}
}
return (true);
}
static void closeFiles(vector<PartitionFile>& partitionFiles, FILE *& pitFile)
{
// Close PIT file
if (pitFile)
{
FileClose(pitFile);
pitFile = nullptr;
}
// Close partition files
for (vector<PartitionFile>::const_iterator it = partitionFiles.begin(); it != partitionFiles.end(); it++)
FileClose(it->file);
partitionFiles.clear();
}
static bool sendTotalTransferSize(BridgeManager *bridgeManager, const vector<PartitionFile>& partitionFiles, FILE *pitFile, bool repartition)
{
unsigned int totalBytes = 0;
for (vector<PartitionFile>::const_iterator it = partitionFiles.begin(); it != partitionFiles.end(); it++)
{
FileSeek(it->file, 0, SEEK_END);
totalBytes += (unsigned int)FileTell(it->file);
FileRewind(it->file);
}
if (repartition)
{
FileSeek(pitFile, 0, SEEK_END);
totalBytes += (unsigned int)FileTell(pitFile);
FileRewind(pitFile);
}
bool success;
TotalBytesPacket *totalBytesPacket = new TotalBytesPacket(totalBytes);
success = bridgeManager->SendPacket(totalBytesPacket);
delete totalBytesPacket;
if (!success)
{
Interface::PrintError("Failed to send total bytes packet!\n");
return (false);
}
SessionSetupResponse *totalBytesResponse = new SessionSetupResponse();
success = bridgeManager->ReceivePacket(totalBytesResponse);
int totalBytesResult = totalBytesResponse->GetResult();
delete totalBytesResponse;
if (!success)
{
Interface::PrintError("Failed to receive session total bytes response!\n");
return (false);
}
if (totalBytesResult != 0)
{
Interface::PrintError("Unexpected session total bytes response!\nExpected: 0\nReceived:%d\n", totalBytesResult);
return (false);
}
return (true);
}
static bool setupPartitionFlashInfo(const vector<PartitionFile>& partitionFiles, const PitData *pitData, vector<PartitionFlashInfo>& partitionFlashInfos)
{
for (vector<PartitionFile>::const_iterator it = partitionFiles.begin(); it != partitionFiles.end(); it++)
{
const PitEntry *pitEntry = nullptr;
// Was the argument a partition identifier?
unsigned int partitionIdentifier;
if (Utility::ParseUnsignedInt(partitionIdentifier, it->argumentName) == kNumberParsingStatusSuccess)
{
pitEntry = pitData->FindEntry(partitionIdentifier);
if (!pitEntry)
{
Interface::PrintError("No partition with identifier \"%s\" exists in the specified PIT.\n", it->argumentName);
return (false);
}
}
else
{
// The argument must be an partition name e.g. "ZIMAGE"
pitEntry = pitData->FindEntry(it->argumentName);
if (!pitEntry)
{
Interface::PrintError("Partition \"%s\" does not exist in the specified PIT.\n", it->argumentName);
return (false);
}
}
partitionFlashInfos.push_back(PartitionFlashInfo(pitEntry, it->file));
}
return (true);
}
static bool flashPitData(BridgeManager *bridgeManager, const PitData *pitData)
{
Interface::Print("Uploading PIT\n");
if (bridgeManager->SendPitData(pitData))
{
Interface::Print("PIT upload successful\n\n");
return (true);
}
else
{
Interface::PrintError("PIT upload failed!\n\n");
return (false);
}
}
static bool flashFile(BridgeManager *bridgeManager, const PartitionFlashInfo& partitionFlashInfo)
{
if (partitionFlashInfo.pitEntry->GetBinaryType() == PitEntry::kBinaryTypeCommunicationProcessor) // Modem
{
Interface::Print("Uploading %s\n", partitionFlashInfo.pitEntry->GetPartitionName());
if (bridgeManager->SendFile(partitionFlashInfo.file, EndModemFileTransferPacket::kDestinationModem,
partitionFlashInfo.pitEntry->GetDeviceType()))
{
Interface::Print("%s upload successful\n\n", partitionFlashInfo.pitEntry->GetPartitionName());
return (true);
}
else
{
Interface::PrintError("%s upload failed!\n\n", partitionFlashInfo.pitEntry->GetPartitionName());
return (false);
}
}
else // partitionFlashInfo.pitEntry->GetBinaryType() == PitEntry::kBinaryTypeApplicationProcessor
{
Interface::Print("Uploading %s\n", partitionFlashInfo.pitEntry->GetPartitionName());
if (bridgeManager->SendFile(partitionFlashInfo.file, EndPhoneFileTransferPacket::kDestinationPhone,
partitionFlashInfo.pitEntry->GetDeviceType(), partitionFlashInfo.pitEntry->GetIdentifier()))
{
Interface::Print("%s upload successful\n\n", partitionFlashInfo.pitEntry->GetPartitionName());
return (true);
}
else
{
Interface::PrintError("%s upload failed!\n\n", partitionFlashInfo.pitEntry->GetPartitionName());
return (false);
}
}
}
static bool flashPartitions(BridgeManager *bridgeManager, const vector<PartitionFile>& partitionFiles, const PitData *pitData, bool repartition)
{
vector<PartitionFlashInfo> partitionFlashInfos;
// Map the files being flashed to partitions stored in the PIT file.
if (!setupPartitionFlashInfo(partitionFiles, pitData, partitionFlashInfos))
return (false);
// If we're repartitioning then we need to flash the PIT file first (if it is listed in the PIT file).
if (repartition)
{
if (!flashPitData(bridgeManager, pitData))
return (false);
}
// Flash partitions in the same order that arguments were specified in.
for (vector<PartitionFlashInfo>::const_iterator it = partitionFlashInfos.begin(); it != partitionFlashInfos.end(); it++)
{
if (!flashFile(bridgeManager, *it))
return (false);
}
return (true);
}
static PitData *getPitData(BridgeManager *bridgeManager, FILE *pitFile, bool repartition)
{
PitData *pitData;
PitData *localPitData = nullptr;
// If a PIT file was passed as an argument then we must unpack it.
if (pitFile)
{
// Load the local pit file into memory.
FileSeek(pitFile, 0, SEEK_END);
unsigned int localPitFileSize = (unsigned int)FileTell(pitFile);
FileRewind(pitFile);
unsigned char *pitFileBuffer = new unsigned char[localPitFileSize];
memset(pitFileBuffer, 0, localPitFileSize);
int dataRead = fread(pitFileBuffer, 1, localPitFileSize, pitFile);
if (dataRead > 0)
{
FileRewind(pitFile);
localPitData = new PitData();
localPitData->Unpack(pitFileBuffer);
delete [] pitFileBuffer;
}
else
{
Interface::PrintError("Failed to read PIT file.\n");
delete [] pitFileBuffer;
return (nullptr);
}
}
if (repartition)
{
// Use the local PIT file data.
pitData = localPitData;
}
else
{
// If we're not repartitioning then we need to retrieve the device's PIT file and unpack it.
unsigned char *pitFileBuffer;
if (bridgeManager->DownloadPitFile(&pitFileBuffer) == 0)
return (nullptr);
pitData = new PitData();
pitData->Unpack(pitFileBuffer);
delete [] pitFileBuffer;
if (localPitData != nullptr)
{
// The user has specified a PIT without repartitioning, we should verify the local and device PIT data match!
bool pitsMatch = pitData->Matches(localPitData);
delete localPitData;
if (!pitsMatch)
{
Interface::Print("Local and device PIT files don't match and repartition wasn't specified!\n");
Interface::PrintError("Flash aborted!\n");
return (nullptr);
}
}
}
return (pitData);
}
static bool enableTFlash(BridgeManager *bridgeManager)
{
bool success;
EnableTFlashPacket *enableTFlashPacket = new EnableTFlashPacket();
success = bridgeManager->SendPacket(enableTFlashPacket);
delete enableTFlashPacket;
if (!success)
{
Interface::PrintError("Failed to send T-Flash packet!\n");
return false;
}
SessionSetupResponse *enableTFlashResponse = new SessionSetupResponse();
success = bridgeManager->ReceivePacket(enableTFlashResponse, 5000);
unsigned int result = enableTFlashResponse->GetResult();
delete enableTFlashResponse;
if (!success)
{
Interface::PrintError("Failed to receive T-Flash response!\n");
return false;
}
if (result)
{
Interface::PrintError("Unexpected T-Flash response!\nExpected: 0\nReceived: %d\n", result);
return false;
}
return true;
}
int FlashAction::Execute(int argc, char **argv)
{
// Setup argument types
map<string, ArgumentType> argumentTypes;
map<string, string> shortArgumentAliases;
argumentTypes["repartition"] = kArgumentTypeFlag;
argumentTypes["no-reboot"] = kArgumentTypeFlag;
argumentTypes["resume"] = kArgumentTypeFlag;
argumentTypes["verbose"] = kArgumentTypeFlag;
argumentTypes["stdout-errors"] = kArgumentTypeFlag;
argumentTypes["usb-log-level"] = kArgumentTypeString;
argumentTypes["tflash"] = kArgumentTypeFlag;
argumentTypes["pit"] = kArgumentTypeString;
shortArgumentAliases["pit"] = "pit";
// Add wild-cards "%d" and "%s", for partition identifiers and partition names respectively.
argumentTypes["%d"] = kArgumentTypeString;
shortArgumentAliases["%d"] = "%d";
argumentTypes["%s"] = kArgumentTypeString;
shortArgumentAliases["%s"] = "%s";
map<string, string> argumentAliases;
argumentAliases["PIT"] = "pit"; // Map upper-case PIT argument (i.e. partition name) to known lower-case pit argument.
// Handle arguments
Arguments arguments(argumentTypes, shortArgumentAliases, argumentAliases);
if (!arguments.ParseArguments(argc, argv, 2))
{
Interface::Print(FlashAction::usage);
return (0);
}
bool reboot = arguments.GetArgument("no-reboot") == nullptr;
bool resume = arguments.GetArgument("resume") != nullptr;
bool verbose = arguments.GetArgument("verbose") != nullptr;
bool tflash = arguments.GetArgument("tflash") != nullptr;
if (arguments.GetArgument("stdout-errors") != nullptr)
Interface::SetStdoutErrors(true);
const StringArgument *usbLogLevelArgument = static_cast<const StringArgument *>(arguments.GetArgument("usb-log-level"));
BridgeManager::UsbLogLevel usbLogLevel = BridgeManager::UsbLogLevel::Default;
if (usbLogLevelArgument)
{
const string& usbLogLevelString = usbLogLevelArgument->GetValue();
if (usbLogLevelString.compare("none") == 0 || usbLogLevelString.compare("NONE") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::None;
}
else if (usbLogLevelString.compare("error") == 0 || usbLogLevelString.compare("ERROR") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Error;
}
else if (usbLogLevelString.compare("warning") == 0 || usbLogLevelString.compare("WARNING") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Warning;
}
else if (usbLogLevelString.compare("info") == 0 || usbLogLevelString.compare("INFO") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Info;
}
else if (usbLogLevelString.compare("debug") == 0 || usbLogLevelString.compare("DEBUG") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Debug;
}
else
{
Interface::Print("Unknown USB log level: %s\n\n", usbLogLevelString.c_str());
Interface::Print(FlashAction::usage);
return (0);
}
}
const StringArgument *pitArgument = static_cast<const StringArgument *>(arguments.GetArgument("pit"));
bool repartition = arguments.GetArgument("repartition") != nullptr;
if (repartition && !pitArgument)
{
Interface::Print("If you wish to repartition then a PIT file must be specified.\n\n");
Interface::Print(FlashAction::usage);
return (0);
}
// Open files
FILE *pitFile = nullptr;
vector<PartitionFile> partitionFiles;
if (!openFiles(arguments, partitionFiles, pitFile))
{
closeFiles(partitionFiles, pitFile);
return (1);
}
if (partitionFiles.size() == 0)
{
Interface::Print(FlashAction::usage);
return (0);
}
// Info
Interface::PrintReleaseInfo();
Sleep(1000);
// Perform flash
BridgeManager *bridgeManager = new BridgeManager(verbose);
bridgeManager->SetUsbLogLevel(usbLogLevel);
if (bridgeManager->Initialise(resume) != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession())
{
closeFiles(partitionFiles, pitFile);
delete bridgeManager;
return (1);
}
if (tflash && !enableTFlash(bridgeManager))
{
closeFiles(partitionFiles, pitFile);
delete bridgeManager;
return (1);
}
bool success = sendTotalTransferSize(bridgeManager, partitionFiles, pitFile, repartition);
if (success)
{
PitData *pitData = getPitData(bridgeManager, pitFile, repartition);
if (pitData)
success = flashPartitions(bridgeManager, partitionFiles, pitData, repartition);
else
success = false;
delete pitData;
}
if (!bridgeManager->EndSession(reboot))
success = false;
delete bridgeManager;
closeFiles(partitionFiles, pitFile);
return (success ? 0 : 1);
}

View File

@ -0,0 +1,34 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef FLASHACTION_H
#define FLASHACTION_H
namespace Heimdall
{
namespace FlashAction
{
extern const char *usage;
int Execute(int argc, char **argv);
}
}
#endif

View File

@ -0,0 +1,57 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef FLASHPARTFILETRANSFERPACKET_H
#define FLASHPARTFILETRANSFERPACKET_H
// Heimdall
#include "FileTransferPacket.h"
namespace Heimdall
{
class FlashPartFileTransferPacket : public FileTransferPacket
{
private:
unsigned int sequenceByteCount;
public:
FlashPartFileTransferPacket(unsigned int sequenceByteCount)
: FileTransferPacket(FileTransferPacket::kRequestPart)
{
this->sequenceByteCount = sequenceByteCount;
}
unsigned int GetSequenceByteCount(void) const
{
return (sequenceByteCount);
}
void Pack(void)
{
FileTransferPacket::Pack();
PackInteger(FileTransferPacket::kDataSize, sequenceByteCount);
}
};
}
#endif

View File

@ -0,0 +1,56 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef FLASHPARTPITFILEPACKET_H
#define FLASHPARTPITFILEPACKET_H
// Heimdall
#include "PitFilePacket.h"
namespace Heimdall
{
class FlashPartPitFilePacket : public PitFilePacket
{
private:
unsigned int partSize;
public:
FlashPartPitFilePacket(unsigned int partSize) : PitFilePacket(PitFilePacket::kRequestPart)
{
this->partSize = partSize;
}
unsigned int GetPartSize(void) const
{
return (partSize);
}
void Pack(void)
{
PitFilePacket::Pack();
PackInteger(PitFilePacket::kDataSize, partSize);
}
};
}
#endif

View File

@ -0,0 +1,65 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef HEIMDALL_H
#define HEIMDALL_H
#ifdef _MSC_VER // Microsoft Visual C Standard Library
#include <Windows.h>
#undef GetBinaryType
#ifndef va_copy
#define va_copy(d, s) ((d) = (s))
#endif
#define FileOpen(FILE, MODE) fopen(FILE, MODE)
#define FileClose(FILE) fclose(FILE)
#define FileSeek(FILE, OFFSET, ORIGIN) _fseeki64(FILE, OFFSET, ORIGIN)
#define FileTell(FILE) _ftelli64(FILE)
#define FileRewind(FILE) rewind(FILE)
#else // POSIX Standard Library
#ifdef AUTOCONF
#include "../config.h"
#endif
#include <unistd.h>
#define Sleep(t) usleep(1000*t)
#define FileOpen(FILE, MODE) fopen(FILE, MODE)
#define FileClose(FILE) fclose(FILE)
#define FileSeek(FILE, OFFSET, ORIGIN) fseeko(FILE, OFFSET, ORIGIN)
#define FileTell(FILE) ftello(FILE)
#define FileRewind(FILE) rewind(FILE)
#endif
#if (!(defined _MSC_VER) || (_MSC_VER < 1700))
#ifndef nullptr
#define nullptr 0
#endif
#endif
#endif

View File

@ -0,0 +1,35 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// Heimdall
#include "Heimdall.h"
#include "HelpAction.h"
#include "Interface.h"
using namespace Heimdall;
const char *HelpAction::usage = "Action: help\n\
Description: Displays this dialogue.\n";
int HelpAction::Execute(int argc, char **argv)
{
Interface::PrintUsage();
return (0);
}

View File

@ -0,0 +1,34 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef HELPACTION_H
#define HELPACTION_H
namespace Heimdall
{
namespace HelpAction
{
extern const char *usage;
int Execute(int argc, char **argv);
}
}
#endif

View File

@ -0,0 +1,77 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef INBOUNDPACKET_H
#define INBOUNDPACKET_H
// Heimdall
#include "Packet.h"
namespace Heimdall
{
class InboundPacket : public Packet
{
private:
bool sizeVariable;
unsigned int receivedSize;
protected:
unsigned int UnpackInteger(unsigned int offset) const
{
#ifdef WORDS_BIGENDIAN
unsigned int value = (data[offset] << 24) | (data[offset + 1] << 16) |
(data[offset + 2] << 8) | data[offset + 3];
#else
// Flip endianness
unsigned int value = data[offset] | (data[offset + 1] << 8) |
(data[offset + 2] << 16) | (data[offset + 3] << 24);
#endif
return (value);
}
public:
InboundPacket(unsigned int size, bool sizeVariable = false) : Packet(size)
{
this->sizeVariable = sizeVariable;
}
bool IsSizeVariable(void) const
{
return (sizeVariable);
}
unsigned int GetReceivedSize(void) const
{
return (receivedSize);
}
void SetReceivedSize(unsigned int receivedSize)
{
this->receivedSize = receivedSize;
}
virtual bool Unpack(void) = 0;
};
}
#endif

View File

@ -0,0 +1,35 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// Heimdall
#include "Heimdall.h"
#include "InfoAction.h"
#include "Interface.h"
using namespace Heimdall;
const char *InfoAction::usage = "Action: info\n\
Description: Displays information about Heimdall.\n";
int InfoAction::Execute(int argc, char **argv)
{
Interface::PrintFullInfo();
return (0);
}

View File

@ -0,0 +1,34 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef INFOACTION_H
#define INFOACTION_H
namespace Heimdall
{
namespace InfoAction
{
extern const char *usage;
int Execute(int argc, char **argv);
}
}
#endif

View File

@ -0,0 +1,332 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// C/C++ Standard Library
#include <cstdarg>
#include <cstdlib>
#include <stdio.h>
// Heimdall
#include "ClosePcScreenAction.h"
#include "DetectAction.h"
#include "DownloadPitAction.h"
#include "FlashAction.h"
#include "HelpAction.h"
#include "InfoAction.h"
#include "Heimdall.h"
#include "Interface.h"
#include "PrintPitAction.h"
#include "VersionAction.h"
using namespace std;
using namespace libpit;
using namespace Heimdall;
map<string, Interface::ActionInfo> actionMap;
bool stdoutErrors = false;
const char *version = "v1.4.2";
const char *actionUsage = "Usage: heimdall <action> <action arguments>\n";
const char *releaseInfo = "Heimdall %s\n\n\
Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna\n\
http://www.glassechidna.com.au/\n\n\
This software is provided free of charge. Copying and redistribution is\nencouraged.\n\n\
If you appreciate this software and you would like to support future\ndevelopment please consider donating:\n\
http://www.glassechidna.com.au/donate/\n\n";
static const char *extraInfo = "Heimdall utilises libusbx for all USB communication:\n\
http://www.libusb.org/\n\
\n\
libusbx is licensed under the LGPL-2.1:\n\
http://www.gnu.org/licenses/licenses.html#LGPL\n\n";
void populateActionMap(void)
{
actionMap["close-pc-screen"] = Interface::ActionInfo(&ClosePcScreenAction::Execute, ClosePcScreenAction::usage);
actionMap["detect"] = Interface::ActionInfo(&DetectAction::Execute, DetectAction::usage);
actionMap["download-pit"] = Interface::ActionInfo(&DownloadPitAction::Execute, DownloadPitAction::usage);
actionMap["flash"] = Interface::ActionInfo(&FlashAction::Execute, FlashAction::usage);
actionMap["help"] = Interface::ActionInfo(&HelpAction::Execute, HelpAction::usage);
actionMap["info"] = Interface::ActionInfo(&InfoAction::Execute, InfoAction::usage);
actionMap["print-pit"] = Interface::ActionInfo(&PrintPitAction::Execute, PrintPitAction::usage);
actionMap["version"] = Interface::ActionInfo(&VersionAction::Execute, VersionAction::usage);
}
const map<string, Interface::ActionInfo>& Interface::GetActionMap(void)
{
if (actionMap.size() == 0)
populateActionMap();
return actionMap;
}
void Interface::Print(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stdout, format, args);
fflush(stdout);
va_end(args);
}
void Interface::PrintWarning(const char *format, ...)
{
va_list stderrArgs;
va_start(stderrArgs, format);
if (stdoutErrors)
{
va_list stdoutArgs;
va_copy(stdoutArgs, stderrArgs);
fprintf(stdout, "WARNING: ");
vfprintf(stdout, format, stdoutArgs);
fflush(stdout);
va_end(stdoutArgs);
}
fprintf(stderr, "WARNING: ");
vfprintf(stderr, format, stderrArgs);
fflush(stderr);
va_end(stderrArgs);
}
void Interface::PrintWarningSameLine(const char *format, ...)
{
va_list stderrArgs;
va_start(stderrArgs, format);
if (stdoutErrors)
{
va_list stdoutArgs;
va_copy(stdoutArgs, stderrArgs);
vfprintf(stdout, format, stdoutArgs);
fflush(stdout);
va_end(stdoutArgs);
}
vfprintf(stderr, format, stderrArgs);
fflush(stderr);
va_end(stderrArgs);
}
void Interface::PrintError(const char *format, ...)
{
va_list stderrArgs;
va_start(stderrArgs, format);
if (stdoutErrors)
{
va_list stdoutArgs;
va_copy(stdoutArgs, stderrArgs);
fprintf(stdout, "ERROR: ");
vfprintf(stdout, format, stdoutArgs);
fflush(stdout);
va_end(stdoutArgs);
}
fprintf(stderr, "ERROR: ");
vfprintf(stderr, format, stderrArgs);
fflush(stderr);
va_end(stderrArgs);
}
void Interface::PrintErrorSameLine(const char *format, ...)
{
va_list stderrArgs;
va_start(stderrArgs, format);
if (stdoutErrors)
{
va_list stdoutArgs;
va_copy(stdoutArgs, stderrArgs);
vfprintf(stdout, format, stdoutArgs);
fflush(stdout);
va_end(stdoutArgs);
}
vfprintf(stderr, format, stderrArgs);
fflush(stderr);
va_end(stderrArgs);
}
void Interface::PrintVersion(void)
{
Interface::Print("%s\n", version);
}
void Interface::PrintUsage(void)
{
const map<string, ActionInfo>& actionMap = Interface::GetActionMap();
Interface::Print(actionUsage);
for (map<string, ActionInfo>::const_iterator it = actionMap.begin(); it != actionMap.end(); it++)
Interface::Print("\n%s", it->second.usage);
}
void Interface::PrintReleaseInfo(void)
{
Interface::Print(releaseInfo, version);
}
void Interface::PrintFullInfo(void)
{
Interface::Print(releaseInfo, version);
Interface::Print(extraInfo);
}
void Interface::PrintDeviceDetectionFailed(void)
{
Interface::PrintError("Failed to detect compatible download-mode device.\n");
}
void Interface::PrintPit(const PitData *pitData)
{
Interface::Print("Entry Count: %d\n", pitData->GetEntryCount());
Interface::Print("Unknown 1: %d\n", pitData->GetUnknown1());
Interface::Print("Unknown 2: %d\n", pitData->GetUnknown2());
Interface::Print("Unknown 3: %d\n", pitData->GetUnknown3());
Interface::Print("Unknown 4: %d\n", pitData->GetUnknown4());
Interface::Print("Unknown 5: %d\n", pitData->GetUnknown5());
Interface::Print("Unknown 6: %d\n", pitData->GetUnknown6());
Interface::Print("Unknown 7: %d\n", pitData->GetUnknown7());
Interface::Print("Unknown 8: %d\n", pitData->GetUnknown8());
for (unsigned int i = 0; i < pitData->GetEntryCount(); i++)
{
const PitEntry *entry = pitData->GetEntry(i);
Interface::Print("\n\n--- Entry #%d ---\n", i);
Interface::Print("Binary Type: %d (", entry->GetBinaryType());
switch (entry->GetBinaryType())
{
case PitEntry::kBinaryTypeApplicationProcessor:
Interface::Print("AP");
break;
case PitEntry::kBinaryTypeCommunicationProcessor:
Interface::Print("CP");
break;
default:
Interface::Print("Unknown");
break;
}
Interface::Print(")\n");
Interface::Print("Device Type: %d (", entry->GetDeviceType());
switch (entry->GetDeviceType())
{
case PitEntry::kDeviceTypeOneNand:
Interface::Print("OneNAND");
break;
case PitEntry::kDeviceTypeFile:
Interface::Print("File/FAT");
break;
case PitEntry::kDeviceTypeMMC:
Interface::Print("MMC");
break;
case PitEntry::kDeviceTypeAll:
Interface::Print("All (?)");
break;
default:
Interface::Print("Unknown");
break;
}
Interface::Print(")\n");
Interface::Print("Identifier: %d\n", entry->GetIdentifier());
Interface::Print("Attributes: %d (", entry->GetAttributes());
if (entry->GetAttributes() & PitEntry::kAttributeSTL)
Interface::Print("STL ");
/*if (entry->GetAttributes() & PitEntry::kAttributeBML)
Interface::Print("BML ");*/
if (entry->GetAttributes() & PitEntry::kAttributeWrite)
Interface::Print("Read/Write");
else
Interface::Print("Read-Only");
Interface::Print(")\n");
Interface::Print("Update Attributes: %d", entry->GetUpdateAttributes());
if (entry->GetUpdateAttributes())
{
Interface::Print(" (");
if (entry->GetUpdateAttributes() & PitEntry::kUpdateAttributeFota)
{
if (entry->GetUpdateAttributes() & PitEntry::kUpdateAttributeSecure)
Interface::Print("FOTA, Secure");
else
Interface::Print("FOTA");
}
else
{
if (entry->GetUpdateAttributes() & PitEntry::kUpdateAttributeSecure)
Interface::Print("Secure");
}
Interface::Print(")\n");
}
else
{
Interface::Print("\n");
}
Interface::Print("Partition Block Size/Offset: %d\n", entry->GetBlockSizeOrOffset());
Interface::Print("Partition Block Count: %d\n", entry->GetBlockCount());
Interface::Print("File Offset (Obsolete): %d\n", entry->GetFileOffset());
Interface::Print("File Size (Obsolete): %d\n", entry->GetFileSize());
Interface::Print("Partition Name: %s\n", entry->GetPartitionName());
Interface::Print("Flash Filename: %s\n", entry->GetFlashFilename());
Interface::Print("FOTA Filename: %s\n", entry->GetFotaFilename());
}
Interface::Print("\n");
}
void Interface::SetStdoutErrors(bool enabled)
{
stdoutErrors = enabled;
}

View File

@ -0,0 +1,80 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef INTERFACE_H
#define INTERFACE_H
// C/C++ Standard Library
#include <map>
#include <string>
// libpit
#include "libpit.h"
// Heimdall
#include "Heimdall.h"
namespace Heimdall
{
namespace Interface
{
typedef int (*ActionExecuteFunction)(int, char **);
typedef struct ActionInfo
{
ActionExecuteFunction executeFunction;
const char *usage;
ActionInfo()
{
executeFunction = nullptr;
usage = nullptr;
}
ActionInfo(ActionExecuteFunction executeFunction, const char *usage)
{
this->executeFunction = executeFunction;
this->usage = usage;
}
} ActionInfo;
const std::map<std::string, ActionInfo>& GetActionMap(void);
void Print(const char *format, ...);
void PrintWarning(const char *format, ...);
void PrintWarningSameLine(const char *format, ...);
void PrintError(const char *format, ...);
void PrintErrorSameLine(const char *format, ...);
void PrintVersion(void);
void PrintUsage(void);
void PrintReleaseInfo(void);
void PrintFullInfo(void);
void PrintDeviceDetectionFailed(void);
void PrintPit(const libpit::PitData *pitData);
void SetStdoutErrors(bool enabled);
}
}
#endif

View File

@ -0,0 +1,71 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef OUTBOUNDPACKET_H
#define OUTBOUNDPACKET_H
// Heimdall
#include "Packet.h"
namespace Heimdall
{
class OutboundPacket : public Packet
{
protected:
void PackInteger(unsigned int offset, unsigned int value)
{
#ifdef WORDS_BIGENDIAN
data[offset] = (value & 0xFF000000) >> 24;
data[offset + 1] = (value & 0x00FF0000) >> 16;
data[offset + 2] = (value & 0x0000FF00) >> 8;
data[offset + 3] = value & 0x000000FF;
#else
// Flip endianness
data[offset] = value & 0x000000FF;
data[offset + 1] = (value & 0x0000FF00) >> 8;
data[offset + 2] = (value & 0x00FF0000) >> 16;
data[offset + 3] = (value & 0xFF000000) >> 24;
#endif
}
void PackShort(unsigned int offset, unsigned short value)
{
#ifdef WORDS_BIGENDIAN
data[offset] = (value & 0xFF00) >> 8;
data[offset + 1] = value & 0x00FF;
#else
// Flip endianness
data[offset] = value & 0x00FF;
data[offset + 1] = (value & 0xFF00) >> 8;
#endif
}
public:
OutboundPacket(unsigned int size) : Packet(size)
{
}
virtual void Pack(void) = 0;
};
}
#endif

65
heimdall/source/Packet.h Normal file
View File

@ -0,0 +1,65 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef PACKET_H
#define PACKET_H
// C++ Standard Library
#include <cstring>
namespace Heimdall
{
class Packet
{
private:
unsigned int size;
protected:
unsigned char *data;
public:
Packet(unsigned int size)
{
this->size = size;
data = new unsigned char[size];
memset(data, 0, size);
}
~Packet()
{
delete [] data;
}
unsigned int GetSize(void) const
{
return (size);
}
unsigned char *GetData(void)
{
return (data);
}
};
}
#endif

View File

@ -0,0 +1,73 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef PITFILEPACKET_H
#define PITFILEPACKET_H
// Heimdall
#include "ControlPacket.h"
namespace Heimdall
{
class PitFilePacket : public ControlPacket
{
public:
enum
{
kRequestFlash = 0x00,
kRequestDump = 0x01,
kRequestPart = 0x02,
kRequestEndTransfer = 0x03
};
protected:
enum
{
kDataSize = ControlPacket::kDataSize + 4
};
private:
unsigned int request;
public:
PitFilePacket(unsigned int request) : ControlPacket(ControlPacket::kControlTypePitFile)
{
this->request = request;
}
unsigned int GetRequest(void) const
{
return (request);
}
void Pack(void)
{
ControlPacket::Pack();
PackInteger(ControlPacket::kDataSize, request);
}
};
}
#endif

View File

@ -0,0 +1,58 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef PITFILERESPONSE_H
#define PITFILERESPONSE_H
// Heimdall
#include "ResponsePacket.h"
namespace Heimdall
{
class PitFileResponse : public ResponsePacket
{
private:
unsigned int fileSize;
public:
PitFileResponse() : ResponsePacket(ResponsePacket::kResponseTypePitFile)
{
}
unsigned int GetFileSize(void) const
{
return (fileSize);
}
bool Unpack(void)
{
if (!ResponsePacket::Unpack())
return (false);
fileSize = UnpackInteger(ResponsePacket::kDataSize);
return (true);
}
};
}
#endif

View File

@ -0,0 +1,197 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// C Standard Library
#include <stdio.h>
// Heimdall
#include "Arguments.h"
#include "BridgeManager.h"
#include "Heimdall.h"
#include "Interface.h"
#include "PrintPitAction.h"
using namespace std;
using namespace libpit;
using namespace Heimdall;
const char *PrintPitAction::usage = "Action: print-pit\n\
Arguments: [--file <filename>] [--verbose] [--no-reboot] [--stdout-errors]\n\
[--usb-log-level <none/error/warning/debug>]\n\
Description: Prints the contents of a PIT file in a human readable format. If\n\
a filename is not provided then Heimdall retrieves the PIT file from the \n\
connected device.\n\
Note: --no-reboot causes the device to remain in download mode after the action\n\
is completed. If you wish to perform another action whilst remaining in\n\
download mode, then the following action must specify the --resume flag.\n";
int PrintPitAction::Execute(int argc, char **argv)
{
// Handle arguments
map<string, ArgumentType> argumentTypes;
argumentTypes["file"] = kArgumentTypeString;
argumentTypes["no-reboot"] = kArgumentTypeFlag;
argumentTypes["resume"] = kArgumentTypeFlag;
argumentTypes["verbose"] = kArgumentTypeFlag;
argumentTypes["stdout-errors"] = kArgumentTypeFlag;
argumentTypes["usb-log-level"] = kArgumentTypeString;
Arguments arguments(argumentTypes);
if (!arguments.ParseArguments(argc, argv, 2))
{
Interface::Print(PrintPitAction::usage);
return (0);
}
const StringArgument *fileArgument = static_cast<const StringArgument *>(arguments.GetArgument("file"));
bool reboot = arguments.GetArgument("no-reboot") == nullptr;
bool resume = arguments.GetArgument("resume") != nullptr;
bool verbose = arguments.GetArgument("verbose") != nullptr;
if (arguments.GetArgument("stdout-errors") != nullptr)
Interface::SetStdoutErrors(true);
const StringArgument *usbLogLevelArgument = static_cast<const StringArgument *>(arguments.GetArgument("usb-log-level"));
BridgeManager::UsbLogLevel usbLogLevel = BridgeManager::UsbLogLevel::Default;
if (usbLogLevelArgument)
{
const string& usbLogLevelString = usbLogLevelArgument->GetValue();
if (usbLogLevelString.compare("none") == 0 || usbLogLevelString.compare("NONE") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::None;
}
else if (usbLogLevelString.compare("error") == 0 || usbLogLevelString.compare("ERROR") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Error;
}
else if (usbLogLevelString.compare("warning") == 0 || usbLogLevelString.compare("WARNING") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Warning;
}
else if (usbLogLevelString.compare("info") == 0 || usbLogLevelString.compare("INFO") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Info;
}
else if (usbLogLevelString.compare("debug") == 0 || usbLogLevelString.compare("DEBUG") == 0)
{
usbLogLevel = BridgeManager::UsbLogLevel::Debug;
}
else
{
Interface::Print("Unknown USB log level: %s\n\n", usbLogLevelString.c_str());
Interface::Print(PrintPitAction::usage);
return (0);
}
}
// Open file (if specified).
FILE *localPitFile = nullptr;
if (fileArgument)
{
const char *filename = fileArgument->GetValue().c_str();
localPitFile = FileOpen(filename, "rb");
if (!localPitFile)
{
Interface::PrintError("Failed to open file \"%s\"\n", filename);
return (1);
}
}
// Info
Interface::PrintReleaseInfo();
Sleep(1000);
if (localPitFile)
{
// Print PIT from file; there's no need for a BridgeManager.
FileSeek(localPitFile, 0, SEEK_END);
unsigned int localPitFileSize = (unsigned int)FileTell(localPitFile);
FileRewind(localPitFile);
// Load the local pit file into memory.
unsigned char *pitFileBuffer = new unsigned char[localPitFileSize];
(void)fread(pitFileBuffer, 1, localPitFileSize, localPitFile);
FileClose(localPitFile);
PitData *pitData = new PitData();
pitData->Unpack(pitFileBuffer);
delete [] pitFileBuffer;
Interface::PrintPit(pitData);
delete pitData;
return (0);
}
else
{
// Print PIT from a device.
BridgeManager *bridgeManager = new BridgeManager(verbose);
bridgeManager->SetUsbLogLevel(usbLogLevel);
if (bridgeManager->Initialise(resume) != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession())
{
delete bridgeManager;
return (1);
}
unsigned char *devicePit;
bool success = bridgeManager->DownloadPitFile(&devicePit) != 0;
if (success)
{
PitData *pitData = new PitData();
if (pitData->Unpack(devicePit))
{
Interface::PrintPit(pitData);
}
else
{
Interface::PrintError("Failed to unpack device's PIT file!\n");
success = false;
}
delete pitData;
}
delete [] devicePit;
if (!bridgeManager->EndSession(reboot))
success = false;
delete bridgeManager;
return (success ? 0 : 1);
}
}

View File

@ -0,0 +1,34 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef PRINTPITACTION_H
#define PRINTPITACTION_H
namespace Heimdall
{
namespace PrintPitAction
{
extern const char *usage;
int Execute(int argc, char **argv);
}
}
#endif

View File

@ -0,0 +1,49 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef RECEIVEFILEPARTPACKET_H
#define RECEIVEFILEPARTPACKET_H
// Heimdall
#include "InboundPacket.h"
namespace Heimdall
{
class ReceiveFilePartPacket : public InboundPacket
{
public:
enum
{
kDataSize = 500
};
ReceiveFilePartPacket() : InboundPacket(kDataSize, true)
{
}
bool Unpack(void)
{
return (true);
}
};
}
#endif

View File

@ -0,0 +1,79 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef RESPONSEPACKET_H
#define RESPONSEPACKET_H
// Heimdall
#include "InboundPacket.h"
namespace Heimdall
{
class ResponsePacket : public InboundPacket
{
public:
enum
{
kResponseTypeSendFilePart = 0x00,
kResponseTypeSessionSetup = 0x64,
kResponseTypePitFile = 0x65,
kResponseTypeFileTransfer = 0x66,
kResponseTypeEndSession = 0x67
};
private:
unsigned int responseType;
protected:
enum
{
kDataSize = 4
};
public:
ResponsePacket(int responseType) : InboundPacket(8)
{
this->responseType = responseType;
}
unsigned int GetResponseType(void) const
{
return (responseType);
}
virtual bool Unpack(void)
{
unsigned int receivedResponseType = UnpackInteger(0);
if (receivedResponseType != responseType)
{
responseType = receivedResponseType;
return (false);
}
return (true);
}
};
}
#endif

View File

@ -0,0 +1,63 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef SENDFILEPARTPACKET_H
#define SENDFILEPARTPACKET_H
// C Standard Library
#include <stdio.h>
#include <string.h>
// Heimdall
#include "Packet.h"
namespace Heimdall
{
class SendFilePartPacket : public OutboundPacket
{
public:
SendFilePartPacket(FILE *file, unsigned int size) : OutboundPacket(size)
{
memset(data, 0, size);
unsigned int position = (unsigned int)FileTell(file);
FileSeek(file, 0, SEEK_END);
unsigned int fileSize = (unsigned int)FileTell(file);
FileSeek(file, position, SEEK_SET);
// min(fileSize, size)
unsigned int bytesToRead = (fileSize < size) ? fileSize - position : size;
(void)fread(data, 1, bytesToRead, file);
}
SendFilePartPacket(unsigned char *buffer, unsigned int size) : OutboundPacket(size)
{
memcpy(data, buffer, size);
}
void Pack(void)
{
}
};
}
#endif

View File

@ -0,0 +1,58 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef SENDFILEPARTRESPONSE_H
#define SENDFILEPARTRESPONSE_H
// Heimdall
#include "ResponsePacket.h"
namespace Heimdall
{
class SendFilePartResponse : public ResponsePacket
{
private:
unsigned int partIndex;
public:
SendFilePartResponse() : ResponsePacket(ResponsePacket::kResponseTypeSendFilePart)
{
}
unsigned int GetPartIndex(void) const
{
return (partIndex);
}
bool Unpack(void)
{
if (!ResponsePacket::Unpack())
return (false);
partIndex = UnpackInteger(ResponsePacket::kDataSize);
return (true);
}
};
}
#endif

View File

@ -0,0 +1,75 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef SESSIONSETUPPACKET_H
#define SESSIONSETUPPACKET_H
// Heimdall
#include "ControlPacket.h"
namespace Heimdall
{
class SessionSetupPacket : public ControlPacket
{
public:
enum
{
kBeginSession = 0,
kDeviceType = 1, // ?
kTotalBytes = 2,
//kEnableSomeSortOfFlag = 3,
kFilePartSize = 5,
kEnableTFlash = 8
};
private:
unsigned int request;
protected:
enum
{
kDataSize = ControlPacket::kDataSize + 4
};
public:
SessionSetupPacket(unsigned int request) : ControlPacket(ControlPacket::kControlTypeSession)
{
this->request = request;
}
unsigned int GetRequest(void) const
{
return (request);
}
void Pack(void)
{
ControlPacket::Pack();
PackInteger(ControlPacket::kDataSize, request);
}
};
}
#endif

View File

@ -0,0 +1,58 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef SESSIONSETUPRESPONSE_H
#define SESSIONSETUPRESPONSE_H
// Heimdall
#include "ResponsePacket.h"
namespace Heimdall
{
class SessionSetupResponse : public ResponsePacket
{
private:
unsigned int result;
public:
SessionSetupResponse() : ResponsePacket(ResponsePacket::kResponseTypeSessionSetup)
{
}
unsigned int GetResult(void) const
{
return (result);
}
bool Unpack(void)
{
if (!ResponsePacket::Unpack())
return (false);
result = UnpackInteger(ResponsePacket::kDataSize);
return (true);
}
};
}
#endif

View File

@ -0,0 +1,74 @@
/* Copyright (c) 2010-2012 Benjamin Dobell, Glass Echidna
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.*/
#ifndef SETUPSESSIONPACKET_H
#define SETUPSESSIONPACKET_H
// Heimdall
#include "ControlPacket.h"
namespace Heimdall
{
class SetupSessionPacket : public ControlPacket
{
public:
enum
{
kBeginSession = 0,
kDeviceInfo = 1,
kTotalBytes = 2
};
private:
unsigned int request;
unsigned int unknown3Parameter;
public:
SetupSessionPacket(unsigned int request, unsigned int unknown3Parameter = 0)
: ControlPacket(ControlPacket::kControlTypeSetupSession)
{
this->request = request;
this->unknown3Parameter = unknown3Parameter;
}
unsigned int GetRequest(void) const
{
return (request);
}
unsigned int GetUnknown3Parameter(void) const
{
return (unknown3Parameter);
}
void Pack(void)
{
ControlPacket::Pack();
PackInteger(ControlPacket::kDataSize, request);
PackInteger(ControlPacket::kDataSize + 4, unknown3Parameter);
}
};
}
#endif

View File

@ -0,0 +1,58 @@
/* Copyright (c) 2010-2012 Benjamin Dobell, Glass Echidna
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.*/
#ifndef SETUPSESSIONRESPONSE_H
#define SETUPSESSIONRESPONSE_H
// Heimdall
#include "ResponsePacket.h"
namespace Heimdall
{
class SetupSessionResponse : public ResponsePacket
{
private:
unsigned int unknown;
public:
SetupSessionResponse() : ResponsePacket(ResponsePacket::kResponseTypeBeginSession)
{
}
unsigned int GetUnknown(void) const
{
return (unknown);
}
bool Unpack(void)
{
if (!ResponsePacket::Unpack())
return (false);
unknown = UnpackInteger(ResponsePacket::kDataSize);
return (true);
}
};
}
#endif

View File

@ -0,0 +1,56 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef TOTALBYTESPACKET_H
#define TOTALBYTESPACKET_H
// Heimdall
#include "SessionSetupPacket.h"
namespace Heimdall
{
class TotalBytesPacket : public SessionSetupPacket
{
private:
unsigned int totalBytes;
public:
TotalBytesPacket(unsigned int totalBytes) : SessionSetupPacket(SessionSetupPacket::kTotalBytes)
{
this->totalBytes = totalBytes;
}
unsigned int GetTotalBytes(void) const
{
return (totalBytes);
}
void Pack(void)
{
SessionSetupPacket::Pack();
PackInteger(SessionSetupPacket::kDataSize, totalBytes);
}
};
}
#endif

View File

@ -0,0 +1,82 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// C/C++ Standard Library
#include <cerrno>
#include <limits.h>
#include <stdlib.h>
// Heimdall
#include "Heimdall.h"
#include "Utility.h"
using namespace Heimdall;
NumberParsingStatus Utility::ParseInt(int &intValue, const char *string, int base)
{
errno = 0;
char *end;
long longValue = strtol(string, &end, base);
if (*string == '\0' || *end != '\0')
{
return (kNumberParsingStatusInconvertible);
}
else if (errno == ERANGE)
{
intValue = (longValue == LONG_MAX) ? INT_MAX : INT_MIN;
return (kNumberParsingStatusRangeError);
}
else if (longValue > INT_MAX)
{
intValue = INT_MAX;
return (kNumberParsingStatusRangeError);
}
else if (longValue < INT_MIN)
{
intValue = INT_MIN;
return (kNumberParsingStatusRangeError);
}
intValue = longValue;
return (kNumberParsingStatusSuccess);
}
NumberParsingStatus Utility::ParseUnsignedInt(unsigned int &uintValue, const char *string, int base)
{
errno = 0;
char *end;
unsigned long ulongValue = strtoul(string, &end, base);
if (*string == '\0' || *end != '\0')
{
return kNumberParsingStatusInconvertible;
}
else if (errno == ERANGE || ulongValue > INT_MAX)
{
uintValue = UINT_MAX;
return (kNumberParsingStatusRangeError);
}
uintValue = ulongValue;
return (kNumberParsingStatusSuccess);
}

40
heimdall/source/Utility.h Normal file
View File

@ -0,0 +1,40 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef UTILITY_H
#define UTILITY_H
namespace Heimdall
{
typedef enum
{
kNumberParsingStatusSuccess = 0,
kNumberParsingStatusRangeError,
kNumberParsingStatusInconvertible
} NumberParsingStatus;
namespace Utility
{
NumberParsingStatus ParseInt(int &intValue, const char *string, int base = 0);
NumberParsingStatus ParseUnsignedInt(unsigned int &uintValue, const char *string, int base = 0);
}
}
#endif

View File

@ -0,0 +1,35 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// Heimdall
#include "Heimdall.h"
#include "Interface.h"
#include "VersionAction.h"
using namespace Heimdall;
const char *VersionAction::usage = "Action: version\n\
Description: Displays the version number of this binary.\n";
int VersionAction::Execute(int argc, char **argv)
{
Interface::PrintVersion();
return (0);
}

View File

@ -0,0 +1,34 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef VERSIONACTION_H
#define VERSIONACTION_H
namespace Heimdall
{
namespace VersionAction
{
extern const char *usage;
int Execute(int argc, char **argv);
}
}
#endif

55
heimdall/source/main.cpp Normal file
View File

@ -0,0 +1,55 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// C/C++ Standard Library
#include <algorithm>
#include <map>
#include <stdio.h>
#include <string>
// libpit
#include "libpit.h"
// Heimdall
#include "Heimdall.h"
#include "HelpAction.h"
#include "Interface.h"
using namespace std;
using namespace Heimdall;
int main(int argc, char **argv)
{
if (argc < 2)
{
Interface::PrintUsage();
return (0);
}
int result = 0;
map<string, Interface::ActionInfo>::const_iterator actionIt = Interface::GetActionMap().find(argv[1]);
if (actionIt != Interface::GetActionMap().end())
result = actionIt->second.executeFunction(argc, argv);
else
result = HelpAction::Execute(argc, argv);
return (result);
}

9
libpit/CMakeLists.txt Normal file
View File

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 2.8.4)
project(libpit)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
set(LIBPIT_SOURCE_FILES
source/libpit.cpp)
add_library(pit STATIC ${LIBPIT_SOURCE_FILES})

296
libpit/source/libpit.cpp Normal file
View File

@ -0,0 +1,296 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
// libpit
#include "libpit.h"
using namespace libpit;
PitEntry::PitEntry()
{
binaryType = false;
deviceType = 0;
identifier = 0;
attributes = 0;
updateAttributes = 0;
blockSizeOrOffset = 0;
blockCount = 0;
fileOffset = 0;
fileSize = 0;
memset(partitionName, 0, PitEntry::kPartitionNameMaxLength);
memset(flashFilename, 0, PitEntry::kFlashFilenameMaxLength);
memset(fotaFilename, 0, PitEntry::kFotaFilenameMaxLength);
}
PitEntry::~PitEntry()
{
}
bool PitEntry::Matches(const PitEntry *otherPitEntry) const
{
if (binaryType == otherPitEntry->binaryType && deviceType == otherPitEntry->deviceType && identifier == otherPitEntry->identifier
&& attributes == otherPitEntry->attributes && updateAttributes == otherPitEntry->updateAttributes && blockSizeOrOffset == otherPitEntry->blockSizeOrOffset
&& blockCount == otherPitEntry->blockCount && fileOffset == otherPitEntry->fileOffset && fileSize == otherPitEntry->fileSize
&& strcmp(partitionName, otherPitEntry->partitionName) == 0 && strcmp(flashFilename, otherPitEntry->flashFilename) == 0
&& strcmp(fotaFilename, otherPitEntry->fotaFilename) == 0)
{
return (true);
}
else
{
return (false);
}
}
PitData::PitData()
{
entryCount = 0;
unknown1 = 0;
unknown2 = 0;
unknown3 = 0;
unknown4 = 0;
unknown5 = 0;
unknown6 = 0;
unknown7 = 0;
unknown8 = 0;
}
PitData::~PitData()
{
for (unsigned int i = 0; i < entries.size(); i++)
delete entries[i];
}
bool PitData::Unpack(const unsigned char *data)
{
if (PitData::UnpackInteger(data, 0) != PitData::kFileIdentifier)
return (false);
// Remove existing entries
for (unsigned int i = 0; i < entries.size(); i++)
delete entries[i];
entryCount = PitData::UnpackInteger(data, 4);
entries.resize(entryCount);
unknown1 = PitData::UnpackInteger(data, 8);
unknown2 = PitData::UnpackInteger(data, 12);
unknown3 = PitData::UnpackShort(data, 16);
unknown4 = PitData::UnpackShort(data, 18);
unknown5 = PitData::UnpackShort(data, 20);
unknown6 = PitData::UnpackShort(data, 22);
unknown7 = PitData::UnpackShort(data, 24);
unknown8 = PitData::UnpackShort(data, 26);
unsigned int integerValue;
unsigned int entryOffset;
for (unsigned int i = 0; i < entryCount; i++)
{
entryOffset = PitData::kHeaderDataSize + i * PitEntry::kDataSize;
entries[i] = new PitEntry();
integerValue = PitData::UnpackInteger(data, entryOffset);
entries[i]->SetBinaryType(integerValue);
integerValue = PitData::UnpackInteger(data, entryOffset + 4);
entries[i]->SetDeviceType(integerValue);
integerValue = PitData::UnpackInteger(data, entryOffset + 8);
entries[i]->SetIdentifier(integerValue);
integerValue = PitData::UnpackInteger(data, entryOffset + 12);
entries[i]->SetAttributes(integerValue);
integerValue = PitData::UnpackInteger(data, entryOffset + 16);
entries[i]->SetUpdateAttributes(integerValue);
integerValue = PitData::UnpackInteger(data, entryOffset + 20);
entries[i]->SetBlockSizeOrOffset(integerValue);
integerValue = PitData::UnpackInteger(data, entryOffset + 24);
entries[i]->SetBlockCount(integerValue);
integerValue = PitData::UnpackInteger(data, entryOffset + 28);
entries[i]->SetFileOffset(integerValue);
integerValue = PitData::UnpackInteger(data, entryOffset + 32);
entries[i]->SetFileSize(integerValue);
entries[i]->SetPartitionName((const char *)data + entryOffset + 36);
entries[i]->SetFlashFilename((const char *)data + entryOffset + 36 + PitEntry::kPartitionNameMaxLength);
entries[i]->SetFotaFilename((const char *)data + entryOffset + 36 + PitEntry::kPartitionNameMaxLength + PitEntry::kFlashFilenameMaxLength);
}
return (true);
}
void PitData::Pack(unsigned char *data) const
{
PitData::PackInteger(data, 0, PitData::kFileIdentifier);
PitData::PackInteger(data, 4, entryCount);
PitData::PackInteger(data, 8, unknown1);
PitData::PackInteger(data, 12, unknown2);
PitData::PackShort(data, 16, unknown3);
PitData::PackShort(data, 18, unknown4);
PitData::PackShort(data, 20, unknown5);
PitData::PackShort(data, 22, unknown6);
PitData::PackShort(data, 24, unknown7);
PitData::PackShort(data, 26, unknown8);
int entryOffset;
for (unsigned int i = 0; i < entryCount; i++)
{
entryOffset = PitData::kHeaderDataSize + i * PitEntry::kDataSize;
PitData::PackInteger(data, entryOffset, entries[i]->GetBinaryType());
PitData::PackInteger(data, entryOffset + 4, entries[i]->GetDeviceType());
PitData::PackInteger(data, entryOffset + 8, entries[i]->GetIdentifier());
PitData::PackInteger(data, entryOffset + 12, entries[i]->GetAttributes());
PitData::PackInteger(data, entryOffset + 16, entries[i]->GetUpdateAttributes());
PitData::PackInteger(data, entryOffset + 20, entries[i]->GetBlockSizeOrOffset());
PitData::PackInteger(data, entryOffset + 24, entries[i]->GetBlockCount());
PitData::PackInteger(data, entryOffset + 28, entries[i]->GetFileOffset());
PitData::PackInteger(data, entryOffset + 32, entries[i]->GetFileSize());
memcpy(data + entryOffset + 36, entries[i]->GetPartitionName(), PitEntry::kPartitionNameMaxLength);
memcpy(data + entryOffset + 36 + PitEntry::kPartitionNameMaxLength, entries[i]->GetFlashFilename(), PitEntry::kFlashFilenameMaxLength);
memcpy(data + entryOffset + 36 + PitEntry::kPartitionNameMaxLength + PitEntry::kFlashFilenameMaxLength,
entries[i]->GetFotaFilename(), PitEntry::kFotaFilenameMaxLength);
}
}
bool PitData::Matches(const PitData *otherPitData) const
{
if (entryCount == otherPitData->entryCount && unknown1 == otherPitData->unknown1 && unknown2 == otherPitData->unknown2
&& unknown3 == otherPitData->unknown3 && unknown4 == otherPitData->unknown4 && unknown5 == otherPitData->unknown5
&& unknown6 == otherPitData->unknown6 && unknown7 == otherPitData->unknown7 && unknown8 == otherPitData->unknown8)
{
for (unsigned int i = 0; i < entryCount; i++)
{
if (!entries[i]->Matches(otherPitData->entries[i]))
return (false);
}
return (true);
}
else
{
return (false);
}
}
void PitData::Clear(void)
{
entryCount = 0;
unknown1 = 0;
unknown2 = 0;
unknown3 = 0;
unknown4 = 0;
unknown5 = 0;
unknown6 = 0;
unknown7 = 0;
unknown8 = 0;
for (unsigned int i = 0; i < entries.size(); i++)
delete entries[i];
entries.clear();
}
PitEntry *PitData::GetEntry(unsigned int index)
{
return (entries[index]);
}
const PitEntry *PitData::GetEntry(unsigned int index) const
{
return (entries[index]);
}
PitEntry *PitData::FindEntry(const char *partitionName)
{
for (unsigned int i = 0; i < entries.size(); i++)
{
if (entries[i]->IsFlashable() && strcmp(entries[i]->GetPartitionName(), partitionName) == 0)
return (entries[i]);
}
return (nullptr);
}
const PitEntry *PitData::FindEntry(const char *partitionName) const
{
for (unsigned int i = 0; i < entries.size(); i++)
{
if (entries[i]->IsFlashable() && strcmp(entries[i]->GetPartitionName(), partitionName) == 0)
return (entries[i]);
}
return (nullptr);
}
PitEntry *PitData::FindEntry(unsigned int partitionIdentifier)
{
for (unsigned int i = 0; i < entries.size(); i++)
{
if (entries[i]->IsFlashable() && entries[i]->GetIdentifier() == partitionIdentifier)
return (entries[i]);
}
return (nullptr);
}
const PitEntry *PitData::FindEntry(unsigned int partitionIdentifier) const
{
for (unsigned int i = 0; i < entries.size(); i++)
{
if (entries[i]->IsFlashable() && entries[i]->GetIdentifier() == partitionIdentifier)
return (entries[i]);
}
return (nullptr);
}

417
libpit/source/libpit.h Normal file
View File

@ -0,0 +1,417 @@
/* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
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.*/
#ifndef LIBPIT_H
#define LIBPIT_H
#ifdef WIN32
#pragma warning(disable : 4996)
#endif
#if (!(defined _MSC_VER) || (_MSC_VER < 1700))
#ifndef nullptr
#define nullptr 0
#endif
#endif
// C/C++ Standard Library
#include <cstring>
#include <string>
#include <vector>
namespace libpit
{
class PitEntry
{
public:
enum
{
kDataSize = 132,
kPartitionNameMaxLength = 32,
kFlashFilenameMaxLength = 32,
kFotaFilenameMaxLength = 32
};
enum
{
kBinaryTypeApplicationProcessor = 0,
kBinaryTypeCommunicationProcessor = 1
};
enum
{
kDeviceTypeOneNand = 0,
kDeviceTypeFile, // FAT
kDeviceTypeMMC,
kDeviceTypeAll // ?
};
enum
{
kAttributeWrite = 1,
kAttributeSTL = 1 << 1/*,
kAttributeBML = 1 << 2*/ // ???
};
enum
{
kUpdateAttributeFota = 1,
kUpdateAttributeSecure = 1 << 1
};
private:
unsigned int binaryType;
unsigned int deviceType;
unsigned int identifier;
unsigned int attributes;
unsigned int updateAttributes;
unsigned int blockSizeOrOffset;
unsigned int blockCount;
unsigned int fileOffset; // Obsolete
unsigned int fileSize; // Obsolete
char partitionName[kPartitionNameMaxLength];
char flashFilename[kFlashFilenameMaxLength]; // USB flash filename
char fotaFilename[kFotaFilenameMaxLength]; // Firmware over the air
public:
PitEntry();
~PitEntry();
bool Matches(const PitEntry *otherPitEntry) const;
bool IsFlashable(void) const
{
return strlen(partitionName) != 0;
}
unsigned int GetBinaryType(void) const
{
return binaryType;
}
void SetBinaryType(unsigned int binaryType)
{
this->binaryType = binaryType;
}
unsigned int GetDeviceType(void) const
{
return deviceType;
}
void SetDeviceType(unsigned int deviceType)
{
this->deviceType = deviceType;
}
unsigned int GetIdentifier(void) const
{
return identifier;
}
void SetIdentifier(unsigned int identifier)
{
this->identifier = identifier;
}
unsigned int GetAttributes(void) const
{
return attributes;
}
void SetAttributes(unsigned int attributes)
{
this->attributes = attributes;
}
unsigned int GetUpdateAttributes(void) const
{
return updateAttributes;
}
void SetUpdateAttributes(unsigned int updateAttributes)
{
this->updateAttributes = updateAttributes;
}
// Different versions of Loke (secondary bootloaders) on different devices intepret this differently.
unsigned int GetBlockSizeOrOffset(void) const
{
return blockSizeOrOffset;
}
void SetBlockSizeOrOffset(unsigned int blockSizeOrOffset)
{
this->blockSizeOrOffset = blockSizeOrOffset;
}
unsigned int GetBlockCount(void) const
{
return blockCount;
}
void SetBlockCount(unsigned int blockCount)
{
this->blockCount = blockCount;
}
unsigned int GetFileOffset(void) const
{
return fileOffset;
}
void SetFileOffset(unsigned int fileOffset)
{
this->fileOffset = fileOffset;
}
unsigned int GetFileSize(void) const
{
return fileSize;
}
void SetFileSize(unsigned int fileSize)
{
this->fileSize = fileSize;
}
const char *GetPartitionName(void) const
{
return partitionName;
}
void SetPartitionName(const char *partitionName)
{
// This isn't strictly necessary but ensures no junk is left in our PIT file.
memset(this->partitionName, 0, kPartitionNameMaxLength);
if (strlen(partitionName) < kPartitionNameMaxLength)
strcpy(this->partitionName, partitionName);
else
memcpy(this->partitionName, partitionName, kPartitionNameMaxLength - 1);
}
const char *GetFlashFilename(void) const
{
return flashFilename;
}
void SetFlashFilename(const char *flashFilename)
{
// This isn't strictly necessary but ensures no junk is left in our PIT file.
memset(this->flashFilename, 0, kFlashFilenameMaxLength);
if (strlen(partitionName) < kFlashFilenameMaxLength)
strcpy(this->flashFilename, flashFilename);
else
memcpy(this->flashFilename, flashFilename, kFlashFilenameMaxLength - 1);
}
const char *GetFotaFilename(void) const
{
return fotaFilename;
}
void SetFotaFilename(const char *fotaFilename)
{
// This isn't strictly necessary but ensures no junk is left in our PIT file.
memset(this->fotaFilename, 0, kFotaFilenameMaxLength);
if (strlen(partitionName) < kFotaFilenameMaxLength)
strcpy(this->fotaFilename, fotaFilename);
else
memcpy(this->fotaFilename, fotaFilename, kFotaFilenameMaxLength - 1);
}
};
class PitData
{
public:
enum
{
kFileIdentifier = 0x12349876,
kHeaderDataSize = 28,
kPaddedSizeMultiplicand = 4096
};
private:
unsigned int entryCount; // 0x04
unsigned int unknown1; // 0x08
unsigned int unknown2; // 0x0C
unsigned short unknown3; // 0x10
unsigned short unknown4; // 0x12
unsigned short unknown5; // 0x14
unsigned short unknown6; // 0x16
unsigned short unknown7; // 0x18
unsigned short unknown8; // 0x1A
// Entries start at 0x1C
std::vector<PitEntry *> entries;
static int UnpackInteger(const unsigned char *data, unsigned int offset)
{
#ifdef WORDS_BIGENDIAN
int value = (data[offset] << 24) | (data[offset + 1] << 16) |
(data[offset + 2] << 8) | data[offset + 3];
#else
// Flip endianness
int value = data[offset] | (data[offset + 1] << 8) |
(data[offset + 2] << 16) | (data[offset + 3] << 24);
#endif
return (value);
}
static int UnpackShort(const unsigned char *data, unsigned int offset)
{
#ifdef WORDS_BIGENDIAN
short value = (data[offset] << 8) | data[offset + 1];
#else
// Flip endianness
short value = data[offset] | (data[offset + 1] << 8);
#endif
return (value);
}
static void PackInteger(unsigned char *data, unsigned int offset, unsigned int value)
{
#ifdef WORDS_BIGENDIAN
data[offset] = (value & 0xFF000000) >> 24;
data[offset + 1] = (value & 0x00FF0000) >> 16;
data[offset + 2] = (value & 0x0000FF00) >> 8;
data[offset + 3] = value & 0x000000FF;
#else
// Flip endianness
data[offset] = value & 0x000000FF;
data[offset + 1] = (value & 0x0000FF00) >> 8;
data[offset + 2] = (value & 0x00FF0000) >> 16;
data[offset + 3] = (value & 0xFF000000) >> 24;
#endif
}
static void PackShort(unsigned char *data, unsigned int offset, unsigned short value)
{
#ifdef WORDS_BIGENDIAN
data[offset] = (value & 0xFF00) >> 8;
data[offset + 1] = value & 0x00FF;
#else
// Flip endianness
data[offset] = value & 0x00FF;
data[offset + 1] = (value & 0xFF00) >> 8;
#endif
}
public:
PitData();
~PitData();
bool Unpack(const unsigned char *data);
void Pack(unsigned char *data) const;
bool Matches(const PitData *otherPitData) const;
void Clear(void);
PitEntry *GetEntry(unsigned int index);
const PitEntry *GetEntry(unsigned int index) const;
PitEntry *FindEntry(const char *partitionName);
const PitEntry *FindEntry(const char *partitionName) const;
PitEntry *FindEntry(unsigned int partitionIdentifier);
const PitEntry *FindEntry(unsigned int partitionIdentifier) const;
unsigned int GetEntryCount(void) const
{
return entryCount;
}
unsigned int GetDataSize(void) const
{
return PitData::kHeaderDataSize + entryCount * PitEntry::kDataSize;
}
unsigned int GetPaddedSize(void) const
{
unsigned int dataSize = GetDataSize();
unsigned int paddedSize = (dataSize / kPaddedSizeMultiplicand) * kPaddedSizeMultiplicand;
if (dataSize % kPaddedSizeMultiplicand != 0)
paddedSize += kPaddedSizeMultiplicand;
return paddedSize;
}
unsigned int GetUnknown1(void) const
{
return unknown1;
}
unsigned int GetUnknown2(void) const
{
return unknown2;
}
unsigned short GetUnknown3(void) const
{
return unknown3;
}
unsigned short GetUnknown4(void) const
{
return unknown4;
}
unsigned short GetUnknown5(void) const
{
return unknown5;
}
unsigned short GetUnknown6(void) const
{
return unknown6;
}
unsigned short GetUnknown7(void) const
{
return unknown7;
}
unsigned short GetUnknown8(void) const
{
return unknown8;
}
};
}
#endif