summaryrefslogtreecommitdiffstats
path: root/heimdall/source
diff options
context:
space:
mode:
Diffstat (limited to 'heimdall/source')
-rw-r--r--heimdall/source/Arguments.cpp212
-rw-r--r--heimdall/source/Arguments.h160
-rw-r--r--heimdall/source/BeginSessionPacket.h39
-rw-r--r--heimdall/source/BridgeManager.cpp819
-rw-r--r--heimdall/source/BridgeManager.h37
-rw-r--r--heimdall/source/ClosePcScreenAction.cpp94
-rw-r--r--heimdall/source/ClosePcScreenAction.h34
-rw-r--r--heimdall/source/ControlPacket.h8
-rw-r--r--heimdall/source/DetectAction.cpp64
-rw-r--r--heimdall/source/DetectAction.h34
-rw-r--r--heimdall/source/DeviceTypePacket.h39
-rw-r--r--heimdall/source/DownloadPitAction.cpp135
-rw-r--r--heimdall/source/DownloadPitAction.h34
-rw-r--r--heimdall/source/DumpAction.cpp158
-rw-r--r--heimdall/source/DumpAction.h34
-rw-r--r--heimdall/source/FilePartSizePacket.h56
-rw-r--r--heimdall/source/FlashAction.cpp620
-rw-r--r--heimdall/source/FlashAction.h34
-rw-r--r--heimdall/source/FlashPartFileTransferPacket.h20
-rw-r--r--heimdall/source/Heimdall.h1
-rw-r--r--heimdall/source/HelpAction.cpp35
-rw-r--r--heimdall/source/HelpAction.h34
-rw-r--r--heimdall/source/InfoAction.cpp35
-rw-r--r--heimdall/source/InfoAction.h34
-rw-r--r--heimdall/source/Interface.cpp484
-rw-r--r--heimdall/source/Interface.h281
-rw-r--r--heimdall/source/Packet.h2
-rw-r--r--heimdall/source/PrintPitAction.cpp159
-rw-r--r--heimdall/source/PrintPitAction.h34
-rw-r--r--heimdall/source/ResponsePacket.h10
-rw-r--r--heimdall/source/SendFilePartPacket.h7
-rw-r--r--heimdall/source/SessionSetupPacket.h74
-rw-r--r--heimdall/source/SessionSetupResponse.h58
-rw-r--r--heimdall/source/TotalBytesPacket.h56
-rw-r--r--heimdall/source/Utility.cpp82
-rw-r--r--heimdall/source/Utility.h40
-rw-r--r--heimdall/source/VersionAction.cpp35
-rw-r--r--heimdall/source/VersionAction.h34
-rw-r--r--heimdall/source/main.cpp778
39 files changed, 3193 insertions, 1711 deletions
diff --git a/heimdall/source/Arguments.cpp b/heimdall/source/Arguments.cpp
new file mode 100644
index 0000000..321c12f
--- /dev/null
+++ b/heimdall/source/Arguments.cpp
@@ -0,0 +1,212 @@
+/* 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.*/
+
+// Heimdall
+#include "Arguments.h"
+#include "Heimdall.h"
+#include "Interface.h"
+#include "Utility.h"
+
+using namespace Heimdall;
+
+FlagArgument *FlagArgument::ParseArgument(int argc, char **argv, int& argi)
+{
+ return new FlagArgument();
+}
+
+
+
+StringArgument *StringArgument::ParseArgument(int argc, char **argv, int& argi)
+{
+ if (++argi < argc)
+ {
+ return (new StringArgument(argv[argi]));
+ }
+ else
+ {
+ Interface::Print("Missing parameter for argument: %s\n\n", argv[argi - 1]);
+ return (nullptr);
+ }
+}
+
+
+
+UnsignedIntegerArgument *UnsignedIntegerArgument::ParseArgument(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(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 (map<string, Argument *>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
+ delete it->second;
+}
+
+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";
+ }
+ }
+
+ Argument *argument = nullptr;
+
+ if (argumentTypeIt != argumentTypes.end())
+ {
+ switch (argumentTypeIt->second)
+ {
+ case kArgumentTypeFlag:
+ argument = FlagArgument::ParseArgument(argc, argv, argi);
+ break;
+
+ case kArgumentTypeString:
+ argument = StringArgument::ParseArgument(argc, argv, argi);
+ break;
+
+ case kArgumentTypeUnsignedInteger:
+ argument = UnsignedIntegerArgument::ParseArgument(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]);
+ }
+
+ // We don't want to insert wild-cards into our argument map.
+ if (argumentName == "%d" || argumentName == "%s")
+ argumentName = nonwildcardArgumentName;
+
+ if (argument)
+ {
+ pair<map<string, Argument *>::iterator, bool> insertResult = arguments.insert(pair<string, Argument *>(argumentName, argument));
+
+ if (!insertResult.second)
+ {
+ Interface::Print("Duplicate argument: %s (%s)\n\n", argv[argi], insertResult.first->first.c_str());
+ delete argument;
+
+ return (false);
+ }
+ }
+ else
+ {
+ return (false);
+ }
+ }
+
+ return (true);
+}
diff --git a/heimdall/source/Arguments.h b/heimdall/source/Arguments.h
new file mode 100644
index 0000000..7294e70
--- /dev/null
+++ b/heimdall/source/Arguments.h
@@ -0,0 +1,160 @@
+/* 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 ARGUMENTS_H
+#define ARGUMENTS_H
+
+// C/C++ Standard Library
+#include <map>
+#include <string>
+
+// Heimdall
+#include "Heimdall.h"
+
+using namespace std;
+
+namespace Heimdall
+{
+ typedef enum
+ {
+ kArgumentTypeFlag = 0,
+ kArgumentTypeString,
+ kArgumentTypeUnsignedInteger
+
+ } ArgumentType;
+
+ class Argument
+ {
+ private:
+
+ ArgumentType argumentType;
+
+ protected:
+
+ Argument(ArgumentType argumentType)
+ {
+ this->argumentType = argumentType;
+ }
+
+ public:
+
+ virtual ~Argument()
+ {
+ }
+
+ ArgumentType GetArgumentType(void) const
+ {
+ return argumentType;
+ }
+ };
+
+ class FlagArgument : public Argument
+ {
+ private:
+
+ FlagArgument() : Argument(kArgumentTypeFlag)
+ {
+ }
+
+ public:
+
+ static FlagArgument *ParseArgument(int argc, char **argv, int& argi);
+ };
+
+ class StringArgument : public Argument
+ {
+ private:
+
+ string value;
+
+ StringArgument(const string& value) : Argument(kArgumentTypeString)
+ {
+ this->value = value;
+ }
+
+ public:
+
+ static StringArgument *ParseArgument(int argc, char **argv, int& argi);
+
+ const string& GetValue(void) const
+ {
+ return (value);
+ }
+ };
+
+ class UnsignedIntegerArgument : public Argument
+ {
+ private:
+
+ unsigned int value;
+
+ UnsignedIntegerArgument(unsigned int value) : Argument(kArgumentTypeUnsignedInteger)
+ {
+ this->value = value;
+ }
+
+ public:
+
+ static UnsignedIntegerArgument *ParseArgument(int argc, char **argv, int& argi);
+
+ unsigned int GetValue(void) const
+ {
+ return (value);
+ }
+ };
+
+ class Arguments
+ {
+ private:
+
+ const map<string, ArgumentType> argumentTypes;
+ const map<string, string> shortArgumentAliases;
+ const map<string, string> argumentAliases;
+
+ map<string, Argument *> arguments;
+
+ public:
+
+ Arguments(const map<string, ArgumentType>& argumentTypes, const map<string, string>& shortArgumentAliases = map<string, string>(),
+ const map<string, string> argumentAliases = map<string, string>());
+ ~Arguments();
+
+ // argi is the index of the first argument to parse.
+ bool ParseArguments(int argc, char **argv, int argi);
+
+ const Argument *GetArgument(string argumentName) const
+ {
+ map<string, Argument *>::const_iterator it = arguments.find(argumentName);
+ return (it != arguments.end() ? it->second : nullptr);
+ }
+
+ const map<string, ArgumentType>& GetArgumentTypes(void) const
+ {
+ return (argumentTypes);
+ }
+
+ const map<string, Argument *>& GetArguments(void) const
+ {
+ return (arguments);
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/BeginSessionPacket.h b/heimdall/source/BeginSessionPacket.h
new file mode 100644
index 0000000..d0f9c05
--- /dev/null
+++ b/heimdall/source/BeginSessionPacket.h
@@ -0,0 +1,39 @@
+/* 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 BEGINSESSIONPACKET_H
+#define BEGINSESSIONPACKET_H
+
+// Heimdall
+#include "SessionSetupPacket.h"
+
+namespace Heimdall
+{
+ class BeginSessionPacket : public SessionSetupPacket
+ {
+ public:
+
+ BeginSessionPacket() : SessionSetupPacket(SessionSetupPacket::kBeginSession)
+ {
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/BridgeManager.cpp b/heimdall/source/BridgeManager.cpp
index 0019021..fa83b1c 100644
--- a/heimdall/source/BridgeManager.cpp
+++ b/heimdall/source/BridgeManager.cpp
@@ -26,9 +26,9 @@
// Heimdall
#include "BeginDumpPacket.h"
+#include "BeginSessionPacket.h"
#include "BridgeManager.h"
-#include "SetupSessionPacket.h"
-#include "SetupSessionResponse.h"
+#include "DeviceTypePacket.h"
#include "DumpPartFileTransferPacket.h"
#include "DumpPartPitFilePacket.h"
#include "DumpResponse.h"
@@ -36,6 +36,7 @@
#include "EndPhoneFileTransferPacket.h"
#include "EndPitFileTransferPacket.h"
#include "EndSessionPacket.h"
+#include "FilePartSizePacket.h"
#include "FileTransferPacket.h"
#include "FlashPartFileTransferPacket.h"
#include "FlashPartPitFilePacket.h"
@@ -48,11 +49,13 @@
#include "ResponsePacket.h"
#include "SendFilePartPacket.h"
#include "SendFilePartResponse.h"
+#include "SessionSetupPacket.h"
+#include "SessionSetupResponse.h"
// Future versions of libusb will use usb_interface instead of interface.
#define usb_interface interface
-#define CLASS_CDC 0x0A
+#define USB_CLASS_CDC_DATA 0x0A
using namespace Heimdall;
@@ -64,259 +67,26 @@ const DeviceIdentifier BridgeManager::supportedDevices[BridgeManager::kSupported
enum
{
- kMaxSequenceLength = 800
+ kDumpBufferSize = 4096
};
-bool BridgeManager::CheckProtocol(void) const
-{
- Interface::Print("Checking if protocol is initialised...\n");
-
- SetupSessionPacket deviceInfoPacket(SetupSessionPacket::kDeviceInfo);
-
- if (!SendPacket(&deviceInfoPacket, 100, false))
- {
- Interface::Print("Protocol is not initialised.\n");
- return (false);
- }
-
- SetupSessionResponse deviceInfoResponse;
-
- if (!ReceivePacket(&deviceInfoResponse, 100, false))
- {
- Interface::Print("Protocol is not initialised.\n");
- return (false);
- }
-
- Interface::Print("Protocol is initialised.\n");
- return (true);
-}
-
-bool BridgeManager::InitialiseProtocol(void) const
-{
- Interface::Print("Initialising protocol...\n");
-
- unsigned char *dataBuffer = new unsigned char[7];
-
- int result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x3, 0, nullptr, 0, 1000);
-
- if (result < 0)
- {
- Interface::PrintError("Failed to initialise protocol!\n");
-
- delete [] dataBuffer;
- return (false);
- }
-
- memset(dataBuffer, 0, 7);
- dataBuffer[1] = 0xC2;
- dataBuffer[2] = 0x01;
- dataBuffer[6] = 0x07;
-
- result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x20, 0x0, 0, dataBuffer, 7, 1000);
- if (result < 0)
- {
- Interface::PrintError("Failed to initialise protocol!\n");
-
- delete [] dataBuffer;
- return (false);
- }
-
- result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x3, 0, nullptr, 0, 1000);
- if (result < 0)
- {
- Interface::PrintError("Failed to initialise protocol!\n");
-
- delete [] dataBuffer;
- return (false);
- }
-
- result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000);
- if (result < 0)
- {
- Interface::PrintError("Failed to initialise protocol!\n");
-
- delete [] dataBuffer;
- return (false);
- }
-
- memset(dataBuffer, 0, 7);
- dataBuffer[1] = 0xC2;
- dataBuffer[2] = 0x01;
- dataBuffer[6] = 0x08;
-
- result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x20, 0x0, 0, dataBuffer, 7, 1000);
- if (result < 0)
- {
- Interface::PrintError("Failed to initialise protocol!\n");
-
- delete [] dataBuffer;
- return (false);
- }
-
- result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000);
- if (result < 0)
- {
- Interface::PrintError("Failed to initialise protocol!\n");
-
- delete [] dataBuffer;
- return (false);
- }
-
- Interface::Print("Handshaking with Loke...\n");
-
- int dataTransferred;
-
- // Send "ODIN"
- strcpy((char *)dataBuffer, "ODIN");
-
- result = libusb_bulk_transfer(deviceHandle, outEndpoint, dataBuffer, 4, &dataTransferred, 1000);
- if (result < 0)
- {
- if (verbose)
- Interface::PrintError("Failed to send data: \"%s\"\n", dataBuffer);
- else
- Interface::PrintError("Failed to send data!");
-
- delete [] dataBuffer;
- return (false);
- }
-
- if (dataTransferred != 4)
- {
- if (verbose)
- Interface::PrintError("Failed to complete sending of data: \"%s\"\n", dataBuffer);
- else
- Interface::PrintError("Failed to complete sending of data!");
-
- delete [] dataBuffer;
- return (false);
- }
-
- // Expect "LOKE"
- memset(dataBuffer, 0, 7);
-
- result = libusb_bulk_transfer(deviceHandle, inEndpoint, dataBuffer, 7, &dataTransferred, 1000);
- if (result < 0)
- {
- Interface::PrintError("Failed to receive response!\n");
-
- delete [] dataBuffer;
- return (false);;
- }
-
- if (dataTransferred != 4 || memcmp(dataBuffer, "LOKE", 4) != 0)
- {
- Interface::PrintError("Unexpected communication!\n");
-
- if (verbose)
- Interface::PrintError("Expected: \"%s\"\nReceived: \"%s\"\n", "LOKE", dataBuffer);
-
- Interface::PrintError("Handshake failed!\n");
-
- delete [] dataBuffer;
- return (false);
- }
-
- return (true);
-}
-
-BridgeManager::BridgeManager(bool verbose, int communicationDelay)
-{
- this->verbose = verbose;
- this->communicationDelay = communicationDelay;
-
- libusbContext = nullptr;
- deviceHandle = nullptr;
- heimdallDevice = nullptr;
- inEndpoint = -1;
- outEndpoint = -1;
- interfaceIndex = -1;
-
-#ifdef OS_LINUX
-
- detachedDriver = false;
-
-#endif
-}
-
-BridgeManager::~BridgeManager()
+enum
{
- if (interfaceIndex >= 0)
- libusb_release_interface(deviceHandle, interfaceIndex);
-
-#ifdef OS_LINUX
-
- if (detachedDriver)
- {
- Interface::Print("Re-attaching kernel driver...\n");
- libusb_attach_kernel_driver(deviceHandle, interfaceIndex);
- }
-
-#endif
-
- if (deviceHandle)
- libusb_close(deviceHandle);
-
- if (heimdallDevice)
- libusb_unref_device(heimdallDevice);
-
- if (libusbContext)
- libusb_exit(libusbContext);
-}
+ kFileTransferSequenceMaxLengthDefault = 800,
+ kFileTransferPacketSizeDefault = 131072,
+ kFileTransferSequenceTimeoutDefault = 30000 // 30 seconds
+};
-bool BridgeManager::DetectDevice(void)
+enum
{
- // Initialise libusb-1.0
- int result = libusb_init(&libusbContext);
- if (result != LIBUSB_SUCCESS)
- {
- Interface::PrintError("Failed to initialise libusb. libusb error: %d\n", result);
- return (false);
- }
-
- // Get handle to Galaxy S device
- struct libusb_device **devices;
- int deviceCount = libusb_get_device_list(libusbContext, &devices);
-
- for (int deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++)
- {
- libusb_device_descriptor descriptor;
- libusb_get_device_descriptor(devices[deviceIndex], &descriptor);
-
- for (int i = 0; i < BridgeManager::kSupportedDeviceCount; i++)
- {
- if (descriptor.idVendor == supportedDevices[i].vendorId && descriptor.idProduct == supportedDevices[i].productId)
- {
- libusb_free_device_list(devices, deviceCount);
-
- Interface::Print("Device detected\n");
- return (true);
- }
- }
- }
-
- libusb_free_device_list(devices, deviceCount);
-
- Interface::PrintDeviceDetectionFailed();
- return (false);
-}
+ kHandshakeMaxAttempts = 5,
+ kReceivePacketMaxAttempts = 5
+};
-int BridgeManager::Initialise(void)
+int BridgeManager::FindDeviceInterface(void)
{
- Interface::Print("Initialising connection...\n");
-
- // Initialise libusb-1.0
- int result = libusb_init(&libusbContext);
- if (result != LIBUSB_SUCCESS)
- {
- Interface::PrintError("Failed to initialise libusb. libusb error: %d\n", result);
- Interface::Print("Failed to connect to device!");
- return (BridgeManager::kInitialiseFailed);
- }
-
Interface::Print("Detecting device...\n");
- // Get handle to Galaxy S device
struct libusb_device **devices;
int deviceCount = libusb_get_device_list(libusbContext, &devices);
@@ -347,7 +117,7 @@ int BridgeManager::Initialise(void)
return (BridgeManager::kInitialiseDeviceNotDetected);
}
- result = libusb_open(heimdallDevice, &deviceHandle);
+ int result = libusb_open(heimdallDevice, &deviceHandle);
if (result != LIBUSB_SUCCESS)
{
Interface::PrintError("Failed to access device. libusb error: %d\n", result);
@@ -403,8 +173,8 @@ int BridgeManager::Initialise(void)
return (BridgeManager::kInitialiseFailed);
}
- int interfaceIndex = -1;
- int altSettingIndex;
+ interfaceIndex = -1;
+ altSettingIndex = -1;
for (int i = 0; i < configDescriptor->bNumInterfaces; i++)
{
@@ -440,9 +210,11 @@ int BridgeManager::Initialise(void)
outEndpointAddress = endpoint->bEndpointAddress;
}
- if (interfaceIndex < 0 && configDescriptor->usb_interface[i].altsetting[j].bNumEndpoints == 2
- && configDescriptor->usb_interface[i].altsetting[j].bInterfaceClass == CLASS_CDC
- && inEndpointAddress != -1 && outEndpointAddress != -1)
+ if (interfaceIndex < 0
+ && configDescriptor->usb_interface[i].altsetting[j].bNumEndpoints == 2
+ && configDescriptor->usb_interface[i].altsetting[j].bInterfaceClass == USB_CLASS_CDC_DATA
+ && inEndpointAddress != -1
+ && outEndpointAddress != -1)
{
interfaceIndex = i;
altSettingIndex = j;
@@ -459,9 +231,15 @@ int BridgeManager::Initialise(void)
Interface::PrintError("Failed to find correct interface configuration\n");
return (BridgeManager::kInitialiseFailed);
}
-
+
+ return (BridgeManager::kInitialiseSucceeded);
+}
+
+bool BridgeManager::ClaimDeviceInterface(void)
+{
Interface::Print("Claiming interface...\n");
- result = libusb_claim_interface(deviceHandle, interfaceIndex);
+
+ int result = libusb_claim_interface(deviceHandle, interfaceIndex);
#ifdef OS_LINUX
@@ -479,19 +257,314 @@ int BridgeManager::Initialise(void)
if (result != LIBUSB_SUCCESS)
{
Interface::PrintError("Claiming interface failed!\n");
- return (BridgeManager::kInitialiseFailed);
+ return (false);
}
+ interfaceClaimed = true;
+
+ return (true);
+}
+
+bool BridgeManager::SetupDeviceInterface(void)
+{
Interface::Print("Setting up interface...\n");
- result = libusb_set_interface_alt_setting(deviceHandle, interfaceIndex, altSettingIndex);
+
+ int result = libusb_set_interface_alt_setting(deviceHandle, interfaceIndex, altSettingIndex);
if (result != LIBUSB_SUCCESS)
{
Interface::PrintError("Setting up interface failed!\n");
- return (BridgeManager::kInitialiseFailed);
+ return (false);
+ }
+
+ Interface::Print("\n");
+ return (true);
+}
+
+void BridgeManager::ReleaseDeviceInterface(void)
+{
+ Interface::Print("Releasing device interface...\n");
+
+ libusb_release_interface(deviceHandle, interfaceIndex);
+
+#ifdef OS_LINUX
+
+ if (detachedDriver)
+ {
+ Interface::Print("Re-attaching kernel driver...\n");
+ libusb_attach_kernel_driver(deviceHandle, interfaceIndex);
}
+#endif
+
+ interfaceClaimed = false;
Interface::Print("\n");
+}
+
+bool BridgeManager::CheckProtocol(void) const
+{
+ Interface::Print("Checking if protocol is initialised...\n");
+
+ DeviceTypePacket deviceTypePacket;
+
+ if (!SendPacket(&deviceTypePacket, 150, false))
+ {
+ Interface::Print("Protocol is not initialised.\n");
+ return (false);
+ }
+
+ unsigned char buffer[1024];
+ memset(buffer, 0, sizeof(buffer));
+
+ SessionSetupResponse deviceTypeResponse;
+
+ if (!ReceivePacket(&deviceTypeResponse, 150, false, buffer, sizeof(buffer)))
+ {
+ Interface::Print("Protocol is not initialised.\n\n");
+ return (false);
+ }
+
+ Interface::Print("Protocol is initialised.\n\n");
+ return (true);
+}
+
+bool BridgeManager::InitialiseProtocol(void) const
+{
+ Interface::Print("Initialising protocol...\n");
+
+ unsigned char dataBuffer[7];
+
+ int result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x3, 0, nullptr, 0, 1000);
+
+ if (result < 0 && verbose)
+ Interface::PrintWarning("Control transfer #1 failed. Result: %d\n", result);
+
+ memset(dataBuffer, 0, 7);
+ dataBuffer[1] = 0xC2;
+ dataBuffer[2] = 0x01;
+ dataBuffer[6] = 0x07;
+
+ result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x20, 0x0, 0, dataBuffer, 7, 1000);
+
+ if (result < 0 && verbose)
+ Interface::PrintWarning("Control transfer #2 failed. Result: %d\n", result);
+
+ result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x3, 0, nullptr, 0, 1000);
+
+ if (result < 0 && verbose)
+ Interface::PrintWarning("Control transfer #3 failed. Result: %d\n", result);
+
+ result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000);
+
+ if (result < 0 && verbose)
+ Interface::PrintWarning("Control transfer #4 failed. Result: %d\n", result);
+
+ memset(dataBuffer, 0, 7);
+ dataBuffer[1] = 0xC2;
+ dataBuffer[2] = 0x01;
+ dataBuffer[6] = 0x08;
+
+ result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x20, 0x0, 0, dataBuffer, 7, 1000);
+
+ if (result < 0 && verbose)
+ Interface::PrintWarning("Control transfer #5 failed. Result: %d\n", result);
+
+ result = libusb_control_transfer(deviceHandle, LIBUSB_REQUEST_TYPE_CLASS, 0x22, 0x2, 0, nullptr, 0, 1000);
+
+ if (result < 0 && verbose)
+ Interface::PrintWarning("Control transfer #6 failed. Result: %d\n", result);
+
+ unsigned int attempt = 0;
+
+ // max(250, communicationDelay)
+ int retryDelay = (communicationDelay > 250) ? communicationDelay : 250;
+
+ for (; attempt < kHandshakeMaxAttempts; attempt++)
+ {
+ if (attempt > 0)
+ {
+ if (verbose)
+ Interface::PrintErrorSameLine(" Retrying...\n");
+
+ // Wait longer each retry
+ Sleep(retryDelay * (attempt + 1));
+ }
+
+ int dataTransferred = 0;
+
+ // Send "ODIN"
+ memcpy(dataBuffer, "ODIN", 4);
+ memset(dataBuffer + 4, 0, 1);
+
+ result = libusb_bulk_transfer(deviceHandle, outEndpoint, dataBuffer, 4, &dataTransferred, 1000);
+ if (result < 0)
+ {
+ if (verbose)
+ Interface::PrintError("Failed to send data: \"%s\"\n", dataBuffer);
+ else
+ Interface::PrintError("Failed to send data!");
+
+ return (false);
+ }
+
+ if (dataTransferred != 4)
+ {
+ if (verbose)
+ Interface::PrintError("Failed to complete sending of data: \"%s\"\n", dataBuffer);
+ else
+ Interface::PrintError("Failed to complete sending of data!");
+
+ return (false);
+ }
+
+ // Expect "LOKE"
+ memset(dataBuffer, 0, 7);
+
+ int retry = 0;
+ dataTransferred = 0;
+
+ result = libusb_bulk_transfer(deviceHandle, inEndpoint, dataBuffer, 7, &dataTransferred, 1000);
+
+ if (result < 0)
+ {
+ if (verbose)
+ Interface::PrintError("Failed to receive handshake response.");
+ }
+ else
+ {
+ if (dataTransferred == 4 && memcmp(dataBuffer, "LOKE", 4) == 0)
+ {
+ // Successfully received "LOKE"
+ break;
+ }
+ else
+ {
+ if (verbose)
+ Interface::PrintError("Expected: \"%s\"\nReceived: \"%s\"\n", "LOKE", dataBuffer);
+
+ Interface::PrintError("Unexpected handshake response!");
+ }
+ }
+ }
+
+ if (attempt == kHandshakeMaxAttempts)
+ {
+ if (verbose)
+ Interface::PrintErrorSameLine("\n");
+
+ Interface::PrintError("Protocol initialisation failed!\n\n");
+ return (false);
+ }
+ else
+ {
+ Interface::Print("Protocol initialisation successful.\n\n");
+ return (true);
+ }
+}
+
+BridgeManager::BridgeManager(bool verbose, int communicationDelay)
+{
+ this->verbose = verbose;
+ this->communicationDelay = communicationDelay;
+
+ libusbContext = nullptr;
+ deviceHandle = nullptr;
+ heimdallDevice = nullptr;
+
+ inEndpoint = -1;
+ outEndpoint = -1;
+ interfaceIndex = -1;
+ altSettingIndex = -1;
+
+ interfaceClaimed = false;
+
+#ifdef OS_LINUX
+
+ detachedDriver = false;
+
+#endif
+
+ fileTransferSequenceMaxLength = kFileTransferSequenceMaxLengthDefault;
+ fileTransferPacketSize = kFileTransferPacketSizeDefault;
+ fileTransferSequenceTimeout = kFileTransferSequenceTimeoutDefault;
+}
+
+BridgeManager::~BridgeManager()
+{
+ if (interfaceClaimed)
+ ReleaseDeviceInterface();
+
+ if (deviceHandle)
+ libusb_close(deviceHandle);
+
+ if (heimdallDevice)
+ libusb_unref_device(heimdallDevice);
+
+ if (libusbContext)
+ libusb_exit(libusbContext);
+}
+
+bool BridgeManager::DetectDevice(void)
+{
+ // Initialise libusb-1.0
+ int result = libusb_init(&libusbContext);
+ if (result != LIBUSB_SUCCESS)
+ {
+ Interface::PrintError("Failed to initialise libusb. libusb error: %d\n", result);
+ return (false);
+ }
+
+ // Get handle to Galaxy S device
+ struct libusb_device **devices;
+ int deviceCount = libusb_get_device_list(libusbContext, &devices);
+
+ for (int deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++)
+ {
+ libusb_device_descriptor descriptor;
+ libusb_get_device_descriptor(devices[deviceIndex], &descriptor);
+
+ for (int i = 0; i < BridgeManager::kSupportedDeviceCount; i++)
+ {
+ if (descriptor.idVendor == supportedDevices[i].vendorId && descriptor.idProduct == supportedDevices[i].productId)
+ {
+ libusb_free_device_list(devices, deviceCount);
+
+ Interface::Print("Device detected\n");
+ return (true);
+ }
+ }
+ }
+
+ libusb_free_device_list(devices, deviceCount);
+
+ Interface::PrintDeviceDetectionFailed();
+ return (false);
+}
+
+int BridgeManager::Initialise()
+{
+ Interface::Print("Initialising connection...\n");
+
+ // Initialise libusb-1.0
+ int result = libusb_init(&libusbContext);
+
+ if (result != LIBUSB_SUCCESS)
+ {
+ Interface::PrintError("Failed to initialise libusb. libusb error: %d\n", result);
+ Interface::Print("Failed to connect to device!");
+ return (BridgeManager::kInitialiseFailed);
+ }
+
+ result = FindDeviceInterface();
+
+ if (result != BridgeManager::kInitialiseSucceeded)
+ return (result);
+
+ if (!ClaimDeviceInterface())
+ return (BridgeManager::kInitialiseFailed);
+
+ if (!SetupDeviceInterface())
+ return (BridgeManager::kInitialiseFailed);
if (!CheckProtocol())
{
@@ -499,16 +572,14 @@ int BridgeManager::Initialise(void)
return (BridgeManager::kInitialiseFailed);
}
- Interface::Print("\n");
-
return (BridgeManager::kInitialiseSucceeded);
}
-bool BridgeManager::BeginSession(void) const
+bool BridgeManager::BeginSession(void)
{
Interface::Print("Beginning session...\n");
- SetupSessionPacket beginSessionPacket(SetupSessionPacket::kBeginSession);
+ BeginSessionPacket beginSessionPacket;
if (!SendPacket(&beginSessionPacket))
{
@@ -516,22 +587,18 @@ bool BridgeManager::BeginSession(void) const
return (false);
}
- SetupSessionResponse setupSessionResponse;
- if (!ReceivePacket(&setupSessionResponse))
+ SessionSetupResponse beginSessionResponse;
+ if (!ReceivePacket(&beginSessionResponse))
return (false);
- unsigned int result = setupSessionResponse.GetUnknown();
+ unsigned int result = beginSessionResponse.GetResult();
- // 131072 for Galaxy S II, 0 for other devices.
- if (result != 0 && result != 131072)
- {
- Interface::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%d\n", result);
- return (false);
- }
+ if (result != 0) // Assume 0 means don't care, otherwise use the response as the fileTransferPacketSize.
+ fileTransferPacketSize = result;
// -------------------- KIES DOESN'T DO THIS --------------------
- SetupSessionPacket deviceTypePacket(SetupSessionPacket::kDeviceInfo);
+ DeviceTypePacket deviceTypePacket;
if (!SendPacket(&deviceTypePacket))
{
@@ -539,23 +606,67 @@ bool BridgeManager::BeginSession(void) const
return (false);
}
- if (!ReceivePacket(&setupSessionResponse))
+ SessionSetupResponse deviceTypeResponse;
+
+ if (!ReceivePacket(&deviceTypeResponse))
return (false);
- unsigned int deviceType = setupSessionResponse.GetUnknown();
+ unsigned int deviceType = deviceTypeResponse.GetResult();
- // TODO: Work out what this value is... it has been either 180 or 0 for Galaxy S phones, 3 on the Galaxy Tab, 190 for SHW-M110S.
- if (deviceType != 180 && deviceType != 0 && deviceType != 3 && deviceType != 190)
- {
- Interface::PrintError("Unexpected device info response!\nExpected: 180, 0 or 3\nReceived:%d\n", deviceType);
- return (false);
- }
- else
+ switch (deviceType)
{
- Interface::Print("Session begun with device of type: %d\n\n", result);
- }
+ // NOTE: If you add a new device type don't forget to update the error message below!
- return (true);
+ case 0: // Galaxy S etc.
+ case 3: // Galaxy Tab
+ case 30: // Galaxy S 2 Skyrocket
+ case 180: // Galaxy S etc.
+ case 190: // M110S Galaxy S
+
+ if (verbose)
+ Interface::Print("Session begun with device of type: %d.\n\n", deviceType);
+ else
+ Interface::Print("Session begun.\n\n", deviceType);
+
+ if (deviceType == 30)
+ {
+ Interface::Print("In certain situations this device may take up to 2 minutes to respond.\nPlease be patient!\n\n", deviceType);
+ Sleep(2000); // Give the user time to read the message.
+
+ // The SGH-I727 is very unstable/unreliable using the default settings. Flashing
+ // seems to be much more reliable using the following setup.
+
+ fileTransferSequenceMaxLength = 30;
+ fileTransferSequenceTimeout = 120000; // 2 minutes!
+ fileTransferPacketSize = 1048576; // 1 MiB
+
+ FilePartSizePacket filePartSizePacket(fileTransferPacketSize); // 1 MiB
+
+ if (!SendPacket(&filePartSizePacket))
+ {
+ Interface::PrintError("Failed to send file part size packet!\n");
+ return (false);
+ }
+
+ SessionSetupResponse filePartSizeResponse;
+
+ if (!ReceivePacket(&filePartSizeResponse))
+ return (false);
+
+ if (filePartSizeResponse.GetResult() != 0)
+ {
+ Interface::PrintError("Unexpected file part size response!\nExpected: 0\nReceived: %d\n", filePartSizeResponse.GetResult());
+ return (false);
+ }
+ }
+
+ return (true);
+
+ default:
+
+ Interface::PrintError("Unexpected device info response!\nExpected: 0, 3, 30, 180 or 190\nReceived:%d\n", deviceType);
+ return (false);
+ }
}
bool BridgeManager::EndSession(bool reboot) const
@@ -662,58 +773,79 @@ bool BridgeManager::SendPacket(OutboundPacket *packet, int timeout, bool retry)
return (true);
}
-bool BridgeManager::ReceivePacket(InboundPacket *packet, int timeout, bool retry) const
+bool BridgeManager::ReceivePacket(InboundPacket *packet, int timeout, bool retry, unsigned char *buffer, unsigned int bufferSize) const
{
- int dataTransferred;
- int result = libusb_bulk_transfer(deviceHandle, inEndpoint, packet->GetData(), packet->GetSize(),
- &dataTransferred, timeout);
+ bool bufferProvided = buffer != nullptr && bufferSize >= packet->GetSize();
- if (result < 0 && retry)
+ if (!bufferProvided)
{
- // max(250, communicationDelay)
- int retryDelay = (communicationDelay > 250) ? communicationDelay : 250;
+ buffer = packet->GetData();
+ bufferSize = packet->GetSize();
+ }
- if (verbose)
- Interface::PrintError("libusb error %d whilst receiving packet.", result);
+ int dataTransferred;
+ int result;
- // Retry
- for (int i = 0; i < 5; i++)
+ unsigned int attempt = 0;
+ unsigned int maxAttempts = (retry) ? kReceivePacketMaxAttempts : 1;
+
+ // max(250, communicationDelay)
+ int retryDelay = (communicationDelay > 250) ? communicationDelay : 250;
+
+ for (; attempt < maxAttempts; attempt++)
+ {
+ if (attempt > 0)
{
if (verbose)
Interface::PrintErrorSameLine(" Retrying...\n");
-
+
// Wait longer each retry
- Sleep(retryDelay * (i + 1));
-
- result = libusb_bulk_transfer(deviceHandle, inEndpoint, packet->GetData(), packet->GetSize(),
- &dataTransferred, timeout);
+ Sleep(retryDelay * (attempt + 1));
+ }
- if (result >= 0)
- break;
+ result = libusb_bulk_transfer(deviceHandle, inEndpoint, buffer, bufferSize, &dataTransferred, timeout);
- if (verbose)
- Interface::PrintError("libusb error %d whilst receiving packet.", result);
- }
+ if (result >= 0)
+ break;
if (verbose)
- Interface::PrintErrorSameLine("\n");
+ Interface::PrintError("libusb error %d whilst receiving packet.", result);
}
+ if (verbose && attempt > 0)
+ Interface::PrintErrorSameLine("\n");
+
+ if (attempt == maxAttempts)
+ return (false);
+
if (communicationDelay != 0)
Sleep(communicationDelay);
- if (result < 0 || (dataTransferred != packet->GetSize() && !packet->IsSizeVariable()))
+ if (dataTransferred != packet->GetSize() && !packet->IsSizeVariable())
+ {
+ if (verbose)
+ Interface::PrintError("Incorrect packet size received - expected size = %d, received size = %d.\n", packet->GetSize(), dataTransferred);
+
return (false);
+ }
+
+ if (bufferProvided)
+ memcpy(packet->GetData(), buffer, dataTransferred);
packet->SetReceivedSize(dataTransferred);
- return (packet->Unpack());
+ bool unpacked = packet->Unpack();
+
+ if (!unpacked && verbose)
+ Interface::PrintError("Failed to unpack received packet.\n");
+
+ return (unpacked);
}
-bool BridgeManager::RequestDeviceInfo(unsigned int request, int *result) const
+bool BridgeManager::RequestDeviceType(unsigned int request, int *result) const
{
- SetupSessionPacket beginSessionPacket(request);
- bool success = SendPacket(&beginSessionPacket);
+ DeviceTypePacket deviceTypePacket;
+ bool success = SendPacket(&deviceTypePacket);
if (!success)
{
@@ -725,11 +857,12 @@ bool BridgeManager::RequestDeviceInfo(unsigned int request, int *result) const
return (false);
}
- SetupSessionResponse deviceInfoResponse;
- if (!ReceivePacket(&deviceInfoResponse))
+ SessionSetupResponse deviceTypeResponse;
+
+ if (!ReceivePacket(&deviceTypeResponse))
return (false);
- *result = deviceInfoResponse.GetUnknown();
+ *result = deviceTypeResponse.GetResult();
return (true);
}
@@ -921,7 +1054,23 @@ int BridgeManager::ReceivePitFile(unsigned char **pitBuffer) const
return (fileSize);
}
-bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int chipIdentifier, unsigned int fileIdentifier) const
+int BridgeManager::DownloadPitFile(unsigned char **pitBuffer) const
+{
+ Interface::Print("Downloading device's PIT file...\n");
+
+ int devicePitFileSize = ReceivePitFile(pitBuffer);
+
+ if (!*pitBuffer)
+ {
+ Interface::PrintError("Failed to download PIT file!\n");
+ return (0);
+ }
+
+ Interface::Print("PIT file download successful.\n\n");
+ return (devicePitFileSize);
+}
+
+bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int deviceType, unsigned int fileIdentifier) const
{
if (destination != EndFileTransferPacket::kDestinationModem && destination != EndFileTransferPacket::kDestinationPhone)
{
@@ -959,16 +1108,16 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int
return (false);
}
- unsigned int sequenceCount = fileSize / (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize);
- unsigned int lastSequenceSize = kMaxSequenceLength;
- unsigned int partialPacketByteCount = fileSize % SendFilePartPacket::kDefaultPacketSize;
+ unsigned int sequenceCount = fileSize / (fileTransferSequenceMaxLength * fileTransferPacketSize);
+ unsigned int lastSequenceSize = fileTransferSequenceMaxLength;
+ unsigned int partialPacketByteCount = fileSize % fileTransferPacketSize;
- if (fileSize % (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize) != 0)
+ if (fileSize % (fileTransferSequenceMaxLength * fileTransferPacketSize) != 0)
{
sequenceCount++;
- int lastSequenceBytes = fileSize % (kMaxSequenceLength * SendFilePartPacket::kDefaultPacketSize);
- lastSequenceSize = lastSequenceBytes / SendFilePartPacket::kDefaultPacketSize;
+ int lastSequenceBytes = fileSize % (fileTransferSequenceMaxLength * fileTransferPacketSize);
+ lastSequenceSize = lastSequenceBytes / fileTransferPacketSize;
if (partialPacketByteCount != 0)
lastSequenceSize++;
@@ -981,12 +1130,16 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int
for (unsigned int sequenceIndex = 0; sequenceIndex < sequenceCount; sequenceIndex++)
{
- // Min(lastSequenceSize, 131072)
- bool isLastSequence = sequenceIndex == sequenceCount - 1;
- unsigned int sequenceSize = (isLastSequence) ? lastSequenceSize : kMaxSequenceLength;
- unsigned int sequenceByteCount = ((isLastSequence) ? lastSequenceSize : kMaxSequenceLength) * SendFilePartPacket::kDefaultPacketSize + partialPacketByteCount;
+ bool isLastSequence = (sequenceIndex == sequenceCount - 1);
+ unsigned int sequenceSize = (isLastSequence) ? lastSequenceSize : fileTransferSequenceMaxLength;
+ unsigned int sequenceByteCount;
+
+ if (isLastSequence)
+ sequenceByteCount = ((partialPacketByteCount) ? lastSequenceSize - 1 : lastSequenceSize) * fileTransferPacketSize + partialPacketByteCount;
+ else
+ sequenceByteCount = fileTransferSequenceMaxLength * fileTransferPacketSize;
- FlashPartFileTransferPacket *beginFileTransferPacket = new FlashPartFileTransferPacket(0, 2 * sequenceSize);
+ FlashPartFileTransferPacket *beginFileTransferPacket = new FlashPartFileTransferPacket(sequenceByteCount);
success = SendPacket(beginFileTransferPacket);
delete beginFileTransferPacket;
@@ -1014,7 +1167,7 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int
for (unsigned int filePartIndex = 0; filePartIndex < sequenceSize; filePartIndex++)
{
// Send
- sendFilePartPacket = new SendFilePartPacket(file);
+ sendFilePartPacket = new SendFilePartPacket(file, fileTransferPacketSize);
success = SendPacket(sendFilePartPacket);
delete sendFilePartPacket;
@@ -1050,7 +1203,7 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int
Interface::PrintError("Retrying...");
// Send
- sendFilePartPacket = new SendFilePartPacket(file);
+ sendFilePartPacket = new SendFilePartPacket(file, fileTransferPacketSize);
success = SendPacket(sendFilePartPacket);
delete sendFilePartPacket;
@@ -1097,7 +1250,8 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int
return (false);
}
- bytesTransferred += SendFilePartPacket::kDefaultPacketSize;
+ bytesTransferred += fileTransferPacketSize;
+
if (bytesTransferred > fileSize)
bytesTransferred = fileSize;
@@ -1123,8 +1277,7 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int
if (destination == EndFileTransferPacket::kDestinationPhone)
{
- EndPhoneFileTransferPacket *endPhoneFileTransferPacket = new EndPhoneFileTransferPacket(sequenceByteCount, 0, chipIdentifier,
- fileIdentifier, isLastSequence);
+ EndPhoneFileTransferPacket *endPhoneFileTransferPacket = new EndPhoneFileTransferPacket(sequenceByteCount, 0, deviceType, fileIdentifier, isLastSequence);
success = SendPacket(endPhoneFileTransferPacket, 3000);
delete endPhoneFileTransferPacket;
@@ -1138,7 +1291,7 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int
}
else // destination == EndFileTransferPacket::kDestinationModem
{
- EndModemFileTransferPacket *endModemFileTransferPacket = new EndModemFileTransferPacket(sequenceByteCount, 0, chipIdentifier, isLastSequence);
+ EndModemFileTransferPacket *endModemFileTransferPacket = new EndModemFileTransferPacket(sequenceByteCount, 0, deviceType, isLastSequence);
success = SendPacket(endModemFileTransferPacket, 3000);
delete endModemFileTransferPacket;
@@ -1152,7 +1305,7 @@ bool BridgeManager::SendFile(FILE *file, unsigned int destination, unsigned int
}
fileTransferResponse = new ResponsePacket(ResponsePacket::kResponseTypeFileTransfer);
- success = ReceivePacket(fileTransferResponse, 30000);
+ success = ReceivePacket(fileTransferResponse, fileTransferSequenceTimeout);
delete fileTransferResponse;
if (!success)
diff --git a/heimdall/source/BridgeManager.h b/heimdall/source/BridgeManager.h
index f131bda..1c3a435 100644
--- a/heimdall/source/BridgeManager.h
+++ b/heimdall/source/BridgeManager.h
@@ -41,8 +41,8 @@ namespace Heimdall
const int productId;
DeviceIdentifier(int vid, int pid) :
- vendorId(vid),
- productId(pid)
+ vendorId(vid),
+ productId(pid)
{
}
};
@@ -53,10 +53,12 @@ namespace Heimdall
enum
{
- kSupportedDeviceCount = 3,
+ kSupportedDeviceCount = 3,
+ };
- kCommunicationDelayDefault = 0,
- kDumpBufferSize = 4096
+ enum
+ {
+ kCommunicationDelayDefault = 0
};
enum
@@ -83,15 +85,18 @@ namespace Heimdall
static const DeviceIdentifier supportedDevices[kSupportedDeviceCount];
bool verbose;
+ int communicationDelay;
libusb_context *libusbContext;
libusb_device_handle *deviceHandle;
libusb_device *heimdallDevice;
+
int interfaceIndex;
+ int altSettingIndex;
int inEndpoint;
int outEndpoint;
- int communicationDelay;
+ bool interfaceClaimed;
#ifdef OS_LINUX
@@ -99,29 +104,39 @@ namespace Heimdall
#endif
+ unsigned int fileTransferSequenceMaxLength;
+ unsigned int fileTransferPacketSize;
+ unsigned int fileTransferSequenceTimeout;
+
+ int FindDeviceInterface(void);
+ bool ClaimDeviceInterface(void);
+ bool SetupDeviceInterface(void);
+ void ReleaseDeviceInterface(void);
+
bool CheckProtocol(void) const;
bool InitialiseProtocol(void) const;
public:
- BridgeManager(bool verbose, int communicationDelay);
+ BridgeManager(bool verbose, int communicationDelay = BridgeManager::kCommunicationDelayDefault);
~BridgeManager();
bool DetectDevice(void);
int Initialise(void);
- bool BeginSession(void) const;
+ bool BeginSession(void);
bool EndSession(bool reboot) const;
bool SendPacket(OutboundPacket *packet, int timeout = 3000, bool retry = true) const;
- bool ReceivePacket(InboundPacket *packet, int timeout = 3000, bool retry = true) const;
+ bool ReceivePacket(InboundPacket *packet, int timeout = 3000, bool retry = true, unsigned char *buffer = nullptr, unsigned int bufferSize = -1) const;
- bool RequestDeviceInfo(unsigned int request, int *result) const;
+ bool RequestDeviceType(unsigned int request, int *result) const;
bool SendPitFile(FILE *file) 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 chipIdentifier, unsigned int fileIdentifier = 0xFFFFFFFF) const;
+ bool SendFile(FILE *file, unsigned int destination, unsigned int deviceType, unsigned int fileIdentifier = 0xFFFFFFFF) const;
bool ReceiveDump(unsigned int chipType, unsigned int chipId, FILE *file) const;
bool IsVerbose(void) const
diff --git a/heimdall/source/ClosePcScreenAction.cpp b/heimdall/source/ClosePcScreenAction.cpp
new file mode 100644
index 0000000..a7de9d9
--- /dev/null
+++ b/heimdall/source/ClosePcScreenAction.cpp
@@ -0,0 +1,94 @@
+/* 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.*/
+
+// Heimdall
+#include "Arguments.h"
+#include "BridgeManager.h"
+#include "ClosePcScreenAction.h"
+#include "Heimdall.h"
+#include "Interface.h"
+
+using namespace Heimdall;
+
+const char *ClosePcScreenAction::usage = "Action: close-pc-screen\n\
+Arguments: [--verbose] [--no-reboot] [--stdout-errors] [--delay <ms>]\n\
+Description: Attempts to get rid off the \"connect phone to PC\" screen.\n";
+
+int ClosePcScreenAction::Execute(int argc, char **argv)
+{
+ // Handle arguments
+
+ map<string, ArgumentType> argumentTypes;
+ argumentTypes["no-reboot"] = kArgumentTypeFlag;
+ argumentTypes["delay"] = kArgumentTypeUnsignedInteger;
+ argumentTypes["verbose"] = kArgumentTypeFlag;
+ argumentTypes["stdout-errors"] = kArgumentTypeFlag;
+
+ Arguments arguments(argumentTypes);
+
+ if (!arguments.ParseArguments(argc, argv, 2))
+ {
+ Interface::Print(ClosePcScreenAction::usage);
+ return (0);
+ }
+
+ const UnsignedIntegerArgument *communicationDelayArgument = static_cast<const UnsignedIntegerArgument *>(arguments.GetArgument("delay"));
+
+ bool reboot = arguments.GetArgument("no-reboot") == 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.
+
+ int communicationDelay = BridgeManager::kCommunicationDelayDefault;
+
+ if (communicationDelayArgument)
+ communicationDelay = communicationDelayArgument->GetValue();
+
+ BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay);
+
+ if (bridgeManager->Initialise() != 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);
+ }
+}
diff --git a/heimdall/source/ClosePcScreenAction.h b/heimdall/source/ClosePcScreenAction.h
new file mode 100644
index 0000000..e4470a2
--- /dev/null
+++ b/heimdall/source/ClosePcScreenAction.h
@@ -0,0 +1,34 @@
+/* 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 CLOSEPCSCREENACTION_H
+#define CLOSEPCSCREENACTION_H
+
+namespace Heimdall
+{
+ namespace ClosePcScreenAction
+ {
+ extern const char *usage;
+
+ int Execute(int argc, char **argv);
+ };
+}
+
+#endif
diff --git a/heimdall/source/ControlPacket.h b/heimdall/source/ControlPacket.h
index eb12b09..7f46d7d 100644
--- a/heimdall/source/ControlPacket.h
+++ b/heimdall/source/ControlPacket.h
@@ -32,10 +32,10 @@ namespace Heimdall
enum
{
- kControlTypeSetupSession = 0x64,
- kControlTypePitFile = 0x65,
- kControlTypeFileTransfer = 0x66,
- kControlTypeEndSession = 0x67
+ kControlTypeSession = 0x64,
+ kControlTypePitFile = 0x65,
+ kControlTypeFileTransfer = 0x66,
+ kControlTypeEndSession = 0x67
};
protected:
diff --git a/heimdall/source/DetectAction.cpp b/heimdall/source/DetectAction.cpp
new file mode 100644
index 0000000..319433f
--- /dev/null
+++ b/heimdall/source/DetectAction.cpp
@@ -0,0 +1,64 @@
+/* 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.*/
+
+// Heimdall
+#include "Arguments.h"
+#include "BridgeManager.h"
+#include "DetectAction.h"
+#include "Heimdall.h"
+#include "Interface.h"
+
+using namespace Heimdall;
+
+const char *DetectAction::usage = "Action: detect\n\
+Arguments: [--verbose] [--stdout-errors]\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;
+
+ 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);
+
+ // Download PIT file from device.
+
+ BridgeManager *bridgeManager = new BridgeManager(verbose);
+
+ bool detected = bridgeManager->DetectDevice();
+
+ delete bridgeManager;
+
+ return ((detected) ? 0 : 1);
+}
diff --git a/heimdall/source/DetectAction.h b/heimdall/source/DetectAction.h
new file mode 100644
index 0000000..374306b
--- /dev/null
+++ b/heimdall/source/DetectAction.h
@@ -0,0 +1,34 @@
+/* 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 DETECTACTION_H
+#define DETECTACTION_H
+
+namespace Heimdall
+{
+ namespace DetectAction
+ {
+ extern const char *usage;
+
+ int Execute(int argc, char **argv);
+ };
+}
+
+#endif
diff --git a/heimdall/source/DeviceTypePacket.h b/heimdall/source/DeviceTypePacket.h
new file mode 100644
index 0000000..72dbfc6
--- /dev/null
+++ b/heimdall/source/DeviceTypePacket.h
@@ -0,0 +1,39 @@
+/* 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 DEVICETYPEPACKET_H
+#define DEVICETYPEPACKET_H
+
+// Heimdall
+#include "SessionSetupPacket.h"
+
+namespace Heimdall
+{
+ class DeviceTypePacket : public SessionSetupPacket
+ {
+ public:
+
+ DeviceTypePacket() : SessionSetupPacket(SessionSetupPacket::kDeviceType)
+ {
+ }
+ };
+}
+
+#endif
diff --git a/heimdall/source/DownloadPitAction.cpp b/heimdall/source/DownloadPitAction.cpp
new file mode 100644
index 0000000..b4b81a9
--- /dev/null
+++ b/heimdall/source/DownloadPitAction.cpp
@@ -0,0 +1,135 @@
+/* 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.*/
+
+// C Standard Library
+#include <stdio.h>
+
+// Heimdall
+#include "Arguments.h"
+#include "BridgeManager.h"
+#include "DownloadPitAction.h"
+#include "Heimdall.h"
+#include "Interface.h"
+
+using namespace Heimdall;
+
+const char *DownloadPitAction::usage = "Action: download-pit\n\
+Arguments: --output <filename> [--verbose] [--no-reboot] [--stdout-errors]\n\
+ [--delay <ms>]\n\
+Description: Downloads the connected device's PIT file to the specified\n\
+ output file.\n";
+
+int DownloadPitAction::Execute(int argc, char **argv)
+{
+ // Handle arguments
+
+ map<string, ArgumentType> argumentTypes;
+ argumentTypes["output"] = kArgumentTypeString;
+ argumentTypes["no-reboot"] = kArgumentTypeFlag;
+ argumentTypes["delay"] = kArgumentTypeUnsignedInteger;
+ argumentTypes["verbose"] = kArgumentTypeFlag;
+ argumentTypes["stdout-errors"] = kArgumentTypeFlag;
+
+ 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);
+ }
+
+ const UnsignedIntegerArgument *communicationDelayArgument = static_cast<const UnsignedIntegerArgument *>(arguments.GetArgument("delay"));
+
+ bool reboot = arguments.GetArgument("no-reboot") == nullptr;
+ bool verbose = arguments.GetArgument("verbose") != nullptr;
+
+ if (arguments.GetArgument("stdout-errors") != nullptr)
+ Interface::SetStdoutErrors(true);
+
+ // Info
+
+ Interface::PrintReleaseInfo();
+ Sleep(1000);
+
+ // Open output file
+
+ const char *outputFilename = outputArgument->GetValue().c_str();
+ FILE *outputPitFile = fopen(outputFilename, "wb");
+
+ if (!outputPitFile)
+ {
+ Interface::PrintError("Failed to open output file \"%s\"\n", outputFilename);
+ return (1);
+ }
+
+ // Download PIT file from device.
+
+ int communicationDelay = BridgeManager::kCommunicationDelayDefault;
+
+ if (communicationDelayArgument)
+ communicationDelay = communicationDelayArgument->GetValue();
+
+ BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay);
+
+ if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession())
+ {
+ fclose(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;
+
+ fclose(outputPitFile);
+ delete [] pitBuffer;
+
+ return (success ? 0 : 1);
+}
diff --git a/heimdall/source/DownloadPitAction.h b/heimdall/source/DownloadPitAction.h
new file mode 100644
index 0000000..7ccc0bd
--- /dev/null
+++ b/heimdall/source/DownloadPitAction.h
@@ -0,0 +1,34 @@
+/* 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 DOWNLOADPITACTION_H
+#define DOWNLOADPITACTION_H
+
+namespace Heimdall
+{
+ namespace DownloadPitAction
+ {
+ extern const char *usage;
+
+ int Execute(int argc, char **argv);
+ };
+}
+
+#endif
diff --git a/heimdall/source/DumpAction.cpp b/heimdall/source/DumpAction.cpp
new file mode 100644
index 0000000..38ccbf9
--- /dev/null
+++ b/heimdall/source/DumpAction.cpp
@@ -0,0 +1,158 @@
+/* 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.*/
+
+// C Standard Library
+#include <stdio.h>
+
+// Heimdall
+#include "Arguments.h"
+#include "BridgeManager.h"
+#include "DumpAction.h"
+#include "Heimdall.h"
+#include "Interface.h"
+
+using namespace Heimdall;
+
+const char *DumpAction::usage = "Action: dump\n\
+Arguments: --chip-type <NAND | RAM> --chip-id <integer> --output <filename>\n\
+ [--verbose] [--no-reboot] [--stdout-errors] [--delay <ms>]\n\
+Description: Attempts to dump data from the phone corresponding to the\n\
+ specified chip type and chip ID.\n\
+NOTE: Galaxy S phones don't appear to properly support this functionality.\n";
+
+int DumpAction::Execute(int argc, char **argv)
+{
+ // Handle arguments
+
+ map<string, ArgumentType> argumentTypes;
+
+ argumentTypes["chip-type"] = kArgumentTypeString;
+ argumentTypes["chip-id"] = kArgumentTypeUnsignedInteger;
+ argumentTypes["output"] = kArgumentTypeString;
+
+ argumentTypes["no-reboot"] = kArgumentTypeFlag;
+ argumentTypes["delay"] = kArgumentTypeUnsignedInteger;
+ argumentTypes["verbose"] = kArgumentTypeFlag;
+ argumentTypes["stdout-errors"] = kArgumentTypeFlag;
+
+ Arguments arguments(argumentTypes);
+
+ if (!arguments.ParseArguments(argc, argv, 2))
+ {
+ Interface::Print(DumpAction::usage);
+ return (0);
+ }
+
+ const StringArgument *chipTypeArgument = static_cast<const StringArgument *>(arguments.GetArgument("chip-type"));
+ const UnsignedIntegerArgument *chipIdArgument = static_cast<const UnsignedIntegerArgument *>(arguments.GetArgument("chip-id"));
+ const StringArgument *outputArgument = static_cast<const StringArgument *>(arguments.GetArgument("output"));
+
+ if (!outputArgument)
+ {
+ Interface::Print("Output file was not specified.\n\n");
+ Interface::Print(DumpAction::usage);
+ return (false);
+ }
+
+ if (!chipTypeArgument)
+ {
+ Interface::Print("You must specify a chip type.\n\n");
+ Interface::Print(DumpAction::usage);
+ return (false);
+ }
+
+ if (!(chipTypeArgument->GetValue() == "RAM" || chipTypeArgument->GetValue() == "ram" || chipTypeArgument->GetValue() == "NAND"
+ || chipTypeArgument->GetValue() == "nand"))
+ {
+ Interface::Print("Unknown chip type: %s.\n\n", chipTypeArgument->GetValue().c_str());
+ Interface::Print(DumpAction::usage);
+ return (false);
+ }
+
+ if (!chipIdArgument)
+ {
+ Interface::Print("You must specify a chip ID.\n\n");
+ Interface::Print(DumpAction::usage);
+ return (false);
+ }
+
+ const UnsignedIntegerArgument *communicationDelayArgument = static_cast<const UnsignedIntegerArgument *>(arguments.GetArgument("delay"));
+
+ bool reboot = arguments.GetArgument("no-reboot") == nullptr;
+ bool verbose = arguments.GetArgument("verbose") != nullptr;
+
+ if (arguments.GetArgument("stdout-errors") != nullptr)
+ Interface::SetStdoutErrors(true);
+
+ // Open output file
+
+ const char *outputFilename = outputArgument->GetValue().c_str();
+ FILE *dumpFile = fopen(outputFilename, "wb");
+
+ if (!dumpFile)
+ {
+ Interface::PrintError("Failed to open file \"%s\"\n", outputFilename);
+ return (1);
+ }
+
+ // Info
+
+ Interface::PrintReleaseInfo();
+ Sleep(1000);
+
+ // Dump
+
+ int communicationDelay = BridgeManager::kCommunicationDelayDefault;
+
+ if (communicationDelayArgument)
+ communicationDelay = communicationDelayArgument->GetValue();
+
+ BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay);
+
+ if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession())
+ {
+ fclose(dumpFile);
+ delete bridgeManager;
+ return (1);
+ }
+
+ int chipType = 0;
+
+ if (chipTypeArgument->GetValue() == "NAND" || chipTypeArgument->GetValue() == "nand")
+ chipType = 1;
+
+ bool success = bridgeManager->ReceiveDump(chipType, chipIdArgument->GetValue(), dumpFile);
+ fclose(dumpFile);
+
+ if (!bridgeManager->EndSession(reboot))
+ success = false;
+
+ delete bridgeManager;
+
+ if (success)
+ {
+ Interface::Print("Attempt complete\n");
+ return (0);
+ }
+ else
+ {
+ return (1);
+ }
+}
diff --git a/heimdall/source/DumpAction.h b/heimdall/source/DumpAction.h
new file mode 100644
index 0000000..eb97bca
--- /dev/null
+++ b/heimdall/source/DumpAction.h
@@ -0,0 +1,34 @@
+/* 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 DUMPACTION_H
+#define DUMPACTION_H
+
+namespace Heimdall
+{
+ namespace DumpAction
+ {
+ extern const char *usage;
+
+ int Execute(int argc, char **argv);
+ };
+}
+
+#endif
diff --git a/heimdall/source/FilePartSizePacket.h b/heimdall/source/FilePartSizePacket.h
new file mode 100644
index 0000000..561ec5b
--- /dev/null
+++ b/heimdall/source/FilePartSizePacket.h
@@ -0,0 +1,56 @@
+/* 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 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
diff --git a/heimdall/source/FlashAction.cpp b/heimdall/source/FlashAction.cpp
new file mode 100644
index 0000000..d79235e
--- /dev/null
+++ b/heimdall/source/FlashAction.cpp
@@ -0,0 +1,620 @@
+/* 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.*/
+
+// C Standard Library
+#include <stdio.h>
+
+// Heimdall
+#include "Arguments.h"
+#include "BridgeManager.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 Heimdall;
+
+const char *FlashAction::usage = "Action: flash\n\
+Arguments:\n\
+ --repartition --pit <filename> [--factoryfs <filename>]\n\
+ [--cache <filename>] [--dbdata <filename>] [--primary-boot <filename>]\n\
+ [--secondary-boot <filename>] [--param <filename>] [--kernel <filename>]\n\
+ [--modem <filename>] [--radio <filename>] [--normal-boot <filename>]\n\
+ [--system <filename>] [--user-data <filename>] [--fota <filename>]\n\
+ [--hidden <filename>] [--movinand <filename>] [--data <filename>]\n\
+ [--ums <filename>] [--emmc <filename>]\n\
+ [--<partition identifier> <filename>]\n\
+ [--<partition name> <filename>]\n\
+ [--verbose] [--no-reboot] [--stdout-errors] [--delay <ms>]\n\
+ or:\n\
+ [--factoryfs <filename>] [--cache <filename>] [--dbdata <filename>]\n\
+ [--primary-boot <filename>] [--secondary-boot <filename>]\n\
+ [--secondary-boot-backup <filename>] [--param <filename>]\n\
+ [--kernel <filename>] [--recovery <filename>] [--efs <filename>]\n\
+ [--modem <filename>] [--radio <filename>] [--normal-boot <filename>]\n\
+ [--system <filename>] [--user-data <filename>] [--fota <filename>]\n\
+ [--hidden <filename>] [--movinand <filename>] [--data <filename>]\n\
+ [--ums <filename>] [--emmc <filename>] [--pit <filename>]\n\
+ [--<partition identifier> <filename>]\n\
+ [--<partition name> <filename>]\n\
+ [--verbose] [--no-reboot] [--stdout-errors] [--delay <ms>]\n\
+Description: Flashes firmware files to your phone. Partition identifiers are\n\
+ integer values, they can be obtained by executing the print-pit action.\n\
+WARNING: If you're repartitioning it's strongly recommended you specify\n\
+ all files at your disposal, including bootloaders.\n";
+
+struct PartitionFlashInfo
+{
+ const PitEntry *pitEntry;
+ FILE *file;
+
+ PartitionFlashInfo(const PitEntry *pitEntry, FILE *file)
+ {
+ this->pitEntry = pitEntry;
+ this->file = file;
+ }
+};
+
+static void buildArgumentPartitionNamesMap(map< string, vector<string> >& argumentPartitionNamesMap, map<string, string>& shortArgumentAliases)
+{
+ argumentPartitionNamesMap["pit"].push_back("PIT");
+ argumentPartitionNamesMap["factoryfs"].push_back("FACTORYFS");
+ argumentPartitionNamesMap["cache"].push_back("CACHE");
+ argumentPartitionNamesMap["dbdata"].push_back("DBDATAFS");
+
+ argumentPartitionNamesMap["primary-boot"].push_back("IBL+PBL");
+ argumentPartitionNamesMap["primary-boot"].push_back("BOOT");
+
+ argumentPartitionNamesMap["secondary-boot"].push_back("SBL");
+ argumentPartitionNamesMap["secondary-boot"].push_back("SBL1");
+
+ argumentPartitionNamesMap["secondary-boot-backup"].push_back("SBL2");
+ argumentPartitionNamesMap["param"].push_back("PARAM");
+ argumentPartitionNamesMap["kernel"].push_back("KERNEL");
+ argumentPartitionNamesMap["recovery"].push_back("RECOVERY");
+ argumentPartitionNamesMap["efs"].push_back("EFS");
+ argumentPartitionNamesMap["modem"].push_back("MODEM");
+ argumentPartitionNamesMap["radio"].push_back("RADIO");
+ argumentPartitionNamesMap["normal-boot"].push_back("NORMALBOOT");
+ argumentPartitionNamesMap["system"].push_back("SYSTEM");
+ argumentPartitionNamesMap["user-data"].push_back("USERDATA");
+ argumentPartitionNamesMap["fota"].push_back("FOTA");
+ argumentPartitionNamesMap["hidden"].push_back("HIDDEN");
+ argumentPartitionNamesMap["movinand"].push_back("MOVINAND");
+ argumentPartitionNamesMap["data"].push_back("DATAFS");
+ argumentPartitionNamesMap["ums"].push_back("UMS.EN");
+ argumentPartitionNamesMap["emmc"].push_back("GANG");
+
+ shortArgumentAliases["pit"] = "pit";
+ shortArgumentAliases["fs"] = "factoryfs";
+ shortArgumentAliases["cache"] = "cache";
+ shortArgumentAliases["db"] = "dbdata";
+ shortArgumentAliases["boot"] = "primary-boot";
+ shortArgumentAliases["sbl"] = "secondary-boot";
+ shortArgumentAliases["sbl2"] = "secondary-boot-backup";
+ shortArgumentAliases["param"] = "param";
+ shortArgumentAliases["z"] = "kernel";
+ shortArgumentAliases["rec"] = "recovery";
+ shortArgumentAliases["efs"] = "efs";
+ shortArgumentAliases["m"] = "modem";
+ shortArgumentAliases["rdio"] = "radio";
+ shortArgumentAliases["norm"] = "normal-boot";
+ shortArgumentAliases["sys"] = "system";
+ shortArgumentAliases["udata"] = "user-data";
+ shortArgumentAliases["fota"] = "fota";
+ shortArgumentAliases["hide"] = "hidden";
+ shortArgumentAliases["nand"] = "movinand";
+ shortArgumentAliases["data"] = "data";
+ shortArgumentAliases["ums"] = "ums";
+ shortArgumentAliases["emmc"] = "emmc";
+}
+
+static bool openFiles(Arguments& arguments, const map< string, vector<string> >& argumentPartitionNamesMap,
+ map<string, FILE *>& argumentFileMap)
+{
+ for (map<string, Argument *>::const_iterator it = arguments.GetArguments().begin(); it != arguments.GetArguments().end(); it++)
+ {
+ bool isPartitionArgument = false;
+ const string& argumentName = it->first;
+
+ if (arguments.GetArgumentTypes().find(argumentName) == arguments.GetArgumentTypes().end())
+ {
+ // 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.
+ isPartitionArgument = true;
+ }
+ else
+ {
+ // The argument wasn't a wild-card, check if it's a known partition name.
+ if (argumentPartitionNamesMap.find(argumentName) != argumentPartitionNamesMap.end())
+ isPartitionArgument = true;
+ }
+
+ if (isPartitionArgument)
+ {
+ const StringArgument *stringArgument = static_cast<StringArgument *>(it->second);
+ FILE *file = fopen(stringArgument->GetValue().c_str(), "rb");
+
+ if (!file)
+ {
+ Interface::PrintError("Failed to open file \"%s\"\n", stringArgument->GetValue().c_str());
+ return (false);
+ }
+
+ argumentFileMap[it->first] = file;
+ }
+ }
+
+ return (true);
+}
+
+static void closeFiles(map<string, FILE *> argumentfileMap)
+{
+ for (map<string, FILE *>::iterator it = argumentfileMap.begin(); it != argumentfileMap.end(); it++)
+ fclose(it->second);
+
+ argumentfileMap.clear();
+}
+
+static bool sendTotalTransferSize(BridgeManager *bridgeManager, const map<string, FILE *>& argumentFileMap, bool repartition)
+{
+ int totalBytes = 0;
+ for (map<string, FILE *>::const_iterator it = argumentFileMap.begin(); it != argumentFileMap.end(); it++)
+ {
+ if (repartition || it->first != "pit")
+ {
+ fseek(it->second, 0, SEEK_END);
+ totalBytes += ftell(it->second);
+ rewind(it->second);
+ }
+ }
+
+ bool success;
+
+ TotalBytesPacket *totalBytesPacket = new TotalBytesPacket(totalBytes);
+ success = bridgeManager->SendPacket(totalBytesPacket);
+ delete totalBytesPacket;
+
+ if (!success)
+ {
+ Interface::PrintError("Failed to send total bytes device info 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 device info response!\n");
+ return (false);
+ }
+
+ if (totalBytesResult != 0)
+ {
+ Interface::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%d\n", totalBytesResponse);
+ return (false);
+ }
+
+ return (true);
+}
+
+static bool setupPartitionFlashInfo(const map<string, FILE *>& argumentFileMap, const map< string, vector<string> >& argumentPartitionNamesMap,
+ const PitData *pitData, vector<PartitionFlashInfo>& partitionFlashInfos)
+{
+ for (map<string, FILE *>::const_iterator it = argumentFileMap.begin(); it != argumentFileMap.end(); it++)
+ {
+ const string& argumentName = it->first;
+ FILE *partitionFile = it->second;
+
+ const PitEntry *pitEntry = nullptr;
+
+ // Was the argument a partition identifier?
+ unsigned int partitionIdentifier;
+
+ if (Utility::ParseUnsignedInt(partitionIdentifier, argumentName.c_str()) == kNumberParsingStatusSuccess)
+ {
+ pitEntry = pitData->FindEntry(partitionIdentifier);
+
+ if (!pitEntry)
+ {
+ Interface::PrintError("No partition with identifier \"%s\" exists in the specified PIT.\n", argumentName.c_str());
+ return (false);
+ }
+ }
+ else
+ {
+ // The argument wasn't a partition identifier. Was it a known human-readable partition name?
+ map< string, vector<string> >::const_iterator argumentPartitionNamesIt = argumentPartitionNamesMap.find(argumentName);
+
+ if (argumentPartitionNamesIt != argumentPartitionNamesMap.end())
+ {
+ const vector<string>& partitionNames = argumentPartitionNamesIt->second;
+
+ // Check for the partition in the PIT file using all known names.
+ for (vector<string>::const_iterator nameIt = partitionNames.begin(); nameIt != partitionNames.end(); nameIt++)
+ {
+ pitEntry = pitData->FindEntry(nameIt->c_str());
+
+ if (pitEntry)
+ break;
+ }
+
+ if (!pitEntry)
+ {
+ Interface::PrintError("Partition name for \"%s\" could not be located\n", argumentName.c_str());
+ return (false);
+ }
+ }
+ else
+ {
+ // The argument must be an actual partition name. e.g. "ZIMAGE", instead of human-readable "kernel".
+ pitEntry = pitData->FindEntry(argumentName.c_str());
+
+ if (!pitEntry)
+ {
+ Interface::PrintError("Partition \"%s\" does not exist in the specified PIT.\n", argumentName.c_str());
+ return (false);
+ }
+ }
+ }
+
+ partitionFlashInfos.push_back(PartitionFlashInfo(pitEntry, partitionFile));
+ }
+
+ return (true);
+}
+
+static bool isKnownPartition(const map<string, vector<string> >& argumentPartitionNamesMap, const string& argumentName, const string& partitionName)
+{
+ const vector<string>& partitionNames = argumentPartitionNamesMap.find(argumentName)->second;
+
+ for (vector<string>::const_iterator it = partitionNames.begin(); it != partitionNames.end(); it++)
+ {
+ if (partitionName == *it)
+ return (true);
+ }
+
+ return (false);
+}
+
+static bool isKnownBootPartition(const map<string, vector<string> >& argumentPartitionNamesMap, const char *partitionName)
+{
+ return (isKnownPartition(argumentPartitionNamesMap, "primary-boot", partitionName)
+ || isKnownPartition(argumentPartitionNamesMap, "secondary-boot", partitionName)
+ || isKnownPartition(argumentPartitionNamesMap, "secondary-boot-backup", partitionName)
+ || isKnownPartition(argumentPartitionNamesMap, "param", partitionName)
+ || isKnownPartition(argumentPartitionNamesMap, "normal-boot", partitionName)
+ || strcmp(partitionName, "SBL3") == 0
+ || strcmp(partitionName, "ABOOT") == 0
+ || strcmp(partitionName, "RPM") == 0
+ || strcmp(partitionName, "TZ") == 0);
+}
+
+static bool flashFile(BridgeManager *bridgeManager, const map< string, vector<string> >& argumentPartitionNamesMap,
+ const PartitionFlashInfo& partitionFlashInfo)
+{
+ // PIT files need to be handled differently, try determine if the partition we're flashing to is a PIT partition.
+
+ if (isKnownPartition(argumentPartitionNamesMap, "pit", partitionFlashInfo.pitEntry->GetPartitionName()))
+ {
+ Interface::Print("Uploading %s\n", partitionFlashInfo.pitEntry->GetPartitionName());
+
+ if (bridgeManager->SendPitFile(partitionFlashInfo.file))
+ {
+ 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
+ {
+ 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())) // <-- Odin method
+ {
+ 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);
+ }
+ }
+ }
+
+ return (true);
+}
+
+static bool flashPartitions(const map<string, FILE *>& argumentFileMap, const map< string, vector<string> >& argumentPartitionNamesMap,
+ const PitData *pitData, BridgeManager *bridgeManager, bool repartition)
+{
+ vector<PartitionFlashInfo> partitionFlashInfos;
+
+ // Map the files being flashed to partitions stored in the PIT file.
+ if (!setupPartitionFlashInfo(argumentFileMap, argumentPartitionNamesMap, pitData, partitionFlashInfos))
+ return (false);
+
+ // If we're repartitioning then we need to flash the PIT file first.
+ if (repartition)
+ {
+ vector<PartitionFlashInfo>::const_iterator it;
+
+ for (it = partitionFlashInfos.begin(); it != partitionFlashInfos.end(); it++)
+ {
+ if (isKnownPartition(argumentPartitionNamesMap, "pit", it->pitEntry->GetPartitionName()))
+ {
+ if (!flashFile(bridgeManager, argumentPartitionNamesMap, *it))
+ return (false);
+
+ break;
+ }
+ }
+
+ if (it == partitionFlashInfos.end())
+ {
+ Interface::PrintError("Could not identify the PIT partition within the specified PIT file.\n\n");
+ return (false);
+ }
+ }
+
+ // Flash partitions not involved in the boot process second.
+ for (vector<PartitionFlashInfo>::const_iterator it = partitionFlashInfos.begin(); it != partitionFlashInfos.end(); it++)
+ {
+ if (!isKnownPartition(argumentPartitionNamesMap, "pit", it->pitEntry->GetPartitionName())
+ && !isKnownBootPartition(argumentPartitionNamesMap, it->pitEntry->GetPartitionName()))
+ {
+ if (!flashFile(bridgeManager, argumentPartitionNamesMap, *it))
+ return (false);
+ }
+ }
+
+ // Flash boot partitions last.
+ for (vector<PartitionFlashInfo>::const_iterator it = partitionFlashInfos.begin(); it != partitionFlashInfos.end(); it++)
+ {
+ if (isKnownBootPartition(argumentPartitionNamesMap, it->pitEntry->GetPartitionName()))
+ {
+ if (!flashFile(bridgeManager, argumentPartitionNamesMap, *it))
+ return (false);
+ }
+ }
+
+ return (true);
+}
+
+static PitData *getPitData(const map<string, FILE *>& argumentFileMap, BridgeManager *bridgeManager, bool repartition)
+{
+ PitData *pitData;
+ PitData *localPitData = nullptr;
+
+ // If a PIT file was passed as an argument then we must unpack it.
+
+ map<string, FILE *>::const_iterator localPitFileIt = argumentFileMap.find("pit");
+
+ if (localPitFileIt != argumentFileMap.end())
+ {
+ FILE *localPitFile = localPitFileIt->second;
+
+ // Load the local pit file into memory.
+ unsigned char *pitFileBuffer = new unsigned char[4096];
+ memset(pitFileBuffer, 0, 4096);
+
+ fseek(localPitFile, 0, SEEK_END);
+ long localPitFileSize = ftell(localPitFile);
+ rewind(localPitFile);
+
+ // dataRead is discarded, it's here to remove warnings.
+ int dataRead = fread(pitFileBuffer, 1, localPitFileSize, localPitFile);
+ rewind(localPitFile);
+
+ localPitData = new PitData();
+ localPitData->Unpack(pitFileBuffer);
+
+ delete [] pitFileBuffer;
+ }
+
+ 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);
+}
+
+int FlashAction::Execute(int argc, char **argv)
+{
+ // Setup argument types
+
+ map<string, ArgumentType> argumentTypes;
+
+ argumentTypes["repartition"] = kArgumentTypeString;
+
+ argumentTypes["no-reboot"] = kArgumentTypeFlag;
+ argumentTypes["delay"] = kArgumentTypeUnsignedInteger;
+ argumentTypes["verbose"] = kArgumentTypeFlag;
+ argumentTypes["stdout-errors"] = kArgumentTypeFlag;
+
+ map< string, vector<string> > argumentPartitionNamesMap;
+ map<string, string> shortArgumentAliases;
+
+ buildArgumentPartitionNamesMap(argumentPartitionNamesMap, shortArgumentAliases);
+
+ for (map< string, vector<string> >::const_iterator it = argumentPartitionNamesMap.begin(); it != argumentPartitionNamesMap.end(); it++)
+ argumentTypes[it->first] = kArgumentTypeString;
+
+ // 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);
+ }
+
+ const UnsignedIntegerArgument *communicationDelayArgument = static_cast<const UnsignedIntegerArgument *>(arguments.GetArgument("delay"));
+
+ bool reboot = arguments.GetArgument("no-reboot") == nullptr;
+ bool verbose = arguments.GetArgument("verbose") != nullptr;
+
+ if (arguments.GetArgument("stdout-errors") != nullptr)
+ Interface::SetStdoutErrors(true);
+
+ 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
+
+ map<string, FILE *> argumentFileMap;
+
+ if (!openFiles(arguments, argumentPartitionNamesMap, argumentFileMap))
+ {
+ closeFiles(argumentFileMap);
+ return (1);
+ }
+
+ if (argumentFileMap.size() == 0)
+ {
+ Interface::Print(FlashAction::usage);
+ return (0);
+ }
+
+ // Info
+
+ Interface::PrintReleaseInfo();
+ Sleep(1000);
+
+ // Perform flash
+
+ int communicationDelay = BridgeManager::kCommunicationDelayDefault;
+
+ if (communicationDelayArgument)
+ communicationDelay = communicationDelayArgument->GetValue();
+
+ BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay);
+
+ if (bridgeManager->Initialise() != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession())
+ {
+ closeFiles(argumentFileMap);
+ delete bridgeManager;
+
+ return (1);
+ }
+
+ bool success = sendTotalTransferSize(bridgeManager, argumentFileMap, repartition);
+
+ if (success)
+ {
+ PitData *pitData = getPitData(argumentFileMap, bridgeManager, repartition);
+
+ if (pitData)
+ success = flashPartitions(argumentFileMap, argumentPartitionNamesMap, pitData, bridgeManager, repartition);
+ else
+ success = false;
+
+ delete pitData;
+ }
+
+ closeFiles(argumentFileMap);
+
+ if (!bridgeManager->EndSession(reboot))
+ success = false;
+
+ delete bridgeManager;
+
+ return (success ? 0 : 1);
+}
diff --git a/heimdall/source/FlashAction.h b/heimdall/source/FlashAction.h
new file mode 100644
index 0000000..b4e1b6b
--- /dev/null
+++ b/heimdall/source/FlashAction.h
@@ -0,0 +1,34 @@
+/* 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 FLASHACTION_H
+#define FLASHACTION_H
+
+namespace Heimdall
+{
+ namespace FlashAction
+ {
+ extern const char *usage;
+
+ int Execute(int argc, char **argv);
+ };
+}
+
+#endif
diff --git a/heimdall/source/FlashPartFileTransferPacket.h b/heimdall/source/FlashPartFileTransferPacket.h
index a444211..dcf3422 100644
--- a/heimdall/source/FlashPartFileTransferPacket.h
+++ b/heimdall/source/FlashPartFileTransferPacket.h
@@ -30,34 +30,26 @@ namespace Heimdall
{
private:
- unsigned short unknown;
- unsigned int transferCount;
+ unsigned int sequenceByteCount;
public:
- FlashPartFileTransferPacket(unsigned short unknown, unsigned int transferCount)
+ FlashPartFileTransferPacket(unsigned int sequenceByteCount)
: FileTransferPacket(FileTransferPacket::kRequestPart)
{
- this->unknown = unknown;
- this->transferCount = transferCount;
+ this->sequenceByteCount = sequenceByteCount;
}
- unsigned short GetUnknown(void) const
+ unsigned int GetSequenceByteCount(void) const
{
- return (unknown);
- }
-
- unsigned int GetTransferCount(void) const
- {
- return (transferCount);
+ return (sequenceByteCount);
}
void Pack(void)
{
FileTransferPacket::Pack();
- PackShort(FileTransferPacket::kDataSize, unknown);
- PackInteger(FileTransferPacket::kDataSize + 2, transferCount);
+ PackInteger(FileTransferPacket::kDataSize, sequenceByteCount);
}
};
}
diff --git a/heimdall/source/Heimdall.h b/heimdall/source/Heimdall.h
index eb3c96c..1cb2eaa 100644
--- a/heimdall/source/Heimdall.h
+++ b/heimdall/source/Heimdall.h
@@ -23,6 +23,7 @@
#ifdef OS_WINDOWS
#include <Windows.h>
+#undef GetBinaryType
#else
#include "../config.h"
diff --git a/heimdall/source/HelpAction.cpp b/heimdall/source/HelpAction.cpp
new file mode 100644
index 0000000..f041a81
--- /dev/null
+++ b/heimdall/source/HelpAction.cpp
@@ -0,0 +1,35 @@
+/* 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.*/
+
+// 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);
+}
diff --git a/heimdall/source/HelpAction.h b/heimdall/source/HelpAction.h
new file mode 100644
index 0000000..7fb3e82
--- /dev/null
+++ b/heimdall/source/HelpAction.h
@@ -0,0 +1,34 @@
+/* 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 HELPACTION_H
+#define HELPACTION_H
+
+namespace Heimdall
+{
+ namespace HelpAction
+ {
+ extern const char *usage;
+
+ int Execute(int argc, char **argv);
+ };
+}
+
+#endif
diff --git a/heimdall/source/InfoAction.cpp b/heimdall/source/InfoAction.cpp
new file mode 100644
index 0000000..740f4e2
--- /dev/null
+++ b/heimdall/source/InfoAction.cpp
@@ -0,0 +1,35 @@
+/* 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.*/
+
+// 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);
+}
diff --git a/heimdall/source/InfoAction.h b/heimdall/source/InfoAction.h
new file mode 100644
index 0000000..8829d4a
--- /dev/null
+++ b/heimdall/source/InfoAction.h
@@ -0,0 +1,34 @@
+/* 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 INFOACTION_H
+#define INFOACTION_H
+
+namespace Heimdall
+{
+ namespace InfoAction
+ {
+ extern const char *usage;
+
+ int Execute(int argc, char **argv);
+ };
+}
+
+#endif
diff --git a/heimdall/source/Interface.cpp b/heimdall/source/Interface.cpp
index 4d42ad0..67f1bee 100644
--- a/heimdall/source/Interface.cpp
+++ b/heimdall/source/Interface.cpp
@@ -24,342 +24,108 @@
#include <stdio.h>
// Heimdall
+#include "ClosePcScreenAction.h"
+#include "DetectAction.h"
+#include "DownloadPitAction.h"
+#include "DumpAction.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;
-bool Interface::stdoutErrors = false;
+map<string, Interface::ActionInfo> actionMap;
+bool stdoutErrors = false;
+
+const char *version = "v1.4 RC1";
+const char *actionUsage = "Usage: heimdall <action> <action arguments>\n";
-const char *Interface::version = "v1.3.2";
-
-const char *Interface::usage = "Usage: heimdall <action> <action arguments> <common arguments>\n\
-\n\
-Common Arguments:\n\
- [--verbose] [--no-reboot] [--stdout-errors] [--delay <ms>]\n\
-\n\
-\n\
-Action: flash\n\
-Arguments:\n\
- --repartition --pit <filename> [--factoryfs <filename>]\n\
- [--cache <filename>] [--dbdata <filename>] [--primary-boot <filename>]\n\
- [--secondary-boot <filename>] [--param <filename>] [--kernel <filename>]\n\
- [--modem <filename>] [--normal-boot <filename>] [--system <filename>]\n\
- [--user-data <filename>] [--fota <filename>] [--hidden <filename>]\n\
- [--movinand <filename>] [--data <filename>] [--ums <filename>]\n\
- [--emmc <filename>] [--<partition identifier> <filename>]\n\
- or:\n\
- [--factoryfs <filename>] [--cache <filename>] [--dbdata <filename>]\n\
- [--primary-boot <filename>] [--secondary-boot <filename>]\n\
- [--secondary-boot-backup <filename>] [--param <filename>]\n\
- [--kernel <filename>] [--recovery <filename>] [--efs <filename>]\n\
- [--modem <filename>] [--normal-boot <filename>] [--system <filename>]\n\
- [--user-data <filename>] [--fota <filename>] [--hidden <filename>]\n\
- [--movinand <filename>] [--data <filename>] [--ums <filename>]\n\
- [--emmc <filename>] [--<partition identifier> <filename>]\n\
-Description: Flashes firmware files to your phone.\n\
-WARNING: If you're repartitioning it's strongly recommended you specify\n\
- all files at your disposal, including bootloaders.\n\
-\n\
-Action: close-pc-screen\n\
-Description: Attempts to get rid off the \"connect phone to PC\" screen.\n\
-\n\
-Action: download-pit\n\
-Arguments: --output <filename>\n\
-Description: Downloads the connected device's PIT file to the specified\n\
- output file.\n\
-\n\
-Action: detect\n\
-Description: Indicates whether or not a download mode device can be detected.\n\
-\n\
-Action: dump\n\
-Arguments: --chip-type <NAND | RAM> --chip-id <integer> --output <filename>\n\
-Description: Attempts to dump data from the phone corresponding to the\n\
- specified chip type and chip ID.\n\
-NOTE: Galaxy S phones don't appear to properly support this functionality.\n\
-\n\
-Action: print-pit\n\
-Description: Dumps the PIT file from the connected device and prints it in\n\
- a human readable format.\n\
-\n\
-Action: version\n\
-Description: Displays the version number of this binary.\n\
-\n\
-Action: help\n\
-Description: Displays this dialogue.\n";
-
-const char *Interface::releaseInfo = "Heimdall %s, Copyright (c) 2010-2012, Benjamin Dobell, Glass Echidna\n\
-http://www.glassechidna.com.au\n\n\
+const char *releaseInfo = "Heimdall %s\n\n\
+Copyright (c) 2010-2012, 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";
-const char *Interface::extraInfo = "Heimdall utilises libusb-1.0 for all USB communication:\n\
+static const char *extraInfo = "Heimdall utilises libusb-1.0 for all USB communication:\n\
http://www.libusb.org/\n\
\n\
libusb-1.0 is licensed under the LGPL-2.1:\n\
http://www.gnu.org/licenses/licenses.html#LGPL\n\n";
-// Flash arguments
-string Interface::flashValueArguments[kFlashValueArgCount] = {
- "-pit", "-factoryfs", "-cache", "-dbdata", "-primary-boot", "-secondary-boot", "-secondary-boot-backup", "-param", "-kernel", "-recovery", "-efs", "-modem",
- "-normal-boot", "-system", "-user-data", "-fota", "-hidden", "-movinand", "-data", "-ums", "-emmc", "-%d"
-};
-
-string Interface::flashValueShortArguments[kFlashValueArgCount] = {
- "pit", "fs", "cache", "db", "boot", "sbl", "sbl2", "param", "z", "rec", "efs", "m",
- "norm", "sys", "udata", "fota", "hide", "nand", "data", "ums", "emmc", "%d"
-};
-
-string Interface::flashValuelessArguments[kFlashValuelessArgCount] = {
- "-repartition"
-};
-
-string Interface::flashValuelessShortArguments[kFlashValuelessArgCount] = {
- "r"
-};
-
-// Download PIT arguments
-string Interface::downloadPitValueArguments[kDownloadPitValueArgCount] = {
- "-output"
-};
-
-string Interface::downloadPitValueShortArguments[kDownloadPitValueArgCount] = {
- "o"
-};
-
-// Dump arguments
-string Interface::dumpValueArguments[kDumpValueArgCount] = {
- "-chip-type", "-chip-id", "-output"
-};
-
-string Interface::dumpValueShortArguments[kDumpValueArgCount] = {
- "type", "id", "out"
-};
-
-// Common arguments
-string Interface::commonValueArguments[kCommonValueArgCount] = {
- "-delay"
-};
-
-string Interface::commonValueShortArguments[kCommonValueArgCount] = {
- "d"
-};
-
-string Interface::commonValuelessArguments[kCommonValuelessArgCount] = {
- "-verbose", "-no-reboot", "-stdout-errors"
-};
-
-string Interface::commonValuelessShortArguments[kCommonValuelessArgCount] = {
- "v", "nobt", "err"
-};
-
-Action Interface::actions[Interface::kActionCount] = {
- // kActionFlash
- Action("flash", flashValueArguments, flashValueShortArguments, kFlashValueArgCount,
- flashValuelessArguments, flashValuelessShortArguments, kFlashValuelessArgCount),
-
- // kActionClosePcScreen
- Action("close-pc-screen", nullptr, nullptr, kClosePcScreenValueArgCount,
- nullptr, nullptr, kClosePcScreenValuelessArgCount),
-
- // kActionDump
- Action("dump", dumpValueArguments, dumpValueShortArguments, kDumpValueArgCount,
- nullptr, nullptr, kDumpValuelessArgCount),
-
- // kActionPrintPit
- Action("print-pit", nullptr, nullptr, kPrintPitValueArgCount,
- nullptr, nullptr, kPrintPitValuelessArgCount),
-
- // kActionVersion
- Action("version", nullptr, nullptr, kVersionValueArgCount,
- nullptr, nullptr, kVersionValuelessArgCount),
-
- // kActionHelp
- Action("help", nullptr, nullptr, kHelpValueArgCount,
- nullptr, nullptr, kHelpValuelessArgCount),
-
- // kActionDetect
- Action("detect", nullptr, nullptr, kDetectValueArgCount,
- nullptr, nullptr, kDetectValuelessArgCount),
-
- // kActionDownloadPit
- Action("download-pit", downloadPitValueArguments, downloadPitValueShortArguments, kDownloadPitValueArgCount,
- nullptr, nullptr, kDownloadPitValuelessArgCount),
-
- // kActionInfo
- Action("info", nullptr, nullptr, kInfoValueArgCount,
- nullptr, nullptr, kInfoValuelessArgCount)
-};
-
-bool Interface::GetArguments(int argc, char **argv, map<string, string>& argumentMap, int *actionIndex)
+void populateActionMap(void)
{
- if (argc < 2)
- {
- Print(usage, version);
- return (false);
- }
-
- const char *actionName = argv[1];
- *actionIndex = -1;
-
- for (int i = 0; i < kActionCount; i++)
- {
- if (actions[i].name == actionName)
- {
- *actionIndex = i;
- break;
- }
- }
-
- if (*actionIndex < 0)
- {
- Print("Unknown action \"%s\"\n\n", actionName);
- Print(usage, version);
- return (false);
- }
-
- const Action& action = actions[*actionIndex];
-
- for (int argIndex = 2; argIndex < argc; argIndex++)
- {
- if (*(argv[argIndex]) != '-')
- {
- Print(usage, version);
- return (false);
- }
-
- string argumentName = (char *)(argv[argIndex] + 1);
-
- // Check if the argument is a valid valueless argument
- bool valid = false;
-
- for (unsigned int i = 0; i < action.valuelessArgumentCount; i++)
- {
- if (argumentName == action.valuelessArguments[i] || argumentName == action.valuelessShortArguments[i])
- {
- argumentName = action.valuelessArguments[i];
- valid = true;
- break;
- }
- }
-
- if (!valid)
- {
- // Check if it's a common valueless argument
- for (unsigned int i = 0; i < kCommonValuelessArgCount; i++)
- {
- if (argumentName == commonValuelessArguments[i] || argumentName == commonValuelessShortArguments[i])
- {
- argumentName = commonValuelessArguments[i];
- valid = true;
- break;
- }
- }
- }
+ 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["dump"] = Interface::ActionInfo(&DumpAction::Execute, DumpAction::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);
+}
- if (valid)
- {
- // The argument is valueless
- argumentMap.insert(pair<string, string>(argumentName, ""));
- continue;
- }
+const map<string, Interface::ActionInfo>& Interface::GetActionMap(void)
+{
+ if (actionMap.size() == 0)
+ populateActionMap();
- // Check if the argument is a valid value argument
- for (unsigned int i = 0; i < action.valueArgumentCount; i++)
- {
- // Support for --<integer> and -<integer> parameters.
- if (argumentName.length() > 1 && action.valueArguments[i] == "-%d")
- {
- if (atoi(argumentName.substr(1).c_str()) > 0 || argumentName == "-0")
- {
- valid = true;
- break;
- }
- }
- else if (action.valueArguments[i] == "%d")
- {
- if (atoi(argumentName.c_str()) > 0 || argumentName == "0")
- {
- argumentName = "-" + argumentName;
- valid = true;
- break;
- }
- }
+ return actionMap;
+}
- if (argumentName == action.valueArguments[i] || argumentName == action.valueShortArguments[i])
- {
- argumentName = action.valueArguments[i];
- valid = true;
- break;
- }
- }
+void Interface::Print(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
- if (!valid)
- {
- // Check if it's a common value argument
- for (unsigned int i = 0; i < kCommonValueArgCount; i++)
- {
- // Support for --<integer> and -<integer> parameters.
- if (argumentName.length() > 1 && commonValueArguments[i] == "-%d")
- {
- if (atoi(argumentName.substr(1).c_str()) > 0 || argumentName == "-0")
- {
- valid = true;
- break;
- }
- }
- else if (commonValueArguments[i] == "%d")
- {
- if (atoi(argumentName.c_str()) > 0 || argumentName == "0")
- {
- argumentName = "-" + argumentName;
- valid = true;
- break;
- }
- }
-
- if (argumentName == commonValueArguments[i] || argumentName == commonValueShortArguments[i])
- {
- argumentName = commonValueArguments[i];
- valid = true;
- break;
- }
- }
- }
+ vfprintf(stdout, format, args);
+ fflush(stdout);
- if (!valid)
- {
- PrintError("\"%s\" is not a valid argument\n", argumentName.c_str());
- return (false);
- }
+ va_end(args);
+
+}
- argIndex++;
+void Interface::PrintWarning(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
- if (argIndex >= argc)
- {
- PrintError("\"%s\" is missing a value\n", argumentName.c_str());
- return (false);
- }
+ fprintf(stderr, "WARNING: ");
+ vfprintf(stderr, format, args);
+ fflush(stderr);
- argumentMap.insert(pair<string, string>(argumentName, argv[argIndex]));
+ if (stdoutErrors)
+ {
+ fprintf(stdout, "WARNING: ");
+ vfprintf(stdout, format, args);
+ fflush(stdout);
}
- return (true);
+ va_end(args);
}
-void Interface::Print(const char *format, ...)
+void Interface::PrintWarningSameLine(const char *format, ...)
{
va_list args;
va_start(args, format);
- vfprintf(stdout, format, args);
- fflush(stdout);
+ vfprintf(stderr, format, args);
+ fflush(stderr);
+
+ if (stdoutErrors)
+ {
+ vfprintf(stdout, format, args);
+ fflush(stdout);
+ }
va_end(args);
-
}
void Interface::PrintError(const char *format, ...)
@@ -400,28 +166,33 @@ void Interface::PrintErrorSameLine(const char *format, ...)
void Interface::PrintVersion(void)
{
- Print("%s\n", version);
+ Interface::Print("%s\n", version);
}
void Interface::PrintUsage(void)
{
- Print(usage);
+ 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)
{
- Print(releaseInfo, version);
+ Interface::Print(releaseInfo, version);
}
void Interface::PrintFullInfo(void)
{
- Print(releaseInfo, version);
- Print(extraInfo);
+ Interface::Print(releaseInfo, version);
+ Interface::Print(extraInfo);
}
void Interface::PrintDeviceDetectionFailed(void)
{
- Print("Failed to detect compatible download-mode device.\n");
+ Interface::PrintError("Failed to detect compatible download-mode device.\n");
}
void Interface::PrintPit(const PitData *pitData)
@@ -442,34 +213,107 @@ void Interface::PrintPit(const PitData *pitData)
const PitEntry *entry = pitData->GetEntry(i);
Interface::Print("\n\n--- Entry #%d ---\n", i);
- Interface::Print("Unused: %s\n", (entry->GetUnused()) ? "Yes" : "No");
+ Interface::Print("Binary Type: %d (", entry->GetBinaryType());
- const char *chipIdentifierText = "Unknown";
+ switch (entry->GetBinaryType())
+ {
+ case PitEntry::kBinaryTypeApplicationProcessor:
+ Interface::Print("AP");
+ break;
- Interface::Print("Chip Identifier: %d (%s)\n", entry->GetChipIdentifier());
+ case PitEntry::kBinaryTypeCommunicationProcessor:
+ Interface::Print("CP");
+ break;
- Interface::Print("Partition Identifier: %d\n", entry->GetPartitionIdentifier());
+ default:
+ Interface::Print("Unknown");
+ break;
+ }
- Interface::Print("Partition Flags: %d (", entry->GetPartitionFlags());
+ Interface::Print(")\n");
- if (entry->GetPartitionFlags() & PitEntry::kPartitionFlagWrite)
- Interface::Print("R/W");
+ 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::kAttributeWrite)
+ Interface::Print("Read/Write");
else
- Interface::Print("R");
+ Interface::Print("Read-Only");
Interface::Print(")\n");
- Interface::Print("Unknown 1: %d\n", entry->GetUnknown1());
+ 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: %d\n", entry->GetPartitionBlockSize());
- Interface::Print("Partition Block Count: %d\n", entry->GetPartitionBlockCount());
+ Interface::Print("Partition Block Size: %d\n", entry->GetBlockSize());
+ Interface::Print("Partition Block Count: %d\n", entry->GetBlockCount());
- Interface::Print("Unknown 2: %d\n", entry->GetUnknown2());
- Interface::Print("Unknown 3: %d\n", entry->GetUnknown3());
+ 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("Filename: %s\n", entry->GetFilename());
+ 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;
+}
diff --git a/heimdall/source/Interface.h b/heimdall/source/Interface.h
index ddb7f55..ab4b538 100644
--- a/heimdall/source/Interface.h
+++ b/heimdall/source/Interface.h
@@ -28,276 +28,55 @@
// libpit
#include "libpit.h"
+// Heimdall
+#include "Heimdall.h"
+
using namespace std;
using namespace libpit;
namespace Heimdall
{
- struct Action
+ namespace Interface
{
- public:
-
- string name;
-
- string *valueArguments;
- string *valueShortArguments;
- unsigned int valueArgumentCount;
+ typedef int (*ActionExecuteFunction)(int, char **);
- string *valuelessArguments;
- string *valuelessShortArguments;
- unsigned int valuelessArgumentCount;
+ typedef struct ActionInfo
+ {
+ ActionExecuteFunction executeFunction;
+ const char *usage;
- Action(const char *name, string *valueArguments, string *valueShortArguments, unsigned int valueArgumentCount,
- string *valuelessArguments, string *valuelessShortArguments, unsigned int valuelessArgumentCount)
+ ActionInfo()
{
- this->name = name;
-
- this->valueArguments = valueArguments;
- this->valueShortArguments = valueShortArguments;
- this->valueArgumentCount = valueArgumentCount;
-
- this->valuelessArguments = valuelessArguments;
- this->valuelessShortArguments = valuelessShortArguments;
- this->valuelessArgumentCount = valuelessArgumentCount;
+ executeFunction = nullptr;
+ usage = nullptr;
}
- };
-
- class Interface
- {
- public:
-
- // Actions
- enum
- {
- kActionFlash = 0,
- kActionClosePcScreen,
- kActionDump,
- kActionPrintPit,
- kActionVersion,
- kActionHelp,
- kActionDetect,
- kActionDownloadPit,
- kActionInfo,
- kActionCount
- };
- // Flash value arguments
- enum
+ ActionInfo(ActionExecuteFunction executeFunction, const char *usage)
{
- kFlashValueArgPit,
- kFlashValueArgFactoryFs,
- kFlashValueArgCache,
- kFlashValueArgDatabaseData,
- kFlashValueArgPrimaryBootloader,
- kFlashValueArgSecondaryBootloader,
- kFlashValueArgSecondaryBootloaderBackup,
- kFlashValueArgParam,
- kFlashValueArgKernel,
- kFlashValueArgRecovery,
- kFlashValueArgEfs,
- kFlashValueArgModem,
-
- kFlashValueArgNormalBoot,
- kFlashValueArgSystem,
- kFlashValueArgUserData,
- kFlashValueArgFota,
- kFlashValueArgHidden,
- kFlashValueArgMovinand,
- kFlashValueArgData,
- kFlashValueArgUms,
- kFlashValueArgEmmc,
-
- kFlashValueArgPartitionIndex,
-
- kFlashValueArgCount
- };
-
- // Flash valueless arguments
- enum
- {
- kFlashValuelessArgRepartition = 0,
-
- kFlashValuelessArgCount
- };
-
- // Close PC Screen value arguments
- enum
- {
- kClosePcScreenValueArgCount = 0
- };
-
- // Close PC Screen valueless arguments
- enum
- {
- kClosePcScreenValuelessArgCount = 0
- };
-
- // Dump value arguments
- enum
- {
- kDumpValueArgChipType = 0,
- kDumpValueArgChipId,
- kDumpValueArgOutput,
-
- kDumpValueArgCount
- };
-
- // Dump valueless arguments
- enum
- {
- kDumpValuelessArgCount = 0
- };
-
- // Print PIT value arguments
- enum
- {
- kPrintPitValueArgCount = 0
- };
-
- // Print PIT valueless arguments
- enum
- {
- kPrintPitValuelessArgCount = 0
- };
-
- // Version value arguments
- enum
- {
- kVersionValueArgCount = 0
- };
-
- // Version valueless arguments
- enum
- {
- kVersionValuelessArgCount = 0
- };
-
- // Help value arguments
- enum
- {
- kHelpValueArgCount = 0
- };
-
- // Help valueless arguments
- enum
- {
- kHelpValuelessArgCount = 0
- };
-
- // Info value arguments
- enum
- {
- kInfoValueArgCount = 0
- };
-
- // Info valueless arguments
- enum
- {
- kInfoValuelessArgCount = 0
- };
-
- // Detect value arguments
- enum
- {
- kDetectValueArgCount = 0
- };
-
- // Detect valueless arguments
- enum
- {
- kDetectValuelessArgCount = 0
- };
-
- // Download PIT value arguments
- enum
- {
- kDownloadPitValueArgOutput = 0,
- kDownloadPitValueArgCount
- };
-
- // Download PIT valueless arguments
- enum
- {
- kDownloadPitValuelessArgCount = 0
- };
-
- // Common value arguments
- enum
- {
- kCommonValueArgDelay = 0,
-
- kCommonValueArgCount
- };
-
- // Comon valueless arguments
- enum
- {
- kCommonValuelessArgVerbose = 0,
- kCommonValuelessArgNoReboot,
- kCommonValuelessArgStdoutErrors,
-
- kCommonValuelessArgCount
- };
-
- private:
-
- static bool stdoutErrors;
-
- static const char *version;
- static const char *usage;
- static const char *releaseInfo;
- static const char *extraInfo;
-
- // Flash arguments
- static string flashValueArguments[kFlashValueArgCount];
- static string flashValueShortArguments[kFlashValueArgCount];
-
- static string flashValuelessArguments[kFlashValuelessArgCount];
- static string flashValuelessShortArguments[kFlashValuelessArgCount];
-
- // Download PIT arguments
- static string downloadPitValueArguments[kDownloadPitValueArgCount];
- static string downloadPitValueShortArguments[kDownloadPitValueArgCount];
-
- // Dump arguments
- static string dumpValueArguments[kDumpValueArgCount];
- static string dumpValueShortArguments[kDumpValueArgCount];
-
- public:
-
- // Common arguments
- static string commonValueArguments[kCommonValueArgCount];
- static string commonValueShortArguments[kCommonValueArgCount];
-
- static string commonValuelessArguments[kCommonValuelessArgCount];
- static string commonValuelessShortArguments[kCommonValuelessArgCount];
-
- static Action actions[kActionCount];
+ this->executeFunction = executeFunction;
+ this->usage = usage;
+ }
- static bool GetArguments(int argc, char **argv, map<string, string>& argumentMap, int *actionIndex);
+ } ActionInfo;
- static void Print(const char *format, ...);
- static void PrintError(const char *format, ...);
- static void PrintErrorSameLine(const char *format, ...);
+ const map<string, ActionInfo>& GetActionMap(void);
- static void PrintVersion(void);
- static void PrintUsage(void);
- static void PrintReleaseInfo(void);
- static void PrintFullInfo(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, ...);
- static void PrintDeviceDetectionFailed(void);
+ void PrintVersion(void);
+ void PrintUsage(void);
+ void PrintReleaseInfo(void);
+ void PrintFullInfo(void);
- static void PrintPit(const PitData *pitData);
+ void PrintDeviceDetectionFailed(void);
- static string& GetPitArgument(void)
- {
- return (flashValueArguments[kFlashValueArgPit]);
- }
+ void PrintPit(const PitData *pitData);
- static void SetStdoutErrors(bool enabled)
- {
- stdoutErrors = enabled;
- }
+ void SetStdoutErrors(bool enabled);
};
}
diff --git a/heimdall/source/Packet.h b/heimdall/source/Packet.h
index 41ce081..9f47e33 100644
--- a/heimdall/source/Packet.h
+++ b/heimdall/source/Packet.h
@@ -50,7 +50,7 @@ namespace Heimdall
delete [] data;
}
- int GetSize(void) const
+ unsigned int GetSize(void) const
{
return (size);
}
diff --git a/heimdall/source/PrintPitAction.cpp b/heimdall/source/PrintPitAction.cpp
new file mode 100644
index 0000000..c520d1c
--- /dev/null
+++ b/heimdall/source/PrintPitAction.cpp
@@ -0,0 +1,159 @@
+/* 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.*/
+
+// C Standard Library
+#include <stdio.h>
+
+// Heimdall
+#include "Arguments.h"
+#include "BridgeManager.h"
+#include "Heimdall.h"
+#include "Interface.h"
+#include "PrintPitAction.h"
+
+using namespace Heimdall;
+
+const char *PrintPitAction::usage = "Action: print-pit\n\
+Arguments: [--file <filename>] [--verbose] [--no-reboot] [--stdout-errors]\n\
+ [--delay <ms>]\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";
+
+int PrintPitAction::Execute(int argc, char **argv)
+{
+ // Handle arguments
+
+ map<string, ArgumentType> argumentTypes;
+ argumentTypes["file"] = kArgumentTypeString;
+ argumentTypes["no-reboot"] = kArgumentTypeFlag;
+ argumentTypes["delay"] = kArgumentTypeUnsignedInteger;
+ argumentTypes["verbose"] = kArgumentTypeFlag;
+ argumentTypes["stdout-errors"] = kArgumentTypeFlag;
+
+ 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"));
+ const UnsignedIntegerArgument *communicationDelayArgument = static_cast<const UnsignedIntegerArgument *>(arguments.GetArgument("delay"));
+
+ bool reboot = arguments.GetArgument("no-reboot") == nullptr;
+ bool verbose = arguments.GetArgument("verbose") != nullptr;
+
+ if (arguments.GetArgument("stdout-errors") != nullptr)
+ Interface::SetStdoutErrors(true);
+
+ // Open file (if specified).
+
+ FILE *localPitFile = nullptr;
+
+ if (fileArgument)
+ {
+ const char *filename = fileArgument->GetValue().c_str();
+
+ localPitFile = fopen(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.
+
+ fseek(localPitFile, 0, SEEK_END);
+ long localPitFileSize = ftell(localPitFile);
+ rewind(localPitFile);
+
+ // Load the local pit file into memory.
+ unsigned char *pitFileBuffer = new unsigned char[localPitFileSize];
+ size_t dataRead = fread(pitFileBuffer, 1, localPitFileSize, localPitFile); // dataRead is discarded, it's here to remove warnings.
+ fclose(localPitFile);
+
+ PitData *pitData = new PitData();
+ pitData->Unpack(pitFileBuffer);
+
+ delete [] pitFileBuffer;
+
+ Interface::PrintPit(pitData);
+ delete pitData;
+
+ return (0);
+ }
+ else
+ {
+ // Print PIT from a device.
+
+ int communicationDelay = BridgeManager::kCommunicationDelayDefault;
+
+ if (communicationDelayArgument)
+ communicationDelay = communicationDelayArgument->GetValue();
+
+ BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay);
+
+ if (bridgeManager->Initialise() != 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);
+ }
+}
diff --git a/heimdall/source/PrintPitAction.h b/heimdall/source/PrintPitAction.h
new file mode 100644
index 0000000..5bbfd3d
--- /dev/null
+++ b/heimdall/source/PrintPitAction.h
@@ -0,0 +1,34 @@
+/* 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 PRINTPITACTION_H
+#define PRINTPITACTION_H
+
+namespace Heimdall
+{
+ namespace PrintPitAction
+ {
+ extern const char *usage;
+
+ int Execute(int argc, char **argv);
+ };
+}
+
+#endif
diff --git a/heimdall/source/ResponsePacket.h b/heimdall/source/ResponsePacket.h
index e8678cf..9c5c2cc 100644
--- a/heimdall/source/ResponsePacket.h
+++ b/heimdall/source/ResponsePacket.h
@@ -32,11 +32,11 @@ namespace Heimdall
enum
{
- kResponseTypeSendFilePart = 0x00,
- kResponseTypeBeginSession = 0x64,
- kResponseTypePitFile = 0x65,
- kResponseTypeFileTransfer = 0x66,
- kResponseTypeEndSession = 0x67
+ kResponseTypeSendFilePart = 0x00,
+ kResponseTypeSessionSetup = 0x64,
+ kResponseTypePitFile = 0x65,
+ kResponseTypeFileTransfer = 0x66,
+ kResponseTypeEndSession = 0x67
};
private:
diff --git a/heimdall/source/SendFilePartPacket.h b/heimdall/source/SendFilePartPacket.h
index 8f6e27f..066aacb 100644
--- a/heimdall/source/SendFilePartPacket.h
+++ b/heimdall/source/SendFilePartPacket.h
@@ -34,12 +34,7 @@ namespace Heimdall
{
public:
- enum
- {
- kDefaultPacketSize = 131072
- };
-
- SendFilePartPacket(FILE *file, int size = SendFilePartPacket::kDefaultPacketSize) : OutboundPacket(size)
+ SendFilePartPacket(FILE *file, int size) : OutboundPacket(size)
{
memset(data, 0, size);
diff --git a/heimdall/source/SessionSetupPacket.h b/heimdall/source/SessionSetupPacket.h
new file mode 100644
index 0000000..9a91684
--- /dev/null
+++ b/heimdall/source/SessionSetupPacket.h
@@ -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 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
+ };
+
+ 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
diff --git a/heimdall/source/SessionSetupResponse.h b/heimdall/source/SessionSetupResponse.h
new file mode 100644
index 0000000..f7c1175
--- /dev/null
+++ b/heimdall/source/SessionSetupResponse.h
@@ -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 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
diff --git a/heimdall/source/TotalBytesPacket.h b/heimdall/source/TotalBytesPacket.h
new file mode 100644
index 0000000..60190ec
--- /dev/null
+++ b/heimdall/source/TotalBytesPacket.h
@@ -0,0 +1,56 @@
+/* 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 TOTALBYTESSPACKET_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
diff --git a/heimdall/source/Utility.cpp b/heimdall/source/Utility.cpp
new file mode 100644
index 0000000..1dba264
--- /dev/null
+++ b/heimdall/source/Utility.cpp
@@ -0,0 +1,82 @@
+/* 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.*/
+
+// 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);
+}
diff --git a/heimdall/source/Utility.h b/heimdall/source/Utility.h
new file mode 100644
index 0000000..4d3f3e4
--- /dev/null
+++ b/heimdall/source/Utility.h
@@ -0,0 +1,40 @@
+/* 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 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
diff --git a/heimdall/source/VersionAction.cpp b/heimdall/source/VersionAction.cpp
new file mode 100644
index 0000000..d76c1da
--- /dev/null
+++ b/heimdall/source/VersionAction.cpp
@@ -0,0 +1,35 @@
+/* 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.*/
+
+// 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);
+}
diff --git a/heimdall/source/VersionAction.h b/heimdall/source/VersionAction.h
new file mode 100644
index 0000000..fa9035c
--- /dev/null
+++ b/heimdall/source/VersionAction.h
@@ -0,0 +1,34 @@
+/* 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 VERSIONACTION_H
+#define VERSIONACTION_H
+
+namespace Heimdall
+{
+ namespace VersionAction
+ {
+ extern const char *usage;
+
+ int Execute(int argc, char **argv);
+ };
+}
+
+#endif
diff --git a/heimdall/source/main.cpp b/heimdall/source/main.cpp
index db7de1c..41d7a3c 100644
--- a/heimdall/source/main.cpp
+++ b/heimdall/source/main.cpp
@@ -28,782 +28,28 @@
#include "libpit.h"
// Heimdall
-#include "BridgeManager.h"
-#include "SetupSessionPacket.h"
-#include "SetupSessionResponse.h"
-#include "EndModemFileTransferPacket.h"
-#include "EndPhoneFileTransferPacket.h"
+#include "Heimdall.h"
+#include "HelpAction.h"
#include "Interface.h"
using namespace std;
using namespace Heimdall;
-// Known partitions
-enum
-{
- kKnownPartitionPit = 0,
- kKnownPartitionFactoryFs,
- kKnownPartitionCache,
- kKnownPartitionDatabaseData,
- kKnownPartitionPrimaryBootloader,
- kKnownPartitionSecondaryBootloader,
- kKnownPartitionSecondaryBootloaderBackup,
- kKnownPartitionParam,
- kKnownPartitionKernel,
- kKnownPartitionRecovery,
- kKnownPartitionEfs,
- kKnownPartitionModem,
-
- kKnownPartitionNormalBoot,
- kKnownPartitionSystem,
- kKnownPartitionUserData,
- kKnownPartitionFota,
- kKnownPartitionHidden,
- kKnownPartitionMovinand,
- kKnownPartitionData,
- kKnownPartitionUms,
- kKnownPartitionEmmc,
-
- kKnownPartitionCount
-};
-
-vector<const char *> knownPartitionNames[kKnownPartitionCount];
-
-struct PartitionInfo
-{
- unsigned int chipIdentifier;
- string partitionName;
- FILE *file;
-
- PartitionInfo(unsigned int chipIdentifier, const char *partitionName, FILE *file)
- {
- this->chipIdentifier = chipIdentifier;
- this->partitionName = partitionName;
- this->file = file;
- }
-};
-
-void initialiseKnownPartitionNames(void)
-{
- knownPartitionNames[kKnownPartitionPit].push_back("PIT");
- knownPartitionNames[kKnownPartitionFactoryFs].push_back("FACTORYFS");
- knownPartitionNames[kKnownPartitionCache].push_back("CACHE");
- knownPartitionNames[kKnownPartitionDatabaseData].push_back("DBDATAFS");
-
- knownPartitionNames[kKnownPartitionPrimaryBootloader].push_back("IBL+PBL");
- knownPartitionNames[kKnownPartitionPrimaryBootloader].push_back("BOOT");
-
- knownPartitionNames[kKnownPartitionSecondaryBootloader].push_back("SBL");
- knownPartitionNames[kKnownPartitionSecondaryBootloader].push_back("SBL1");
-
- knownPartitionNames[kKnownPartitionSecondaryBootloaderBackup].push_back("SBL2");
- knownPartitionNames[kKnownPartitionParam].push_back("PARAM");
- knownPartitionNames[kKnownPartitionKernel].push_back("KERNEL");
- knownPartitionNames[kKnownPartitionRecovery].push_back("RECOVERY");
- knownPartitionNames[kKnownPartitionEfs].push_back("EFS");
- knownPartitionNames[kKnownPartitionModem].push_back("MODEM");
-
- knownPartitionNames[kKnownPartitionNormalBoot].push_back("NORMALBOOT");
- knownPartitionNames[kKnownPartitionSystem].push_back("SYSTEM");
- knownPartitionNames[kKnownPartitionUserData].push_back("USERDATA");
- knownPartitionNames[kKnownPartitionFota].push_back("FOTA");
- knownPartitionNames[kKnownPartitionHidden].push_back("HIDDEN");
- knownPartitionNames[kKnownPartitionMovinand].push_back("MOVINAND");
- knownPartitionNames[kKnownPartitionData].push_back("DATAFS");
- knownPartitionNames[kKnownPartitionUms].push_back("UMS.EN");
- knownPartitionNames[kKnownPartitionEmmc].push_back("GANG");
-}
-
-bool isKnownPartition(const char *partitionName, unsigned int knownPartitionIndex)
-{
- for (unsigned int i = 0; i < knownPartitionNames[knownPartitionIndex].size(); i++)
- {
- if (strcmp(partitionName, knownPartitionNames[knownPartitionIndex][i]) == 0)
- return (true);
- }
-
- return (false);
-}
-
-bool isKnownBootPartition(const char *partitionName)
-{
- return (isKnownPartition(partitionName, kKnownPartitionPrimaryBootloader) ||
- isKnownPartition(partitionName, kKnownPartitionSecondaryBootloader) ||
- isKnownPartition(partitionName, kKnownPartitionSecondaryBootloaderBackup) ||
- isKnownPartition(partitionName, kKnownPartitionParam) ||
- isKnownPartition(partitionName, kKnownPartitionNormalBoot));
-}
-
-bool openFiles(const map<string, string>& argumentMap, map<string, FILE *>& argumentFileMap)
-{
- map<string, string>::const_iterator it = argumentMap.begin();
-
- for (it = argumentMap.begin(); it != argumentMap.end(); it++)
- {
- bool isFileArgument = false;
-
- int partitionIndex = atoi(it->first.substr(it->first.find_first_not_of('-')).c_str());
-
- // Was the argument a partition index?
- if (partitionIndex > 0 || it->first.compare("-0") == 0)
- {
- isFileArgument = true;
- }
- else
- {
- // The argument wasn't a partition index, check if it's a known partition name.
- for (int knownPartition = 0; knownPartition < kKnownPartitionCount; knownPartition++)
- {
- if (it->first == Interface::actions[Interface::kActionFlash].valueArguments[knownPartition])
- {
- isFileArgument = true;
- break;
- }
- }
- }
-
- if (!isFileArgument)
- continue;
-
- pair<string, FILE *> argumentFilePair;
- argumentFilePair.first = it->first;
- argumentFilePair.second = fopen(it->second.c_str(), "rb");
-
- if (!argumentFilePair.second)
- {
- Interface::PrintError("Failed to open file \"%s\"\n", it->second.c_str());
- return (false);
- }
-
- argumentFileMap.insert(argumentFilePair);
- }
-
- return (true);
-}
-
-bool mapFilesToPartitions(const map<string, FILE *>& argumentFileMap, const PitData *pitData, map<unsigned int, PartitionInfo>& partitionInfoMap)
-{
- map<string, FILE *>::const_iterator it = argumentFileMap.begin();
-
- for (it = argumentFileMap.begin(); it != argumentFileMap.end(); it++)
- {
- int partitionIndex = atoi(it->first.substr(it->first.find_first_not_of('-')).c_str());
-
- const PitEntry *pitEntry = nullptr;
-
- // Was the argument a partition index?
- if (partitionIndex > 0 || it->first.compare("-0") == 0)
- {
- pitEntry = pitData->FindEntry(partitionIndex);
- }
- else
- {
- // The argument wasn't a partition index, so it must be a known partition name.
- int knownPartition;
-
- for (knownPartition = 0; knownPartition < kKnownPartitionCount; knownPartition++)
- {
- if (it->first == Interface::actions[Interface::kActionFlash].valueArguments[knownPartition])
- break;
- }
-
- // Check for the partition in the PIT file using all known names.
- for (unsigned int i = 0; i < knownPartitionNames[knownPartition].size(); i++)
- {
- pitEntry = pitData->FindEntry(knownPartitionNames[knownPartition][i]);
-
- if (pitEntry)
- break;
- }
-
- if (!pitEntry && knownPartition == kKnownPartitionPit)
- {
- // NOTE: We're assuming a PIT file always has chipIdentifier zero.
- PartitionInfo partitionInfo(0, knownPartitionNames[kKnownPartitionPit][0], it->second);
- partitionInfoMap.insert(pair<unsigned int, PartitionInfo>(0xFFFFFFFF, partitionInfo));
-
- return (true);
- }
- }
-
- if (!pitEntry)
- {
- Interface::PrintError("Partition corresponding to %s argument could not be located\n", it->first.c_str());
- return (false);
- }
-
- PartitionInfo partitionInfo(pitEntry->GetChipIdentifier(), pitEntry->GetPartitionName(), it->second);
- partitionInfoMap.insert(pair<unsigned int, PartitionInfo>(pitEntry->GetPartitionIdentifier(), partitionInfo));
- }
-
- return (true);
-}
-
-void closeFiles(map<string, FILE *> argumentfileMap)
-{
- for (map<string, FILE *>::iterator it = argumentfileMap.begin(); it != argumentfileMap.end(); it++)
- fclose(it->second);
-
- argumentfileMap.clear();
-}
-
-int downloadPitFile(BridgeManager *bridgeManager, unsigned char **pitBuffer)
-{
- Interface::Print("Downloading device's PIT file...\n");
-
- int devicePitFileSize = bridgeManager->ReceivePitFile(pitBuffer);
-
- if (!*pitBuffer)
- {
- Interface::PrintError("Failed to download PIT file!\n");
-
- return (-1);
- }
-
- Interface::Print("PIT file download sucessful\n\n");
- return (devicePitFileSize);
-}
-
-bool flashFile(BridgeManager *bridgeManager, unsigned int chipIdentifier, unsigned int partitionIndex, const char *partitionName, FILE *file)
-{
- // PIT files need to be handled differently, try determine if the partition we're flashing to is a PIT partition.
- bool isPit = false;
-
- for (unsigned int i = 0; i < knownPartitionNames[kKnownPartitionPit].size(); i++)
- {
- if (strcmp(partitionName, knownPartitionNames[kKnownPartitionPit][i]) == 0)
- {
- isPit = true;
- break;
- }
- }
-
- if (isPit)
- {
- Interface::Print("Uploading %s\n", partitionName);
-
- if (bridgeManager->SendPitFile(file))
- {
- Interface::Print("%s upload successful\n", partitionName);
- return (true);
- }
- else
- {
- Interface::Print("%s upload failed!\n", partitionName);
- return (false);
- }
- }
- else
- {
- // Modems need to be handled differently, try determine if the partition we're flashing to is a modem partition.
- bool isModem = false;
-
- for (unsigned int i = 0; i < knownPartitionNames[kKnownPartitionModem].size(); i++)
- {
- if (strcmp(partitionName, knownPartitionNames[kKnownPartitionModem][i]) == 0)
- {
- isModem = true;
- break;
- }
- }
-
- if (isModem)
- {
- Interface::Print("Uploading %s\n", partitionName);
-
- //if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, // <-- Kies method. WARNING: Doesn't work on Galaxy Tab!
- // EndPhoneFileTransferPacket::kFileModem))
- if (bridgeManager->SendFile(file, EndModemFileTransferPacket::kDestinationModem, chipIdentifier)) // <-- Odin method
- {
- Interface::Print("%s upload successful\n", partitionName);
- return (true);
- }
- else
- {
- Interface::Print("%s upload failed!\n", partitionName);
- return (false);
- }
- }
- else
- {
- // We're uploading to a phone partition
- Interface::Print("Uploading %s\n", partitionName);
-
- if (bridgeManager->SendFile(file, EndPhoneFileTransferPacket::kDestinationPhone, chipIdentifier, partitionIndex))
- {
- Interface::Print("%s upload successful\n", partitionName);
- return (true);
- }
- else
- {
- Interface::Print("%s upload failed!\n", partitionName);
- return (false);
- }
- }
- }
-
- return (true);
-}
-
-bool attemptFlash(BridgeManager *bridgeManager, map<string, FILE *> argumentFileMap, bool repartition)
-{
- bool success;
-
- // ------------- SEND TOTAL BYTES TO BE TRANSFERRED -------------
-
- int totalBytes = 0;
- for (map<string, FILE *>::const_iterator it = argumentFileMap.begin(); it != argumentFileMap.end(); it++)
- {
- if (repartition || it->first != Interface::GetPitArgument())
- {
- fseek(it->second, 0, SEEK_END);
- totalBytes += ftell(it->second);
- rewind(it->second);
- }
- }
-
- SetupSessionPacket *deviceInfoPacket = new SetupSessionPacket(SetupSessionPacket::kTotalBytes, totalBytes);
- success = bridgeManager->SendPacket(deviceInfoPacket);
- delete deviceInfoPacket;
-
- if (!success)
- {
- Interface::PrintError("Failed to send total bytes device info packet!\n");
- return (false);
- }
-
- SetupSessionResponse *deviceInfoResponse = new SetupSessionResponse();
- success = bridgeManager->ReceivePacket(deviceInfoResponse);
- int deviceInfoResult = deviceInfoResponse->GetUnknown();
- delete deviceInfoResponse;
-
- if (!success)
- {
- Interface::PrintError("Failed to receive device info response!\n");
- return (false);
- }
-
- if (deviceInfoResult != 0)
- {
- Interface::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%d\n", deviceInfoResult);
- return (false);
- }
-
- // -----------------------------------------------------
-
- PitData *pitData;
- PitData *localPitData = nullptr;
-
- FILE *localPitFile = nullptr;
-
- // If a PIT file was passed as an argument then we must unpack it.
- map<string, FILE *>::iterator it = argumentFileMap.find(Interface::actions[Interface::kActionFlash].valueArguments[Interface::kFlashValueArgPit]);
-
- if (it != argumentFileMap.end())
- {
- localPitFile = it->second;
-
- // Load the local pit file into memory.
- unsigned char *pitFileBuffer = new unsigned char[4096];
- memset(pitFileBuffer, 0, 4096);
-
- fseek(localPitFile, 0, SEEK_END);
- long localPitFileSize = ftell(localPitFile);
- rewind(localPitFile);
-
- // dataRead is discarded, it's here to remove warnings.
- int dataRead = fread(pitFileBuffer, 1, localPitFileSize, localPitFile);
- rewind(localPitFile);
-
- localPitData = new PitData();
- localPitData->Unpack(pitFileBuffer);
-
- delete [] pitFileBuffer;
- }
-
- 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;
- downloadPitFile(bridgeManager, &pitFileBuffer);
-
- 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");
-
- delete pitData;
- return (false);
- }
- }
- }
-
- map<unsigned int, PartitionInfo> partitionInfoMap;
-
- // Map the files being flashed to partitions stored in the PIT file.
- if (!mapFilesToPartitions(argumentFileMap, pitData, partitionInfoMap))
- {
- delete pitData;
- return (false);
- }
-
- delete pitData;
-
- // If we're repartitioning then we need to flash the PIT file first.
- if (repartition)
- {
- for (map<unsigned int, PartitionInfo>::iterator it = partitionInfoMap.begin(); it != partitionInfoMap.end(); it++)
- {
- if (it->second.file == localPitFile)
- {
- PartitionInfo *partitionInfo = &(it->second);
-
- if (!flashFile(bridgeManager, partitionInfo->chipIdentifier, it->first, partitionInfo->partitionName.c_str(), partitionInfo->file))
- return (false);
-
- break;
- }
- }
- }
-
- // Flash partitions not involved in the boot process second.
- for (map<unsigned int, PartitionInfo>::iterator it = partitionInfoMap.begin(); it != partitionInfoMap.end(); it++)
- {
- if (!isKnownPartition(it->second.partitionName.c_str(), kKnownPartitionPit) && !isKnownBootPartition(it->second.partitionName.c_str()))
- {
- PartitionInfo *partitionInfo = &(it->second);
-
- if (!flashFile(bridgeManager, partitionInfo->chipIdentifier, it->first, partitionInfo->partitionName.c_str(), partitionInfo->file))
- return (false);
- }
- }
-
- // Flash boot partitions last.
- for (map<unsigned int, PartitionInfo>::iterator it = partitionInfoMap.begin(); it != partitionInfoMap.end(); it++)
- {
- if (isKnownBootPartition(it->second.partitionName.c_str()))
- {
- PartitionInfo *partitionInfo = &(it->second);
-
- if (!flashFile(bridgeManager, partitionInfo->chipIdentifier, it->first, partitionInfo->partitionName.c_str(), partitionInfo->file))
- return (false);
- }
- }
-
- return (true);
-}
-
int main(int argc, char **argv)
{
- map<string, string> argumentMap;
- int actionIndex;
-
- if (!Interface::GetArguments(argc, argv, argumentMap, &actionIndex))
+ if (argc < 2)
{
- Sleep(250);
+ Interface::PrintUsage();
return (0);
}
- initialiseKnownPartitionNames();
-
- switch (actionIndex)
- {
- case Interface::kActionFlash:
- if (argumentMap.find(Interface::actions[Interface::kActionFlash].valuelessArguments[Interface::kFlashValuelessArgRepartition]) != argumentMap.end()
- && argumentMap.find(Interface::actions[Interface::kActionFlash].valueArguments[Interface::kFlashValueArgPit]) == argumentMap.end())
- {
- Interface::Print("If you wish to repartition then a PIT file must be specified.\n\n");
- Interface::PrintUsage();
- return (0);
- }
-
- break;
-
- case Interface::kActionDownloadPit:
- if (argumentMap.find(Interface::actions[Interface::kActionDownloadPit].valueArguments[Interface::kDownloadPitValueArgOutput]) == argumentMap.end())
- {
- Interface::Print("Output file was not specified.\n\n");
- Interface::PrintUsage();
- return (0);
- }
-
- break;
-
- case Interface::kActionDump:
- {
- if (argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgOutput]) == argumentMap.end())
- {
- Interface::Print("Output file was not specified.\n\n");
- Interface::PrintUsage();
- return (0);
- }
-
- if (argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipType]) == argumentMap.end())
- {
- Interface::Print("You must specify a chip type.\n\n");
- Interface::PrintUsage();
- return (0);
- }
-
- string chipType = argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipType])->second;
- if (!(chipType == "RAM" || chipType == "ram" || chipType == "NAND" || chipType == "nand"))
- {
- Interface::Print("Unknown chip type: %s.\n\n", chipType.c_str());
- Interface::PrintUsage();
- return (0);
- }
-
- if (argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipId]) == argumentMap.end())
- {
- Interface::Print("You must specify a Chip ID.\n\n");
- Interface::PrintUsage();
- return (0);
- }
-
- int chipId = atoi(argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipId])->second.c_str());
- if (chipId < 0)
- {
- Interface::Print("Chip ID must be a non-negative integer.\n");
- Interface::PrintUsage();
- return (0);
- }
-
- break;
- }
-
- case Interface::kActionVersion:
- Interface::PrintVersion();
- return (0);
-
- case Interface::kActionHelp:
- Interface::PrintUsage();
- return (0);
-
- case Interface::kActionInfo:
- Interface::PrintFullInfo();
- return (0);
- }
-
- bool verbose = argumentMap.find(Interface::commonValuelessArguments[Interface::kCommonValuelessArgVerbose]) != argumentMap.end();
- bool reboot = argumentMap.find(Interface::commonValuelessArguments[Interface::kCommonValuelessArgNoReboot]) == argumentMap.end();
-
- Interface::SetStdoutErrors(argumentMap.find(Interface::commonValuelessArguments[Interface::kCommonValuelessArgStdoutErrors]) != argumentMap.end());
-
- int communicationDelay = BridgeManager::kCommunicationDelayDefault;
+ int result = 0;
+ map<string, Interface::ActionInfo>::const_iterator actionIt = Interface::GetActionMap().find(argv[1]);
- if (argumentMap.find(Interface::commonValueArguments[Interface::kCommonValueArgDelay]) != argumentMap.end())
- communicationDelay = atoi(argumentMap.find(Interface::commonValueArguments[Interface::kCommonValueArgDelay])->second.c_str());
-
- BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay);
-
- if (actionIndex == Interface::kActionDetect)
- {
- bool detected = bridgeManager->DetectDevice();
- delete bridgeManager;
-
- return ((detected) ? 0 : 1);
- }
-
- Interface::PrintReleaseInfo();
- Sleep(1000);
-
- int initialiseResult = bridgeManager->Initialise();
-
- if (initialiseResult != 0)
- {
- delete bridgeManager;
- return ((initialiseResult == BridgeManager::kInitialiseDeviceNotDetected) ? 1 : 0);
- }
-
- bool success;
-
- switch (actionIndex)
- {
- case Interface::kActionFlash:
- {
- map<string, FILE *> argumentFileMap;
-
- // We open the files before doing anything else to ensure they exist.
- if (!openFiles(argumentMap, argumentFileMap))
- {
- closeFiles(argumentFileMap);
- delete bridgeManager;
-
- return (0);
- }
-
- if (!bridgeManager->BeginSession())
- {
- closeFiles(argumentFileMap);
- delete bridgeManager;
-
- return (-1);
- }
-
- bool repartition = argumentMap.find(Interface::actions[Interface::kActionFlash].valuelessArguments[Interface::kFlashValuelessArgRepartition]) != argumentMap.end();
- success = attemptFlash(bridgeManager, argumentFileMap, repartition);
-
- success = bridgeManager->EndSession(reboot) && success;
-
- closeFiles(argumentFileMap);
-
- break;
- }
-
- case Interface::kActionClosePcScreen:
- {
- if (!bridgeManager->BeginSession())
- {
- delete bridgeManager;
- return (-1);
- }
-
- Interface::Print("Attempting to close connect to pc screen...\n");
-
- success = bridgeManager->EndSession(reboot);
-
- if (success)
- Interface::Print("Attempt complete\n");
-
- break;
- }
-
- case Interface::kActionDownloadPit:
- {
- map<string, string>::const_iterator it = argumentMap.find(Interface::actions[Interface::kActionDownloadPit].valueArguments[Interface::kDownloadPitValueArgOutput]);
- FILE *outputPitFile = fopen(it->second.c_str(), "wb");
-
- if (!outputPitFile)
- {
- delete bridgeManager;
- return (0);
- }
-
- if (!bridgeManager->BeginSession())
- {
- delete bridgeManager;
- fclose(outputPitFile);
- return (-1);
- }
-
- unsigned char *pitBuffer;
- int fileSize = downloadPitFile(bridgeManager, &pitBuffer);
-
- if (fileSize > 0)
- {
- success = fwrite(pitBuffer, 1, fileSize, outputPitFile) == fileSize;
- fclose(outputPitFile);
-
- if (!success)
- Interface::PrintError("Failed to write PIT data to output file.\n");
-
- success = bridgeManager->EndSession(reboot) && success;
- }
- else
- {
- fclose(outputPitFile);
- success = false;
- bridgeManager->EndSession(reboot);
- }
-
- delete [] pitBuffer;
-
- break;
- }
-
- case Interface::kActionDump:
- {
- const char *outputFilename = argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgOutput])->second.c_str();
- FILE *dumpFile = fopen(outputFilename, "wb");
- if (!dumpFile)
- {
- Interface::PrintError("Failed to open file \"%s\"\n", outputFilename);
-
- delete bridgeManager;
- return (-1);
- }
-
- int chipType = 0;
- string chipTypeName = argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipType])->second;
- if (chipTypeName == "NAND" || chipTypeName == "nand")
- chipType = 1;
-
- int chipId = atoi(argumentMap.find(Interface::actions[Interface::kActionDump].valueArguments[Interface::kDumpValueArgChipId])->second.c_str());
-
- if (!bridgeManager->BeginSession())
- {
- fclose(dumpFile);
-
- delete bridgeManager;
- return (-1);
- }
-
- success = bridgeManager->ReceiveDump(chipType, chipId, dumpFile);
-
- fclose(dumpFile);
-
- success = bridgeManager->EndSession(reboot) && success;
-
- break;
- }
-
- case Interface::kActionPrintPit:
- {
- if (!bridgeManager->BeginSession())
- {
- delete bridgeManager;
- return (-1);
- }
-
- unsigned char *devicePit;
-
- if (downloadPitFile(bridgeManager, &devicePit) < -1)
- {
- bridgeManager->EndSession(reboot);
-
- delete bridgeManager;
- return (-1);
- }
-
- PitData *pitData = new PitData();
-
- if (pitData->Unpack(devicePit))
- {
- Interface::PrintPit(pitData);
- success = true;
- }
- else
- {
- Interface::PrintError("Failed to unpack device's PIT file!\n");
- success = false;
- }
-
- delete [] devicePit;
- delete pitData;
-
- success = bridgeManager->EndSession(reboot) && success;
-
- break;
- }
- }
-
- delete bridgeManager;
-
- return ((success) ? 0 : -1);
+ if (actionIt != Interface::GetActionMap().end())
+ result = actionIt->second.executeFunction(argc, argv);
+ else
+ result = HelpAction::Execute(argc, argv);
+
+ return (result);
}