Index: courgette/courgette_tool.cc |
diff --git a/courgette/courgette_tool.cc b/courgette/courgette_tool.cc |
index 5ca91d1aa96d165c518f0a45e6128e9ab93a2ad7..46bd578e1d38b4db610295686a3d97dcb870ef40 100644 |
--- a/courgette/courgette_tool.cc |
+++ b/courgette/courgette_tool.cc |
@@ -2,9 +2,11 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include <stdarg.h> |
#include <stddef.h> |
#include <stdint.h> |
+#include <initializer_list> |
#include <memory> |
#include <string> |
#include <vector> |
@@ -15,26 +17,45 @@ |
#include "base/files/file_util.h" |
#include "base/files/memory_mapped_file.h" |
#include "base/logging.h" |
+#include "base/macros.h" |
#include "base/strings/string_number_conversions.h" |
#include "base/strings/string_util.h" |
#include "base/strings/utf_string_conversions.h" |
#include "courgette/assembly_program.h" |
#include "courgette/courgette.h" |
+#include "courgette/courgette_flow.h" |
#include "courgette/encoded_program.h" |
#include "courgette/program_detector.h" |
#include "courgette/streams.h" |
#include "courgette/third_party/bsdiff/bsdiff.h" |
+namespace { |
+ |
+using courgette::CourgetteFlow; |
+ |
+const char kUsageGen[] = "-gen <old_in> <new_in> <patch_out>"; |
+const char kUsageApply[] = "-apply <old_in> <patch_in> <new_out>"; |
+const char kUsageGenbsdiff[] = "-genbsdiff <old_in> <new_in> <patch_out>"; |
+const char kUsageApplybsdiff[] = "-applybsdiff <old_in> <patch_in> <new_out>"; |
+const char kUsageSupported[] = "-supported <exec_file_in>"; |
+const char kUsageDis[] = "-dis <exec_file_in> <assembly_file_out>"; |
+const char kUsageAsm[] = "-asm <assembly_file_in> <exec_file_out>"; |
+const char kUsageDisadj[] = "-disadj <old_in> <new_in> <new_assembly_file_out>"; |
+const char kUsageGen1[] = "-gen1[au] <old_in> <new_in> <patch_base_out>"; |
+ |
+/******** Utilities to print help and exit ********/ |
+ |
void PrintHelp() { |
- fprintf(stderr, |
- "Usage:\n" |
- " courgette -supported <executable_file>\n" |
- " courgette -dis <executable_file> <binary_assembly_file>\n" |
- " courgette -asm <binary_assembly_file> <executable_file>\n" |
- " courgette -disadj <executable_file> <reference> <binary_assembly_file>\n" |
- " courgette -gen <v1> <v2> <patch>\n" |
- " courgette -apply <v1> <patch> <v2>\n" |
- "\n"); |
+ fprintf(stderr, "Main Usage:\n"); |
+ for (auto usage : |
+ {kUsageGen, kUsageApply, kUsageGenbsdiff, kUsageApplybsdiff}) { |
+ fprintf(stderr, " courgette %s\n", usage); |
+ } |
+ fprintf(stderr, "Diagnosis Usage:\n"); |
+ for (auto usage : |
+ {kUsageSupported, kUsageDis, kUsageAsm, kUsageDisadj, kUsageGen1}) { |
+ fprintf(stderr, " courgette %s\n", usage); |
+ } |
} |
void UsageProblem(const char* message) { |
@@ -53,20 +74,29 @@ void Problem(const char* format, ...) { |
exit(1); |
} |
+/******** BufferedFileReader ********/ |
+ |
// A file reader that calls Problem() on failure. |
-class BufferedFileReader { |
+class BufferedFileReader : public courgette::BasicBuffer { |
public: |
BufferedFileReader(const base::FilePath& file_name, const char* kind) { |
if (!buffer_.Initialize(file_name)) |
Problem("Can't read %s file.", kind); |
} |
- const uint8_t* data() const { return buffer_.data(); } |
- size_t length() const { return buffer_.length(); } |
+ ~BufferedFileReader() override {} |
+ |
+ // courgette::BasicBuffer: |
+ const uint8_t* data() const override { return buffer_.data(); } |
+ size_t length() const override { return buffer_.length(); } |
private: |
base::MemoryMappedFile buffer_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BufferedFileReader); |
}; |
+/******** Various helpers ********/ |
+ |
void WriteSinkToFile(const courgette::SinkStream *sink, |
const base::FilePath& output_file) { |
int count = |
@@ -79,38 +109,6 @@ void WriteSinkToFile(const courgette::SinkStream *sink, |
Problem("Incomplete write."); |
} |
-void Disassemble(const base::FilePath& input_file, |
- const base::FilePath& output_file) { |
- BufferedFileReader buffer(input_file, "input"); |
- |
- std::unique_ptr<courgette::AssemblyProgram> program; |
- const courgette::Status parse_status = courgette::ParseDetectedExecutable( |
- buffer.data(), buffer.length(), &program); |
- if (parse_status != courgette::C_OK) |
- Problem("Can't parse input (code = %d).", parse_status); |
- |
- std::unique_ptr<courgette::EncodedProgram> encoded; |
- const courgette::Status encode_status = Encode(*program, &encoded); |
- if (encode_status != courgette::C_OK) |
- Problem("Can't encode program."); |
- |
- program.reset(); |
- |
- courgette::SinkStreamSet sinks; |
- const courgette::Status write_status = |
- courgette::WriteEncodedProgram(encoded.get(), &sinks); |
- if (write_status != courgette::C_OK) |
- Problem("Can't serialize encoded program."); |
- |
- encoded.reset(); |
- |
- courgette::SinkStream sink; |
- if (!sinks.CopyTo(&sink)) |
- Problem("Can't combine serialized encoded program streams."); |
- |
- WriteSinkToFile(&sink, output_file); |
-} |
- |
bool Supported(const base::FilePath& input_file) { |
bool result = false; |
@@ -153,50 +151,41 @@ bool Supported(const base::FilePath& input_file) { |
return result; |
} |
-void DisassembleAndAdjust(const base::FilePath& program_file, |
- const base::FilePath& model_file, |
- const base::FilePath& output_file) { |
- BufferedFileReader program_buffer(program_file, "program"); |
- BufferedFileReader model_buffer(model_file, "model"); |
- |
- std::unique_ptr<courgette::AssemblyProgram> program; |
- const courgette::Status parse_program_status = |
- courgette::ParseDetectedExecutable(program_buffer.data(), |
- program_buffer.length(), &program); |
- if (parse_program_status != courgette::C_OK) |
- Problem("Can't parse program input (code = %d).", parse_program_status); |
- |
- std::unique_ptr<courgette::AssemblyProgram> model; |
- const courgette::Status parse_model_status = |
- courgette::ParseDetectedExecutable(model_buffer.data(), |
- model_buffer.length(), &model); |
- if (parse_model_status != courgette::C_OK) |
- Problem("Can't parse model input (code = %d).", parse_model_status); |
- |
- const courgette::Status adjust_status = Adjust(*model, program.get()); |
- if (adjust_status != courgette::C_OK) |
- Problem("Can't adjust program."); |
- |
- model.reset(); |
- |
- std::unique_ptr<courgette::EncodedProgram> encoded; |
- const courgette::Status encode_status = Encode(*program, &encoded); |
- if (encode_status != courgette::C_OK) |
- Problem("Can't encode program."); |
- |
- program.reset(); |
- |
- courgette::SinkStreamSet sinks; |
- const courgette::Status write_status = |
- courgette::WriteEncodedProgram(encoded.get(), &sinks); |
- if (write_status != courgette::C_OK) |
- Problem("Can't serialize encoded program."); |
+void Disassemble(const base::FilePath& input_file, |
+ const base::FilePath& output_file) { |
+ CourgetteFlow flow; |
+ BufferedFileReader input_buffer(input_file, flow.name(flow.ONLY)); |
+ flow.ReadAssemblyProgramFromBuffer(flow.ONLY, input_buffer, false); |
+ flow.CreateEncodedProgramFromAssemblyProgram(flow.ONLY); |
+ flow.DestroyAssemblyProgram(flow.ONLY); |
+ flow.WriteSinkStreamSetFromEncodedProgram(flow.ONLY); |
+ flow.DestroyEncodedProgram(flow.ONLY); |
+ courgette::SinkStream sink; |
+ flow.WriteSinkStreamFromSinkStreamSet(flow.ONLY, &sink); |
+ if (flow.failed()) |
+ Problem(flow.message().c_str()); |
- encoded.reset(); |
+ WriteSinkToFile(&sink, output_file); |
+} |
+void DisassembleAndAdjust(const base::FilePath& old_file, |
+ const base::FilePath& new_file, |
+ const base::FilePath& output_file) { |
+ CourgetteFlow flow; |
+ BufferedFileReader old_buffer(old_file, flow.name(flow.OLD)); |
+ BufferedFileReader new_buffer(new_file, flow.name(flow.NEW)); |
+ flow.ReadAssemblyProgramFromBuffer(flow.OLD, old_buffer, true); |
+ flow.ReadAssemblyProgramFromBuffer(flow.NEW, new_buffer, true); |
+ flow.AdjustNewAssemblyProgramToMatchOld(); |
+ flow.DestroyAssemblyProgram(flow.OLD); |
+ flow.CreateEncodedProgramFromAssemblyProgram(flow.NEW); |
+ flow.DestroyAssemblyProgram(flow.NEW); |
+ flow.WriteSinkStreamSetFromEncodedProgram(flow.NEW); |
+ flow.DestroyEncodedProgram(flow.NEW); |
courgette::SinkStream sink; |
- if (!sinks.CopyTo(&sink)) |
- Problem("Can't combine serialized encoded program streams."); |
+ flow.WriteSinkStreamFromSinkStreamSet(flow.NEW, &sink); |
+ if (flow.failed()) |
+ Problem(flow.message().c_str()); |
WriteSinkToFile(&sink, output_file); |
} |
@@ -206,69 +195,32 @@ void DisassembleAndAdjust(const base::FilePath& program_file, |
// original file's stream and the new file's stream. This is completely |
// uninteresting to users, but it is handy for seeing how much each which |
// streams are contributing to the final file size. Adjustment is optional. |
-void DisassembleAdjustDiff(const base::FilePath& model_file, |
- const base::FilePath& program_file, |
+void DisassembleAdjustDiff(const base::FilePath& old_file, |
+ const base::FilePath& new_file, |
const base::FilePath& output_file_root, |
bool adjust) { |
- BufferedFileReader model_buffer(model_file, "old"); |
- BufferedFileReader program_buffer(program_file, "new"); |
- |
- auto parser = adjust ? courgette::ParseDetectedExecutableWithAnnotation |
- : courgette::ParseDetectedExecutable; |
- |
- std::unique_ptr<courgette::AssemblyProgram> model; |
- const courgette::Status parse_model_status = |
- parser(model_buffer.data(), model_buffer.length(), &model); |
- if (parse_model_status != courgette::C_OK) |
- Problem("Can't parse model input (code = %d).", parse_model_status); |
- |
- std::unique_ptr<courgette::AssemblyProgram> program; |
- const courgette::Status parse_program_status = |
- parser(program_buffer.data(), program_buffer.length(), &program); |
- if (parse_program_status != courgette::C_OK) |
- Problem("Can't parse program input (code = %d).", parse_program_status); |
- |
- if (adjust) { |
- const courgette::Status adjust_status = Adjust(*model, program.get()); |
- if (adjust_status != courgette::C_OK) |
- Problem("Can't adjust program."); |
- } |
- |
- std::unique_ptr<courgette::EncodedProgram> encoded_program; |
- const courgette::Status encode_program_status = |
- Encode(*program, &encoded_program); |
- if (encode_program_status != courgette::C_OK) |
- Problem("Can't encode program."); |
- |
- program.reset(); |
- |
- std::unique_ptr<courgette::EncodedProgram> encoded_model; |
- const courgette::Status encode_model_status = Encode(*model, &encoded_model); |
- if (encode_model_status != courgette::C_OK) |
- Problem("Can't encode model."); |
- |
- model.reset(); |
- |
- courgette::SinkStreamSet program_sinks; |
- const courgette::Status write_program_status = |
- courgette::WriteEncodedProgram(encoded_program.get(), &program_sinks); |
- if (write_program_status != courgette::C_OK) |
- Problem("Can't serialize encoded program."); |
- |
- encoded_program.reset(); |
- |
- courgette::SinkStreamSet model_sinks; |
- const courgette::Status write_model_status = |
- courgette::WriteEncodedProgram(encoded_model.get(), &model_sinks); |
- if (write_model_status != courgette::C_OK) |
- Problem("Can't serialize encoded model."); |
- |
- encoded_model.reset(); |
+ CourgetteFlow flow; |
+ BufferedFileReader old_buffer(old_file, flow.name(flow.OLD)); |
+ BufferedFileReader new_buffer(new_file, flow.name(flow.NEW)); |
+ flow.ReadAssemblyProgramFromBuffer(flow.OLD, old_buffer, adjust); |
+ flow.ReadAssemblyProgramFromBuffer(flow.NEW, new_buffer, adjust); |
+ if (adjust) |
+ flow.AdjustNewAssemblyProgramToMatchOld(); |
+ flow.CreateEncodedProgramFromAssemblyProgram(flow.OLD); |
+ flow.DestroyAssemblyProgram(flow.OLD); |
+ flow.CreateEncodedProgramFromAssemblyProgram(flow.NEW); |
+ flow.DestroyAssemblyProgram(flow.NEW); |
+ flow.WriteSinkStreamSetFromEncodedProgram(flow.OLD); |
+ flow.DestroyEncodedProgram(flow.OLD); |
+ flow.WriteSinkStreamSetFromEncodedProgram(flow.NEW); |
+ flow.DestroyEncodedProgram(flow.NEW); |
+ if (flow.failed()) |
+ Problem(flow.message().c_str()); |
courgette::SinkStream empty_sink; |
for (int i = 0; ; ++i) { |
- courgette::SinkStream* old_stream = model_sinks.stream(i); |
- courgette::SinkStream* new_stream = program_sinks.stream(i); |
+ courgette::SinkStream* old_stream = flow.data(flow.OLD)->sinks.stream(i); |
+ courgette::SinkStream* new_stream = flow.data(flow.NEW)->sinks.stream(i); |
if (old_stream == NULL && new_stream == NULL) |
break; |
@@ -291,24 +243,14 @@ void DisassembleAdjustDiff(const base::FilePath& model_file, |
void Assemble(const base::FilePath& input_file, |
const base::FilePath& output_file) { |
- BufferedFileReader buffer(input_file, "input"); |
- |
- courgette::SourceStreamSet sources; |
- if (!sources.Init(buffer.data(), buffer.length())) |
- Problem("Bad input file."); |
- |
- std::unique_ptr<courgette::EncodedProgram> encoded; |
- const courgette::Status read_status = |
- courgette::ReadEncodedProgram(&sources, &encoded); |
- if (read_status != courgette::C_OK) |
- Problem("Bad encoded program."); |
- |
+ CourgetteFlow flow; |
+ BufferedFileReader input_buffer(input_file, flow.name(flow.ONLY)); |
+ flow.ReadSourceStreamSetFromBuffer(flow.ONLY, input_buffer); |
+ flow.ReadEncodedProgramFromSourceStreamSet(flow.ONLY); |
courgette::SinkStream sink; |
- |
- const courgette::Status assemble_status = |
- courgette::Assemble(encoded.get(), &sink); |
- if (assemble_status != courgette::C_OK) |
- Problem("Can't assemble."); |
+ flow.WriteExecutableFromEncodedProgram(flow.ONLY, &sink); |
+ if (flow.failed()) |
+ Problem(flow.message().c_str()); |
WriteSinkToFile(&sink, output_file); |
} |
@@ -430,6 +372,8 @@ void ApplyBSDiffPatch(const base::FilePath& old_file, |
WriteSinkToFile(&new_stream, new_file); |
} |
+} // namespace |
+ |
int main(int argc, const char* argv[]) { |
base::AtExitManager at_exit_manager; |
base::CommandLine::Init(argc, argv); |
@@ -468,50 +412,51 @@ int main(int argc, const char* argv[]) { |
repeat_count = 1; |
if (cmd_sup + cmd_dis + cmd_asm + cmd_disadj + cmd_make_patch + |
- cmd_apply_patch + cmd_make_bsdiff_patch + cmd_apply_bsdiff_patch + |
- cmd_spread_1_adjusted + cmd_spread_1_unadjusted |
- != 1) |
+ cmd_apply_patch + cmd_make_bsdiff_patch + cmd_apply_bsdiff_patch + |
+ cmd_spread_1_adjusted + cmd_spread_1_unadjusted != |
+ 1) { |
UsageProblem( |
- "Must have exactly one of:\n" |
- " -supported -asm, -dis, -disadj, -gen or -apply, -genbsdiff" |
- " or -applybsdiff."); |
+ "First argument must be one of:\n" |
+ " -supported, -asm, -dis, -disadj, -gen, -apply, -genbsdiff," |
+ " -applybsdiff, or -gen1[au]."); |
+ } |
while (repeat_count-- > 0) { |
if (cmd_sup) { |
if (values.size() != 1) |
- UsageProblem("-supported <executable_file>"); |
+ UsageProblem(kUsageSupported); |
return !Supported(values[0]); |
} else if (cmd_dis) { |
- if (values.size() != 2) |
- UsageProblem("-dis <executable_file> <courgette_file>"); |
- Disassemble(values[0], values[1]); |
+ if (values.size() != 2) |
+ UsageProblem(kUsageDis); |
+ Disassemble(values[0], values[1]); |
} else if (cmd_asm) { |
if (values.size() != 2) |
- UsageProblem("-asm <courgette_file_input> <executable_file_output>"); |
+ UsageProblem(kUsageAsm); |
Assemble(values[0], values[1]); |
} else if (cmd_disadj) { |
if (values.size() != 3) |
- UsageProblem("-disadj <executable_file> <model> <courgette_file>"); |
+ UsageProblem(kUsageDisadj); |
DisassembleAndAdjust(values[0], values[1], values[2]); |
} else if (cmd_make_patch) { |
if (values.size() != 3) |
- UsageProblem("-gen <old_file> <new_file> <patch_file>"); |
+ UsageProblem(kUsageGen); |
GenerateEnsemblePatch(values[0], values[1], values[2]); |
} else if (cmd_apply_patch) { |
if (values.size() != 3) |
- UsageProblem("-apply <old_file> <patch_file> <new_file>"); |
+ UsageProblem(kUsageApply); |
ApplyEnsemblePatch(values[0], values[1], values[2]); |
} else if (cmd_make_bsdiff_patch) { |
if (values.size() != 3) |
- UsageProblem("-genbsdiff <old_file> <new_file> <patch_file>"); |
+ UsageProblem(kUsageGenbsdiff); |
GenerateBSDiffPatch(values[0], values[1], values[2]); |
} else if (cmd_apply_bsdiff_patch) { |
if (values.size() != 3) |
- UsageProblem("-applybsdiff <old_file> <patch_file> <new_file>"); |
+ UsageProblem(kUsageApplybsdiff); |
ApplyBSDiffPatch(values[0], values[1], values[2]); |
} else if (cmd_spread_1_adjusted || cmd_spread_1_unadjusted) { |
if (values.size() != 3) |
- UsageProblem("-gen1[au] <old_file> <new_file> <patch_files_root>"); |
+ UsageProblem(kUsageGen1); |
DisassembleAdjustDiff(values[0], values[1], values[2], |
cmd_spread_1_adjusted); |
} else { |