Inial population of repository.
This commit is contained in:
195
simulator/bin_patch/bin_patch.cpp
Normal file
195
simulator/bin_patch/bin_patch.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <fstream>
|
||||
#include "utils.h"
|
||||
#include "config_file.h"
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
int PrintUsage(const char *aExecName, const char *ErrorStr = nullptr) {
|
||||
if (ErrorStr != nullptr) std::cout << "Error: " << ErrorStr << std::endl;
|
||||
std::cout << "Usage: " << aExecName << " <image file> <patch file> <output file> [<options>]" << std::endl;
|
||||
std::cout << " The following options are available:" << std::endl;
|
||||
std::cout << " -m: allow multiple matches" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::regex CommentLine("[ \t]*#.*");
|
||||
std::regex MatchLine("[ \t]*(0x[0-9a-fA-F]+):(0x[0-9a-fA-F]+)[ \t]*(#.*)?");
|
||||
std::regex PatchLine("[ \t]*(0x[0-9a-fA-F]+):(0x[0-9a-fA-F]+)[ \t]*(0x[0-9a-fA-F]+):(0x[0-9a-fA-F]+)[ \t]*(#.*)?");
|
||||
|
||||
struct ValMask_s {
|
||||
uint16_t mValue;
|
||||
uint16_t mMask;
|
||||
};
|
||||
|
||||
struct Patch_s {
|
||||
ValMask_s mMatch;
|
||||
ValMask_s mPatch;
|
||||
};
|
||||
|
||||
std::string Trim(const std::string& aStr, const std::string& aWhitespace = " \t") {
|
||||
const auto FirstNonSpace = aStr.find_first_not_of(aWhitespace);
|
||||
if (FirstNonSpace == std::string::npos) return "";
|
||||
|
||||
const auto LastNonSpace = aStr.find_last_not_of(aWhitespace);
|
||||
const auto TrimRange = LastNonSpace - FirstNonSpace + 1;
|
||||
|
||||
return aStr.substr(FirstNonSpace, TrimRange);
|
||||
}
|
||||
|
||||
boost::optional<Patch_s> ParseLine(std::string &aLine, size_t aLineNo) {
|
||||
std::string Line = Trim(aLine);
|
||||
if (Line.length() == 0) return boost::optional<Patch_s>(); // Empty lines are skipped
|
||||
std::smatch Matches;
|
||||
if (std::regex_match(Line, Matches, PatchLine)) {
|
||||
CRAY_ASSERT(Matches.size() > 5);
|
||||
Patch_s Patch;
|
||||
Patch.mMatch.mValue = FromString<uint16_t>(Matches[1]);
|
||||
Patch.mMatch.mMask = FromString<uint16_t>(Matches[2]);
|
||||
Patch.mPatch.mValue = FromString<uint16_t>(Matches[3]);
|
||||
Patch.mPatch.mMask = FromString<uint16_t>(Matches[4]);
|
||||
return Patch;
|
||||
}
|
||||
if (std::regex_match(Line, Matches, MatchLine)) {
|
||||
CRAY_ASSERT(Matches.size() > 3);
|
||||
Patch_s Patch;
|
||||
Patch.mMatch.mValue = FromString<uint16_t>(Matches[1]);
|
||||
Patch.mMatch.mMask = FromString<uint16_t>(Matches[2]);
|
||||
Patch.mPatch.mValue = 0;
|
||||
Patch.mPatch.mMask = 0x0000; // Patch is not applied
|
||||
return Patch;
|
||||
}
|
||||
if (std::regex_match(Line, CommentLine)) return boost::optional<Patch_s>(); // Comment lines are skipped
|
||||
throw Generic_x() << "Can't parse line " << DecPrinter(aLineNo);
|
||||
}
|
||||
|
||||
class PatchFile_c {
|
||||
public:
|
||||
PatchFile_c() {}
|
||||
void Read(std::ifstream &aStrm) {
|
||||
size_t LineNo = 1;
|
||||
while (!aStrm.eof()) {
|
||||
std::string Line;
|
||||
std::getline(aStrm, Line);
|
||||
boost::optional<Patch_s> Patch = ParseLine(Line, LineNo);
|
||||
if (Patch.is_initialized()) {
|
||||
mPatch.push_back(Patch.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<Patch_s> mPatch;
|
||||
|
||||
unsigned int Apply(std::vector<uint16_t> &aArray) {
|
||||
unsigned int MatchCount = 0;
|
||||
size_t Start = 0;
|
||||
size_t LastStart = aArray.size() - mPatch.size();
|
||||
while (Start < LastStart) {
|
||||
bool Found = true;
|
||||
for (size_t Idx = 0; Idx < mPatch.size(); ++Idx) {
|
||||
if (((aArray[Start + Idx] ^ mPatch[Idx].mMatch.mValue) & mPatch[Idx].mMatch.mMask) != 0) {
|
||||
Found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Found) {
|
||||
for (size_t Idx = 0; Idx < mPatch.size(); ++Idx) {
|
||||
aArray[Start + Idx] =
|
||||
(aArray[Start + Idx] & ~mPatch[Idx].mPatch.mMask) |
|
||||
(mPatch[Idx].mPatch.mValue & mPatch[Idx].mPatch.mMask);
|
||||
}
|
||||
++MatchCount;
|
||||
}
|
||||
++Start;
|
||||
}
|
||||
return MatchCount;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
CommandLine_c CommandLine(argc, argv);
|
||||
std::string InFileName;
|
||||
std::string PatchFileName;
|
||||
std::string OutFileName;
|
||||
bool UniqueMatch = true;
|
||||
|
||||
try {
|
||||
while (CommandLine.HasMoreParams()) {
|
||||
std::string CurParam = CommandLine.GetNextParam();
|
||||
if (CurParam.length() == 0) continue;
|
||||
if (CurParam == "-m") {
|
||||
UniqueMatch = false;
|
||||
}
|
||||
else if (InFileName.empty()) {
|
||||
InFileName = CurParam;
|
||||
}
|
||||
else if (PatchFileName.empty()) {
|
||||
PatchFileName = CurParam;
|
||||
}
|
||||
else if (OutFileName.empty()) {
|
||||
OutFileName = CurParam;
|
||||
}
|
||||
else {
|
||||
throw Generic_x("Unkown command line parameter");
|
||||
}
|
||||
}
|
||||
if (InFileName.length() == 0) throw Generic_x() << "Input file must be specified";
|
||||
if (!boost::filesystem::exists(InFileName)) throw Generic_x() << "File: " << InFileName << " doesn't exist";
|
||||
if (PatchFileName.length() == 0) throw Generic_x() << "Patch file must be specified";
|
||||
if (!boost::filesystem::exists(PatchFileName)) throw Generic_x() << "File: " << PatchFileName << " doesn't exist";
|
||||
if (OutFileName.length() == 0) throw Generic_x() << "Output file must be specified";
|
||||
|
||||
size_t FileSize = boost::filesystem::file_size(InFileName);
|
||||
if ((FileSize % 2) != 0) throw Generic_x() << "This prorgam only supports binary files with even number of bytes";
|
||||
std::vector<uint16_t> FileContent(FileSize / 2);
|
||||
std::ifstream InFile(InFileName, std::ios::binary | std::ios::in);
|
||||
InFile.read((char*)&(FileContent[0]), FileSize);
|
||||
if (InFile.bad()) throw Generic_x() << "Can't read input file: " << InFileName;
|
||||
InFile.close();
|
||||
for (auto &Word : FileContent) {
|
||||
Word = SwapBytes(Word);
|
||||
}
|
||||
|
||||
std::ifstream PatchStrm(PatchFileName, std::ios::in);
|
||||
if (PatchStrm.bad()) throw Generic_x() << "Can't open patch file: " << PatchFileName;
|
||||
|
||||
PatchFile_c PatchFile;
|
||||
PatchFile.Read(PatchStrm);
|
||||
PatchStrm.close();
|
||||
|
||||
unsigned int MatchCnt = PatchFile.Apply(FileContent);
|
||||
|
||||
if (MatchCnt == 0) {
|
||||
std::cout << "Patch wasn't applied: no match was found" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
if (MatchCnt > 1 && UniqueMatch) {
|
||||
std::cout << "Patch wasn't applied: multiple matches were found" << std::endl;
|
||||
return 3;
|
||||
}
|
||||
std::cout << "Patch applied " << MatchCnt << " times" << std::endl;
|
||||
|
||||
std::ofstream OutFile(OutFileName, std::ios::binary | std::ios::out);
|
||||
if (OutFile.bad()) throw Generic_x() << "Can't open output file " << OutFileName;
|
||||
for (auto &Word : FileContent) {
|
||||
Word = SwapBytes(Word);
|
||||
}
|
||||
OutFile.write((char*)&(FileContent[0]), FileSize);
|
||||
if (OutFile.bad()) throw Generic_x() << "Can't write output file: " << OutFileName;
|
||||
OutFile.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch(std::exception &Ex) {
|
||||
return PrintUsage(argv[0], Ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user