std::shared_ptr<DependencyValidation> Store::MakeDependencyValidation(const ResChar intermediateFileName[]) const { // When we process a file, we write a little text file to the // ".deps" directory. This contains a list of dependency files, and // the state of those files when this file was compiled. // If the current files don't match the state that's recorded in // the .deps file, then we can assume that it is out of date and // must be recompiled. ResChar buffer[MaxPath]; MakeDepFileName(buffer, _baseDirectory.c_str(), intermediateFileName); if (!DoesFileExist(buffer)) return nullptr; Data data; data.LoadFromFile(buffer); auto* basePath = data.StrAttribute("BasePath"); auto validation = std::make_shared<DependencyValidation>(); auto* dependenciesBlock = data.ChildWithValue("Dependencies"); if (dependenciesBlock) { for (auto* dependency = dependenciesBlock->child; dependency; dependency = dependency->next) { auto* depName = dependency->value; if (!depName || !depName[0]) continue; auto dateLow = (unsigned)dependency->IntAttribute("ModTimeL"); auto dateHigh = (unsigned)dependency->IntAttribute("ModTimeH"); std::shared_ptr<RetainedFileRecord> record; if (basePath && basePath[0]) { XlConcatPath(buffer, dimof(buffer), basePath, depName, XlStringEnd(depName)); record = GetRetainedFileRecord(buffer); } else record = GetRetainedFileRecord(depName); RegisterAssetDependency(validation, record); if (record->_state._status == DependentFileState::Status::Shadowed) { LogInfo << "Asset (" << intermediateFileName << ") is invalidated because dependency (" << depName << ") is marked shadowed"; return nullptr; } if (!record->_state._timeMarker) { LogInfo << "Asset (" << intermediateFileName << ") is invalidated because of missing dependency (" << depName << ")"; return nullptr; } else if (record->_state._timeMarker != ((uint64(dateHigh) << 32ull) | uint64(dateLow))) { LogInfo << "Asset (" << intermediateFileName << ") is invalidated because of file data on dependency (" << depName << ")"; return nullptr; } } } return validation; }
void DirectorySearchRules::ResolveFile(ResChar destination[], unsigned destinationCount, const ResChar baseName[]) const { ResChar tempBuffer[MaxPath]; auto splitter = MakeFileNameSplitter(baseName); bool baseFileExist = false; if (!splitter.ParametersWithDivider().Empty()) { XlCopyString(tempBuffer, splitter.AllExceptParameters()); baseFileExist = DoesFileExist(tempBuffer); } else { baseFileExist = DoesFileExist(baseName); } // by definition, we always check the unmodified file name first if (!baseFileExist) { const ResChar* b = _buffer; if (!_bufferOverflow.empty()) { b = AsPointer(_bufferOverflow.begin()); } // We want to support the case were destination == baseName // But that cases requires another temporary buffer, because we // don't want to trash "baseName" while searching for matches ResChar* workingBuffer = (baseName!=destination) ? destination : tempBuffer; unsigned workingBufferSize = (baseName!=destination) ? destinationCount : unsigned(dimof(tempBuffer)); for (unsigned c=0; c<_startPointCount; ++c) { XlConcatPath(workingBuffer, workingBufferSize, &b[_startOffsets[c]], splitter.AllExceptParameters().begin(), splitter.AllExceptParameters().end()); if (DoesFileExist(workingBuffer)) { SplitPath<ResChar>(workingBuffer).Simplify().Rebuild(workingBuffer, workingBufferSize); if (workingBuffer != destination) { auto workingBufferLen = std::min((ptrdiff_t)XlStringLen(workingBuffer), ptrdiff_t(destinationCount) - 1); auto colonLen = (ptrdiff_t)splitter.ParametersWithDivider().Length(); auto colonCopy = std::min(ptrdiff_t(destinationCount) - workingBufferLen - 1, colonLen); assert((workingBufferLen + colonCopy) < ptrdiff_t(destinationCount)); if (colonCopy > 0) XlMoveMemory(&destination[workingBufferLen], splitter.ParametersWithDivider().begin(), colonCopy); destination[workingBufferLen + colonCopy] = '\0'; assert(workingBufferLen < (ptrdiff_t(destinationCount)-1)); XlCopyMemory(destination, workingBuffer, workingBufferLen); } else { XlCatString(destination, destinationCount, splitter.ParametersWithDivider()); } return; } } } if (baseName != destination) XlCopyString(destination, destinationCount, baseName); SplitPath<ResChar>(destination).Simplify().Rebuild(destination, destinationCount); }
static void SetWorkingDirectory() { // // For convenience, set the working directory to be ../Working // (relative to the application path) // nchar_t appPath [MaxPath]; nchar_t appDir [MaxPath]; nchar_t workingDir [MaxPath]; XlGetProcessPath (appPath, dimof(appPath)); XlDirname (appDir, dimof(appDir), appPath); const auto* fn = a2n("..\\Working"); XlConcatPath (workingDir, dimof(workingDir), appDir, fn, XlStringEnd(fn)); XlChDir (workingDir); }
void DirectorySearchRules::ResolveDirectory( ResChar destination[], unsigned destinationCount, const ResChar baseName[]) const { // We have a problem with basic paths (like '../') // These will match for most directories -- which means that // there is some ambiguity. Let's prefer to use the first // registered path for simple relative paths like this. bool useBaseName = (baseName[0] != '.' && DoesDirectoryExist(baseName)); if (!useBaseName) { const ResChar* b = _buffer; if (!_bufferOverflow.empty()) { b = AsPointer(_bufferOverflow.begin()); } const auto* baseEnd = XlStringEnd(baseName); ResChar tempBuffer[MaxPath]; ResChar* workingBuffer = (baseName!=destination) ? destination : tempBuffer; unsigned workingBufferSize = (baseName!=destination) ? destinationCount : unsigned(dimof(tempBuffer)); for (unsigned c=0; c<_startPointCount; ++c) { XlConcatPath(workingBuffer, workingBufferSize, &b[_startOffsets[c]], baseName, baseEnd); if (DoesDirectoryExist(workingBuffer)) { if (workingBuffer != destination) XlCopyString(destination, destinationCount, workingBuffer); return; } } } if (baseName != destination) XlCopyString(destination, destinationCount, baseName); }