1 /*
2  * Part of WCM Commander
3  * https://github.com/corporateshark/WCMCommander
4  * wcm@linderdaum.com
5  */
6 
7 #include <wal.h>
8 
9 #ifdef _WIN32
10 
11 #include "ext-app.h"
12 #include "string-util.h"
13 #include "w32util.h"
14 
GetOpenApp(const std::string & ext)15 static std::vector<wchar_t> GetOpenApp( const std::string& ext )
16 {
17 	if ( ext.empty() ) { return std::vector<wchar_t>(); }
18 
19 	RegKey key;
20 
21 	std::string Key = "software\\classes\\" + ext;
22 
23 	if ( !key.Open( HKEY_CURRENT_USER, widen(Key).c_str() ) )
24 	{
25 		key.Open( HKEY_CLASSES_ROOT, widen(ext).c_str() );
26 	}
27 
28 	std::vector<wchar_t> p = key.GetString();
29 
30 	if ( !key.Open( HKEY_CURRENT_USER, carray_cat<wchar_t>( L"software\\classes\\", p.data(), L"\\shell\\open\\command" ).data() ) )
31 	{
32 		key.Open( HKEY_CLASSES_ROOT, carray_cat<wchar_t>( p.data(), L"\\shell\\open\\command" ).data() );
33 	}
34 
35 	return key.GetString();
36 }
37 
CfgStringToCommand(const wchar_t * cfgCmd,const unicode_t * uri)38 static std::vector<unicode_t> CfgStringToCommand( const wchar_t* cfgCmd, const unicode_t* uri )
39 {
40 	std::vector<unicode_t> res;
41 	int insCount = 0;
42 
43 	int prev = 0;
44 
45 	for ( const wchar_t* s = cfgCmd; *s; prev = *s, s++ )
46 	{
47 		if ( *s == '%' && ( s[1] == '1' || s[1] == 'l' || s[1] == 'L' ) )
48 		{
49 			if ( prev != '"' && prev != '\'' ) { res.push_back( '"' ); }
50 
51 			for ( const unicode_t* t = uri; *t; t++ ) { res.push_back( *t ); }
52 
53 			if ( prev != '"' && prev != '\'' ) { res.push_back( '"' ); }
54 
55 			s++;
56 			insCount++;
57 		}
58 		else { res.push_back( *s ); }
59 	}
60 
61 	if ( !insCount )
62 	{
63 		res.push_back( ' ' );
64 		res.push_back( '"' );
65 
66 		for ( const unicode_t* t = uri; *t; t++ ) { res.push_back( *t ); }
67 
68 		res.push_back( '"' );
69 	}
70 
71 	res.push_back( 0 );
72 
73 	return res;
74 }
75 
NormalizeStr(unicode_t * s)76 static std::vector<unicode_t> NormalizeStr( unicode_t* s )
77 {
78 	if ( !s ) { return std::vector<unicode_t>(); }
79 
80 	int n = unicode_strlen( s );
81 	std::vector<unicode_t> p( n + 1 );
82 	unicode_t* t = p.data();
83 
84 	for ( ; *s; s++ ) if ( *s != '&' ) { *( t++ ) = *s; }
85 
86 	*t = 0;
87 	return p;
88 }
89 
GetAppList(const unicode_t * uri)90 clPtr<AppList> GetAppList( const unicode_t* uri )
91 {
92 	std::string ext = GetFileExt( uri );
93 
94 	if ( ext.empty() ) { return 0; }
95 
96 	RegKey key;
97 
98 	std::string Key = "software\\classes\\" + ext;
99 
100 	if ( !key.Open( HKEY_CURRENT_USER, widen(Key).c_str() ) )
101 	{
102 		key.Open( HKEY_CLASSES_ROOT, widen(ext).c_str() );
103 	}
104 
105 	std::vector<wchar_t> p = key.GetString();
106 
107 	RegKey key2;
108 
109 	if ( !key2.Open( HKEY_CURRENT_USER, carray_cat<wchar_t>( L"software\\classes\\", p.data(), L"\\shell" ).data() ) )
110 	{
111 		key2.Open( HKEY_CLASSES_ROOT, carray_cat<wchar_t>( p.data(), L"\\shell" ).data() );
112 	}
113 
114 
115 	if ( !key2.Ok() ) { return 0; }
116 
117 	clPtr<AppList> ret = new AppList();
118 
119 	std::vector<wchar_t> pref = key2.GetString();
120 
121 	for ( int i = 0; i < 10; i++ )
122 	{
123 		std::vector<wchar_t> sub = key2.SubKey( i );
124 
125 		if ( !sub.data() ) { break; }
126 
127 		RegKey key25;
128 		key25.Open( key2.Key(), sub.data() );
129 
130 		if ( !key25.Ok() ) { continue; }
131 
132 		std::vector<wchar_t> name = key25.GetString();
133 //wprintf(L"%s, %s\n", sub.ptr(), name.ptr());
134 		RegKey key3;
135 		key3.Open( key25.Key(), L"command" );
136 		std::vector<wchar_t> command = key3.GetString();
137 
138 		if ( command.data() )
139 		{
140 			AppList::Node node;
141 			node.name = NormalizeStr( Utf16ToUnicode( name.data() && name[0] ? name.data() : sub.data() ).data() );
142 			node.cmd = CfgStringToCommand( command.data(), uri );
143 
144 			bool IsPref = pref.data() && !_wcsicmp( pref.data(), sub.data() );
145 			bool IsOpen = !pref.data() && !_wcsicmp( L"Open", sub.data() );
146 
147 			if ( IsPref || ( IsOpen && ret->list.count() > 0 ) )
148 			{
149 				ret->list.insert( 0 );
150 				ret->list[0] = node;
151 			}
152 			else
153 			{
154 				ret->list.append( node );
155 			}
156 		}
157 	}
158 
159 	key2.Open( key.Key(), L"OpenWithList" );
160 
161 	if ( key2.Ok() )
162 	{
163 		clPtr<AppList> openWith = new AppList();
164 
165 		for ( int i = 0; i < 10; i++ )
166 		{
167 			std::vector<wchar_t> sub = key2.SubKey( i );
168 
169 			if ( !sub.data() ) { break; }
170 
171 			RegKey keyApplication;
172 			keyApplication.Open( HKEY_CLASSES_ROOT,
173 			                     carray_cat<wchar_t>( L"Applications\\", sub.data(), L"\\shell\\open\\command" ).data() );
174 			std::vector<wchar_t> command = keyApplication.GetString();
175 
176 			if ( command.data() )
177 			{
178 				AppList::Node node;
179 				node.name = NormalizeStr( Utf16ToUnicode( sub.data() ).data() );
180 				node.cmd = CfgStringToCommand( command.data(), uri );
181 				openWith->list.append( node );
182 			}
183 		}
184 
185 		if ( openWith->Count() > 0 )
186 		{
187 			AppList::Node node;
188 			static unicode_t openWidthString[] = { 'O', 'p', 'e', 'n', ' ', 'w', 'i', 't', 'h', 0};
189 			node.name = new_unicode_str( openWidthString );
190 			node.sub = openWith;
191 			ret->list.append( node );
192 		}
193 	}
194 
195 	return ret->Count() ? ret : 0;
196 }
197 
198 
GetOpenCommand(const unicode_t * uri,bool * needTerminal,const unicode_t ** pAppName)199 std::vector<unicode_t> GetOpenCommand( const unicode_t* uri, bool* needTerminal, const unicode_t** pAppName )
200 {
201 	std::vector<wchar_t> wCmd = GetOpenApp( GetFileExt( uri ).data() );
202 
203 	if ( !wCmd.data() ) { return std::vector<unicode_t>(); }
204 
205 	return CfgStringToCommand( wCmd.data(), uri );
206 }
207 
208 
209 #endif
210