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