bool SVNDiff::DiffWCFile(const CTSVNPath& filePath, bool ignoreprops, svn_wc_status_kind status, /* = svn_wc_status_none */ svn_wc_status_kind text_status /* = svn_wc_status_none */, svn_wc_status_kind prop_status /* = svn_wc_status_none */, svn_wc_status_kind remotetext_status /* = svn_wc_status_none */, svn_wc_status_kind remoteprop_status /* = svn_wc_status_none */) { CTSVNPath basePath; CTSVNPath remotePath; SVNRev remoteRev; svn_revnum_t baseRev = 0; // first diff the remote properties against the wc props // TODO: should we attempt to do a three way diff with the properties too // if they're modified locally and remotely? if (!ignoreprops && (remoteprop_status > svn_wc_status_normal)) { DiffProps(filePath, SVNRev::REV_HEAD, SVNRev::REV_WC, baseRev); } if (!ignoreprops && (prop_status > svn_wc_status_normal)&&(filePath.IsDirectory())) { DiffProps(filePath, SVNRev::REV_WC, SVNRev::REV_BASE, baseRev); } if (filePath.IsDirectory()) return true; if ((status > svn_wc_status_normal) || (text_status > svn_wc_status_normal)) { basePath = SVN::GetPristinePath(filePath); if (baseRev == 0) { SVNStatus stat; CTSVNPath dummy; svn_client_status_t * s = stat.GetFirstFileStatus(filePath, dummy); if (s) baseRev = s->revision >= 0 ? s->revision : s->changed_rev; } // If necessary, convert the line-endings on the file before diffing if ((DWORD)CRegDWORD(L"Software\\TortoiseSVN\\ConvertBase", TRUE)) { CTSVNPath temporaryFile = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE); if (!m_pSVN->Export(filePath, temporaryFile, SVNRev(SVNRev::REV_BASE), SVNRev(SVNRev::REV_BASE))) { temporaryFile.Reset(); } else { basePath = temporaryFile; SetFileAttributes(basePath.GetWinPath(), FILE_ATTRIBUTE_READONLY); } } } if (remotetext_status > svn_wc_status_normal) { remotePath = CTempFiles::Instance().GetTempFilePath(false, filePath, SVNRev::REV_HEAD); CProgressDlg progDlg; progDlg.SetTitle(IDS_APPNAME); progDlg.SetTime(false); m_pSVN->SetAndClearProgressInfo(&progDlg, true); // activate progress bar progDlg.ShowModeless(GetHWND()); progDlg.FormatPathLine(1, IDS_PROGRESSGETFILE, (LPCTSTR)filePath.GetUIFileOrDirectoryName()); remoteRev = SVNRev::REV_HEAD; if (!m_pSVN->Export(filePath, remotePath, remoteRev, remoteRev)) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); SetFileAttributes(remotePath.GetWinPath(), FILE_ATTRIBUTE_READONLY); } CString name = filePath.GetUIFileOrDirectoryName(); CString n1, n2, n3; n1.Format(IDS_DIFF_WCNAME, (LPCTSTR)name); if (baseRev) n2.FormatMessage(IDS_DIFF_BASENAMEREV, (LPCTSTR)name, baseRev); else n2.Format(IDS_DIFF_BASENAME, (LPCTSTR)name); n3.Format(IDS_DIFF_REMOTENAME, (LPCTSTR)name); if ((text_status <= svn_wc_status_normal)&&(prop_status <= svn_wc_status_normal)&&(status <= svn_wc_status_normal)) { // Hasn't changed locally - diff remote against WC return CAppUtils::StartExtDiff( filePath, remotePath, n1, n3, filePath, filePath, SVNRev::REV_WC, remoteRev, remoteRev, CAppUtils::DiffFlags().AlternativeTool(m_bAlternativeTool), m_JumpLine, filePath.GetFileOrDirectoryName(), L""); } else if (remotePath.IsEmpty()) { return DiffFileAgainstBase(filePath, baseRev, ignoreprops, status, text_status, prop_status); } else { // Three-way diff CAppUtils::MergeFlags flags; flags.bAlternativeTool = m_bAlternativeTool; flags.bReadOnly = true; return !!CAppUtils::StartExtMerge(flags, basePath, remotePath, filePath, CTSVNPath(), false, n2, n3, n1, CString(), filePath.GetFileOrDirectoryName()); } }
bool SVNDiff::UnifiedDiff(CTSVNPath& tempfile, const CTSVNPath& url1, const SVNRev& rev1, const CTSVNPath& url2, const SVNRev& rev2, const SVNRev& peg, const CString& options, bool bIgnoreAncestry /* = false */, bool bIgnoreProperties /* = true */) { tempfile = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, CTSVNPath(L"Test.diff")); bool bIsUrl = !!SVN::PathIsURL(url1); CProgressDlg progDlg; progDlg.SetTitle(IDS_APPNAME); progDlg.SetLine(1, CString(MAKEINTRESOURCE(IDS_PROGRESS_UNIFIEDDIFF))); progDlg.SetTime(false); m_pSVN->SetAndClearProgressInfo(&progDlg); progDlg.ShowModeless(GetHWND()); // find the root of the files CTSVNPathList plist; plist.AddPath(url1); plist.AddPath(url2); CTSVNPath relativeTo = plist.GetCommonRoot(); if (!relativeTo.IsUrl()) { if (!relativeTo.IsDirectory()) relativeTo = relativeTo.GetContainingDirectory(); } if (relativeTo.IsEmpty() && url1.Exists() && url2.IsUrl()) { // the source path exists, i.e. it's a local path, so // use this as the relative url relativeTo = url1.GetDirectory(); } // the 'relativeTo' path must be a path: svn throws an error if it's used for urls. else if ((!url2.IsEquivalentTo(url1) && (relativeTo.IsEquivalentTo(url1) || relativeTo.IsEquivalentTo(url2))) || url1.IsUrl() || url2.IsUrl()) relativeTo.Reset(); if ((!url1.IsEquivalentTo(url2))||((rev1.IsWorking() || rev1.IsBase())&&(rev2.IsWorking() || rev2.IsBase()))) { if (!m_pSVN->Diff(url1, rev1, url2, rev2, relativeTo, svn_depth_infinity, true, false, false, false, false, false, bIgnoreProperties, false, options, bIgnoreAncestry, tempfile)) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } else { if (!m_pSVN->PegDiff(url1, (peg.IsValid() ? peg : (bIsUrl ? m_headPeg : SVNRev::REV_WC)), rev1, rev2, relativeTo, svn_depth_infinity, true, false, false, false, false, false, bIgnoreProperties, false, options, false, tempfile)) { if (!m_pSVN->Diff(url1, rev1, url2, rev2, relativeTo, svn_depth_infinity, true, false, false, false, false, false, bIgnoreProperties, false, options, false, tempfile)) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); m_pSVN->ShowErrorDialog(GetHWND()); return false; } } } if (CAppUtils::CheckForEmptyDiff(tempfile)) { progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); TaskDialog(GetHWND(), AfxGetResourceHandle(), MAKEINTRESOURCE(IDS_APPNAME), MAKEINTRESOURCE(IDS_ERR_ERROROCCURED), MAKEINTRESOURCE(IDS_ERR_EMPTYDIFF), TDCBF_OK_BUTTON, TD_ERROR_ICON, NULL); return false; } progDlg.Stop(); m_pSVN->SetAndClearProgressInfo((HWND)NULL); return true; }
bool SVNDiff::DiffFileAgainstBase( const CTSVNPath& filePath, svn_revnum_t & baseRev, bool ignoreprops, svn_wc_status_kind status /*= svn_wc_status_none*/, svn_wc_status_kind text_status /*= svn_wc_status_none*/, svn_wc_status_kind prop_status /*= svn_wc_status_none*/ ) { bool retvalue = false; bool fileexternal = false; if ((text_status == svn_wc_status_none)||(prop_status == svn_wc_status_none)) { SVNStatus stat; stat.GetStatus(filePath); if (stat.status == NULL) return false; text_status = stat.status->text_status; prop_status = stat.status->prop_status; fileexternal = stat.status->file_external != 0; } if (!ignoreprops && (prop_status > svn_wc_status_normal)) { DiffProps(filePath, SVNRev::REV_WC, SVNRev::REV_BASE, baseRev); } if (filePath.IsDirectory()) return true; if ((status >= svn_wc_status_normal) || (text_status >= svn_wc_status_normal)) { CTSVNPath basePath(SVN::GetPristinePath(filePath)); if (baseRev == 0) { SVNInfo info; const SVNInfoData * infodata = info.GetFirstFileInfo(filePath, SVNRev(), SVNRev()); if (infodata) { if (infodata->copyfromurl && infodata->copyfromurl[0]) baseRev = infodata->copyfromrev; else baseRev = infodata->lastchangedrev; } } // If necessary, convert the line-endings on the file before diffing // note: file externals can not be exported if (((DWORD)CRegDWORD(L"Software\\TortoiseSVN\\ConvertBase", TRUE)) && (!fileexternal)) { CTSVNPath temporaryFile = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE); if (!m_pSVN->Export(filePath, temporaryFile, SVNRev(SVNRev::REV_BASE), SVNRev(SVNRev::REV_BASE))) { temporaryFile.Reset(); } else { basePath = temporaryFile; SetFileAttributes(basePath.GetWinPath(), FILE_ATTRIBUTE_READONLY); } } // for added/deleted files, we don't have a BASE file. // create an empty temp file to be used. if (!basePath.Exists()) { basePath = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE); SetFileAttributes(basePath.GetWinPath(), FILE_ATTRIBUTE_READONLY); } CString name = filePath.GetFilename(); CTSVNPath wcFilePath = filePath; if (!wcFilePath.Exists()) { wcFilePath = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE); SetFileAttributes(wcFilePath.GetWinPath(), FILE_ATTRIBUTE_READONLY); } CString n1, n2; n1.Format(IDS_DIFF_WCNAME, (LPCTSTR)name); if (baseRev) n2.FormatMessage(IDS_DIFF_BASENAMEREV, (LPCTSTR)name, baseRev); else n2.Format(IDS_DIFF_BASENAME, (LPCTSTR)name); retvalue = CAppUtils::StartExtDiff( basePath, wcFilePath, n2, n1, filePath, filePath, SVNRev::REV_BASE, SVNRev::REV_WC, SVNRev::REV_BASE, CAppUtils::DiffFlags().Wait().AlternativeTool(m_bAlternativeTool), m_JumpLine, name, L""); } return retvalue; }
bool CheckoutCommand::Execute() { bool bRet = false; // Get the directory supplied in the command line. If there isn't // one then we should use first the default checkout path // specified in the settings dialog, and fall back to the current // working directory instead if no such path was specified. CTSVNPath checkoutDirectory; CRegString regDefCheckoutPath(_T("Software\\TortoiseSVN\\DefaultCheckoutPath")); if (cmdLinePath.IsEmpty()) { if (CString(regDefCheckoutPath).IsEmpty()) { checkoutDirectory.SetFromWin(sOrigCWD, true); DWORD len = ::GetTempPath(0, NULL); std::unique_ptr<TCHAR[]> tszPath(new TCHAR[len]); ::GetTempPath(len, tszPath.get()); if (_tcsncicmp(checkoutDirectory.GetWinPath(), tszPath.get(), len-2 /* \\ and \0 */) == 0) { // if the current directory is set to a temp directory, // we don't use that but leave it empty instead. checkoutDirectory.Reset(); } } else { checkoutDirectory.SetFromWin(CString(regDefCheckoutPath)); } } else { checkoutDirectory = cmdLinePath; } CCheckoutDlg dlg; dlg.m_URLs.LoadFromAsteriskSeparatedString (parser.GetVal(_T("url"))); if (dlg.m_URLs.GetCount()==0) { SVN svn; if (svn.IsRepository(cmdLinePath)) { CString url; // The path points to a local repository. // Add 'file:///' so the repository browser recognizes // it as an URL to the local repository. if (cmdLinePath.GetWinPathString().GetAt(0) == '\\') // starts with '\' means an UNC path { CString p = cmdLinePath.GetWinPathString(); p.TrimLeft('\\'); url = _T("file://")+p; } else url = _T("file:///")+cmdLinePath.GetWinPathString(); url.Replace('\\', '/'); dlg.m_URLs.AddPath(CTSVNPath(url)); checkoutDirectory.AppendRawString(L"wc"); } } dlg.m_strCheckoutDirectory = checkoutDirectory.GetWinPathString(); // if there is no url specified on the command line, check if there's one // specified in the settings dialog to use as the default and use that CRegString regDefCheckoutUrl(_T("Software\\TortoiseSVN\\DefaultCheckoutUrl")); if (!CString(regDefCheckoutUrl).IsEmpty()) { // if the URL specified is a child of the default URL, we also // adjust the default checkout path // e.g. // Url specified on command line: http://server.com/repos/project/trunk/folder // Url specified as default : http://server.com/repos/project/trunk // checkout path specified : c:\work\project // --> // checkout path adjusted : c:\work\project\folder CTSVNPath clurl = dlg.m_URLs.GetCommonDirectory(); CTSVNPath defurl = CTSVNPath(CString(regDefCheckoutUrl)); if (defurl.IsAncestorOf(clurl)) { // the default url is the parent of the specified url if (CTSVNPath::CheckChild(CTSVNPath(CString(regDefCheckoutPath)), CTSVNPath(dlg.m_strCheckoutDirectory))) { dlg.m_strCheckoutDirectory = CString(regDefCheckoutPath) + clurl.GetWinPathString().Mid(defurl.GetWinPathString().GetLength()); dlg.m_strCheckoutDirectory.Replace(_T("\\\\"), _T("\\")); } } if (dlg.m_URLs.GetCount() == 0) dlg.m_URLs.AddPath (defurl); } for (int i = 0; i < dlg.m_URLs.GetCount(); ++i) { CString pathString = dlg.m_URLs[i].GetWinPathString(); if (pathString.Left(5).Compare(_T("tsvn:"))==0) { pathString = pathString.Mid(5); if (pathString.Find('?') >= 0) { dlg.Revision = SVNRev(pathString.Mid(pathString.Find('?')+1)); pathString = pathString.Left(pathString.Find('?')); } } dlg.m_URLs[i].SetFromWin (pathString); } if (parser.HasKey(_T("revision"))) { SVNRev Rev = SVNRev(parser.GetVal(_T("revision"))); dlg.Revision = Rev; } dlg.m_blockPathAdjustments = parser.HasKey(L"blockpathadjustments"); if (dlg.DoModal() == IDOK) { checkoutDirectory.SetFromWin(dlg.m_strCheckoutDirectory, true); CSVNProgressDlg progDlg; theApp.m_pMainWnd = &progDlg; bool useStandardCheckout = dlg.m_standardCheckout || ((dlg.m_URLs.GetCount() > 1) && dlg.m_bIndependentWCs); progDlg.SetCommand (useStandardCheckout ? dlg.m_checkoutDepths.size() ? CSVNProgressDlg::SVNProgress_SparseCheckout : CSVNProgressDlg::SVNProgress_Checkout : dlg.m_parentExists && (dlg.m_URLs.GetCount() == 1) ? CSVNProgressDlg::SVNProgress_Update : CSVNProgressDlg::SVNProgress_SingleFileCheckout); if (dlg.m_checkoutDepths.size()) progDlg.SetPathDepths(dlg.m_checkoutDepths); progDlg.SetAutoClose (parser); progDlg.SetOptions(dlg.m_bNoExternals ? ProgOptIgnoreExternals : ProgOptNone); progDlg.SetPathList(CTSVNPathList(checkoutDirectory)); progDlg.SetUrl(dlg.m_URLs.CreateAsteriskSeparatedString()); progDlg.SetRevision(dlg.Revision); progDlg.SetDepth(dlg.m_depth); progDlg.DoModal(); bRet = !progDlg.DidErrorsOccur(); } return bRet; }
////////////////////////////////////////////////////////////////////////// // IDataObject ////////////////////////////////////////////////////////////////////////// STDMETHODIMP SVNDataObject::GetData(FORMATETC* pformatetcIn, STGMEDIUM* pmedium) { if (pformatetcIn == NULL) return E_INVALIDARG; if (pmedium == NULL) return E_POINTER; pmedium->hGlobal = NULL; if ((pformatetcIn->tymed & TYMED_ISTREAM) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_FILECONTENTS)) { // supports the IStream format. // The lindex param is the index of the file to return // Note: we don't get called for directories since those are simply created and don't // need to be fetched. // Note2: It would be really nice if we could get a stream from the subversion library // from where we could read the file contents. But the Subversion lib is not implemented // to *read* from a remote stream but so that the library *writes* to a stream we pass. // Since we can't get such a read stream, we have to fetch the file in whole first to // a temp location and then pass the shell an IStream for that temp file. CTSVNPath filepath; IStream * pIStream = NULL; if (m_revision.IsWorking()) { if ((pformatetcIn->lindex >= 0)&&(pformatetcIn->lindex < (LONG)m_allPaths.size())) { filepath = m_allPaths[pformatetcIn->lindex].rootpath; } } else { filepath = CTempFiles::Instance().GetTempFilePath(true); if ((pformatetcIn->lindex >= 0)&&(pformatetcIn->lindex < (LONG)m_allPaths.size())) { if (!m_svn.Cat(CTSVNPath(m_allPaths[pformatetcIn->lindex].infodata.url), m_pegRev, m_revision, filepath)) { DeleteFile(filepath.GetWinPath()); return STG_E_ACCESSDENIED; } } } HRESULT res = SHCreateStreamOnFile(filepath.GetWinPath(), STGM_READ, &pIStream); if (res == S_OK) { pmedium->pstm = pIStream; pmedium->tymed = TYMED_ISTREAM; return S_OK; } return res; } else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_FILEDESCRIPTOR)) { // now it is time to get all sub folders for the directories we have SVNInfo svnInfo; // find the common directory of all the paths CTSVNPath commonDir; bool bAllUrls = true; for (int i=0; i<m_svnPaths.GetCount(); ++i) { if (!m_svnPaths[i].IsUrl()) bAllUrls = false; if (commonDir.IsEmpty()) commonDir = m_svnPaths[i].GetContainingDirectory(); if (!commonDir.IsEquivalentTo(m_svnPaths[i].GetContainingDirectory())) { commonDir.Reset(); break; } } if (bAllUrls && (m_svnPaths.GetCount() > 1) && !commonDir.IsEmpty()) { // if all paths are in the same directory, we can fetch the info recursively // from the parent folder to save a lot of time. const SVNInfoData * infodata = svnInfo.GetFirstFileInfo(commonDir, m_pegRev, m_revision, svn_depth_infinity); while (infodata) { // check if the returned item is one in our list for (int i=0; i<m_svnPaths.GetCount(); ++i) { if (m_svnPaths[i].IsAncestorOf(CTSVNPath(infodata->url))) { SVNDataObject::SVNObjectInfoData id = {m_svnPaths[i], *infodata}; m_allPaths.push_back(id); break; } } infodata = svnInfo.GetNextFileInfo(); } } else { for (int i = 0; i < m_svnPaths.GetCount(); ++i) { if (m_svnPaths[i].IsUrl()) { const SVNInfoData * infodata = svnInfo.GetFirstFileInfo(m_svnPaths[i], m_pegRev, m_revision, svn_depth_infinity); while (infodata) { SVNDataObject::SVNObjectInfoData id = {m_svnPaths[i], *infodata}; m_allPaths.push_back(id); infodata = svnInfo.GetNextFileInfo(); } } else { SVNDataObject::SVNObjectInfoData id = {m_svnPaths[i], SVNInfoData()}; m_allPaths.push_back(id); } } } size_t dataSize = sizeof(FILEGROUPDESCRIPTOR) + ((m_allPaths.size() - 1) * sizeof(FILEDESCRIPTOR)); HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, dataSize); FILEGROUPDESCRIPTOR* files = (FILEGROUPDESCRIPTOR*)GlobalLock(data); files->cItems = static_cast<UINT>(m_allPaths.size()); int index = 0; for (vector<SVNDataObject::SVNObjectInfoData>::const_iterator it = m_allPaths.begin(); it != m_allPaths.end(); ++it) { CString temp; if (it->rootpath.IsUrl()) { temp = CUnicodeUtils::GetUnicode(CPathUtils::PathEscape(CUnicodeUtils::GetUTF8(it->rootpath.GetContainingDirectory().GetSVNPathString()))); temp = it->infodata.url.Mid(temp.GetLength()+1); // we have to unescape the urls since the local file system doesn't need them // escaped and it would only look really ugly (and be wrong). temp = CPathUtils::PathUnescape(temp); } else { temp = it->rootpath.GetUIFileOrDirectoryName(); } _tcscpy_s(files->fgd[index].cFileName, MAX_PATH, (LPCTSTR)temp); files->fgd[index].dwFlags = FD_ATTRIBUTES | FD_PROGRESSUI | FD_FILESIZE | FD_LINKUI; if (it->rootpath.IsUrl()) { files->fgd[index].dwFileAttributes = (it->infodata.kind == svn_node_dir) ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; } else { files->fgd[index].dwFileAttributes = it->rootpath.IsDirectory() ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; } // Always set the file size to 0 even if we 'know' the file size (infodata.size64). // Because for text files, the file size is too low due to the EOLs getting converted // to CRLF (from LF as stored in the repository). And a too low file size set here // prevents the shell from reading the full file later - it only reads the stream up // to the number of bytes specified here. Which means we would end up with a truncated // text file (binary files are still ok though). files->fgd[index].nFileSizeLow = 0; files->fgd[index].nFileSizeHigh = 0; ++index; } GlobalUnlock(data); pmedium->hGlobal = data; pmedium->tymed = TYMED_HGLOBAL; return S_OK; } // handling CF_PREFERREDDROPEFFECT is necessary to tell the shell that it should *not* ask for the // CF_FILEDESCRIPTOR until the drop actually occurs. If we don't handle CF_PREFERREDDROPEFFECT, the shell // will ask for the file descriptor for every object (file/folder) the mouse pointer hovers over and is // a potential drop target. else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->cfFormat == CF_PREFERREDDROPEFFECT)) { HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD)); DWORD* effect = (DWORD*) GlobalLock(data); (*effect) = DROPEFFECT_COPY; GlobalUnlock(data); pmedium->hGlobal = data; pmedium->tymed = TYMED_HGLOBAL; return S_OK; } else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_TEXT)) { // caller wants text // create the string from the path list CString text; if (m_svnPaths.GetCount()) { // create a single string where the URLs are separated by newlines for (int i=0; i<m_svnPaths.GetCount(); ++i) { if (m_svnPaths[i].IsUrl()) text += m_svnPaths[i].GetSVNPathString(); else text += m_svnPaths[i].GetWinPathString(); text += _T("\r\n"); } } CStringA texta = CUnicodeUtils::GetUTF8(text); pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = GlobalAlloc(GHND, (texta.GetLength()+1)*sizeof(char)); if (pmedium->hGlobal) { char* pMem = (char*)GlobalLock(pmedium->hGlobal); strcpy_s(pMem, texta.GetLength()+1, (LPCSTR)texta); GlobalUnlock(pmedium->hGlobal); } pmedium->pUnkForRelease = NULL; return S_OK; } else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_UNICODETEXT)) { // caller wants Unicode text // create the string from the path list CString text; if (m_svnPaths.GetCount()) { // create a single string where the URLs are separated by newlines for (int i=0; i<m_svnPaths.GetCount(); ++i) { if (m_svnPaths[i].IsUrl()) text += m_svnPaths[i].GetSVNPathString(); else text += m_svnPaths[i].GetWinPathString(); text += _T("\r\n"); } } pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = GlobalAlloc(GHND, (text.GetLength()+1)*sizeof(TCHAR)); if (pmedium->hGlobal) { TCHAR* pMem = (TCHAR*)GlobalLock(pmedium->hGlobal); _tcscpy_s(pMem, text.GetLength()+1, (LPCTSTR)text); GlobalUnlock(pmedium->hGlobal); } pmedium->pUnkForRelease = NULL; return S_OK; } else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_SVNURL)) { // caller wants the svn url // create the string from the path list CString text; if (m_svnPaths.GetCount()) { // create a single string where the URLs are separated by newlines for (int i=0; i<m_svnPaths.GetCount(); ++i) { if (m_svnPaths[i].IsUrl()) { text += m_svnPaths[i].GetSVNPathString(); text += _T("?"); text += m_revision.ToString(); } else text += m_svnPaths[i].GetWinPathString(); text += _T("\r\n"); } } pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = GlobalAlloc(GHND, (text.GetLength()+1)*sizeof(TCHAR)); if (pmedium->hGlobal) { TCHAR* pMem = (TCHAR*)GlobalLock(pmedium->hGlobal); _tcscpy_s(pMem, text.GetLength()+1, (LPCTSTR)text); GlobalUnlock(pmedium->hGlobal); } pmedium->pUnkForRelease = NULL; return S_OK; } else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_HDROP)) { int nLength = 0; for (int i=0;i<m_svnPaths.GetCount();i++) { nLength += m_svnPaths[i].GetWinPathString().GetLength(); nLength += 1; // '\0' separator } int nBufferSize = sizeof(DROPFILES) + (nLength+1)*sizeof(TCHAR); char * pBuffer = new char[nBufferSize]; SecureZeroMemory(pBuffer, nBufferSize); DROPFILES* df = (DROPFILES*)pBuffer; df->pFiles = sizeof(DROPFILES); df->fWide = 1; TCHAR* pFilenames = (TCHAR*)(pBuffer + sizeof(DROPFILES)); TCHAR* pCurrentFilename = pFilenames; for (int i=0;i<m_svnPaths.GetCount();i++) { CString str = m_svnPaths[i].GetWinPathString(); wcscpy_s(pCurrentFilename, str.GetLength()+1, (LPCWSTR)str); pCurrentFilename += str.GetLength(); *pCurrentFilename = '\0'; // separator between file names pCurrentFilename++; } *pCurrentFilename = '\0'; // terminate array pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE, nBufferSize); if (pmedium->hGlobal) { LPVOID pMem = ::GlobalLock(pmedium->hGlobal); if (pMem) memcpy(pMem, pBuffer, nBufferSize); GlobalUnlock(pmedium->hGlobal); } pmedium->pUnkForRelease = NULL; delete [] pBuffer; return S_OK; } for (size_t i=0; i<m_vecFormatEtc.size(); ++i) { if ((pformatetcIn->tymed == m_vecFormatEtc[i]->tymed) && (pformatetcIn->dwAspect == m_vecFormatEtc[i]->dwAspect) && (pformatetcIn->cfFormat == m_vecFormatEtc[i]->cfFormat)) { CopyMedium(pmedium, m_vecStgMedium[i], m_vecFormatEtc[i]); return S_OK; } } return DV_E_FORMATETC; }
bool CheckoutCommand::Execute() { bool bRet = false; // Get the directory supplied in the command line. If there isn't // one then we should use first the default checkout path // specified in the settings dialog, and fall back to the current // working directory instead if no such path was specified. CTSVNPath checkoutDirectory; CRegString regDefCheckoutPath(_T("Software\\TortoiseGit\\DefaultCheckoutPath")); if (cmdLinePath.IsEmpty()) { if (CString(regDefCheckoutPath).IsEmpty()) { checkoutDirectory.SetFromWin(sOrigCWD, true); DWORD len = ::GetTempPath(0, NULL); TCHAR * tszPath = new TCHAR[len]; ::GetTempPath(len, tszPath); if (_tcsncicmp(checkoutDirectory.GetWinPath(), tszPath, len-2 /* \\ and \0 */) == 0) { // if the current directory is set to a temp directory, // we don't use that but leave it empty instead. checkoutDirectory.Reset(); } delete [] tszPath; } else { checkoutDirectory.SetFromWin(CString(regDefCheckoutPath)); } } else { checkoutDirectory = cmdLinePath; } CCheckoutDlg dlg; dlg.m_strCheckoutDirectory = checkoutDirectory.GetWinPathString(); dlg.m_URL = parser.GetVal(_T("url")); // if there is no url specified on the command line, check if there's one // specified in the settings dialog to use as the default and use that CRegString regDefCheckoutUrl(_T("Software\\TortoiseGit\\DefaultCheckoutUrl")); if (!CString(regDefCheckoutUrl).IsEmpty()) { // if the URL specified is a child of the default URL, we also // adjust the default checkout path // e.g. // Url specified on command line: http://server.com/repos/project/trunk/folder // Url specified as default : http://server.com/repos/project/trunk // checkout path specified : c:\work\project // --> // checkout path adjusted : c:\work\project\folder CTSVNPath clurl = CTSVNPath(dlg.m_URL); CTSVNPath defurl = CTSVNPath(CString(regDefCheckoutUrl)); if (defurl.IsAncestorOf(clurl)) { // the default url is the parent of the specified url if (CTSVNPath::CheckChild(CTSVNPath(CString(regDefCheckoutPath)), CTSVNPath(dlg.m_strCheckoutDirectory))) { dlg.m_strCheckoutDirectory = CString(regDefCheckoutPath) + clurl.GetWinPathString().Mid(defurl.GetWinPathString().GetLength()); dlg.m_strCheckoutDirectory.Replace(_T("\\\\"), _T("\\")); } } if (dlg.m_URL.IsEmpty()) dlg.m_URL = regDefCheckoutUrl; } if (dlg.m_URL.Left(5).Compare(_T("tsvn:"))==0) { dlg.m_URL = dlg.m_URL.Mid(5); if (dlg.m_URL.Find('?') >= 0) { dlg.Revision = SVNRev(dlg.m_URL.Mid(dlg.m_URL.Find('?')+1)); dlg.m_URL = dlg.m_URL.Left(dlg.m_URL.Find('?')); } } if (parser.HasKey(_T("revision"))) { SVNRev Rev = SVNRev(parser.GetVal(_T("revision"))); dlg.Revision = Rev; } if (dlg.m_URL.Find('*')>=0) { // multiple URL's specified // ask where to check them out to CBrowseFolder foldbrowse; foldbrowse.SetInfo(CString(MAKEINTRESOURCE(IDS_PROC_CHECKOUTTO))); foldbrowse.SetCheckBoxText(CString(MAKEINTRESOURCE(IDS_PROC_CHECKOUTTOPONLY))); foldbrowse.SetCheckBoxText2(CString(MAKEINTRESOURCE(IDS_PROC_CHECKOUTNOEXTERNALS))); foldbrowse.m_style = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | BIF_USENEWUI | BIF_VALIDATE; TCHAR checkoutpath[MAX_PATH]; if (foldbrowse.Show(hwndExplorer, checkoutpath, MAX_PATH, CString(regDefCheckoutPath))==CBrowseFolder::OK) { CSVNProgressDlg progDlg; theApp.m_pMainWnd = &progDlg; if (parser.HasVal(_T("closeonend"))) progDlg.SetAutoClose(parser.GetLongVal(_T("closeonend"))); progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Checkout); progDlg.SetOptions(foldbrowse.m_bCheck2 ? ProgOptIgnoreExternals : ProgOptNone); progDlg.SetPathList(CTSVNPathList(CTSVNPath(CString(checkoutpath)))); progDlg.SetUrl(dlg.m_URL); progDlg.SetRevision(dlg.Revision); progDlg.SetDepth(foldbrowse.m_bCheck ? svn_depth_empty : svn_depth_infinity); progDlg.DoModal(); bRet = !progDlg.DidErrorsOccur(); } } else if (dlg.DoModal() == IDOK) { checkoutDirectory.SetFromWin(dlg.m_strCheckoutDirectory, true); CSVNProgressDlg progDlg; theApp.m_pMainWnd = &progDlg; progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Checkout); if (parser.HasVal(_T("closeonend"))) progDlg.SetAutoClose(parser.GetLongVal(_T("closeonend"))); progDlg.SetOptions(dlg.m_bNoExternals ? ProgOptIgnoreExternals : ProgOptNone); progDlg.SetPathList(CTSVNPathList(checkoutDirectory)); progDlg.SetUrl(dlg.m_URL); progDlg.SetRevision(dlg.Revision); progDlg.SetDepth(dlg.m_depth); progDlg.DoModal(); bRet = !progDlg.DidErrorsOccur(); } return bRet; }