38 static bool SetAndSaveZipAssetData(
const std::string& filename,
39 const std::string& source) {
44 static const std::string GetZipAssetFileData(
const std::string& filename) {
59 class IncludeComposer::IncludeComposerHelper :
public base::Allocatable {
61 IncludeComposerHelper(
const base::Allocatable& owner,
62 const std::string& filename,
66 bool insert_line_directives)
70 source_loader_(source_loader),
71 source_saver_(source_saver),
72 source_time_(source_time),
73 insert_line_directives_(insert_line_directives),
75 const size_t pos = filename_.rfind(
'/');
76 if (pos != std::string::npos) {
77 search_path_ = filename_.substr(0, pos);
78 filename_ = filename_.substr(pos + 1, std::string::npos);
87 std::vector<std::string> changed;
88 for (FileInfoMap::iterator it = used_files_.begin();
89 it != used_files_.end(); ++it) {
90 std::chrono::system_clock::time_point timestamp;
91 const bool found = source_time_(it->first, ×tamp);
92 if (found && timestamp > it->second.timestamp) {
93 it->second.timestamp = timestamp;
94 changed.push_back(it->first);
103 std::stack<InputInfo> stack;
105 std::set<std::string> file_names;
107 std::vector<std::string> output_source;
110 unsigned int input_id = 1;
118 stack.push(InputInfo(BuildFilename(filename_)));
119 while (!stack.empty()) {
121 InputInfo info = stack.top();
124 if (info.lines.size() == 0) {
126 if (file_names.count(info.name) != 0) {
127 LOG(
WARNING) << stack.top().name <<
":" << (stack.top().line - 1U)
128 <<
": Recursive $input ignored while trying to $input"
129 <<
" \"" << info.name <<
"\".\n";
134 const std::string source = source_loader_(info.name);
140 info.lines.push_back(
"");
141 const std::vector<std::string> lines =
143 info.lines.insert(info.lines.end(), lines.begin(), lines.end());
146 file_names.insert(info.name);
147 std::chrono::system_clock::time_point timestamp;
148 source_time_(info.name, ×tamp);
149 used_files_[info.name] = FileInfo(timestamp);
152 if (file_to_id_.count(info.name) == 0) {
153 file_to_id_[info.name] = input_id;
154 id_to_file_[input_id] = info.name;
159 info.id = file_to_id_[info.name];
162 if (insert_line_directives_ && !stack.empty()) {
165 output_source.push_back(GetLineDirectiveString(1, info.id));
167 }
else if (insert_line_directives_) {
170 output_source.push_back(GetLineDirectiveString(info.line - 1, info.id));
172 if (ParseInputLines(&stack, &info, &output_source)) {
175 file_names.erase(info.name);
187 source_time_(dependency, &used_files_[dependency].timestamp);
188 return source_loader_(dependency);
190 return std::string();
196 const std::string& source) {
198 const bool ret = source_saver_(dependency, source);
199 source_time_(dependency, &used_files_[dependency].timestamp);
207 bool DependsOn(
const std::string& dependency)
const {
208 return file_to_id_.find(dependency) != file_to_id_.end();
215 IdToFileMap::const_iterator it = id_to_file_.find(
id);
216 if (it != id_to_file_.end())
223 std::vector<std::string> names(file_to_id_.size());
225 for (FileToIdMap::const_iterator it = file_to_id_.begin();
226 it != file_to_id_.end(); ++it, ++i)
227 names[i] = it->first;
234 explicit InputInfo(
const std::string& file_name)
235 : name(file_name), lines(), id(-1), line(-1) {}
237 std::vector<std::string> lines;
245 explicit FileInfo(std::chrono::system_clock::time_point timestamp)
246 : timestamp(timestamp) {}
247 std::chrono::system_clock::time_point timestamp;
251 typedef base::AllocMap<std::string, unsigned int> FileToIdMap;
252 typedef base::AllocMap<unsigned int, std::string> IdToFileMap;
253 typedef base::AllocMap<std::string, FileInfo> FileInfoMap;
256 const std::string BuildFilename(
const std::string& filename) {
257 const std::string base_path = base_path_.empty() ?
258 "" : base_path_ +
'/';
259 const std::string search_path = search_path_.empty() ?
260 "" : search_path_ +
'/';
261 return base_path + search_path + filename;
265 std::string GetLineDirectiveString(
size_t line,
unsigned int file_id) {
266 std::stringstream
str;
267 str <<
"#line " << line <<
" " << file_id;
275 bool ParseInputLines(std::stack<InputInfo>* stack, InputInfo* info,
276 std::vector<std::string>* output_lines) {
278 for (; info->line < info->lines.size(); ++info->line) {
279 const std::string trimmed =
285 const size_t start_pos = trimmed.find(
"\"") + 1;
286 const size_t end_pos = trimmed.find_last_of(
"\"");
287 const std::string input_file =
288 trimmed.substr(start_pos, end_pos - start_pos);
289 const InputInfo new_info(BuildFilename(input_file));
290 if (new_info.name.empty()) {
293 LOG(
WARNING) << info->name <<
":" << info->line
294 <<
": Invalid $input directive, perhaps missing a '\"'?";
302 stack->push(new_info);
307 output_lines->push_back(info->lines[info->line]);
308 if (insert_line_directives_) {
313 if (trimmed.find(
"#if") != std::string::npos ||
314 trimmed.find(
"#el") != std::string::npos ||
315 trimmed.find(
"#endif") != std::string::npos)
316 output_lines->push_back(
317 GetLineDirectiveString(info->line, info->id));
325 FileToIdMap file_to_id_;
326 IdToFileMap id_to_file_;
329 std::string filename_;
331 std::string search_path_;
333 std::string base_path_;
341 bool insert_line_directives_;
344 FileInfoMap used_files_;
366 const std::string& filename,
const SourceLoader& source_loader,
368 bool insert_line_directives)
369 : helper_(new(GetAllocator()) IncludeComposerHelper(
370 *this, filename, source_loader, source_saver, source_time,
371 insert_line_directives)) {}
375 helper_->SetBasePath(path);
379 return helper_->GetChangedDependencies();
383 return helper_->GetSource();
387 const std::string& dependency)
const {
388 return helper_->GetDependencySource(dependency);
392 const std::string& source) {
393 return helper_->SetDependencySource(dependency, source);
397 return helper_->DependsOn(resource);
401 return helper_->GetDependencyName(
id);
405 return helper_->GetDependencyNames();
416 bool insert_line_directives)
418 SetAndSaveZipAssetData,
419 base::ZipAssetManager::UpdateFileIfChanged,
420 insert_line_directives) {}
std::function< bool(const std::string &name, const std::string &source)> SourceSaver
A function that saves a string source given a filename.
bool IsInvalidReference(const T &value)
IsInvalidReference() returns true if a passed const reference of type T has an address of InvalidRefe...
bool StartsWith(const std::string &target, const std::string &start)
Returns whether target begins with start.
const std::vector< std::string > GetDependencyNames() const override
Returns a vector containing all names that this composer depends on, or an empty vector if there are ...
void SetBasePath(const std::string &path)
Sets a path that will be prepended to all files (including the top-level filename) loaded by this com...
static bool SetFileData(const std::string &filename, const std::string &source)
Sets the data of the passed filename if the manager contains it.
std::function< bool(const std::string &filename, std::chrono::system_clock::time_point *timestamp)> SourceModificationTime
A function that returns the last time the source in filename was modified.
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
std::string TrimStartAndEndWhitespace(const std::string &target)
Removes any whitespace characters at the beginning and end of the string.
~ShaderSourceComposer() override
The destructor is protected since this is derived from base::Referent.
const std::string GetDependencySource(const std::string &dependency) const override
Returns the source of the passed dependency.
static const std::string & GetFileData(const std::string &filename)
Returns the data of the passed filename if the manager contains it.
bool SetDependencySource(const std::string &dependency, const std::string &source) override
Requests that the composer set the source of the dependency.
IncludeComposer(const std::string &filename, const SourceLoader &source_loader, const SourceSaver &source_saver, const SourceModificationTime &source_time, bool insert_line_directives)
The constructor requires a base filename that represents the top-level file, functions for loading...
~ZipAssetComposer() override
The destructor is protected since this is derived from base::Referent.
ZipAssetComposer(const std::string &filename, bool insert_line_directives)
ZipAssetComposer definition.
static bool SaveFileData(const std::string &filename)
Attempts to save the latest cached data of the passed filename back to the original source file on di...
~IncludeComposer() override
The destructor is protected since this is derived from base::Referent.
std::string JoinStrings(const std::vector< std::string > &strings, const std::string &glue)
Joins the strings in the passed vector together with the passed glue.
std::function< const std::string(const std::string &name)> SourceLoader
A function that returns a string source given a filename.
ShaderSourceComposer()
The constructor is protected since this is an abstract base class.
Loads a shader source from a resource that may include other resources using the special directive '$...
const std::vector< std::string > GetChangedDependencies() override
Determines if any dependencies have changed (e.g., if a file has changed on disk since the last call ...
std::vector< std::string > ION_API SplitStringWithoutSkipping(const std::string &str, const std::string &delimiters)
Splits a string into a vector of substrings, given a set of delimiter characters (expressed as a stri...
const std::string GetDependencyName(unsigned int id) const override
Returns the name of a dependency identified by the passed id.
const std::string GetSource() override
Returns the source string of a shader.
bool DependsOn(const std::string &dependency) const override
Returns whether this composer depends on the named dependency, which might be a filename or some othe...