string_view path::__parent_path() const { if (empty() || pbegin(*this) == --pend(*this)) { return {}; } auto end_it = --(--pend(*this)); auto end_i = parser::end_of(__pn_, end_it.__pos_); return string_view(__pn_).substr(0, end_i+1); }
inline string_view to_string( inclusion_style i ) { switch ( i ) { case inclusion_style::angle_bracket: return "angle bracket"; case inclusion_style::quote: return "quote"; } return string_view(); }
string Panel::GetTitle() const { if (m_PanelMode == panel_mode::NORMAL_PANEL) return m_ShowShortNames? ConvertNameToShort(m_CurDir) : m_CurDir; OpenPanelInfo Info; GetOpenPanelInfo(&Info); return string(trim(string_view(NullToEmpty(Info.PanelTitle)))); }
int DialogBuilder::AddTextWrap(const wchar_t *text, bool center, int width) { int LineCount = 0; for(const auto& i: wrapped_text(string_view(text), width <= 0? ScrX - 1 - 10 : width)) { const auto Text = AddText(null_terminated(i).c_str()); Text->Flags = center? DIF_CENTERTEXT : 0; ++LineCount; } return LineCount; }
static string_view_t signature_tail(string_view_t str) { string_view_t tail = str; const char * p = find_next_arrow(str); if (p == NULL) return string_view(); tail.begin = p+1; return tail; }
string Panel::CreateFullPathName(string_view const Name, bool const Directory, bool const UNC, bool const ShortNameAsIs) const { auto FullName = FindSlash(Name) == string::npos? ConvertNameToFull(Name) : string(Name); if (m_ShowShortNames && ShortNameAsIs) FullName = ConvertNameToShort(FullName); /* $ 29.01.2001 VVM + По CTRL+ALT+F в командную строку сбрасывается UNC-имя текущего файла. */ if (UNC) FullName = ConvertNameToUNC(FullName); // $ 20.10.2000 SVS Сделаем фичу Ctrl-F опциональной! if (Global->Opt->PanelCtrlFRule) { /* $ 13.10.2000 tran по Ctrl-f имя должно отвечать условиям на панели */ if (m_ViewSettings.Flags&PVS_FOLDERUPPERCASE) { if (Directory) { inplace::upper(FullName); } else { inplace::upper(FullName, 0, FindLastSlash(FullName)); } } if ((m_ViewSettings.Flags&PVS_FILEUPPERTOLOWERCASE) && !Directory) { const auto pos = FindLastSlash(FullName); if (pos != string::npos && !IsCaseMixed(string_view(FullName).substr(pos))) { inplace::lower(FullName, pos); } } if ((m_ViewSettings.Flags&PVS_FILELOWERCASE) && !Directory) { const auto pos = FindLastSlash(FullName); if (pos != string::npos) { inplace::lower(FullName, pos); } } } return FullName; }
string_view path::__relative_path() const { if (empty()) { return {__pn_}; } auto end_i = parser::root_directory_end(__pn_); if (not parser::good(end_i)) { end_i = parser::root_name_end(__pn_); } if (not parser::good(end_i)) { return {__pn_}; } return string_view(__pn_).substr(end_i+1); }
string ConvertNameToUNC(string_view const Object) { auto strFileName = ConvertNameToFull(Object); // Посмотрим на тип файловой системы string strFileSystemName; os::fs::GetVolumeInformation(GetPathRoot(strFileName), nullptr, nullptr, nullptr, nullptr, &strFileSystemName); DWORD uniSize = 1024; block_ptr<UNIVERSAL_NAME_INFO> uni(uniSize); // применяем WNetGetUniversalName для чего угодно, только не для Novell`а if (!equal_icase(strFileSystemName, L"NWFS"sv)) { switch (WNetGetUniversalName(strFileName.c_str(), UNIVERSAL_NAME_INFO_LEVEL, uni.get(), &uniSize)) { case NO_ERROR: strFileName = uni->lpUniversalName; break; case ERROR_MORE_DATA: uni.reset(uniSize); if (WNetGetUniversalName(strFileName.c_str(),UNIVERSAL_NAME_INFO_LEVEL,uni.get(),&uniSize)==NO_ERROR) strFileName = uni->lpUniversalName; break; } } else if (strFileName.size() > 1 && strFileName[1] == L':') { // BugZ#449 - Неверная работа CtrlAltF с ресурсами Novell DS // Здесь, если не получилось получить UniversalName и если это // мапленный диск - получаем как для меню выбора дисков string strTemp; if (DriveLocalToRemoteName(DRIVE_UNKNOWN,strFileName[0],strTemp)) { const auto SlashPos = FindSlash(strFileName); if (SlashPos != string::npos) path::append(strTemp, string_view(strFileName).substr(SlashPos + 1)); strFileName = strTemp; } } return ConvertNameToReal(strFileName); }
/* Преобразует Src в полный РЕАЛЬНЫЙ путь с учетом reparse point. Note that Src can be partially non-existent. */ string ConvertNameToReal(string_view const Object) { SCOPED_ACTION(elevation::suppress); // Получим сначала полный путь до объекта обычным способом const auto FullPath = ConvertNameToFull(Object); auto strDest = FullPath; string Path = FullPath; os::fs::file File; for (;;) { if (File.Open(Path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING)) break; if (IsRootPath(Path)) break; Path = ExtractFilePath(Path); } if (File) { string FinalFilePath; File.GetFinalPathName(FinalFilePath); File.Close(); //assert(!FinalFilePath.empty()); if (!FinalFilePath.empty()) { // append non-existent path part (if present) DeleteEndSlash(Path); if (FullPath.size() > Path.size() + 1) path::append(FinalFilePath, string_view(FullPath).substr(Path.size() + 1)); FinalFilePath = TryConvertVolumeGuidToDrivePath(FinalFilePath); strDest = FinalFilePath; } } return strDest; }
int main() { { string_view_t f0 = string_view(); string_view_t f1 = make_string_view(""); string_view_t f2 = make_string_view("CInt"); string_view_t f3 = make_string_view(" CInt "); string_view_t f4 = make_string_view("CInt "); string_view_t f5 = make_string_view(" CInt "); string_view_t f6 = make_string_view("Action SkBuff"); string_view_t f7 = make_string_view(" Action SkBuff"); string_view_t f8 = make_string_view(" Action SkBuff "); string_view_t f9 = make_string_view("Action SkBuff "); assert(compare_argument(f0, f0) == true); assert(compare_argument(f1, f0) == true); assert(compare_argument(f0, f1) == true); assert(compare_argument(f2, f2) == true); assert(compare_argument(f2, f3) == true); assert(compare_argument(f2, f4) == true); assert(compare_argument(f2, f5) == true); assert(compare_argument(f3, f3) == true); assert(compare_argument(f3, f4) == true); assert(compare_argument(f3, f5) == true); assert(compare_argument(f4, f4) == true); assert(compare_argument(f4, f5) == true); assert(compare_argument(f5, f5) == true); assert(compare_argument(f6, f6) == true); assert(compare_argument(f6, f7) == true); assert(compare_argument(f6, f8) == true); assert(compare_argument(f6, f9) == true); assert(compare_argument(f7, f7) == true); assert(compare_argument(f7, f8) == true); assert(compare_argument(f7, f9) == true); assert(compare_argument(f8, f8) == true); assert(compare_argument(f8, f9) == true); assert(compare_argument(f9, f9) == true); assert(compare_argument(f0, f2) == false); assert(compare_argument(f0, f3) == false); assert(compare_argument(f0, f4) == false); assert(compare_argument(f0, f5) == false); assert(compare_argument(f0, f6) == false); assert(compare_argument(f0, f7) == false); assert(compare_argument(f0, f8) == false); assert(compare_argument(f0, f9) == false); } { string_view_t f0 = string_view(); string_view_t f1 = make_string_view(""); string_view_t f2 = make_string_view("CInt"); string_view_t f3 = make_string_view(" CInt "); string_view_t f4 = make_string_view("CInt "); string_view_t f5 = make_string_view(" CInt "); string_view_t f6 = make_string_view("Action SkBuff"); string_view_t f7 = make_string_view(" Action SkBuff"); string_view_t f8 = make_string_view(" Action SkBuff "); string_view_t f9 = make_string_view("Action SkBuff "); string_view_t f10 = string_view(); string_view_t f11 = make_string_view(""); string_view_t f12 = make_string_view("CInt"); string_view_t f13 = make_string_view(" CInt -> CInt "); string_view_t f14 = make_string_view("CInt -> (CInt) "); string_view_t f15 = make_string_view(" CInt "); string_view_t f16 = make_string_view("Action SkBuff -> ( (CInt ) )"); string_view_t f17 = make_string_view(" Action SkBuff"); string_view_t f18 = make_string_view(" Action SkBuff "); string_view_t f19 = make_string_view("Action SkBuff "); assert(count_outmost_brackets(f0) == 0); assert(count_outmost_brackets(f1) == 0); assert(count_outmost_brackets(f2) == 0); assert(count_outmost_brackets(f3) == 0); assert(count_outmost_brackets(f4) == 0); assert(count_outmost_brackets(f5) == 0); assert(count_outmost_brackets(f6) == 0); assert(count_outmost_brackets(f7) == 0); assert(count_outmost_brackets(f8) == 0); assert(count_outmost_brackets(f9) == 0); assert(count_outmost_brackets(f10) == 0); assert(count_outmost_brackets(f11) == 0); assert(count_outmost_brackets(f12) == 0); assert(count_outmost_brackets(f13) == 0); assert(count_outmost_brackets(f14) == 0); assert(count_outmost_brackets(f15) == 0); assert(count_outmost_brackets(f16) == 0); assert(count_outmost_brackets(f17) == 0); assert(count_outmost_brackets(f18) == 0); assert(count_outmost_brackets(f19) == 0); } { string_view_t g1 = make_string_view("()"); string_view_t g2 = make_string_view("(CInt)"); string_view_t g3 = make_string_view("( CInt )"); string_view_t g4 = make_string_view("(CInt )"); string_view_t g5 = make_string_view("( CInt ) "); string_view_t g6 = make_string_view("(Action SkBuff)"); string_view_t g7 = make_string_view("( Action SkBuff)"); string_view_t g8 = make_string_view("( Action SkBuff )"); string_view_t g9 = make_string_view("(Action SkBuff )"); assert(count_outmost_brackets(g1) == 1); assert(count_outmost_brackets(g2) == 1); assert(count_outmost_brackets(g3) == 1); assert(count_outmost_brackets(g4) == 1); assert(count_outmost_brackets(g5) == 1); assert(count_outmost_brackets(g6) == 1); assert(count_outmost_brackets(g7) == 1); assert(count_outmost_brackets(g8) == 1); assert(count_outmost_brackets(g9) == 1); } { string_view_t g1 = make_string_view("(CInt) -> Bool"); string_view_t g2 = make_string_view("( CInt )-> Char"); string_view_t g3 = make_string_view("(CInt ) ->Char"); string_view_t g4 = make_string_view("( CInt ) ->(Char)"); string_view_t g5 = make_string_view("(Action SkBuff) -> ( (Char))"); string_view_t g6 = make_string_view("( Action SkBuff)-> Char"); string_view_t g7 = make_string_view("( Action SkBuff ) ->(Char)"); string_view_t g8 = make_string_view("(Action SkBuff ) -> (( Char ))"); assert(count_outmost_brackets(g1) == 0); assert(count_outmost_brackets(g2) == 0); assert(count_outmost_brackets(g3) == 0); assert(count_outmost_brackets(g4) == 0); assert(count_outmost_brackets(g5) == 0); assert(count_outmost_brackets(g6) == 0); assert(count_outmost_brackets(g7) == 0); assert(count_outmost_brackets(g8) == 0); } { string_view_t g1 = make_string_view("((CInt) -> Bool)"); string_view_t g2 = make_string_view("(( CInt )-> Char)"); string_view_t g3 = make_string_view("((CInt ) ->Char )"); string_view_t g4 = make_string_view("(( CInt ) ->(Char))"); string_view_t g5 = make_string_view("((Action SkBuff) -> ( (Char)))"); string_view_t g6 = make_string_view("(( Action SkBuff)-> Char)"); string_view_t g7 = make_string_view("(( Action SkBuff ) ->(Char))"); string_view_t g8 = make_string_view("((Action SkBuff ) -> (( Char )))"); assert(count_outmost_brackets(g1) == 1); assert(count_outmost_brackets(g2) == 1); assert(count_outmost_brackets(g3) == 1); assert(count_outmost_brackets(g4) == 1); assert(count_outmost_brackets(g5) == 1); assert(count_outmost_brackets(g6) == 1); assert(count_outmost_brackets(g7) == 1); assert(count_outmost_brackets(g8) == 1); } { string_view_t g1 = make_string_view("(((CInt) -> Bool))"); string_view_t g2 = make_string_view("( (( CInt )-> Char) )"); string_view_t g3 = make_string_view("( ((CInt ) ->Char ))"); string_view_t g4 = make_string_view("(( ( CInt ) ->(Char)) )"); string_view_t g5 = make_string_view("( ((Action SkBuff) -> ( (Char))))"); string_view_t g6 = make_string_view("((( Action SkBuff)-> Char))"); string_view_t g7 = make_string_view("(( ( Action SkBuff ) ->(Char)) )"); string_view_t g8 = make_string_view("( ((Action SkBuff ) -> (( Char ) )) )"); assert(count_outmost_brackets(g1) == 2); assert(count_outmost_brackets(g2) == 2); assert(count_outmost_brackets(g3) == 2); assert(count_outmost_brackets(g4) == 2); assert(count_outmost_brackets(g5) == 2); assert(count_outmost_brackets(g6) == 2); assert(count_outmost_brackets(g7) == 2); assert(count_outmost_brackets(g8) == 2); } { string_view_t f0 = string_view(); string_view_t f1 = make_string_view(""); string_view_t f2 = make_string_view("CInt"); string_view_t f3 = make_string_view(" CInt "); string_view_t f4 = make_string_view("CInt "); string_view_t f5 = make_string_view(" CInt "); string_view_t f6 = make_string_view("Action SkBuff"); string_view_t f7 = make_string_view(" Action SkBuff"); string_view_t f8 = make_string_view(" Action SkBuff "); string_view_t f9 = make_string_view("Action SkBuff "); string_view_t f10 = make_string_view("(CInt) -> Bool"); string_view_t f11 = make_string_view("( CInt )-> Char"); string_view_t f12 = make_string_view("(CInt ) ->Char"); string_view_t f13 = make_string_view("( CInt ) ->(Char)"); string_view_t f14 = make_string_view("(Action SkBuff) -> ( (Char))"); string_view_t f15 = make_string_view("( Action SkBuff)-> Char"); string_view_t f16 = make_string_view("( Action SkBuff ) ->(Char)"); string_view_t f17 = make_string_view("(Action SkBuff ) -> (( Char ))"); assert(find_next_arrow(f0) == NULL); assert(find_next_arrow(f1) == NULL); assert(find_next_arrow(f2) == NULL); assert(find_next_arrow(f3) == NULL); assert(find_next_arrow(f4) == NULL); assert(find_next_arrow(f5) == NULL); assert(find_next_arrow(f6) == NULL); assert(find_next_arrow(f7) == NULL); assert(find_next_arrow(f8) == NULL); assert(find_next_arrow(f9) == NULL); assert(find_next_arrow(f10) != NULL); assert(find_next_arrow(f11) != NULL); assert(find_next_arrow(f12) != NULL); assert(find_next_arrow(f13) != NULL); assert(find_next_arrow(f14) != NULL); assert(find_next_arrow(f15) != NULL); assert(find_next_arrow(f16) != NULL); assert(find_next_arrow(f17) != NULL); } printf("All test passed.\n"); return 0; }
// try to replace volume GUID (if present) with drive letter // used by ConvertNameToReal() only static string TryConvertVolumeGuidToDrivePath(string_view const Path, const string_view AbsPath = {}) { string Result(Path); size_t DirectoryOffset; if (ParsePath(Path, &DirectoryOffset) == root_type::volume) { if (imports.GetVolumePathNamesForVolumeNameW) { string VolumePathNames; if (os::fs::GetVolumePathNamesForVolumeName(ExtractPathRoot(Path), VolumePathNames)) { for(const auto& i: enum_substrings(VolumePathNames.c_str())) { if (!AbsPath.empty() && starts_with_icase(AbsPath, i)) return string(i); if (IsRootPath(i)) { Result.replace(0, DirectoryOffset, i.data(), i.size()); break; } } } if (!AbsPath.empty()) Result.clear(); } else if (!AbsPath.empty()) Result.clear(); else { string strVolumeGuid; const os::fs::enum_drives Enumerator(os::fs::get_logical_drives()); const auto ItemIterator = std::find_if(ALL_CONST_RANGE(Enumerator), [&](const auto& i) { return os::fs::GetVolumeNameForVolumeMountPoint(os::fs::get_root_directory(i), strVolumeGuid) && starts_with(Path, string_view(strVolumeGuid).substr(0, DirectoryOffset)); }); if (ItemIterator != Enumerator.cend()) { Result.replace(0, DirectoryOffset, os::fs::get_drive(*ItemIterator)); } } } else if (!AbsPath.empty()) Result.clear(); return Result; }
// Кусок для создания SymLink для каталогов. int MkSymLink(const string& Target, const string& LinkName, ReparsePointTypes LinkType, bool Silent, bool HoldTarget) { if (!Target.empty() && !LinkName.empty()) { string strFullTarget; // выделим имя auto strSelOnlyName = Target; DeleteEndSlash(strSelOnlyName); const auto SlashPos = FindLastSlash(strSelOnlyName); const auto symlink = LinkType==RP_SYMLINK || LinkType==RP_SYMLINKFILE || LinkType==RP_SYMLINKDIR; if (Target[1] == L':' && (!Target[2] || (IsSlash(Target[2]) && !Target[3]))) // C: или C:/ { // if(Flags&FCOPY_VOLMOUNT) { strFullTarget = Target; AddEndSlash(strFullTarget); } /* Вот здесь - ну очень умное поведение! Т.е. если в качестве SelName передали "C:", то в этом куске происходит коррекция типа линка - с symlink`а на volmount */ LinkType=RP_VOLMOUNT; } else strFullTarget = ConvertNameToFull(Target); auto strFullLink = ConvertNameToFull(LinkName); if (IsSlash(strFullLink.back())) { if (LinkType != RP_VOLMOUNT) { const auto SelName = SlashPos != string::npos? string_view(strSelOnlyName).substr(SlashPos + 1) : string_view(strSelOnlyName); append(strFullLink, SelName); } else { append(strFullLink, L"Disk_"sv, Target.front()); } } if (LinkType==RP_VOLMOUNT) { AddEndSlash(strFullTarget); AddEndSlash(strFullLink); } if (symlink) { // в этом случае создается путь, но не сам каталог string strPath=strFullLink; if (CutToSlash(strPath)) { if (!os::fs::exists(strPath)) CreatePath(strPath); } } else { bool CreateDir=true; if (LinkType==RP_EXACTCOPY) { // в этом случае создается или каталог, или пустой файл if (os::fs::is_file(strFullTarget)) CreateDir=false; } if (CreateDir) { if (os::fs::create_directory(strFullLink)) TreeList::AddTreeName(strFullLink); else CreatePath(strFullLink); } else { string strPath=strFullLink; if (CutToSlash(strPath)) { if (!os::fs::exists(strPath)) CreatePath(strPath); os::fs::file(strFullLink, 0, 0, nullptr, CREATE_NEW, os::fs::get_file_attributes(strFullTarget)); } } if (!os::fs::exists(strFullLink)) { if (!Silent) { const auto ErrorState = error_state::fetch(); Message(MSG_WARNING, ErrorState, msg(lng::MError), { msg(lng::MCopyCannotCreateLink), strFullLink }, { lng::MOk }); } return 0; } } if (LinkType!=RP_VOLMOUNT) { if (CreateReparsePoint(HoldTarget && symlink ? Target : strFullTarget, strFullLink, LinkType)) { return 1; } else { if (!Silent) { const auto ErrorState = error_state::fetch(); Message(MSG_WARNING, ErrorState, msg(lng::MError), { msg(lng::MCopyCannotCreateLink), strFullLink }, { lng::MOk }); } return 0; } } else { if (CreateVolumeMountPoint(strFullTarget,strFullLink)) { return 1; } else { if (!Silent) { const auto ErrorState = error_state::fetch(); Message(MSG_WARNING, ErrorState, msg(lng::MError), { format(msg(lng::MCopyMountVolFailed), Target), format(msg(lng::MCopyMountVolFailed2), strFullLink) }, { lng::MOk }); } return 0; } } } return 2; }
static string_view ProcessMetasymbol(string_view const CurStr, subst_data& SubstData, string& Out) { const auto append_with_escape = [EscapeAmpersands = SubstData.EscapeAmpersands](string& Destination, string_view const Str) { if (EscapeAmpersands && contains(Str, L"&"sv)) { string Escaped(Str); replace(Escaped, L"&"sv, L"&&"sv); append(Destination, Escaped); } else { append(Destination, Str); } }; if (const auto Tail = tokens::skip(CurStr, tokens::passive_panel)) { SubstData.PassivePanel = true; return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::active_panel)) { SubstData.PassivePanel = false; return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::exclamation)) { if (!starts_with(Tail, L'?')) { Out.push_back(L'!'); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::name_extension)) { if (!starts_with(Tail, L'?')) { append_with_escape(Out, SubstData.Default().Normal.Name); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::short_name)) { append_with_escape(Out, SubstData.Default().Short.NameOnly); return Tail; } const auto GetExtension = [](string_view const Name) { const auto Extension = PointToExt(Name); return Extension.empty()? Extension : Extension.substr(1); }; if (const auto Tail = tokens::skip(CurStr, tokens::short_extension)) { append_with_escape(Out, GetExtension(SubstData.Default().Short.Name)); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::extension)) { append_with_escape(Out, GetExtension(SubstData.Default().Normal.Name)); return Tail; } const auto CollectNames = [&SubstData, &append_with_escape](string& Str, auto const Selector) { append_with_escape(Str, join(select(SubstData.Default().Panel->enum_selected(), Selector), L" "sv)); }; if (const auto Tail = tokens::skip(CurStr, tokens::short_list)) { if (!starts_with(Tail, L'?')) { CollectNames(Out, &os::fs::find_data::AlternateFileName); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::list)) { if (!starts_with(Tail, L'?')) { CollectNames(Out, [](const os::fs::find_data& Data) { return quote_space(Data.FileName); }); return Tail; } } const auto GetListName = [&Out, &append_with_escape](string_view const Tail, subst_data& Data, bool Short) { const auto ExclPos = Tail.find(L'!'); if (ExclPos == Tail.npos || starts_with(Tail.substr(ExclPos + 1), L'?')) return size_t{}; const auto Modifiers = Tail.substr(0, ExclPos); if (Data.ListNames) { string Str; if (Data.Default().Panel->MakeListFile(Str, Short, Modifiers)) { if (Short) Str = ConvertNameToShort(Str); append_with_escape(Out, Str); Data.ListNames->add(std::move(Str)); } } else { append(Out, L'!', Short? L'$' : L'@', Modifiers, L'!'); } return Modifiers.size() + 1; }; if (const auto Tail = tokens::skip(CurStr, tokens::list_file)) { if (const auto Offset = GetListName(Tail, SubstData, false)) return string_view(Tail).substr(Offset); } if (const auto Tail = tokens::skip(CurStr, tokens::short_list_file)) { if (const auto Offset = GetListName(Tail, SubstData, true)) return string_view(Tail).substr(Offset); } if (const auto Tail = tokens::skip(CurStr, tokens::short_name_extension)) { if (!starts_with(Tail, L'?')) { append_with_escape(Out, SubstData.Default().Short.Name); return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::short_name_extension_safe)) { if (!starts_with(Tail, L'?')) { append_with_escape(Out, SubstData.Default().Short.Name); SubstData.PreserveLFN = true; return Tail; } } if (const auto Tail = tokens::skip(CurStr, tokens::current_drive)) { const auto CurDir = IsAbsolutePath(SubstData.This.Normal.Name)? SubstData.This.Normal.Name : SubstData.PassivePanel? SubstData.Another.Panel->GetCurDir() : SubstData.CmdDir; auto RootDir = GetPathRoot(CurDir); DeleteEndSlash(RootDir); append_with_escape(Out, RootDir); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::description)) { Out += SubstData.Default().GetDescription(); return Tail; } const auto GetPath = [](string_view const Tail, const subst_data& Data, bool Short, bool Real) { // TODO: paths on plugin panels are ambiguous auto CurDir = Data.PassivePanel? Data.Another.Panel->GetCurDir() : Data.CmdDir; if (Real) CurDir = ConvertNameToReal(CurDir); if (Short) CurDir = ConvertNameToShort(CurDir); AddEndSlash(CurDir); return CurDir; }; if (const auto Tail = tokens::skip(CurStr, tokens::path)) { Out += GetPath(Tail, SubstData, false, false); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::short_path)) { Out += GetPath(Tail, SubstData, true, false); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::real_path)) { Out += GetPath(Tail, SubstData, false, true); return Tail; } if (const auto Tail = tokens::skip(CurStr, tokens::real_short_path)) { Out += GetPath(Tail, SubstData, true, true); return Tail; } // !?<title>?<init>! if (const auto Tail = tokens::skip(CurStr, tokens::input)) { auto SkipSize = SkipInputToken(CurStr); // if bad format string skip 1 char if (!SkipSize) SkipSize = 1; Out.append(CurStr.data(), SkipSize); return CurStr.substr(SkipSize); } if (const auto Tail = tokens::skip(CurStr, tokens::name)) { append(Out, PointToName(SubstData.Default().Normal.NameOnly)); return Tail; } return CurStr; }
size_t TypeDesc::fromstring (const char *typestring) { return fromstring (string_view(typestring)); }
string_view gview() const { auto const sz = base::egptr() - base::gptr(); return string_view(base::gptr(), sz); }
string_view pview() const { auto const sz = base::pptr() - base::pbase(); return string_view(pbase(), sz); }
tpool::TaskSPtr CxxIwyu::iwyuCommand(const doim::FsDirectorySPtr& directory, const doim::CxxFileSPtr& cxxFile) const { auto arguments = CxxCompiler::includeArguments(directory, cxxFile->cxxIncludeDirectories()); arguments->insert(CxxCompiler::gStdCpp14Argument); arguments->insert(CxxCompiler::gOptimizationLevel0Argument); const string& file = cxxFile->file()->path(directory); auto argument_file = doim::SysArgument::unique(file); arguments->insert(argument_file); arguments = doim::SysArgumentSet::unique(arguments); auto command = doim::SysCommand::unique(nullptr, mTool, arguments); auto fn = [directory, cxxFile](int exit, const string& output) -> ECode { if (exit == 0) { ELOG("Unexpected exit code from iwyu tool: {}", exit); EHBan(kUnexpected); } bool success = true; static std::regex removeItemsRegex( "(?:^|\n)(.*?) should remove these lines:" "(?:[\\s\\r\\n]+- #include.*?\\/\\/ lines \\d+-\\d+)+"); static std::regex removeItemRegex("- (#include.*?)\\s*\\/\\/ lines (\\d+)-\\d+"); auto its = std::sregex_iterator(output.begin(), output.end(), removeItemsRegex); for (std::sregex_iterator items = its; items != std::sregex_iterator(); ++items) { std::smatch smatchs = *items; const auto& removes = smatchs.str(); auto it = std::sregex_iterator(removes.begin(), removes.end(), removeItemRegex); for (std::sregex_iterator item = it; item != std::sregex_iterator(); ++item) { success = false; std::smatch smatch = *item; ELOG("\n{}:{}:1: error: extra {} ", smatchs[1].str(), smatch[2].str(), smatch[1].str()); } } static std::regex addItemsRegex("(?:^|\n)(.*?) should add these lines:" "(?:[\\s\\r\\n]+#include.*?\\/\\/[^\\n]*)+"); static std::regex addItemRegex("(#include\\s[\"<]([^\">]+)[^\\n]+)"); struct Warning { std::string erroredFile; std::string missingHeader; }; std::vector<Warning> warnings; its = std::sregex_iterator(output.begin(), output.end(), addItemsRegex); for (std::sregex_iterator items = its; items != std::sregex_iterator(); ++items) { std::smatch smatchs = *items; const auto& adds = smatchs.str(); auto it = std::sregex_iterator(adds.begin(), adds.end(), addItemRegex); for (std::sregex_iterator item = it; item != std::sregex_iterator(); ++item) { std::smatch smatch = *item; warnings.push_back(Warning{smatchs[1].str(), smatch[2].str()}); } } for (const auto& warning : warnings) { auto file = doim::FsFile::find(directory, warning.erroredFile); if (file == nullptr) { success = false; ELOG("IWYU reports issues for unknown file {}", warning.erroredFile); continue; } doim::CxxIncludeDirectory::CxxHeaderInfo headerInfo; if (cxxFile->file() == file) { EHLog(doim::CxxIncludeDirectory::findHeaderDeep( string_view(warning.missingHeader), nullptr, cxxFile->cxxIncludeDirectories(), headerInfo)); } else { EHLog(doim::CxxIncludeDirectory::findHeaderDeep( file, nullptr, cxxFile->cxxIncludeDirectories(), headerInfo)); if (headerInfo.mHeader == nullptr) { success = false; ELOG("IWYU reports issues for unknown file {}", warning.erroredFile); continue; } EHLog(doim::CxxIncludeDirectory::findHeaderDeep( string_view(warning.missingHeader), headerInfo.mIncludeDirectory, headerInfo.mHeader->cxxIncludeDirectories(), headerInfo)); } if (headerInfo.mHeader == nullptr) { success = false; ELOG("IWYU suggest adding unknown header {}", warning.missingHeader); continue; } if (headerInfo.mHeader->visibility() == doim::CxxHeader::EVisibility::kProtected) { TLOG("IWYU suggest protected header {}, ignore those", warning.missingHeader); continue; } success = false; ELOG("\n{}:1:1: warning: missing {} ", warning.erroredFile, warning.missingHeader); } if (!success) { ELOG("\n{}", output); EHBan(kFailed); } EHEnd; }; return task::ParseStdoutTask::valid( command, nullptr, rtti::RttiInfo<CxxIwyu>::classId(), fn, "Iwyu " + file); }
bool JpgInput::open(const std::string& name, ImageSpec& newspec) { m_filename = name; if (m_io) { // If an IOProxy was passed, it had better be a File or a // MemReader, that's all we know how to use with jpeg. std::string proxytype = m_io->proxytype(); if (proxytype != "file" && proxytype != "memreader") { errorf("JPEG reader can't handle proxy type %s", proxytype); return false; } } else { // If no proxy was supplied, create a file reader m_io = new Filesystem::IOFile(name, Filesystem::IOProxy::Mode::Read); m_local_io.reset(m_io); } if (!m_io || m_io->mode() != Filesystem::IOProxy::Mode::Read) { errorf("Could not open file \"%s\"", name); return false; } // Check magic number to assure this is a JPEG file uint8_t magic[2] = { 0, 0 }; if (m_io->pread(magic, sizeof(magic), 0) != sizeof(magic)) { errorf("Empty file \"%s\"", name); close_file(); return false; } if (magic[0] != JPEG_MAGIC1 || magic[1] != JPEG_MAGIC2) { close_file(); errorf( "\"%s\" is not a JPEG file, magic number doesn't match (was 0x%x%x)", name, int(magic[0]), int(magic[1])); return false; } // Set up the normal JPEG error routines, then override error_exit and // output_message so we intercept all the errors. m_cinfo.err = jpeg_std_error((jpeg_error_mgr*)&m_jerr); m_jerr.pub.error_exit = my_error_exit; m_jerr.pub.output_message = my_output_message; if (setjmp(m_jerr.setjmp_buffer)) { // Jump to here if there's a libjpeg internal error // Prevent memory leaks, see example.c in jpeg distribution jpeg_destroy_decompress(&m_cinfo); close_file(); return false; } // initialize decompressor jpeg_create_decompress(&m_cinfo); m_decomp_create = true; // specify the data source if (!strcmp(m_io->proxytype(), "file")) { auto fd = ((Filesystem::IOFile*)m_io)->handle(); jpeg_stdio_src(&m_cinfo, fd); } else { auto buffer = ((Filesystem::IOMemReader*)m_io)->buffer(); jpeg_mem_src(&m_cinfo, const_cast<unsigned char*>(buffer.data()), buffer.size()); } // Request saving of EXIF and other special tags for later spelunking for (int mark = 0; mark < 16; ++mark) jpeg_save_markers(&m_cinfo, JPEG_APP0 + mark, 0xffff); jpeg_save_markers(&m_cinfo, JPEG_COM, 0xffff); // comment marker // read the file parameters if (jpeg_read_header(&m_cinfo, FALSE) != JPEG_HEADER_OK || m_fatalerr) { error("Bad JPEG header for \"%s\"", filename().c_str()); return false; } int nchannels = m_cinfo.num_components; if (m_cinfo.jpeg_color_space == JCS_CMYK || m_cinfo.jpeg_color_space == JCS_YCCK) { // CMYK jpegs get converted by us to RGB m_cinfo.out_color_space = JCS_CMYK; // pre-convert YCbCrK->CMYK nchannels = 3; m_cmyk = true; } if (m_raw) m_coeffs = jpeg_read_coefficients(&m_cinfo); else jpeg_start_decompress(&m_cinfo); // start working if (m_fatalerr) return false; m_next_scanline = 0; // next scanline we'll read m_spec = ImageSpec(m_cinfo.output_width, m_cinfo.output_height, nchannels, TypeDesc::UINT8); // Assume JPEG is in sRGB unless the Exif or XMP tags say otherwise. m_spec.attribute("oiio:ColorSpace", "sRGB"); if (m_cinfo.jpeg_color_space == JCS_CMYK) m_spec.attribute("jpeg:ColorSpace", "CMYK"); else if (m_cinfo.jpeg_color_space == JCS_YCCK) m_spec.attribute("jpeg:ColorSpace", "YCbCrK"); // If the chroma subsampling is detected and matches something // we expect, then set an attribute so that it can be preserved // in future operations. std::string subsampling = comp_info_to_attr(m_cinfo); if (!subsampling.empty()) m_spec.attribute(JPEG_SUBSAMPLING_ATTR, subsampling); for (jpeg_saved_marker_ptr m = m_cinfo.marker_list; m; m = m->next) { if (m->marker == (JPEG_APP0 + 1) && !strcmp((const char*)m->data, "Exif")) { // The block starts with "Exif\0\0", so skip 6 bytes to get // to the start of the actual Exif data TIFF directory decode_exif(string_view((char*)m->data + 6, m->data_length - 6), m_spec); } else if (m->marker == (JPEG_APP0 + 1) && !strcmp((const char*)m->data, "http://ns.adobe.com/xap/1.0/")) { #ifndef NDEBUG std::cerr << "Found APP1 XMP! length " << m->data_length << "\n"; #endif std::string xml((const char*)m->data, m->data_length); decode_xmp(xml, m_spec); } else if (m->marker == (JPEG_APP0 + 13) && !strcmp((const char*)m->data, "Photoshop 3.0")) jpeg_decode_iptc((unsigned char*)m->data); else if (m->marker == JPEG_COM) { if (!m_spec.find_attribute("ImageDescription", TypeDesc::STRING)) m_spec.attribute("ImageDescription", std::string((const char*)m->data, m->data_length)); } } // Handle density/pixelaspect. We need to do this AFTER the exif is // decoded, in case it contains useful information. float xdensity = m_spec.get_float_attribute("XResolution"); float ydensity = m_spec.get_float_attribute("YResolution"); if (!xdensity || !ydensity) { xdensity = float(m_cinfo.X_density); ydensity = float(m_cinfo.Y_density); if (xdensity && ydensity) { m_spec.attribute("XResolution", xdensity); m_spec.attribute("YResolution", ydensity); } } if (xdensity && ydensity) { float aspect = ydensity / xdensity; if (aspect != 1.0f) m_spec.attribute("PixelAspectRatio", aspect); switch (m_cinfo.density_unit) { case 0: m_spec.attribute("ResolutionUnit", "none"); break; case 1: m_spec.attribute("ResolutionUnit", "in"); break; case 2: m_spec.attribute("ResolutionUnit", "cm"); break; } } read_icc_profile(&m_cinfo, m_spec); /// try to read icc profile newspec = m_spec; return true; }
static void exif_parser_cb (ImageSpec* spec, int tag, int tifftype, int len, unsigned int byteorder, LibRaw_abstract_datastream* ifp) { // Oy, the data offsets are all going to be relative to the start of the // stream, not relative to our current position and data block. So we // need to remember that offset and pass its negative as the // offset_adjustment to the handler. size_t streampos = ifp->tell(); // std::cerr << "Stream position " << streampos << "\n"; TypeDesc type = tiff_datatype_to_typedesc (TIFFDataType(tifftype), size_t(len)); const TagInfo* taginfo = tag_lookup ("Exif", tag); if (! taginfo) { // Strutil::fprintf (std::cerr, "NO TAGINFO FOR CALLBACK tag=%d (0x%x): tifftype=%d,len=%d (%s), byteorder=0x%x\n", // tag, tag, tifftype, len, type, byteorder); return; } if (type.size() >= (1<<20)) return; // sanity check -- too much memory size_t size = tiff_data_size(TIFFDataType(tifftype)) * len; std::vector<unsigned char> buf (size); ifp->read (buf.data(), size, 1); // debug scaffolding // Strutil::fprintf (std::cerr, "CALLBACK tag=%s: tifftype=%d,len=%d (%s), byteorder=0x%x\n", // taginfo->name, tifftype, len, type, byteorder); // for (int i = 0; i < std::min(16UL,size); ++i) { // if (buf[i] >= ' ' && buf[i] < 128) // std::cerr << char(buf[i]); // Strutil::fprintf (std::cerr, "(%d) ", int(buf[i])); // } // std::cerr << "\n"; bool swab = (littleendian() != (byteorder == 0x4949)); if (swab) { if (type.basetype == TypeDesc::UINT16) swap_endian ((uint16_t *)buf.data(), len); if (type.basetype == TypeDesc::UINT32) swap_endian ((uint32_t *)buf.data(), len); } if (taginfo->handler) { TIFFDirEntry dir; dir.tdir_tag = uint16_t(tag); dir.tdir_type = uint16_t(tifftype); dir.tdir_count = uint32_t(len); dir.tdir_offset = 0; taginfo->handler (*taginfo, dir, buf, *spec, swab, -int(streampos)); // std::cerr << "HANDLED " << taginfo->name << "\n"; return; } if (taginfo->tifftype == TIFF_NOTYPE) return; // skip if (tifftype == TIFF_RATIONAL || tifftype == TIFF_SRATIONAL) { spec->attribute (taginfo->name, type, buf.data()); return; } if (type.basetype == TypeDesc::UINT16) { spec->attribute (taginfo->name, type, buf.data()); return; } if (type.basetype == TypeDesc::UINT32) { spec->attribute (taginfo->name, type, buf.data()); return; } if (type == TypeString) { spec->attribute (taginfo->name, string_view((char*)buf.data(), size)); return; } // Strutil::fprintf (std::cerr, "RAW metadata NOT HANDLED: tag=%s: tifftype=%d,len=%d (%s), byteorder=0x%x\n", // taginfo->name, tifftype, len, type, byteorder); }