blob: d9786532e114c1596e37b96bbd9c9d159c243d4e [file] [log] [blame] [edit]
// Copyright 2013 The Flutter 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 "impeller/compiler/includer.h"
#include <cstring>
#include "flutter/fml/paths.h"
namespace impeller {
namespace compiler {
Includer::Includer(std::shared_ptr<fml::UniqueFD> working_directory,
std::vector<IncludeDir> include_dirs,
std::function<void(std::string)> on_file_included)
: working_directory_(std::move(working_directory)),
include_dirs_(std::move(include_dirs)),
on_file_included_(std::move(on_file_included)) {}
// |shaderc::CompileOptions::IncluderInterface|
Includer::~Includer() = default;
std::unique_ptr<fml::FileMapping> Includer::TryOpenMapping(
const IncludeDir& dir,
const char* requested_source) {
if (!dir.dir || !dir.dir->is_valid()) {
return nullptr;
}
if (requested_source == nullptr) {
return nullptr;
}
std::string source(requested_source);
if (source.empty()) {
return nullptr;
}
auto mapping = fml::FileMapping::CreateReadOnly(*dir.dir, requested_source);
if (!mapping || !mapping->IsValid()) {
return nullptr;
}
on_file_included_(fml::paths::JoinPaths({dir.name, requested_source}));
return mapping;
}
std::unique_ptr<fml::FileMapping> Includer::FindFirstMapping(
const char* requested_source) {
// Always try the working directory first no matter what the include
// directories are.
{
IncludeDir dir;
dir.name = ".";
dir.dir = working_directory_;
if (auto mapping = TryOpenMapping(dir, requested_source)) {
return mapping;
}
}
for (const auto& include_dir : include_dirs_) {
if (auto mapping = TryOpenMapping(include_dir, requested_source)) {
return mapping;
}
}
return nullptr;
}
shaderc_include_result* Includer::GetInclude(const char* requested_source,
shaderc_include_type type,
const char* requesting_source,
size_t include_depth) {
auto result = std::make_unique<shaderc_include_result>();
// Default initialize to failed inclusion.
result->source_name = "";
result->source_name_length = 0;
constexpr const char* kFileNotFoundMessage = "Included file not found.";
result->content = kFileNotFoundMessage;
result->content_length = ::strlen(kFileNotFoundMessage);
result->user_data = nullptr;
if (!working_directory_ || !working_directory_->is_valid()) {
return result.release();
}
if (requested_source == nullptr) {
return result.release();
}
auto file = FindFirstMapping(requested_source);
if (!file || file->GetMapping() == nullptr) {
return result.release();
}
auto includer_data =
std::make_unique<IncluderData>(requested_source, std::move(file));
result->source_name = includer_data->file_name.c_str();
result->source_name_length = includer_data->file_name.length();
result->content = reinterpret_cast<decltype(result->content)>(
includer_data->mapping->GetMapping());
result->content_length = includer_data->mapping->GetSize();
result->user_data = includer_data.release();
return result.release();
}
void Includer::ReleaseInclude(shaderc_include_result* data) {
delete reinterpret_cast<IncluderData*>(data->user_data);
delete data;
}
} // namespace compiler
} // namespace impeller