diff options
Diffstat (limited to 'libpit/source')
-rw-r--r-- | libpit/source/libpit.cpp | 296 | ||||
-rw-r--r-- | libpit/source/libpit.h | 417 |
2 files changed, 713 insertions, 0 deletions
diff --git a/libpit/source/libpit.cpp b/libpit/source/libpit.cpp new file mode 100644 index 0000000..73bc1b8 --- /dev/null +++ b/libpit/source/libpit.cpp @@ -0,0 +1,296 @@ +/* Copyright (c) 2010-2014 Benjamin Dobell, Glass Echidna + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE.*/ + +// libpit +#include "libpit.h" + +using namespace libpit; + +PitEntry::PitEntry() +{ + binaryType = false; + deviceType = 0; + identifier = 0; + attributes = 0; + updateAttributes = 0; + blockSizeOrOffset = 0; + blockCount = 0; + fileOffset = 0; + fileSize = 0; + + memset(partitionName, 0, PitEntry::kPartitionNameMaxLength); + memset(flashFilename, 0, PitEntry::kFlashFilenameMaxLength); + memset(fotaFilename, 0, PitEntry::kFotaFilenameMaxLength); +} + +PitEntry::~PitEntry() +{ +} + +bool PitEntry::Matches(const PitEntry *otherPitEntry) const +{ + if (binaryType == otherPitEntry->binaryType && deviceType == otherPitEntry->deviceType && identifier == otherPitEntry->identifier + && attributes == otherPitEntry->attributes && updateAttributes == otherPitEntry->updateAttributes && blockSizeOrOffset == otherPitEntry->blockSizeOrOffset + && blockCount == otherPitEntry->blockCount && fileOffset == otherPitEntry->fileOffset && fileSize == otherPitEntry->fileSize + && strcmp(partitionName, otherPitEntry->partitionName) == 0 && strcmp(flashFilename, otherPitEntry->flashFilename) == 0 + && strcmp(fotaFilename, otherPitEntry->fotaFilename) == 0) + { + return (true); + } + else + { + return (false); + } +} + + + +PitData::PitData() +{ + entryCount = 0; + + unknown1 = 0; + unknown2 = 0; + + unknown3 = 0; + unknown4 = 0; + + unknown5 = 0; + unknown6 = 0; + + unknown7 = 0; + unknown8 = 0; +} + +PitData::~PitData() +{ + for (unsigned int i = 0; i < entries.size(); i++) + delete entries[i]; +} + +bool PitData::Unpack(const unsigned char *data) +{ + if (PitData::UnpackInteger(data, 0) != PitData::kFileIdentifier) + return (false); + + // Remove existing entries + for (unsigned int i = 0; i < entries.size(); i++) + delete entries[i]; + + entryCount = PitData::UnpackInteger(data, 4); + + entries.resize(entryCount); + + unknown1 = PitData::UnpackInteger(data, 8); + unknown2 = PitData::UnpackInteger(data, 12); + + unknown3 = PitData::UnpackShort(data, 16); + unknown4 = PitData::UnpackShort(data, 18); + + unknown5 = PitData::UnpackShort(data, 20); + unknown6 = PitData::UnpackShort(data, 22); + + unknown7 = PitData::UnpackShort(data, 24); + unknown8 = PitData::UnpackShort(data, 26); + + unsigned int integerValue; + unsigned int entryOffset; + + for (unsigned int i = 0; i < entryCount; i++) + { + entryOffset = PitData::kHeaderDataSize + i * PitEntry::kDataSize; + + entries[i] = new PitEntry(); + + integerValue = PitData::UnpackInteger(data, entryOffset); + entries[i]->SetBinaryType(integerValue); + + integerValue = PitData::UnpackInteger(data, entryOffset + 4); + entries[i]->SetDeviceType(integerValue); + + integerValue = PitData::UnpackInteger(data, entryOffset + 8); + entries[i]->SetIdentifier(integerValue); + + integerValue = PitData::UnpackInteger(data, entryOffset + 12); + entries[i]->SetAttributes(integerValue); + + integerValue = PitData::UnpackInteger(data, entryOffset + 16); + entries[i]->SetUpdateAttributes(integerValue); + + integerValue = PitData::UnpackInteger(data, entryOffset + 20); + entries[i]->SetBlockSizeOrOffset(integerValue); + + integerValue = PitData::UnpackInteger(data, entryOffset + 24); + entries[i]->SetBlockCount(integerValue); + + integerValue = PitData::UnpackInteger(data, entryOffset + 28); + entries[i]->SetFileOffset(integerValue); + + integerValue = PitData::UnpackInteger(data, entryOffset + 32); + entries[i]->SetFileSize(integerValue); + + entries[i]->SetPartitionName((const char *)data + entryOffset + 36); + entries[i]->SetFlashFilename((const char *)data + entryOffset + 36 + PitEntry::kPartitionNameMaxLength); + entries[i]->SetFotaFilename((const char *)data + entryOffset + 36 + PitEntry::kPartitionNameMaxLength + PitEntry::kFlashFilenameMaxLength); + } + + return (true); +} + +void PitData::Pack(unsigned char *data) const +{ + PitData::PackInteger(data, 0, PitData::kFileIdentifier); + + PitData::PackInteger(data, 4, entryCount); + + PitData::PackInteger(data, 8, unknown1); + PitData::PackInteger(data, 12, unknown2); + + PitData::PackShort(data, 16, unknown3); + PitData::PackShort(data, 18, unknown4); + + PitData::PackShort(data, 20, unknown5); + PitData::PackShort(data, 22, unknown6); + + PitData::PackShort(data, 24, unknown7); + PitData::PackShort(data, 26, unknown8); + + int entryOffset; + + for (unsigned int i = 0; i < entryCount; i++) + { + entryOffset = PitData::kHeaderDataSize + i * PitEntry::kDataSize; + + PitData::PackInteger(data, entryOffset, entries[i]->GetBinaryType()); + + PitData::PackInteger(data, entryOffset + 4, entries[i]->GetDeviceType()); + PitData::PackInteger(data, entryOffset + 8, entries[i]->GetIdentifier()); + PitData::PackInteger(data, entryOffset + 12, entries[i]->GetAttributes()); + + PitData::PackInteger(data, entryOffset + 16, entries[i]->GetUpdateAttributes()); + + PitData::PackInteger(data, entryOffset + 20, entries[i]->GetBlockSizeOrOffset()); + PitData::PackInteger(data, entryOffset + 24, entries[i]->GetBlockCount()); + + PitData::PackInteger(data, entryOffset + 28, entries[i]->GetFileOffset()); + PitData::PackInteger(data, entryOffset + 32, entries[i]->GetFileSize()); + + memcpy(data + entryOffset + 36, entries[i]->GetPartitionName(), PitEntry::kPartitionNameMaxLength); + memcpy(data + entryOffset + 36 + PitEntry::kPartitionNameMaxLength, entries[i]->GetFlashFilename(), PitEntry::kFlashFilenameMaxLength); + memcpy(data + entryOffset + 36 + PitEntry::kPartitionNameMaxLength + PitEntry::kFlashFilenameMaxLength, + entries[i]->GetFotaFilename(), PitEntry::kFotaFilenameMaxLength); + } +} + +bool PitData::Matches(const PitData *otherPitData) const +{ + if (entryCount == otherPitData->entryCount && unknown1 == otherPitData->unknown1 && unknown2 == otherPitData->unknown2 + && unknown3 == otherPitData->unknown3 && unknown4 == otherPitData->unknown4 && unknown5 == otherPitData->unknown5 + && unknown6 == otherPitData->unknown6 && unknown7 == otherPitData->unknown7 && unknown8 == otherPitData->unknown8) + { + for (unsigned int i = 0; i < entryCount; i++) + { + if (!entries[i]->Matches(otherPitData->entries[i])) + return (false); + } + + return (true); + } + else + { + return (false); + } +} + +void PitData::Clear(void) +{ + entryCount = 0; + + unknown1 = 0; + unknown2 = 0; + + unknown3 = 0; + unknown4 = 0; + + unknown5 = 0; + unknown6 = 0; + + unknown7 = 0; + unknown8 = 0; + + for (unsigned int i = 0; i < entries.size(); i++) + delete entries[i]; + + entries.clear(); +} + +PitEntry *PitData::GetEntry(unsigned int index) +{ + return (entries[index]); +} + +const PitEntry *PitData::GetEntry(unsigned int index) const +{ + return (entries[index]); +} + +PitEntry *PitData::FindEntry(const char *partitionName) +{ + for (unsigned int i = 0; i < entries.size(); i++) + { + if (entries[i]->IsFlashable() && strcmp(entries[i]->GetPartitionName(), partitionName) == 0) + return (entries[i]); + } + + return (nullptr); +} + +const PitEntry *PitData::FindEntry(const char *partitionName) const +{ + for (unsigned int i = 0; i < entries.size(); i++) + { + if (entries[i]->IsFlashable() && strcmp(entries[i]->GetPartitionName(), partitionName) == 0) + return (entries[i]); + } + + return (nullptr); +} + +PitEntry *PitData::FindEntry(unsigned int partitionIdentifier) +{ + for (unsigned int i = 0; i < entries.size(); i++) + { + if (entries[i]->IsFlashable() && entries[i]->GetIdentifier() == partitionIdentifier) + return (entries[i]); + } + + return (nullptr); +} + +const PitEntry *PitData::FindEntry(unsigned int partitionIdentifier) const +{ + for (unsigned int i = 0; i < entries.size(); i++) + { + if (entries[i]->IsFlashable() && entries[i]->GetIdentifier() == partitionIdentifier) + return (entries[i]); + } + + return (nullptr); +} diff --git a/libpit/source/libpit.h b/libpit/source/libpit.h new file mode 100644 index 0000000..ccdea20 --- /dev/null +++ b/libpit/source/libpit.h @@ -0,0 +1,417 @@ +/* Copyright (c) 2010-2014 Benjamin Dobell, Glass Echidna + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE.*/ + +#ifndef LIBPIT_H +#define LIBPIT_H + +#ifdef WIN32 +#pragma warning(disable : 4996) +#endif + +#if (!(defined _MSC_VER) || (_MSC_VER < 1700)) + +#ifndef nullptr +#define nullptr 0 +#endif + +#endif + +// C/C++ Standard Library +#include <cstring> +#include <string> +#include <vector> + +namespace libpit +{ + class PitEntry + { + public: + + enum + { + kDataSize = 132, + kPartitionNameMaxLength = 32, + kFlashFilenameMaxLength = 32, + kFotaFilenameMaxLength = 32 + }; + + enum + { + kBinaryTypeApplicationProcessor = 0, + kBinaryTypeCommunicationProcessor = 1 + }; + + enum + { + kDeviceTypeOneNand = 0, + kDeviceTypeFile, // FAT + kDeviceTypeMMC, + kDeviceTypeAll // ? + }; + + enum + { + kAttributeWrite = 1, + kAttributeSTL = 1 << 1/*, + kAttributeBML = 1 << 2*/ // ??? + }; + + enum + { + kUpdateAttributeFota = 1, + kUpdateAttributeSecure = 1 << 1 + }; + + private: + + unsigned int binaryType; + unsigned int deviceType; + unsigned int identifier; + unsigned int attributes; + unsigned int updateAttributes; + + unsigned int blockSizeOrOffset; + unsigned int blockCount; + + unsigned int fileOffset; // Obsolete + unsigned int fileSize; // Obsolete + + char partitionName[kPartitionNameMaxLength]; + char flashFilename[kFlashFilenameMaxLength]; // USB flash filename + char fotaFilename[kFotaFilenameMaxLength]; // Firmware over the air + + public: + + PitEntry(); + ~PitEntry(); + + bool Matches(const PitEntry *otherPitEntry) const; + + bool IsFlashable(void) const + { + return strlen(partitionName) != 0; + } + + unsigned int GetBinaryType(void) const + { + return binaryType; + } + + void SetBinaryType(unsigned int binaryType) + { + this->binaryType = binaryType; + } + + unsigned int GetDeviceType(void) const + { + return deviceType; + } + + void SetDeviceType(unsigned int deviceType) + { + this->deviceType = deviceType; + } + + unsigned int GetIdentifier(void) const + { + return identifier; + } + + void SetIdentifier(unsigned int identifier) + { + this->identifier = identifier; + } + + unsigned int GetAttributes(void) const + { + return attributes; + } + + void SetAttributes(unsigned int attributes) + { + this->attributes = attributes; + } + + unsigned int GetUpdateAttributes(void) const + { + return updateAttributes; + } + + void SetUpdateAttributes(unsigned int updateAttributes) + { + this->updateAttributes = updateAttributes; + } + + // Different versions of Loke (secondary bootloaders) on different devices intepret this differently. + unsigned int GetBlockSizeOrOffset(void) const + { + return blockSizeOrOffset; + } + + void SetBlockSizeOrOffset(unsigned int blockSizeOrOffset) + { + this->blockSizeOrOffset = blockSizeOrOffset; + } + + unsigned int GetBlockCount(void) const + { + return blockCount; + } + + void SetBlockCount(unsigned int blockCount) + { + this->blockCount = blockCount; + } + + unsigned int GetFileOffset(void) const + { + return fileOffset; + } + + void SetFileOffset(unsigned int fileOffset) + { + this->fileOffset = fileOffset; + } + + unsigned int GetFileSize(void) const + { + return fileSize; + } + + void SetFileSize(unsigned int fileSize) + { + this->fileSize = fileSize; + } + + const char *GetPartitionName(void) const + { + return partitionName; + } + + void SetPartitionName(const char *partitionName) + { + // This isn't strictly necessary but ensures no junk is left in our PIT file. + memset(this->partitionName, 0, 64); + + if (strlen(partitionName) < 64) + strcpy(this->partitionName, partitionName); + else + memcpy(this->partitionName, partitionName, 63); + } + + const char *GetFlashFilename(void) const + { + return flashFilename; + } + + void SetFlashFilename(const char *flashFilename) + { + // This isn't strictly necessary but ensures no junk is left in our PIT file. + memset(this->flashFilename, 0, kFlashFilenameMaxLength); + + if (strlen(partitionName) < 32) + strcpy(this->flashFilename, flashFilename); + else + memcpy(this->flashFilename, flashFilename, 31); + } + + const char *GetFotaFilename(void) const + { + return fotaFilename; + } + + void SetFotaFilename(const char *fotaFilename) + { + // This isn't strictly necessary but ensures no junk is left in our PIT file. + memset(this->fotaFilename, 0, kFotaFilenameMaxLength); + + if (strlen(partitionName) < 32) + strcpy(this->fotaFilename, fotaFilename); + else + memcpy(this->fotaFilename, fotaFilename, 31); + } + }; + + class PitData + { + public: + + enum + { + kFileIdentifier = 0x12349876, + kHeaderDataSize = 28, + kPaddedSizeMultiplicand = 4096 + }; + + private: + + unsigned int entryCount; // 0x04 + unsigned int unknown1; // 0x08 + unsigned int unknown2; // 0x0C + + unsigned short unknown3; // 0x10 + unsigned short unknown4; // 0x12 + + unsigned short unknown5; // 0x14 + unsigned short unknown6; // 0x16 + + unsigned short unknown7; // 0x18 + unsigned short unknown8; // 0x1A + + // Entries start at 0x1C + std::vector<PitEntry *> entries; + + static int UnpackInteger(const unsigned char *data, unsigned int offset) + { +#ifdef WORDS_BIGENDIAN + int value = (data[offset] << 24) | (data[offset + 1] << 16) | + (data[offset + 2] << 8) | data[offset + 3]; +#else + // Flip endianness + int value = data[offset] | (data[offset + 1] << 8) | + (data[offset + 2] << 16) | (data[offset + 3] << 24); +#endif + return (value); + } + + static int UnpackShort(const unsigned char *data, unsigned int offset) + { +#ifdef WORDS_BIGENDIAN + short value = (data[offset] << 8) | data[offset + 1]; +#else + // Flip endianness + short value = data[offset] | (data[offset + 1] << 8); +#endif + return (value); + } + + static void PackInteger(unsigned char *data, unsigned int offset, unsigned int value) + { +#ifdef WORDS_BIGENDIAN + data[offset] = (value & 0xFF000000) >> 24; + data[offset + 1] = (value & 0x00FF0000) >> 16; + data[offset + 2] = (value & 0x0000FF00) >> 8; + data[offset + 3] = value & 0x000000FF; +#else + // Flip endianness + data[offset] = value & 0x000000FF; + data[offset + 1] = (value & 0x0000FF00) >> 8; + data[offset + 2] = (value & 0x00FF0000) >> 16; + data[offset + 3] = (value & 0xFF000000) >> 24; +#endif + } + + static void PackShort(unsigned char *data, unsigned int offset, unsigned short value) + { +#ifdef WORDS_BIGENDIAN + data[offset] = (value & 0xFF00) >> 8; + data[offset + 1] = value & 0x00FF; +#else + // Flip endianness + data[offset] = value & 0x00FF; + data[offset + 1] = (value & 0xFF00) >> 8; +#endif + } + + public: + + PitData(); + ~PitData(); + + bool Unpack(const unsigned char *data); + void Pack(unsigned char *data) const; + + bool Matches(const PitData *otherPitData) const; + + void Clear(void); + + PitEntry *GetEntry(unsigned int index); + const PitEntry *GetEntry(unsigned int index) const; + + PitEntry *FindEntry(const char *partitionName); + const PitEntry *FindEntry(const char *partitionName) const; + + PitEntry *FindEntry(unsigned int partitionIdentifier); + const PitEntry *FindEntry(unsigned int partitionIdentifier) const; + + unsigned int GetEntryCount(void) const + { + return entryCount; + } + + unsigned int GetDataSize(void) const + { + return PitData::kHeaderDataSize + entryCount * PitEntry::kDataSize; + } + + unsigned int GetPaddedSize(void) const + { + unsigned int dataSize = GetDataSize(); + unsigned int paddedSize = (dataSize / kPaddedSizeMultiplicand) * kPaddedSizeMultiplicand; + + if (dataSize % kPaddedSizeMultiplicand != 0) + paddedSize += kPaddedSizeMultiplicand; + + return paddedSize; + } + + unsigned int GetUnknown1(void) const + { + return unknown1; + } + + unsigned int GetUnknown2(void) const + { + return unknown2; + } + + unsigned short GetUnknown3(void) const + { + return unknown3; + } + + unsigned short GetUnknown4(void) const + { + return unknown4; + } + + unsigned short GetUnknown5(void) const + { + return unknown5; + } + + unsigned short GetUnknown6(void) const + { + return unknown6; + } + + unsigned short GetUnknown7(void) const + { + return unknown7; + } + + unsigned short GetUnknown8(void) const + { + return unknown8; + } + }; +} + +#endif |