1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_shell.hxx"
26 #include "internal/global.hxx"
27 #include "internal/infotips.hxx"
28 #include "internal/shlxthdl.hxx"
29 #include "internal/metainforeader.hxx"
30 #include "internal/contentreader.hxx"
31 #include "internal/utilities.hxx"
32 #include "internal/registry.hxx"
33 #include "internal/fileextensions.hxx"
34 #include "internal/iso8601_converter.hxx"
35 #include "internal/config.hxx"
36 
37 #include "internal/resource.h"
38 #include <stdio.h>
39 #include <utility>
40 #include <stdlib.h>
41 
42 
43 #define MAX_STRING 80
44 #define KB 1024.0
45 const std::wstring WSPACE = std::wstring(SPACE);
46 
47 //-----------------------------
48 //
49 //-----------------------------
50 
CInfoTip(long RefCnt)51 CInfoTip::CInfoTip(long RefCnt) :
52 	m_RefCnt(RefCnt)
53 {
54 	ZeroMemory(m_szFileName, sizeof(m_szFileName));
55 	InterlockedIncrement(&g_DllRefCnt);
56 }
57 
58 //-----------------------------
59 //
60 //-----------------------------
61 
~CInfoTip()62 CInfoTip::~CInfoTip()
63 {
64 	InterlockedDecrement(&g_DllRefCnt);
65 }
66 
67 //-----------------------------
68 // IUnknown methods
69 //-----------------------------
70 
QueryInterface(REFIID riid,void __RPC_FAR * __RPC_FAR * ppvObject)71 HRESULT STDMETHODCALLTYPE CInfoTip::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
72 {
73 	*ppvObject = 0;
74 
75 	IUnknown* pUnk = 0;
76 
77 	if (IID_IUnknown == riid || IID_IQueryInfo == riid)
78 	{
79 		pUnk = static_cast<IQueryInfo*>(this);
80 		pUnk->AddRef();
81 		*ppvObject = pUnk;
82 		return S_OK;
83 	}
84 	else if (IID_IPersistFile == riid)
85 	{
86 		pUnk = static_cast<IPersistFile*>(this);
87 		pUnk->AddRef();
88 		*ppvObject = pUnk;
89 		return S_OK;
90 	}
91 
92 	return E_NOINTERFACE;
93 }
94 
95 //----------------------------
96 //
97 //----------------------------
98 
AddRef(void)99 ULONG STDMETHODCALLTYPE CInfoTip::AddRef(void)
100 {
101 	return InterlockedIncrement(&m_RefCnt);
102 }
103 
104 //----------------------------
105 //
106 //----------------------------
107 
Release(void)108 ULONG STDMETHODCALLTYPE CInfoTip::Release( void)
109 {
110 	long refcnt = InterlockedDecrement(&m_RefCnt);
111 
112 	if (0 == m_RefCnt)
113 		delete this;
114 
115 	return refcnt;
116 }
117 
118 //********************helper functions for GetInfoTip functions**********************
119 
120 /** get file type information from registry.
121 */
getFileTypeInfo(const std::string & file_extension)122 std::wstring getFileTypeInfo(const std::string& file_extension)
123 {
124 	char extKeyValue[MAX_STRING];
125 	char typeKeyValue[MAX_STRING];
126 	::std::string sDot(".");
127 	if (QueryRegistryKey(HKEY_CLASSES_ROOT, (sDot.append(file_extension)).c_str(), "", extKeyValue, MAX_STRING))
128 		if (QueryRegistryKey( HKEY_CLASSES_ROOT, extKeyValue, "",typeKeyValue, MAX_STRING))
129 			return StringToWString(typeKeyValue);
130 
131 	return EMPTY_STRING;
132 }
133 
134 /** get file size.
135 */
getSizeOfFile(char * FileName)136 DWORD getSizeOfFile( char* FileName )
137 {
138 	HANDLE hFile = CreateFile(StringToWString(FileName).c_str(),			// open file
139 						GENERIC_READ,										// open for reading
140 						FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,	// share for all operations
141 						NULL,												// no security
142 						OPEN_EXISTING,										// existing file only
143 						FILE_ATTRIBUTE_NORMAL,								// normal file
144 						NULL);												// no attr. template
145 
146 	if (hFile != INVALID_HANDLE_VALUE)
147 	{
148 		DWORD dwSize = GetFileSize( HANDLE(hFile), NULL );
149 		CloseHandle( HANDLE(hFile) );
150 		return dwSize;
151 	}
152 
153 	return INVALID_FILE_SIZE;
154 }
155 
156 /** format file size in to be more readable.
157 */
formatSizeOfFile(DWORD dwSize)158 std::wstring formatSizeOfFile( DWORD dwSize )
159 {
160 	if ( dwSize < 1000 )
161 	{
162 		char buffer[3];
163 		int dFileSize = dwSize;
164 
165 		_itoa( dFileSize, buffer, 10 );
166 		return StringToWString( buffer ).append(StringToWString(" B"));
167 	}
168 
169 	char *buffer=NULL;
170 	int decimal, sign;
171 	double dFileSize = (double)dwSize/(double)KB;
172 
173 	buffer = _fcvt( dFileSize, 1, &decimal, &sign );
174 
175 	::std::wstring wsTemp = StringToWString( buffer );
176 	int pos=decimal % 3;
177 	::std::wstring wsBuffer = wsTemp.substr( 0,pos);
178 
179 	if ( decimal )
180 		for (;decimal - pos > 2;pos += 3)
181 		{
182 			if (pos)
183 				wsBuffer.append(StringToWString(","));
184 			wsBuffer.append( wsTemp.substr( pos, 3) );
185 		}
186 	else
187 		wsBuffer.append(StringToWString("0"));
188 
189 	wsBuffer.append(StringToWString("."));
190 	wsBuffer.append(wsTemp.substr( decimal, wsTemp.size()-decimal ));
191 	wsBuffer.append(StringToWString(" KB"));
192 
193 	return wsBuffer;
194 }
195 
196 
197 /** get file size information.
198 */
getFileSizeInfo(char * FileName)199 std::wstring getFileSizeInfo(char* FileName)
200 {
201 	DWORD dwSize=getSizeOfFile(FileName);
202 	if (dwSize != INVALID_FILE_SIZE)
203 		return formatSizeOfFile( dwSize );
204 
205 	return EMPTY_STRING;
206 }
207 
208 //----------------------------
209 // IQueryInfo methods
210 //----------------------------
211 
GetInfoTip(DWORD,wchar_t ** ppwszTip)212 HRESULT STDMETHODCALLTYPE CInfoTip::GetInfoTip(DWORD /*dwFlags*/, wchar_t** ppwszTip)
213 {
214 	std::wstring msg;
215 	const std::wstring CONST_SPACE(SPACE);
216 
217 	// display File Type, no matter other info is loaded successfully or not.
218 	std::wstring tmpTypeStr = getFileTypeInfo( get_file_name_extension(m_szFileName) );
219 	if ( tmpTypeStr != EMPTY_STRING )
220 	{
221 		msg += GetResString(IDS_TYPE_COLON) + CONST_SPACE;
222 		msg += tmpTypeStr;
223 	}
224 
225 	try
226 	{
227 		CMetaInfoReader meta_info_accessor(m_szFileName);
228 
229 		// display document title;
230 		if ( meta_info_accessor.getTagData( META_INFO_TITLE ).length() > 0)
231 		{
232 			if ( msg != EMPTY_STRING )
233 				 msg += L"\n";
234 			msg += GetResString(IDS_TITLE_COLON) + CONST_SPACE;
235 			msg += meta_info_accessor.getTagData( META_INFO_TITLE );
236 		}
237 		else
238 		{
239 			if ( msg != EMPTY_STRING )
240 				 msg += L"\n";
241 			msg += GetResString(IDS_TITLE_COLON) + CONST_SPACE;
242 			msg += m_FileNameOnly;
243 		}
244 
245 		// display document author;
246 		if ( meta_info_accessor.getTagData( META_INFO_AUTHOR ).length() > 0)
247 		{
248 			if ( msg != EMPTY_STRING )
249 				 msg += L"\n";
250 			msg += GetResString( IDS_AUTHOR_COLON ) + CONST_SPACE;
251 			msg += meta_info_accessor.getTagData( META_INFO_AUTHOR );
252 		}
253 
254 		// display document subject;
255 		if ( meta_info_accessor.getTagData( META_INFO_SUBJECT ).length() > 0)
256 		{
257 			if ( msg != EMPTY_STRING )
258 				 msg += L"\n";
259 			msg += GetResString(IDS_SUBJECT_COLON) + CONST_SPACE;
260 			msg += meta_info_accessor.getTagData( META_INFO_SUBJECT );
261 		}
262 
263 		// display document description;
264 		if ( meta_info_accessor.getTagData( META_INFO_DESCRIPTION ).length() > 0)
265 		{
266 			if ( msg != EMPTY_STRING )
267 				 msg += L"\n";
268 			msg += GetResString( IDS_COMMENTS_COLON ) + CONST_SPACE;
269 			msg += meta_info_accessor.getTagData( META_INFO_DESCRIPTION );
270 		}
271 
272 		// display modified time formatted into locale representation.
273 		if ( iso8601_date_to_local_date(meta_info_accessor.getTagData(META_INFO_MODIFIED )).length() > 0)
274 		{
275 			if ( msg != EMPTY_STRING )
276 				 msg += L"\n";
277 			msg += GetResString( IDS_MODIFIED_COLON ) + CONST_SPACE;
278 			msg += iso8601_date_to_local_date(meta_info_accessor.getTagData(META_INFO_MODIFIED ));
279 		}
280 	}
281 
282 	catch (const std::exception&)
283 	{
284 		//return E_FAIL;
285 	}
286 
287 	// display file size, no matter other information is loaded successfully or not.
288 	std::wstring tmpSizeStr = getFileSizeInfo( m_szFileName );
289 	if ( tmpSizeStr != EMPTY_STRING )
290 	{
291 		msg += L"\n";
292 		msg += GetResString( IDS_SIZE_COLON ) + CONST_SPACE;
293 		msg += tmpSizeStr;
294 	}
295 
296 
297 	// finalize and assign the string.
298 	LPMALLOC lpMalloc;
299 	HRESULT hr = SHGetMalloc(&lpMalloc);
300 
301 	if (SUCCEEDED(hr))
302 	{
303 		size_t len = sizeof(wchar_t) * msg.length() + sizeof(wchar_t);
304 		wchar_t* pMem = reinterpret_cast<wchar_t*>(lpMalloc->Alloc(len));
305 
306 		ZeroMemory(pMem, len);
307 
308 		msg.copy(pMem,msg.length() + 1);
309 
310 		*ppwszTip = pMem;
311 		lpMalloc->Release();
312 
313 		return S_OK;
314 	}
315 
316 	return E_FAIL;
317 }
318 
319 //----------------------------
320 //
321 //----------------------------
322 
GetInfoFlags(DWORD *)323 HRESULT STDMETHODCALLTYPE CInfoTip::GetInfoFlags(DWORD * /*pdwFlags*/ )
324 {
325 	return E_NOTIMPL;
326 }
327 
328 //----------------------------
329 // IPersist methods
330 //----------------------------
331 
GetClassID(CLSID * pClassID)332 HRESULT STDMETHODCALLTYPE CInfoTip::GetClassID(CLSID* pClassID)
333 {
334 	pClassID = const_cast<CLSID*>(&CLSID_INFOTIP_HANDLER);
335 	return S_OK;
336 }
337 
338 //----------------------------
339 // IPersistFile methods
340 //----------------------------
341 
Load(LPCOLESTR pszFileName,DWORD)342 HRESULT STDMETHODCALLTYPE CInfoTip::Load(LPCOLESTR pszFileName, DWORD /*dwMode*/)
343 {
344 	std::wstring fname = pszFileName;
345 
346 	// there must be a '\' and there must even be an
347 	// extension, else we would not have been called
348 	std::wstring::iterator begin = fname.begin() + fname.find_last_of(L"\\") + 1;
349 	std::wstring::iterator end   = fname.end();
350 
351 	m_FileNameOnly = std::wstring(begin, end);
352 
353 	fname = getShortPathName( fname );
354 
355 	std::string fnameA = WStringToString(fname);
356 
357 	// #115531#
358 	// ZeroMemory because strncpy doesn't '\0'-terminate the destination
359 	// string; reserve the last place in the buffer for the final '\0'
360 	// that's why '(sizeof(m_szFileName) - 1)'
361 	ZeroMemory(m_szFileName, sizeof(m_szFileName));
362 	strncpy(m_szFileName, fnameA.c_str(), (sizeof(m_szFileName) - 1));
363 
364 	return S_OK;
365 }
366 
367 //----------------------------
368 //
369 //----------------------------
370 
IsDirty(void)371 HRESULT STDMETHODCALLTYPE CInfoTip::IsDirty(void)
372 {
373 	return E_NOTIMPL;
374 }
375 
376 //----------------------------
377 //
378 //----------------------------
379 
Save(LPCOLESTR,BOOL)380 HRESULT STDMETHODCALLTYPE CInfoTip::Save(LPCOLESTR /*pszFileName*/, BOOL /*fRemember*/)
381 {
382 	return E_NOTIMPL;
383 }
384 
385 //----------------------------
386 //
387 //----------------------------
388 
SaveCompleted(LPCOLESTR)389 HRESULT STDMETHODCALLTYPE CInfoTip::SaveCompleted(LPCOLESTR /*pszFileName*/)
390 {
391 	return E_NOTIMPL;
392 }
393 
394 //----------------------------
395 //
396 //----------------------------
397 
GetCurFile(LPOLESTR __RPC_FAR *)398 HRESULT STDMETHODCALLTYPE CInfoTip::GetCurFile(LPOLESTR __RPC_FAR * /*ppszFileName*/)
399 {
400 	return E_NOTIMPL;
401 }
402 
403 /* vim: set noet sw=4 ts=4: */
404