// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "courgette/courgette_flow.h" #include #include #include "base/check.h" #include "base/files/file_path.h" #include "base/memory/ptr_util.h" #include "base/notreached.h" #include "base/strings/stringprintf.h" #include "courgette/assembly_program.h" #include "courgette/disassembler.h" #include "courgette/encoded_program.h" #include "courgette/program_detector.h" namespace courgette { /******** CourgetteFlow::Data ********/ CourgetteFlow::Data::Data() = default; CourgetteFlow::Data::~Data() = default; /******** CourgetteFlow ********/ CourgetteFlow::CourgetteFlow() = default; CourgetteFlow::~CourgetteFlow() = default; // static const char* CourgetteFlow::name(Group group) { switch (group) { case ONLY: return "input"; case OLD: return "'old' input"; case NEW: return "'new' input"; default: NOTREACHED(); break; } return nullptr; } CourgetteFlow::Data* CourgetteFlow::data(Group group) { switch (group) { case ONLY: return &data_only_; case OLD: return &data_old_; case NEW: return &data_new_; default: NOTREACHED(); break; } return nullptr; } bool CourgetteFlow::ok() { return status_ == C_OK; } bool CourgetteFlow::failed() { return status_ != C_OK; } Status CourgetteFlow::status() { return status_; } const std::string& CourgetteFlow::message() { return message_; } void CourgetteFlow::ReadSourceStreamSetFromBuffer(Group group, const BasicBuffer& buffer) { if (failed()) return; Data* d = data(group); if (!check(d->sources.Init(buffer.data(), buffer.length()), C_GENERAL_ERROR)) { setMessage("Cannot read %s as SourceStreamSet.", name(group)); } } void CourgetteFlow::ReadDisassemblerFromBuffer(Group group, const BasicBuffer& buffer) { if (failed()) return; Data* d = data(group); d->disassembler = DetectDisassembler(buffer.data(), buffer.length()); if (!check(d->disassembler.get() != nullptr, C_INPUT_NOT_RECOGNIZED)) setMessage("Cannot detect program for %s.", name(group)); } void CourgetteFlow::ReadEncodedProgramFromSourceStreamSet( Group group, SourceStreamSet* opt_sources /* nullptr */) { if (failed()) return; Data* d = data(group); SourceStreamSet* sources = opt_sources ? opt_sources : &d->sources; if (!check(ReadEncodedProgram(sources, &d->encoded))) setMessage("Cannot read %s as encoded program.", name(group)); } void CourgetteFlow::CreateAssemblyProgramFromDisassembler(Group group, bool annotate) { if (failed()) return; Data* d = data(group); d->program = d->disassembler->CreateProgram(annotate); if (!check(d->program.get() != nullptr, C_DISASSEMBLY_FAILED)) setMessage("Cannot create AssemblyProgram for %s.", name(group)); } void CourgetteFlow::CreateEncodedProgramFromDisassemblerAndAssemblyProgram( Group group) { if (failed()) return; Data* d = data(group); d->encoded = std::make_unique(); if (!check(d->disassembler->DisassembleAndEncode(d->program.get(), d->encoded.get()))) { setMessage("Cannot disassemble to form EncodedProgram for %s.", name(group)); } } void CourgetteFlow::WriteSinkStreamFromSinkStreamSet(Group group, SinkStream* sink) { DCHECK(sink); if (failed()) return; if (!check(data(group)->sinks.CopyTo(sink), C_GENERAL_ERROR)) setMessage("Cannnot combine serialized streams for %s.", name(group)); } void CourgetteFlow::WriteSinkStreamSetFromEncodedProgram( Group group, SinkStreamSet* opt_sinks /* nullptr */) { if (failed()) return; Data* d = data(group); SinkStreamSet* sinks = opt_sinks ? opt_sinks : &d->sinks; if (!check(WriteEncodedProgram(d->encoded.get(), sinks))) setMessage("Cannot serialize encoded %s.", name(group)); } void CourgetteFlow::WriteExecutableFromEncodedProgram(Group group, SinkStream* sink) { DCHECK(sink); if (failed()) return; if (!check(Assemble(data(group)->encoded.get(), sink))) setMessage("Cannot assemble %s.", name(group)); } void CourgetteFlow::AdjustNewAssemblyProgramToMatchOld() { if (failed()) return; if (!check(Adjust(*data_old_.program, data_new_.program.get()))) setMessage("Cannot adjust %s to match %s.", name(OLD), name(NEW)); } void CourgetteFlow::DestroyDisassembler(Group group) { if (failed()) return; data(group)->disassembler.reset(); } void CourgetteFlow::DestroyAssemblyProgram(Group group) { if (failed()) return; data(group)->program.reset(); } void CourgetteFlow::DestroyEncodedProgram(Group group) { if (failed()) return; data(group)->encoded.reset(); } bool CourgetteFlow::check(Status new_status) { if (new_status == C_OK) return true; status_ = new_status; return false; } bool CourgetteFlow::check(bool success, Status failure_mode) { if (success) return true; status_ = failure_mode; return false; } void CourgetteFlow::setMessage(const char* format, ...) { va_list args; va_start(args, format); message_ = base::StringPrintV(format, args); va_end(args); } } // namespace courgette