Check for invalid pointers
[TortoiseGit.git] / src / TortoiseShell / ColumnProvider.cpp
blob659b1bc52bd0946a866d5061d22573774b38152d
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008,2012 - TortoiseSVN
4 // Copyright (C) 2008-2012 - TortoiseGit
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "ShellExt.h"
22 #include "guids.h"
23 #include "PreserveChdir.h"
24 //#include "SVNProperties.h"
25 #include "UnicodeUtils.h"
26 #include "GitStatus.h"
27 #include "PathUtils.h"
28 #include "..\TGitCache\CacheInterface.h"
31 const static int ColumnFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT;
33 // Defines that revision numbers occupy at most MAX_REV_STRING_LEN characters.
34 // There are Perforce repositories out there that have several 100,000 revs.
35 // So, don't be too restrictive by limiting this to 6 digits + 1 separator,
36 // for instance.
38 // Because shorter strings will be extended to have exactly MAX_REV_STRING_LEN
39 // characters, large numbers will produce large strings. These, in turn, will
40 // affect column auto sizing. This setting is a reasonable compromise.
42 STDMETHODIMP CShellExt::GetColumnInfo(DWORD dwIndex, SHCOLUMNINFO *psci)
44 __try
46 return GetColumnInfo_Wrap(dwIndex, psci);
48 __except(CCrashReport::Instance().SendReport(GetExceptionInformation()))
51 return E_FAIL;
54 // IColumnProvider members
55 STDMETHODIMP CShellExt::GetColumnInfo_Wrap(DWORD dwIndex, SHCOLUMNINFO *psci)
57 if (psci == 0)
58 return E_POINTER;
60 PreserveChdir preserveChdir;
61 if (dwIndex > 0) // TODO: keep for now to be able to hide unimplemented columns
62 return S_FALSE;
64 ShellCache::CacheType cachetype = g_ShellCache.GetCacheType();
65 if (cachetype == ShellCache::none)
66 return S_FALSE;
68 LoadLangDll();
69 switch (dwIndex)
71 case 0: // Git Status
72 GetColumnInfo(dwIndex, psci, 15, IDS_COLTITLESTATUS, IDS_COLDESCSTATUS);
73 break;
74 case 1: // Git Revision
75 GetColumnInfo(dwIndex, psci, 40, IDS_COLTITLEREV, IDS_COLDESCREV);
76 break;
77 case 2: // Git Url
78 GetColumnInfo(dwIndex, psci, 30, IDS_COLTITLEURL, IDS_COLDESCURL);
79 break;
80 case 3: // Git Short Url
81 GetColumnInfo(dwIndex, psci, 30, IDS_COLTITLESHORTURL, IDS_COLDESCSHORTURL);
82 break;
83 case 4: // Author and Git Author
84 psci->scid.fmtid = FMTID_SummaryInformation; // predefined FMTID
85 psci->scid.pid = PIDSI_AUTHOR; // Predefined - author
86 psci->vt = VT_LPSTR; // We'll return the data as a string
87 psci->fmt = LVCFMT_LEFT; // Text will be left-aligned in the column
88 psci->csFlags = SHCOLSTATE_TYPE_STR; // Data should be sorted as strings
89 psci->cChars = 32; // Default col width in chars
90 MAKESTRING(IDS_COLTITLEAUTHOR);
91 lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN);
92 MAKESTRING(IDS_COLDESCAUTHOR);
93 lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN);
94 break;
95 default:
96 return S_FALSE;
99 return S_OK;
102 void CShellExt::GetColumnInfo(DWORD dwIndex, SHCOLUMNINFO *psci, UINT characterCount, UINT title, UINT description)
104 psci->scid.fmtid = CLSID_Tortoisegit_UPTODATE;
105 psci->scid.pid = dwIndex;
106 psci->vt = VT_BSTR;
107 psci->fmt = LVCFMT_LEFT;
108 psci->cChars = characterCount;
109 psci->csFlags = ColumnFlags;
111 MAKESTRING(title);
112 lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN);
113 MAKESTRING(description);
114 lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN);
117 STDMETHODIMP CShellExt::GetItemData(LPCSHCOLUMNID pscid, LPCSHCOLUMNDATA pscd, VARIANT *pvarData)
119 __try
121 return GetItemData_Wrap(pscid, pscd, pvarData);
123 __except(CCrashReport::Instance().SendReport(GetExceptionInformation()))
126 return E_FAIL;
129 STDMETHODIMP CShellExt::GetItemData_Wrap(LPCSHCOLUMNID pscid, LPCSHCOLUMNDATA pscd, VARIANT *pvarData)
131 if ((pscid == 0) || (pscd == 0))
132 return E_INVALIDARG;
133 if (pvarData == 0)
134 return E_POINTER;
136 PreserveChdir preserveChdir;
137 if (!g_ShellCache.IsPathAllowed((TCHAR *)pscd->wszFile))
139 return S_FALSE;
141 LoadLangDll();
142 ShellCache::CacheType cachetype = g_ShellCache.GetCacheType();
143 if (pscid->fmtid == CLSID_Tortoisegit_UPTODATE)
145 stdstring szInfo;
146 const TCHAR * path = (TCHAR *)pscd->wszFile;
148 // reserve for the path + trailing \0
150 TCHAR buf[MAX_STATUS_STRING_LENGTH+1];
151 SecureZeroMemory(buf, MAX_STATUS_STRING_LENGTH);
152 switch (pscid->pid)
154 case 0: // Git Status
155 GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
156 GitStatus::GetStatusString(g_hResInst, filestatus, buf, _countof(buf), (WORD)CRegStdDWORD(_T("Software\\TortoiseGit\\LanguageID"), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)));
157 szInfo = buf;
158 break;
159 case 1: // Git Revision
160 #if 0
161 GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
162 if (columnrev >= 0)
164 V_VT(pvarData) = VT_I4;
165 V_I4(pvarData) = columnrev;
167 #endif
168 return S_OK;
169 break;
170 case 2: // Git Url
171 GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
172 szInfo = itemurl;
173 break;
174 case 3: // Git Short Url
175 GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
176 szInfo = itemshorturl;
177 break;
178 default:
179 return S_FALSE;
181 const WCHAR * wsInfo = szInfo.c_str();
182 V_VT(pvarData) = VT_BSTR;
183 V_BSTR(pvarData) = SysAllocString(wsInfo);
184 return S_OK;
186 if (pscid->fmtid == FMTID_SummaryInformation)
188 stdstring szInfo;
189 const TCHAR * path = pscd->wszFile;
191 if (cachetype == ShellCache::none)
192 return S_FALSE;
193 switch (pscid->pid)
195 case PIDSI_AUTHOR: // Author and Git Author
196 GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
197 szInfo = columnauthor;
198 break;
199 default:
200 return S_FALSE;
202 wide_string wsInfo = szInfo;
203 V_VT(pvarData) = VT_BSTR;
204 V_BSTR(pvarData) = SysAllocString(wsInfo.c_str());
205 return S_OK;
208 return S_FALSE;
211 STDMETHODIMP CShellExt::Initialize(LPCSHCOLUMNINIT psci)
213 __try
215 return Initialize_Wrap(psci);
217 __except(CCrashReport::Instance().SendReport(GetExceptionInformation()))
220 return E_FAIL;
223 STDMETHODIMP CShellExt::Initialize_Wrap(LPCSHCOLUMNINIT psci)
225 if (psci == 0)
226 return E_INVALIDARG;
227 // psci->wszFolder (WCHAR) holds the path to the folder to be displayed
228 // Should check to see if its a "SVN" folder and if not return E_FAIL
230 PreserveChdir preserveChdir;
231 if (g_ShellCache.IsColumnsEveryWhere())
232 return S_OK;
233 std::wstring path = psci->wszFolder;
234 if (!path.empty())
236 if (! g_ShellCache.HasGITAdminDir(path.c_str(), TRUE))
237 return E_FAIL;
239 columnfilepath = _T("");
240 return S_OK;
243 void CShellExt::GetColumnStatus(const TCHAR * path, BOOL bIsDir)
245 PreserveChdir preserveChdir;
246 if (_tcscmp(path, columnfilepath.c_str())==0)
247 return;
248 LoadLangDll();
249 columnfilepath = path;
250 const FileStatusCacheEntry * status = NULL;
251 TGITCacheResponse itemStatus;
252 ShellCache::CacheType t = ShellCache::exe;
253 AutoLocker lock(g_csGlobalCOMGuard);
254 t = g_ShellCache.GetCacheType();
256 switch (t)
258 case ShellCache::exe:
260 SecureZeroMemory(&itemStatus, sizeof(itemStatus));
261 if(m_remoteCacheLink.GetStatusFromRemoteCache(CTGitPath(path), &itemStatus, true))
263 filestatus = GitStatus::GetMoreImportant(itemStatus.m_status.text_status, itemStatus.m_status.prop_status);
265 else
267 filestatus = git_wc_status_none;
268 columnauthor.clear();
269 columnrev = GIT_INVALID_REVNUM;
270 itemurl.clear();
271 itemshorturl.clear();
272 return;
275 break;
276 case ShellCache::dll:
277 case ShellCache::dllFull:
279 status = m_CachedStatus.GetFullStatus(CTGitPath(path), bIsDir, TRUE);
280 filestatus = status->status;
282 break;
283 default:
284 case ShellCache::none:
286 if (g_ShellCache.HasGITAdminDir(path, bIsDir))
287 filestatus = git_wc_status_normal;
288 else
289 filestatus = git_wc_status_none;
290 columnauthor.clear();
291 columnrev = GIT_INVALID_REVNUM;
292 itemurl.clear();
293 itemshorturl.clear();
294 return;
296 break;
299 if (t == ShellCache::exe)
301 columnrev = itemStatus.m_entry.cmt_rev;
303 else
305 if (status)
307 columnrev = status->rev;