Skip to content

Commit e659555

Browse files
committed
Merge branch 'feature-issue58'
* feature-issue58: * Implemented support for 'pattern' attribute, Validator::GetPattern() and SetPattern() & tests. * Also updated documentation for 'pattern' attribute. For issue #58. Moved Validator::GetDriveLetter() and Validator::GetDrivePath() to DriveClass.h. Updated documentation of 'inverse' attribute regarding 'class' attribute of <visibility> and <validity> elements. For issue #58. Added missing elements in User Manual TOC. Fixed minor issues in the USer Manual documentation. Updated documentation about fileextensions and unit tests. Updated documentation for 'class' attribute of <visibility> and <validity> elements. For issue #58. Implemented parsing of 'class' attribute for <visibility> and <validity> elements. For issue #58. Implemented support for 'class' attribute, Validator::GetClass() and SetClass() & tests. For issue #58. Moved GetDriveLetter() and GetDrivePath() functions from Context.cpp to Validator class. These functions will be required for Implementing the Validator's 'class' attribute. Moved validation code in Validator::Validate() of each attributes into their own functions. This is to allow reusability and to reduce the complexity of the Validator::Validate() function. Code cleanup. The function `WildcardMatch()` have a new algorithm which is much faster and simpler to understand. Modified unit tests to test both `WildcardSolve()` and `WildcardMatch()`. Completed Wildcard.h functions for issue #58. Code cleanup. Also updated WildcardSolve() function to use size_t instead of int. Fixed a minor bug in the solving algorithm. Partially reverted 17b6225 back to a98b66d (with some variations) Partial implementation for WildcardMatch() function. Completed documentation of Wildcard.h First draft of wildcard functions. For issue #58. Enalbed building of branch feature-issue58 on appveyor. Updated user manual for properties `selection.drive.letter` and `selection.drive.path`. For issue #58. Created properties `selection.drive.letter` and `selection.drive.path`. For issue #58.
2 parents 8f9d433 + 4e2449f commit e659555

18 files changed

+2255
-101
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Changes for 0.5.0
88
* Fixed issue #51: Action "Open command prompt here" from default.xml configuration does not work.
99
* Fixed issue #52: Define a specific property for use as separator for handling multiple file selection.
1010
* Fixed issue #55: Menu name maximum length limit and escape string.
11+
* Fixed issue #58: More useful features: class and pattern attributes for validity / visibility.
1112
* Fixed issue #61: Support for WIX installer.
1213
* Fixed issue #66: Github don't identify the repository LICENSE as MIT.
1314
* Fixed issue #68: INSTALL.md mentions that 'application does not provides pre-build binaries' which is incorrect.

UserManual.md

Lines changed: 105 additions & 23 deletions
Large diffs are not rendered by default.

include/shellanything/Validator.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,26 @@ namespace shellanything
9494
/// </summary>
9595
void SetFileExists(const std::string & iFileExists);
9696

97+
/// <summary>
98+
/// Getter for the 'class' parameter.
99+
/// </summary>
100+
const std::string & GetClass() const;
101+
102+
/// <summary>
103+
/// Setter for the 'class' parameter.
104+
/// </summary>
105+
void SetClass(const std::string & iClass);
106+
107+
/// <summary>
108+
/// Getter for the 'pattern' parameter.
109+
/// </summary>
110+
const std::string & GetPattern() const;
111+
112+
/// <summary>
113+
/// Setter for the 'pattern' parameter.
114+
/// </summary>
115+
void SetPattern(const std::string & iPattern);
116+
97117
/// <summary>
98118
/// Getter for the 'inserve' parameter.
99119
/// </summary>
@@ -125,12 +145,22 @@ namespace shellanything
125145
/// <returns>Returns true if the given context is valid against the set of constraints. Returns false otherwise.</returns>
126146
bool Validate(const Context & iContext) const;
127147

148+
private:
149+
bool ValidateProperties(const Context & context, const std::string & properties, bool inversed) const;
150+
bool ValidateFileExtensions(const Context & context, const std::string & file_extensions, bool inversed) const;
151+
bool ValidateExists(const Context & context, const std::string & file_exists, bool inversed) const;
152+
bool ValidateClass(const Context & context, const std::string & class_, bool inversed) const;
153+
bool ValidateClassSingle(const Context & context, const std::string & class_, bool inversed) const;
154+
bool ValidatePattern(const Context & context, const std::string & pattern, bool inversed) const;
155+
128156
private:
129157
int mMaxFiles;
130158
int mMaxDirectories;
131159
std::string mProperties;
132160
std::string mFileExtensions;
133161
std::string mFileExists;
162+
std::string mClass;
163+
std::string mPattern;
134164
std::string mInverse;
135165
};
136166

src/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,16 @@ add_library(shellanything STATIC
7070
Unicode.h
7171
Unicode.cpp
7272
Validator.cpp
73+
DriveClass.h
74+
DriveClass.cpp
7375
ErrorManager.h
7476
ErrorManager.cpp
7577
PropertyManager.h
7678
PropertyManager.cpp
7779
Win32Clipboard.h
7880
Win32Clipboard.cpp
81+
Wildcard.cpp
82+
Wildcard.h
7983
)
8084

8185
add_library(shellext SHARED

src/Context.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
*********************************************************************************/
2424

2525
#include "shellanything/Context.h"
26+
#include "shellanything/Validator.h"
2627
#include "PropertyManager.h"
28+
#include "DriveClass.h"
2729

2830
#include "rapidassist/filesystem_utf8.h"
2931
#include "rapidassist/environment_utf8.h"
@@ -74,6 +76,8 @@ namespace shellanything
7476
std::string selection_filename ;
7577
std::string selection_filename_noext ;
7678
std::string selection_filename_ext ;
79+
std::string selection_drive_letter ;
80+
std::string selection_drive_path ;
7781

7882
// Get the separator string for multiple selection
7983
const std::string & selection_multi_separator = pmgr.GetProperty(Context::MULTI_SELECTION_SEPARATOR_PROPERTY_NAME);
@@ -97,23 +101,28 @@ namespace shellanything
97101
std::string element_selection_filename = ra::filesystem::GetFilename(element_selection_path.c_str());
98102
std::string element_selection_filename_noext = ra::filesystem::GetFilenameWithoutExtension(element_selection_path.c_str());
99103
std::string element_selection_filename_ext = ra::filesystem::GetFileExtention(element_selection_filename);
104+
std::string element_selection_drive_letter = GetDriveLetter(element);
105+
std::string element_selection_drive_path = GetDrivePath(element);
100106

101-
// Append this specific element properties to the global property string
102-
103-
// Add a newline if the property value is not empty. This allows printing all file path on individual lines
107+
// Add a separator between values
104108
if (!selection_path .empty()) selection_path .append( selection_multi_separator );
105109
if (!selection_parent_path .empty()) selection_parent_path .append( selection_multi_separator );
106110
if (!selection_parent_filename.empty()) selection_parent_filename .append( selection_multi_separator );
107111
if (!selection_filename .empty()) selection_filename .append( selection_multi_separator );
108112
if (!selection_filename_noext .empty()) selection_filename_noext .append( selection_multi_separator );
109113
if (!selection_filename_ext .empty()) selection_filename_ext .append( selection_multi_separator );
110-
114+
if (!selection_drive_letter .empty()) selection_drive_letter .append( selection_multi_separator );
115+
if (!selection_drive_path .empty()) selection_drive_path .append( selection_multi_separator );
116+
117+
// Append this specific element properties to the global property string
111118
selection_path .append( element_selection_path );
112119
selection_parent_path .append( element_selection_parent_path );
113120
selection_parent_filename.append( element_selection_parent_filename );
114121
selection_filename .append( element_selection_filename );
115122
selection_filename_noext .append( element_selection_filename_noext );
116123
selection_filename_ext .append( element_selection_filename_ext );
124+
selection_drive_letter .append( element_selection_drive_letter );
125+
selection_drive_path .append( element_selection_drive_path );
117126
}
118127

119128
pmgr.SetProperty("selection.path" , selection_path );
@@ -122,6 +131,8 @@ namespace shellanything
122131
pmgr.SetProperty("selection.filename" , selection_filename );
123132
pmgr.SetProperty("selection.filename.noext" , selection_filename_noext );
124133
pmgr.SetProperty("selection.filename.extension" , selection_filename_ext );
134+
pmgr.SetProperty("selection.drive.letter" , selection_drive_letter );
135+
pmgr.SetProperty("selection.drive.path" , selection_drive_path );
125136
}
126137

127138
void Context::UnregisterProperties() const
@@ -133,6 +144,8 @@ namespace shellanything
133144
pmgr.ClearProperty("selection.filename" );
134145
pmgr.ClearProperty("selection.filename.noext" );
135146
pmgr.ClearProperty("selection.filename.extension" );
147+
pmgr.ClearProperty("selection.drive.letter" );
148+
pmgr.ClearProperty("selection.drive.path" );
136149
}
137150

138151
const Context::ElementList & Context::GetElements() const

src/DriveClass.cpp

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/**********************************************************************************
2+
* MIT License
3+
*
4+
* Copyright (c) 2018 Antoine Beauchamp
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*********************************************************************************/
24+
25+
#include "DriveClass.h"
26+
#include "shellanything/Validator.h"
27+
28+
#include <Windows.h>
29+
30+
namespace shellanything
31+
{
32+
33+
inline bool IsDriveLetter(char c)
34+
{
35+
if ( (c >= 'a' && c <= 'z') ||
36+
(c >= 'A' && c <= 'Z') )
37+
return true;
38+
return false;
39+
}
40+
41+
std::string GetDriveLetter(const std::string & element)
42+
{
43+
std::string letter;
44+
if (element.size() >= 2 && element[1] == ':' && IsDriveLetter(element[0]))
45+
letter.append(1, element[0]);
46+
return letter;
47+
}
48+
49+
std::string GetDrivePath(const std::string & element)
50+
{
51+
std::string letter;
52+
if (element.size() >= 3 && element[1] == ':' && IsDriveLetter(element[0]) && element[2] == '\\')
53+
letter.append(element.c_str(), 3);
54+
return letter;
55+
}
56+
57+
bool IsNetworkPath(const std::string & path)
58+
{
59+
if (path.size() >= 2 && path.substr(0, 2) == "\\\\")
60+
{
61+
// The path starts with \\
62+
// Extract hostname
63+
const char * hostname = &path[2];
64+
if (hostname[0] != '\0')
65+
{
66+
// Get first character of hostname
67+
char first = hostname[0];
68+
if ((first >= 'a' && first <= 'z') ||
69+
(first >= 'A' && first <= 'Z') ||
70+
(first >= '0' && first <= '9') )
71+
{
72+
return true;
73+
}
74+
}
75+
}
76+
return false;
77+
}
78+
79+
DRIVE_CLASS GetDriveClassFromPath(const std::string & path)
80+
{
81+
// Patch for DRIVE_CLASS_NETWORK.
82+
// The function GetDriveTypeA() will return DRIVE_UNKNOWN when the given path is a network path.
83+
// For example \\localhost\shared\public will be reported as DRIVE_UNKNOWN.
84+
// To get the expected DRIVE_REMOTE returned value, the shared directory 'shared' must be mapped to a drive letter.
85+
// For example, mapping \\localhost\shared to Z:, calling GetDriveTypeA("Z:\public") will return DRIVE_REMOTE.
86+
// This is not what we want. The value DRIVE_CLASS_NETWORK is expected when the given path is a network path.
87+
if (IsNetworkPath(path))
88+
return DRIVE_CLASS_NETWORK;
89+
90+
UINT dwDriveType = GetDriveTypeA(path.c_str());
91+
switch(dwDriveType)
92+
{
93+
case DRIVE_NO_ROOT_DIR:
94+
{
95+
// The function GetDriveTypeA() returns DRIVE_NO_ROOT_DIR on a path that does not exist,
96+
// if the given path is a file, or if the given path is a directory that is not the root directory.
97+
// The functions returns DRIVE_NO_ROOT_DIR even if the drive letter, of the given non-existing path, is a CD-ROM or DVD-Drive.
98+
// However, the function will return DRIVE_CDROM is the root path of the same path is used, even if there are no disk in the optical drive.
99+
// To work around these issues, try to resolve with the root path of the drive.
100+
std::string root_path = GetDrivePath(path);
101+
if (root_path.empty() || // We may be dealing with a network path
102+
root_path == path ) // We are already using a root drive path
103+
{
104+
// There is nothing we can do.
105+
return DRIVE_CLASS_UNKNOWN;
106+
}
107+
108+
// Try to resolve with the root path instead
109+
DRIVE_CLASS resolved = GetDriveClassFromPath(root_path);
110+
return resolved;
111+
}
112+
break;
113+
case DRIVE_REMOVABLE:
114+
return DRIVE_CLASS_REMOVABLE;
115+
case DRIVE_FIXED:
116+
return DRIVE_CLASS_FIXED;
117+
case DRIVE_REMOTE:
118+
return DRIVE_CLASS_NETWORK;
119+
case DRIVE_CDROM:
120+
return DRIVE_CLASS_OPTICAL;
121+
case DRIVE_RAMDISK:
122+
return DRIVE_CLASS_RAMDISK;
123+
124+
default:
125+
return DRIVE_CLASS_UNKNOWN;
126+
};
127+
}
128+
129+
DRIVE_CLASS GetDriveClassFromString(const std::string & value)
130+
{
131+
if (value == "drive:removable")
132+
return DRIVE_CLASS_REMOVABLE;
133+
if (value == "drive:fixed")
134+
return DRIVE_CLASS_FIXED;
135+
if (value == "drive:network")
136+
return DRIVE_CLASS_NETWORK;
137+
if (value == "drive:optical")
138+
return DRIVE_CLASS_OPTICAL;
139+
if (value == "drive:ramdisk")
140+
return DRIVE_CLASS_RAMDISK;
141+
if (value == "drive:unknown")
142+
return DRIVE_CLASS_UNKNOWN;
143+
144+
return DRIVE_CLASS_UNKNOWN;
145+
}
146+
147+
const char * ToString(DRIVE_CLASS & value)
148+
{
149+
switch(value)
150+
{
151+
case DRIVE_CLASS_REMOVABLE:
152+
return "drive:removable";
153+
case DRIVE_CLASS_FIXED:
154+
return "drive:fixed";
155+
case DRIVE_CLASS_NETWORK:
156+
return "drive:network";
157+
case DRIVE_CLASS_OPTICAL:
158+
return "drive:optical";
159+
case DRIVE_CLASS_RAMDISK:
160+
return "drive:ramdisk";
161+
default:
162+
return "drive:unknown";
163+
};
164+
}
165+
166+
167+
168+
} //namespace shellanything

0 commit comments

Comments
 (0)