blob: 4a1f7f39a9976073790f69858324cbd8e2f1919d [file] [log] [blame]
// 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 <stdarg.h>
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/ptr_util.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.reset(new EncodedProgram());
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