From c469a4c4bf7b0a2a3833dd17946d62544e35cf42 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sun, 5 Apr 2009 23:30:10 +0800 Subject: [PATCH] Success build TortoiseMerge. Signed-off-by: Frank Li --- src/TortoiseMerge/AboutDlg.cpp | 12 +- src/TortoiseMerge/AppUtils.cpp | 39 +- src/TortoiseMerge/AppUtils.h | 5 +- src/TortoiseMerge/BaseView.cpp | 165 +- src/TortoiseMerge/BaseView.h | 7 +- src/TortoiseMerge/BottomView.cpp | 5 +- src/TortoiseMerge/DiffData.cpp | 52 +- src/TortoiseMerge/DiffData.h | 2 +- src/TortoiseMerge/FileTextLines.cpp | 8 +- src/TortoiseMerge/LeftView.cpp | 18 +- src/TortoiseMerge/LocatorBar.cpp | 5 +- src/TortoiseMerge/MainFrm.cpp | 72 +- src/TortoiseMerge/MainFrm.h | 22 +- src/TortoiseMerge/Patch.cpp | 14 +- src/TortoiseMerge/RightView.cpp | 6 +- src/TortoiseMerge/SetMainPage.cpp | 2 +- src/TortoiseMerge/TortoiseMerge.cpp | 61 +- src/TortoiseMerge/TortoiseMerge.h | 5 +- src/TortoiseMerge/TortoiseMerge.vcproj | 1334 +++++- src/TortoiseMerge/libsvn_diff/SVNLineDiff.cpp | 296 ++ src/TortoiseMerge/libsvn_diff/adler32.c | 48 + src/TortoiseMerge/libsvn_diff/checksum.c | 334 ++ src/TortoiseMerge/libsvn_diff/cmdline.c | 617 +++ src/TortoiseMerge/libsvn_diff/compress.c | 68 + src/TortoiseMerge/libsvn_diff/crc32.c | 162 + src/TortoiseMerge/libsvn_diff/ctype.c | 314 ++ src/TortoiseMerge/libsvn_diff/deflate.c | 1350 ++++++ src/TortoiseMerge/libsvn_diff/deflate.h | 318 ++ src/TortoiseMerge/libsvn_diff/deprecated.c | 4 + src/TortoiseMerge/libsvn_diff/diff.c | 3 + src/TortoiseMerge/libsvn_diff/diff3.c | 3 + src/TortoiseMerge/libsvn_diff/diff4.c | 5 + src/TortoiseMerge/libsvn_diff/diff_file.c | 10 +- src/TortoiseMerge/libsvn_diff/diff_memory.c | 8 +- src/TortoiseMerge/libsvn_diff/dirent_uri.c | 1199 +++++ src/TortoiseMerge/libsvn_diff/dso.c | 132 + src/TortoiseMerge/libsvn_diff/error.c | 549 +++ src/TortoiseMerge/libsvn_diff/gzio.c | 875 ++++ src/TortoiseMerge/libsvn_diff/infblock.c | 403 ++ src/TortoiseMerge/libsvn_diff/infblock.h | 39 + src/TortoiseMerge/libsvn_diff/infcodes.c | 251 + src/TortoiseMerge/libsvn_diff/infcodes.h | 27 + src/TortoiseMerge/libsvn_diff/inffast.c | 183 + src/TortoiseMerge/libsvn_diff/inffast.h | 17 + src/TortoiseMerge/libsvn_diff/inffixed.h | 151 + src/TortoiseMerge/libsvn_diff/inflate.c | 366 ++ src/TortoiseMerge/libsvn_diff/inftrees.c | 454 ++ src/TortoiseMerge/libsvn_diff/inftrees.h | 58 + src/TortoiseMerge/libsvn_diff/infutil.c | 87 + src/TortoiseMerge/libsvn_diff/infutil.h | 98 + src/TortoiseMerge/libsvn_diff/io.c | 3491 ++++++++++++++ src/TortoiseMerge/libsvn_diff/lcs.c | 5 + src/TortoiseMerge/libsvn_diff/maketree.c | 85 + src/TortoiseMerge/libsvn_diff/md5.c | 104 + src/TortoiseMerge/libsvn_diff/md5.h | 66 + src/TortoiseMerge/libsvn_diff/path.c | 1203 +++++ src/TortoiseMerge/libsvn_diff/pool.c | 94 + src/TortoiseMerge/libsvn_diff/porting.c | 44 - src/TortoiseMerge/libsvn_diff/readme.txt | 37 + src/TortoiseMerge/libsvn_diff/sha1.c | 77 + src/TortoiseMerge/libsvn_diff/sha1.h | 65 + src/TortoiseMerge/libsvn_diff/stream.c | 1093 +++++ src/TortoiseMerge/libsvn_diff/svn_base64.h | 118 + src/TortoiseMerge/libsvn_diff/svn_cmdline.h | 383 ++ src/TortoiseMerge/libsvn_diff/svn_dirent_uri.h | 225 + src/TortoiseMerge/libsvn_diff/svn_md5.h | 86 + src/TortoiseMerge/libsvn_diff/svn_nls.h | 51 + src/TortoiseMerge/libsvn_diff/svn_string.c | 601 +++ src/TortoiseMerge/libsvn_diff/svn_utf_private.h | 82 + src/TortoiseMerge/libsvn_diff/svn_xml.h | 361 ++ src/TortoiseMerge/libsvn_diff/token.c | 3 + src/TortoiseMerge/libsvn_diff/trees.c | 1214 +++++ src/TortoiseMerge/libsvn_diff/trees.h | 128 + src/TortoiseMerge/libsvn_diff/uncompr.c | 58 + src/TortoiseMerge/libsvn_diff/unzip.c | 1294 ++++++ src/TortoiseMerge/libsvn_diff/unzip.h | 275 ++ src/TortoiseMerge/libsvn_diff/utf.c | 957 ++++ src/TortoiseMerge/libsvn_diff/utf_validate.c | 375 ++ src/TortoiseMerge/libsvn_diff/util.c | 5 +- src/TortoiseMerge/libsvn_diff/win32_xlate.c | 222 + src/TortoiseMerge/libsvn_diff/win32_xlate.h | 47 + src/TortoiseMerge/libsvn_diff/zconf.h | 279 ++ src/TortoiseMerge/libsvn_diff/zip.c | 719 +++ src/TortoiseMerge/libsvn_diff/zip.h | 150 + src/TortoiseMerge/libsvn_diff/zlib.h | 893 ++++ src/TortoiseMerge/libsvn_diff/zlibcpp.cpp | 131 + src/TortoiseMerge/libsvn_diff/zlibcpp.h | 39 + src/TortoiseMerge/libsvn_diff/zutil.c | 225 + src/TortoiseMerge/libsvn_diff/zutil.h | 220 + src/TortoiseMerge/svninclude/SVNLineDiff.h | 74 + src/TortoiseMerge/svninclude/apr.h | 638 --- src/TortoiseMerge/svninclude/apr_errno.h | 1312 ------ src/TortoiseMerge/svninclude/apr_file_info.h | 6 - src/TortoiseMerge/svninclude/apr_file_io.h | 21 - src/TortoiseMerge/svninclude/apr_general.h | 241 - src/TortoiseMerge/svninclude/apr_getopt.h | 61 - src/TortoiseMerge/svninclude/apr_hash.h | 6 - src/TortoiseMerge/svninclude/apr_mmap.h | 0 src/TortoiseMerge/svninclude/apr_pools.h | 31 - src/TortoiseMerge/svninclude/apr_sha1.h | 0 src/TortoiseMerge/svninclude/apr_strings.h | 361 -- src/TortoiseMerge/svninclude/apr_tables.h | 6 - src/TortoiseMerge/svninclude/apr_time.h | 7 - src/TortoiseMerge/svninclude/apr_want.h | 0 src/TortoiseMerge/svninclude/svn_auth.h | 1220 +++++ src/TortoiseMerge/svninclude/svn_checksum.h | 225 + src/TortoiseMerge/svninclude/svn_config.h | 565 +++ src/TortoiseMerge/svninclude/svn_ctype.h | 191 + src/TortoiseMerge/svninclude/svn_delta.h | 1230 +++++ src/TortoiseMerge/svninclude/svn_diff.h | 745 +++ src/TortoiseMerge/svninclude/svn_dso.h | 106 + src/TortoiseMerge/svninclude/svn_error.h | 84 +- src/TortoiseMerge/svninclude/svn_error_codes.h | 16 +- src/TortoiseMerge/svninclude/svn_io.h | 1666 +++++++ src/TortoiseMerge/svninclude/svn_mergeinfo.h | 452 ++ src/TortoiseMerge/svninclude/svn_opt.h | 741 +++ src/TortoiseMerge/svninclude/svn_path.h | 595 +++ src/TortoiseMerge/svninclude/svn_pools.h | 91 +- src/TortoiseMerge/svninclude/svn_ra.h | 2211 +++++++++ src/TortoiseMerge/svninclude/svn_ra_svn.h | 495 ++ src/TortoiseMerge/svninclude/svn_types.h | 167 +- src/TortoiseMerge/svninclude/svn_utf.h | 221 + src/TortoiseMerge/svninclude/svn_version.h | 258 ++ src/TortoiseMerge/svninclude/svn_wc.h | 5607 +++++++++++++++++++++++ 124 files changed, 42319 insertions(+), 3099 deletions(-) create mode 100644 src/TortoiseMerge/libsvn_diff/SVNLineDiff.cpp create mode 100644 src/TortoiseMerge/libsvn_diff/adler32.c create mode 100644 src/TortoiseMerge/libsvn_diff/checksum.c create mode 100644 src/TortoiseMerge/libsvn_diff/cmdline.c create mode 100644 src/TortoiseMerge/libsvn_diff/compress.c create mode 100644 src/TortoiseMerge/libsvn_diff/crc32.c create mode 100644 src/TortoiseMerge/libsvn_diff/ctype.c create mode 100644 src/TortoiseMerge/libsvn_diff/deflate.c create mode 100644 src/TortoiseMerge/libsvn_diff/deflate.h create mode 100644 src/TortoiseMerge/libsvn_diff/dirent_uri.c create mode 100644 src/TortoiseMerge/libsvn_diff/dso.c create mode 100644 src/TortoiseMerge/libsvn_diff/error.c create mode 100644 src/TortoiseMerge/libsvn_diff/gzio.c create mode 100644 src/TortoiseMerge/libsvn_diff/infblock.c create mode 100644 src/TortoiseMerge/libsvn_diff/infblock.h create mode 100644 src/TortoiseMerge/libsvn_diff/infcodes.c create mode 100644 src/TortoiseMerge/libsvn_diff/infcodes.h create mode 100644 src/TortoiseMerge/libsvn_diff/inffast.c create mode 100644 src/TortoiseMerge/libsvn_diff/inffast.h create mode 100644 src/TortoiseMerge/libsvn_diff/inffixed.h create mode 100644 src/TortoiseMerge/libsvn_diff/inflate.c create mode 100644 src/TortoiseMerge/libsvn_diff/inftrees.c create mode 100644 src/TortoiseMerge/libsvn_diff/inftrees.h create mode 100644 src/TortoiseMerge/libsvn_diff/infutil.c create mode 100644 src/TortoiseMerge/libsvn_diff/infutil.h create mode 100644 src/TortoiseMerge/libsvn_diff/io.c create mode 100644 src/TortoiseMerge/libsvn_diff/maketree.c create mode 100644 src/TortoiseMerge/libsvn_diff/md5.c create mode 100644 src/TortoiseMerge/libsvn_diff/md5.h create mode 100644 src/TortoiseMerge/libsvn_diff/path.c create mode 100644 src/TortoiseMerge/libsvn_diff/pool.c delete mode 100644 src/TortoiseMerge/libsvn_diff/porting.c create mode 100644 src/TortoiseMerge/libsvn_diff/readme.txt create mode 100644 src/TortoiseMerge/libsvn_diff/sha1.c create mode 100644 src/TortoiseMerge/libsvn_diff/sha1.h create mode 100644 src/TortoiseMerge/libsvn_diff/stream.c create mode 100644 src/TortoiseMerge/libsvn_diff/svn_base64.h create mode 100644 src/TortoiseMerge/libsvn_diff/svn_cmdline.h create mode 100644 src/TortoiseMerge/libsvn_diff/svn_dirent_uri.h create mode 100644 src/TortoiseMerge/libsvn_diff/svn_md5.h create mode 100644 src/TortoiseMerge/libsvn_diff/svn_nls.h create mode 100644 src/TortoiseMerge/libsvn_diff/svn_string.c create mode 100644 src/TortoiseMerge/libsvn_diff/svn_utf_private.h create mode 100644 src/TortoiseMerge/libsvn_diff/svn_xml.h create mode 100644 src/TortoiseMerge/libsvn_diff/trees.c create mode 100644 src/TortoiseMerge/libsvn_diff/trees.h create mode 100644 src/TortoiseMerge/libsvn_diff/uncompr.c create mode 100644 src/TortoiseMerge/libsvn_diff/unzip.c create mode 100644 src/TortoiseMerge/libsvn_diff/unzip.h create mode 100644 src/TortoiseMerge/libsvn_diff/utf.c create mode 100644 src/TortoiseMerge/libsvn_diff/utf_validate.c create mode 100644 src/TortoiseMerge/libsvn_diff/win32_xlate.c create mode 100644 src/TortoiseMerge/libsvn_diff/win32_xlate.h create mode 100644 src/TortoiseMerge/libsvn_diff/zconf.h create mode 100644 src/TortoiseMerge/libsvn_diff/zip.c create mode 100644 src/TortoiseMerge/libsvn_diff/zip.h create mode 100644 src/TortoiseMerge/libsvn_diff/zlib.h create mode 100644 src/TortoiseMerge/libsvn_diff/zlibcpp.cpp create mode 100644 src/TortoiseMerge/libsvn_diff/zlibcpp.h create mode 100644 src/TortoiseMerge/libsvn_diff/zutil.c create mode 100644 src/TortoiseMerge/libsvn_diff/zutil.h create mode 100644 src/TortoiseMerge/svninclude/SVNLineDiff.h delete mode 100644 src/TortoiseMerge/svninclude/apr.h delete mode 100644 src/TortoiseMerge/svninclude/apr_errno.h delete mode 100644 src/TortoiseMerge/svninclude/apr_file_info.h delete mode 100644 src/TortoiseMerge/svninclude/apr_file_io.h delete mode 100644 src/TortoiseMerge/svninclude/apr_general.h delete mode 100644 src/TortoiseMerge/svninclude/apr_getopt.h delete mode 100644 src/TortoiseMerge/svninclude/apr_hash.h delete mode 100644 src/TortoiseMerge/svninclude/apr_mmap.h delete mode 100644 src/TortoiseMerge/svninclude/apr_pools.h delete mode 100644 src/TortoiseMerge/svninclude/apr_sha1.h delete mode 100644 src/TortoiseMerge/svninclude/apr_strings.h delete mode 100644 src/TortoiseMerge/svninclude/apr_tables.h delete mode 100644 src/TortoiseMerge/svninclude/apr_time.h delete mode 100644 src/TortoiseMerge/svninclude/apr_want.h create mode 100644 src/TortoiseMerge/svninclude/svn_auth.h create mode 100644 src/TortoiseMerge/svninclude/svn_checksum.h create mode 100644 src/TortoiseMerge/svninclude/svn_config.h create mode 100644 src/TortoiseMerge/svninclude/svn_ctype.h create mode 100644 src/TortoiseMerge/svninclude/svn_delta.h create mode 100644 src/TortoiseMerge/svninclude/svn_diff.h create mode 100644 src/TortoiseMerge/svninclude/svn_dso.h create mode 100644 src/TortoiseMerge/svninclude/svn_io.h create mode 100644 src/TortoiseMerge/svninclude/svn_mergeinfo.h create mode 100644 src/TortoiseMerge/svninclude/svn_opt.h create mode 100644 src/TortoiseMerge/svninclude/svn_path.h create mode 100644 src/TortoiseMerge/svninclude/svn_ra.h create mode 100644 src/TortoiseMerge/svninclude/svn_ra_svn.h create mode 100644 src/TortoiseMerge/svninclude/svn_utf.h create mode 100644 src/TortoiseMerge/svninclude/svn_version.h create mode 100644 src/TortoiseMerge/svninclude/svn_wc.h diff --git a/src/TortoiseMerge/AboutDlg.cpp b/src/TortoiseMerge/AboutDlg.cpp index 258b4a7..617f251 100644 --- a/src/TortoiseMerge/AboutDlg.cpp +++ b/src/TortoiseMerge/AboutDlg.cpp @@ -19,10 +19,10 @@ #include "stdafx.h" #include "TortoiseMerge.h" #include "AboutDlg.h" -//#include "svn_version.h" -//#include "svn_diff.h" -//#include "..\..\\apr\include\apr_version.h" -//#include "..\..\apr-util\include\apu_version.h" +#include "svn_version.h" +#include "svn_diff.h" +#include "..\..\\apr\include\apr_version.h" +#include "..\..\apr-util\include\apu_version.h" #include "..\version.h" // CAboutDlg dialog @@ -93,7 +93,7 @@ BOOL CAboutDlg::OnInitDialog() // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon -#if 0 + //set the version string CString temp, boxtitle; boxtitle.Format(IDS_ABOUTVERSIONBOX, TSVN_VERMAJOR, TSVN_VERMINOR, TSVN_VERMICRO, TSVN_VERBUILD, _T(TSVN_PLATFORM), _T(TSVN_VERDATE)); @@ -117,7 +117,7 @@ BOOL CAboutDlg::OnInitDialog() m_cWebLink.SetURL(_T("http://tortoisesvn.net")); m_cSupportLink.SetURL(_T("http://tortoisesvn.tigris.org/contributors.html")); -#endif + return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } diff --git a/src/TortoiseMerge/AppUtils.cpp b/src/TortoiseMerge/AppUtils.cpp index 2780b21..92bcba4 100644 --- a/src/TortoiseMerge/AppUtils.cpp +++ b/src/TortoiseMerge/AppUtils.cpp @@ -1,6 +1,6 @@ // TortoiseMerge - a Diff/Patch program -// Copyright (C) 2006-2008 - TortoiseSVN +// Copyright (C) 2006-2009 - TortoiseSVN // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -19,15 +19,16 @@ #include "StdAfx.h" #include "Registry.h" #include "AppUtils.h" +#include "PathUtils.h" #include "UnicodeUtils.h" #include "SysProgressDlg.h" -//#include "svn_pools.h" -//#include "svn_io.h" -//#include "svn_path.h" -//#include "svn_diff.h" -//#include "svn_string.h" -//#include "svn_utf.h" +#include "svn_pools.h" +#include "svn_io.h" +#include "svn_path.h" +#include "svn_diff.h" +#include "svn_string.h" +#include "svn_utf.h" CAppUtils::CAppUtils(void) { @@ -43,15 +44,7 @@ BOOL CAppUtils::GetVersionedFile(CString sPath, CString sVersion, CString sSaveP if (sSCMPath.IsEmpty()) { // no path set, so use TortoiseSVN as default - sSCMPath = CRegString(_T("Software\\TortoiseGit\\ProcPath"), _T(""), false, HKEY_LOCAL_MACHINE); - if (sSCMPath.IsEmpty()) - { - TCHAR pszSCMPath[MAX_PATH]; - GetModuleFileName(NULL, pszSCMPath, MAX_PATH); - sSCMPath = pszSCMPath; - sSCMPath = sSCMPath.Left(sSCMPath.ReverseFind('\\')); - sSCMPath += _T("\\TortoiseProc.exe"); - } + sSCMPath = CPathUtils::GetAppDirectory() + _T("TortoiseProc.exe"); sSCMPath += _T(" /command:cat /path:\"%1\" /revision:%2 /savepath:\"%3\" /hwnd:%4"); } CString sTemp; @@ -105,7 +98,7 @@ bool CAppUtils::CreateUnifiedDiff(const CString& orig, const CString& modified, apr_file_t * outfile = NULL; apr_pool_t * pool = svn_pool_create(NULL); - svn_error_t * err = svn_io_file_open (&outfile, svn_path_canonicalize(CUnicodeUtils::GetUTF8(output), pool), + svn_error_t * err = svn_io_file_open (&outfile, svn_path_internal_style(CUnicodeUtils::GetUTF8(output), pool), APR_WRITE | APR_CREATE | APR_BINARY | APR_TRUNCATE, APR_OS_DEFAULT, pool); if (err == NULL) @@ -117,12 +110,12 @@ bool CAppUtils::CreateUnifiedDiff(const CString& orig, const CString& modified, svn_diff_file_options_t * opts = svn_diff_file_options_create(pool); opts->ignore_eol_style = false; opts->ignore_space = svn_diff_file_ignore_space_none; - err = svn_diff_file_diff_2(&diff, svn_path_canonicalize(CUnicodeUtils::GetUTF8(orig), pool), - svn_path_canonicalize(CUnicodeUtils::GetUTF8(modified), pool), opts, pool); + err = svn_diff_file_diff_2(&diff, svn_path_internal_style(CUnicodeUtils::GetUTF8(orig), pool), + svn_path_internal_style(CUnicodeUtils::GetUTF8(modified), pool), opts, pool); if (err == NULL) { - err = svn_diff_file_output_unified(stream, diff, svn_path_canonicalize(CUnicodeUtils::GetUTF8(orig), pool), - svn_path_canonicalize(CUnicodeUtils::GetUTF8(modified), pool), + err = svn_diff_file_output_unified(stream, diff, svn_path_internal_style(CUnicodeUtils::GetUTF8(orig), pool), + svn_path_internal_style(CUnicodeUtils::GetUTF8(modified), pool), NULL, NULL, pool); svn_stream_close(stream); } @@ -142,9 +135,8 @@ bool CAppUtils::CreateUnifiedDiff(const CString& orig, const CString& modified, return true; } -CString CAppUtils::GetErrorString(git_error_t * Err) +CString CAppUtils::GetErrorString(svn_error_t * Err) { -#if 0 CString msg; CString temp; char errbuf[256]; @@ -210,7 +202,6 @@ CString CAppUtils::GetErrorString(git_error_t * Err) } return msg; } -#endif return _T(""); } diff --git a/src/TortoiseMerge/AppUtils.h b/src/TortoiseMerge/AppUtils.h index 2e7bf40..96a5ccf 100644 --- a/src/TortoiseMerge/AppUtils.h +++ b/src/TortoiseMerge/AppUtils.h @@ -17,8 +17,7 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // #pragma once -//#include "svn_types.h" -#include "GitStatus.h" +#include "svn_types.h" class CSysProgressDlg; @@ -49,6 +48,6 @@ public: static bool CreateUnifiedDiff(const CString& orig, const CString& modified, const CString& output, bool bShowError); static bool HasClipboardFormat(UINT format); - static CString GetErrorString(git_error_t * Err); + static CString GetErrorString(svn_error_t * Err); }; diff --git a/src/TortoiseMerge/BaseView.cpp b/src/TortoiseMerge/BaseView.cpp index 76fd3cd..24fdfc2 100644 --- a/src/TortoiseMerge/BaseView.cpp +++ b/src/TortoiseMerge/BaseView.cpp @@ -1,6 +1,6 @@ // TortoiseMerge - a Diff/Patch program -// Copyright (C) 2003-2008 - TortoiseSVN +// Copyright (C) 2003-2009 - TortoiseSVN // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -40,6 +40,8 @@ #define INLINEREMOVED_COLOR RGB(200, 100, 100) #define MODIFIED_COLOR RGB(220, 220, 255) +#define IDT_SCROLLTIMER 101 + CBaseView * CBaseView::m_pwndLeft = NULL; CBaseView * CBaseView::m_pwndRight = NULL; CBaseView * CBaseView::m_pwndBottom = NULL; @@ -182,6 +184,7 @@ BEGIN_MESSAGE_MAP(CBaseView, CView) ON_COMMAND(ID_EDIT_CUT, &CBaseView::OnEditCut) ON_COMMAND(ID_EDIT_PASTE, &CBaseView::OnEditPaste) ON_WM_MOUSELEAVE() + ON_WM_TIMER() END_MESSAGE_MAP() @@ -1369,14 +1372,13 @@ bool CBaseView::DrawInlineDiff(CDC *pDC, const CRect &rc, int nLineIndex, const CString diffline; ExpandChars(pszDiffChars, 0, nDiffLength, diffline); -// svn_diff_t * diff = NULL; -// m_svnlinediff.Diff(&diff, line, line.GetLength(), diffline, diffline.GetLength(), m_bInlineWordDiff); -// if (!diff || !SVNLineDiff::ShowInlineDiff(diff)) -// return false; + svn_diff_t * diff = NULL; + m_svnlinediff.Diff(&diff, line, line.GetLength(), diffline, diffline.GetLength(), m_bInlineWordDiff); + if (!diff || !SVNLineDiff::ShowInlineDiff(diff)) + return false; int lineoffset = 0; std::deque removedPositions; -#if 0 while (diff) { apr_off_t len = diff->original_length; @@ -1399,7 +1401,6 @@ bool CBaseView::DrawInlineDiff(CDC *pDC, const CRect &rc, int nLineIndex, const // Draw vertical bars at removed chunks' positions. for (std::deque::iterator it = removedPositions.begin(); it != removedPositions.end(); ++it) pDC->FillSolidRect(*it, rc.top, 1, rc.Height(), m_InlineRemovedBk); -#endif return true; } @@ -1856,43 +1857,8 @@ void CBaseView::RefreshViews() void CBaseView::GoToFirstDifference() { - int nCenterPos = 0; - if ((m_pViewData)&&(0 < m_pViewData->GetCount())) - { - while (nCenterPos < m_pViewData->GetCount()) - { - DiffStates linestate = m_pViewData->GetState(nCenterPos); - if ((linestate != DIFFSTATE_NORMAL) && - (linestate != DIFFSTATE_UNKNOWN)) - break; - nCenterPos++; - } - if (nCenterPos >= m_pViewData->GetCount()) - nCenterPos = m_pViewData->GetCount()-1; - int nTopPos = nCenterPos - (GetScreenLines()/2); - if (nTopPos < 0) - nTopPos = 0; - if (m_pwndLeft) - { - m_pwndLeft->m_ptCaretPos.x = 0; - m_pwndLeft->m_ptCaretPos.y = nCenterPos; - m_pwndLeft->m_nCaretGoalPos = 0; - } - if (m_pwndRight) - { - m_pwndRight->m_ptCaretPos.x = 0; - m_pwndRight->m_ptCaretPos.y = nCenterPos; - m_pwndRight->m_nCaretGoalPos = 0; - } - if (m_pwndBottom) - { - m_pwndBottom->m_ptCaretPos.x = 0; - m_pwndBottom->m_ptCaretPos.y = nCenterPos; - m_pwndBottom->m_nCaretGoalPos = 0; - } - ScrollAllToLine(nTopPos); - RecalcAllVertScrollBars(TRUE); - } + m_ptCaretPos.y = 0; + SelectNextBlock(1, false, false); } void CBaseView::HiglightLines(int start, int end /* = -1 */) @@ -1950,7 +1916,7 @@ void CBaseView::OnMergePreviousdifference() SelectNextBlock(-1, false); } -void CBaseView::SelectNextBlock(int nDirection, bool bConflict) +void CBaseView::SelectNextBlock(int nDirection, bool bConflict, bool bSkipEndOfCurrentBlock /* = true */) { if (! m_pViewData) return; @@ -1966,11 +1932,14 @@ void CBaseView::SelectNextBlock(int nDirection, bool bConflict) if (nCenterPos >= m_pViewData->GetCount()) nCenterPos = m_pViewData->GetCount()-1; - // Find end of current block - DiffStates state = m_pViewData->GetState(nCenterPos); - while ((nCenterPos != nLimit) && - (m_pViewData->GetState(nCenterPos)==state)) - nCenterPos += nDirection; + if (bSkipEndOfCurrentBlock) + { + // Find end of current block + DiffStates state = m_pViewData->GetState(nCenterPos); + while ((nCenterPos != nLimit) && + (m_pViewData->GetState(nCenterPos)==state)) + nCenterPos += nDirection; + } // Find next diff/conflict block while (nCenterPos != nLimit) @@ -1991,10 +1960,10 @@ void CBaseView::SelectNextBlock(int nDirection, bool bConflict) } // Find end of new block - state = m_pViewData->GetState(nCenterPos); + DiffStates state = m_pViewData->GetState(nCenterPos); int nBlockEnd = nCenterPos; while ((nBlockEnd != nLimit) && - (state == m_pViewData->GetState(nBlockEnd + nDirection))) + (state == m_pViewData->GetState(nBlockEnd + nDirection))) nBlockEnd += nDirection; int nTopPos = nCenterPos - (GetScreenLines()/2); @@ -2293,6 +2262,12 @@ void CBaseView::OnEditCopy() void CBaseView::OnMouseMove(UINT nFlags, CPoint point) { + if (m_pMainFrame->m_nMoveMovesToIgnore > 0) { + --m_pMainFrame->m_nMoveMovesToIgnore; + CView::OnMouseMove(nFlags, point); + return; + } + int nMouseLine = (((point.y - HEADERHEIGHT) / GetLineHeight()) + m_nTopLine); nMouseLine--; //we need the index if (nMouseLine < -1) @@ -2301,19 +2276,43 @@ void CBaseView::OnMouseMove(UINT nFlags, CPoint point) } ShowDiffLines(nMouseLine); + KillTimer(IDT_SCROLLTIMER); if (nFlags & MK_LBUTTON) { + int saveMouseLine = nMouseLine >= 0 ? nMouseLine : 0; + saveMouseLine = saveMouseLine < GetLineCount() ? saveMouseLine : GetLineCount() - 1; + int charIndex = CalculateCharIndex(saveMouseLine, m_nOffsetChar + (point.x - GetMarginWidth()) / GetCharWidth()); if (((m_nSelBlockStart >= 0)&&(m_nSelBlockEnd >= 0))&& ((nMouseLine >= m_nTopLine)&&(nMouseLine < GetLineCount()))) { m_ptCaretPos.y = nMouseLine; - m_ptCaretPos.x = CalculateCharIndex(m_ptCaretPos.y, m_nOffsetChar + (point.x - GetMarginWidth()) / GetCharWidth()); + m_ptCaretPos.x = charIndex; UpdateGoalPos(); AdjustSelection(); UpdateCaret(); Invalidate(); UpdateWindow(); } + if (nMouseLine < m_nTopLine) + { + ScrollToLine(m_nTopLine-1, TRUE); + SetTimer(IDT_SCROLLTIMER, 20, NULL); + } + if (nMouseLine >= m_nTopLine + GetScreenLines()) + { + ScrollToLine(m_nTopLine+1, TRUE); + SetTimer(IDT_SCROLLTIMER, 20, NULL); + } + if (charIndex <= m_nOffsetChar) + { + ScrollSide(-1); + SetTimer(IDT_SCROLLTIMER, 20, NULL); + } + if (charIndex >= (GetScreenChars()+m_nOffsetChar)) + { + ScrollSide(1); + SetTimer(IDT_SCROLLTIMER, 20, NULL); + } } if (!m_bMouseWithin) @@ -2333,10 +2332,55 @@ void CBaseView::OnMouseLeave() { ShowDiffLines(-1); m_bMouseWithin = FALSE; - + KillTimer(IDT_SCROLLTIMER); CView::OnMouseLeave(); } +void CBaseView::OnTimer(UINT_PTR nIDEvent) +{ + if (nIDEvent == IDT_SCROLLTIMER) + { + POINT point; + GetCursorPos(&point); + ScreenToClient(&point); + int nMouseLine = (((point.y - HEADERHEIGHT) / GetLineHeight()) + m_nTopLine); + nMouseLine--; //we need the index + if (nMouseLine < -1) + { + nMouseLine = -1; + } + if (GetKeyState(VK_LBUTTON)&0x8000) + { + int saveMouseLine = nMouseLine >= 0 ? nMouseLine : 0; + saveMouseLine = saveMouseLine < GetLineCount() ? saveMouseLine : GetLineCount() - 1; + int charIndex = CalculateCharIndex(saveMouseLine, m_nOffsetChar + (point.x - GetMarginWidth()) / GetCharWidth()); + if (nMouseLine < m_nTopLine) + { + ScrollToLine(m_nTopLine-1, TRUE); + SetTimer(IDT_SCROLLTIMER, 20, NULL); + } + if (nMouseLine >= m_nTopLine + GetScreenLines()) + { + ScrollToLine(m_nTopLine+1, TRUE); + SetTimer(IDT_SCROLLTIMER, 20, NULL); + } + if (charIndex <= m_nOffsetChar) + { + ScrollSide(-1); + SetTimer(IDT_SCROLLTIMER, 20, NULL); + } + if (charIndex >= GetScreenChars()) + { + ScrollSide(1); + SetTimer(IDT_SCROLLTIMER, 20, NULL); + } + } + + } + + CView::OnTimer(nIDEvent); +} + void CBaseView::SelectLines(int nLine1, int nLine2) { if (nLine2 == -1) @@ -2383,6 +2427,7 @@ void CBaseView::UseTheirAndYourBlock(viewstate &rightstate, viewstate &bottomsta m_pwndBottom->m_pViewData->SetLine(i, m_pwndLeft->m_pViewData->GetLine(i)); bottomstate.linestates[i] = m_pwndBottom->m_pViewData->GetState(i); m_pwndBottom->m_pViewData->SetState(i, m_pwndLeft->m_pViewData->GetState(i)); + m_pwndBottom->m_pViewData->SetLineEnding(i, EOL_AUTOLINE); if (m_pwndBottom->IsLineConflicted(i)) { if (m_pwndLeft->m_pViewData->GetState(i) == DIFFSTATE_CONFLICTEMPTY) @@ -2390,6 +2435,7 @@ void CBaseView::UseTheirAndYourBlock(viewstate &rightstate, viewstate &bottomsta else m_pwndBottom->m_pViewData->SetState(i, DIFFSTATE_CONFLICTRESOLVED); } + m_pwndLeft->m_pViewData->SetState(i, DIFFSTATE_YOURSADDED); } // your block is done, now insert their block @@ -2405,6 +2451,7 @@ void CBaseView::UseTheirAndYourBlock(viewstate &rightstate, viewstate &bottomsta else m_pwndBottom->m_pViewData->SetState(index, DIFFSTATE_CONFLICTRESOLVED); } + m_pwndRight->m_pViewData->SetState(i, DIFFSTATE_THEIRSADDED); index++; } // adjust line numbers @@ -2418,10 +2465,10 @@ void CBaseView::UseTheirAndYourBlock(viewstate &rightstate, viewstate &bottomsta // now insert an empty block in both yours and theirs for (int emptyblocks=0; emptyblocks < m_nSelBlockEnd-m_nSelBlockStart+1; ++emptyblocks) { - leftstate.addedlines.push_back(m_nSelBlockStart); - m_pwndLeft->m_pViewData->InsertData(m_nSelBlockStart, _T(""), DIFFSTATE_EMPTY, -1, EOL_NOENDING); - m_pwndRight->m_pViewData->InsertData(m_nSelBlockEnd+1, _T(""), DIFFSTATE_EMPTY, -1, EOL_NOENDING); - rightstate.addedlines.push_back(m_nSelBlockEnd+1); + rightstate.addedlines.push_back(m_nSelBlockStart); + m_pwndRight->m_pViewData->InsertData(m_nSelBlockStart, _T(""), DIFFSTATE_EMPTY, -1, EOL_NOENDING); + m_pwndLeft->m_pViewData->InsertData(m_nSelBlockEnd+1, _T(""), DIFFSTATE_EMPTY, -1, EOL_NOENDING); + leftstate.addedlines.push_back(m_nSelBlockEnd+1); } RecalcAllVertScrollBars(); m_pwndBottom->SetModified(); @@ -2440,6 +2487,7 @@ void CBaseView::UseYourAndTheirBlock(viewstate &rightstate, viewstate &bottomsta bottomstate.linestates[i] = m_pwndBottom->m_pViewData->GetState(i); m_pwndBottom->m_pViewData->SetState(i, m_pwndRight->m_pViewData->GetState(i)); rightstate.linestates[i] = m_pwndRight->m_pViewData->GetState(i); + m_pwndBottom->m_pViewData->SetLineEnding(i, EOL_AUTOLINE); if (m_pwndBottom->IsLineConflicted(i)) { if (m_pwndRight->m_pViewData->GetState(i) == DIFFSTATE_CONFLICTEMPTY) @@ -3048,3 +3096,4 @@ void CBaseView::OnEditPaste() } } + diff --git a/src/TortoiseMerge/BaseView.h b/src/TortoiseMerge/BaseView.h index 0975d9f..b0635fc 100644 --- a/src/TortoiseMerge/BaseView.h +++ b/src/TortoiseMerge/BaseView.h @@ -18,7 +18,7 @@ // #pragma once #include "DiffData.h" -//#include "SVNLineDiff.h" +#include "SVNLineDiff.h" #include "ScrollTool.h" #include "Undo.h" #include "LocatorBar.h" @@ -125,6 +125,7 @@ protected: afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnEditCopy(); afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnTimer(UINT_PTR nIDEvent); afx_msg void OnMouseLeave(); afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnCaretDown(); @@ -211,7 +212,7 @@ protected: void DrawText(CDC * pDC, const CRect &rc, LPCTSTR text, int textlength, int nLineIndex, POINT coords, bool bModified, bool bInlineDiff); void ClearCurrentSelection(); void AdjustSelection(); - void SelectNextBlock(int nDirection, bool bConflict); + void SelectNextBlock(int nDirection, bool bConflict, bool bSkipEndOfCurrentBlock = true); void RemoveLine(int nLineIndex); void RemoveSelectedText(); @@ -232,7 +233,7 @@ protected: COLORREF m_WhiteSpaceFg; UINT m_nStatusBarID; ///< The ID of the status bar pane used by this view. Must be set by the parent class. -// SVNLineDiff m_svnlinediff; + SVNLineDiff m_svnlinediff; BOOL m_bOtherDiffChecked; BOOL m_bModified; BOOL m_bFocused; diff --git a/src/TortoiseMerge/BottomView.cpp b/src/TortoiseMerge/BottomView.cpp index 54862dc..d692727 100644 --- a/src/TortoiseMerge/BottomView.cpp +++ b/src/TortoiseMerge/BottomView.cpp @@ -1,6 +1,6 @@ // TortoiseMerge - a Diff/Patch program -// Copyright (C) 2006-2008 - TortoiseSVN +// Copyright (C) 2006-2009 - TortoiseSVN // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -137,6 +137,7 @@ void CBottomView::UseTheirTextBlock() m_pViewData->SetLine(i, m_pwndLeft->m_pViewData->GetLine(i)); bottomstate.linestates[i] = m_pViewData->GetState(i); m_pViewData->SetState(i, m_pwndLeft->m_pViewData->GetState(i)); + m_pViewData->SetLineEnding(i, EOL_AUTOLINE); if (IsLineConflicted(i)) { if (m_pwndLeft->m_pViewData->GetState(i) == DIFFSTATE_CONFLICTEMPTY) @@ -164,6 +165,8 @@ void CBottomView::UseMyTextBlock() m_pViewData->SetLine(i, m_pwndRight->m_pViewData->GetLine(i)); bottomstate.linestates[i] = m_pViewData->GetState(i); m_pViewData->SetState(i, m_pwndRight->m_pViewData->GetState(i)); + m_pViewData->SetLineEnding(i, EOL_AUTOLINE); + m_pViewData->SetLineEnding(i, EOL_AUTOLINE); { if (m_pwndRight->m_pViewData->GetState(i) == DIFFSTATE_CONFLICTEMPTY) m_pViewData->SetState(i, DIFFSTATE_CONFLICTRESOLVEDEMPTY); diff --git a/src/TortoiseMerge/DiffData.cpp b/src/TortoiseMerge/DiffData.cpp index 0bbcd64..8c0b143 100644 --- a/src/TortoiseMerge/DiffData.cpp +++ b/src/TortoiseMerge/DiffData.cpp @@ -1,6 +1,6 @@ // TortoiseMerge - a Diff/Patch program -// Copyright (C) 2006-2008 - TortoiseSVN +// Copyright (C) 2006-2009 - TortoiseSVN // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -17,6 +17,8 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // #include "StdAfx.h" +#include "svn_version.h" +#include "svn_io.h" #include "diff.h" #include "TempFiles.h" #include "registry.h" @@ -24,7 +26,7 @@ #include "Diffdata.h" #include "UnicodeUtils.h" #include "GitAdminDir.h" - +#include "svn_dso.h" #pragma warning(push) #pragma warning(disable: 4702) // unreachable code @@ -37,9 +39,9 @@ int CDiffData::abort_on_pool_failure (int /*retcode*/) CDiffData::CDiffData(void) { -// apr_initialize(); -// svn_dso_initialize(); -// g_SVNAdminDir.Init(); + apr_initialize(); + svn_dso_initialize2(); + g_GitAdminDir.Init(); m_bBlame = false; @@ -49,8 +51,8 @@ CDiffData::CDiffData(void) CDiffData::~CDiffData(void) { -//// g_SVNAdminDir.Close(); -// apr_terminate(); + g_GitAdminDir.Close(); + apr_terminate(); } int CDiffData::GetLineCount() @@ -87,7 +89,6 @@ LPCTSTR CDiffData::GetLineChars(int index) BOOL CDiffData::Load() { - CString sConvertedBaseFilename, sConvertedTheirFilename, sConvertedYourFilename; apr_pool_t * pool; @@ -180,17 +181,26 @@ BOOL CDiffData::Load() int lengthHint = max(m_arBaseFile.GetCount(), m_arTheirFile.GetCount()); lengthHint = max(lengthHint, m_arYourFile.GetCount()); - m_YourBaseBoth.Reserve(lengthHint); - m_YourBaseLeft.Reserve(lengthHint); - m_YourBaseRight.Reserve(lengthHint); + try + { + m_YourBaseBoth.Reserve(lengthHint); + m_YourBaseLeft.Reserve(lengthHint); + m_YourBaseRight.Reserve(lengthHint); - m_TheirBaseBoth.Reserve(lengthHint); - m_TheirBaseLeft.Reserve(lengthHint); - m_TheirBaseRight.Reserve(lengthHint); + m_TheirBaseBoth.Reserve(lengthHint); + m_TheirBaseLeft.Reserve(lengthHint); + m_TheirBaseRight.Reserve(lengthHint); - m_arDiff3LinesBase.Reserve(lengthHint); - m_arDiff3LinesYour.Reserve(lengthHint); - m_arDiff3LinesTheir.Reserve(lengthHint); + m_arDiff3LinesBase.Reserve(lengthHint); + m_arDiff3LinesYour.Reserve(lengthHint); + m_arDiff3LinesTheir.Reserve(lengthHint); + } + catch (CMemoryException* e) + { + e->GetErrorMessage(m_sError.GetBuffer(255), 255); + m_sError.ReleaseBuffer(); + return FALSE; + } // Is this a two-way diff? if (IsBaseFileInUse() && IsYourFileInUse() && !IsTheirFileInUse()) @@ -219,20 +229,17 @@ BOOL CDiffData::Load() } apr_pool_destroy (pool); // free the allocated memory - - return TRUE; } bool -CDiffData::DoTwoWayDiff(const CString& sBaseFilename, const CString& sYourFilename, DWORD dwIgnoreWS, bool bIgnoreEOL,apr_pool_t *pool) +CDiffData::DoTwoWayDiff(const CString& sBaseFilename, const CString& sYourFilename, DWORD dwIgnoreWS, bool bIgnoreEOL, apr_pool_t * pool) { // convert CString filenames (UTF-16 or ANSI) to UTF-8 CStringA sBaseFilenameUtf8 = CUnicodeUtils::GetUTF8(sBaseFilename); CStringA sYourFilenameUtf8 = CUnicodeUtils::GetUTF8(sYourFilename); - svn_diff_t * diffYourBase = NULL; svn_error_t * svnerr = NULL; svn_diff_file_options_t * options = svn_diff_file_options_create(pool); @@ -462,13 +469,12 @@ CDiffData::DoTwoWayDiff(const CString& sBaseFilename, const CString& sYourFilena } bool -CDiffData::DoThreeWayDiff(const CString& sBaseFilename, const CString& sYourFilename, const CString& sTheirFilename, DWORD dwIgnoreWS, bool bIgnoreEOL, bool bIgnoreCase,apr_pool_t *pool) +CDiffData::DoThreeWayDiff(const CString& sBaseFilename, const CString& sYourFilename, const CString& sTheirFilename, DWORD dwIgnoreWS, bool bIgnoreEOL, bool bIgnoreCase, apr_pool_t * pool) { // convert CString filenames (UTF-16 or ANSI) to UTF-8 CStringA sBaseFilenameUtf8 = CUnicodeUtils::GetUTF8(sBaseFilename); CStringA sYourFilenameUtf8 = CUnicodeUtils::GetUTF8(sYourFilename); CStringA sTheirFilenameUtf8 = CUnicodeUtils::GetUTF8(sTheirFilename); - svn_diff_t * diffTheirYourBase = NULL; svn_diff_file_options_t * options = svn_diff_file_options_create(pool); options->ignore_eol_style = bIgnoreEOL; diff --git a/src/TortoiseMerge/DiffData.h b/src/TortoiseMerge/DiffData.h index ee698b6..d54220a 100644 --- a/src/TortoiseMerge/DiffData.h +++ b/src/TortoiseMerge/DiffData.h @@ -52,7 +52,7 @@ public: private: bool DoTwoWayDiff(const CString& sBaseFilename, const CString& sYourFilename, DWORD dwIgnoreWS, bool bIgnoreEOL, apr_pool_t * pool); - bool DoThreeWayDiff(const CString& sBaseFilename, const CString& sYourFilename, const CString& sTheirFilename, DWORD dwIgnoreWS, bool bIgnoreEOL, bool bIgnoreCase,apr_pool_t * pool); + bool DoThreeWayDiff(const CString& sBaseFilename, const CString& sYourFilename, const CString& sTheirFilename, DWORD dwIgnoreWS, bool bIgnoreEOL, bool bIgnoreCase, apr_pool_t * pool); public: diff --git a/src/TortoiseMerge/FileTextLines.cpp b/src/TortoiseMerge/FileTextLines.cpp index 55999da..41071c9 100644 --- a/src/TortoiseMerge/FileTextLines.cpp +++ b/src/TortoiseMerge/FileTextLines.cpp @@ -1,6 +1,6 @@ // TortoiseMerge - a Diff/Patch program -// Copyright (C) 2007-2008 - TortoiseSVN +// Copyright (C) 2007-2009 - TortoiseSVN // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -452,7 +452,7 @@ BOOL CFileTextLines::Save(const CString& sFilePath, bool bSaveAsUTF8, DWORD dwIg if (bIgnoreCase) sLine = sLine.MakeLower(); file.Write((LPCTSTR)sLine, sLine.GetLength()*sizeof(TCHAR)); - if ((ending == EOL_AUTOLINE)||(ending == EOL_NOENDING)) + if (ending == EOL_AUTOLINE) ending = m_LineEndings; switch (ending) { @@ -488,7 +488,7 @@ BOOL CFileTextLines::Save(const CString& sFilePath, bool bSaveAsUTF8, DWORD dwIg sLine = sLine.MakeLower(); if ((m_bReturnAtEnd)||(i != GetCount()-1)) { - if ((ending == EOL_AUTOLINE)||(ending == EOL_NOENDING)) + if (ending == EOL_AUTOLINE) ending = m_LineEndings; switch (ending) { @@ -530,7 +530,7 @@ BOOL CFileTextLines::Save(const CString& sFilePath, bool bSaveAsUTF8, DWORD dwIg if ((m_bReturnAtEnd)||(i != GetCount()-1)) { - if ((ending == EOL_AUTOLINE)||(ending == EOL_NOENDING)) + if (ending == EOL_AUTOLINE) ending = m_LineEndings; switch (ending) { diff --git a/src/TortoiseMerge/LeftView.cpp b/src/TortoiseMerge/LeftView.cpp index 653c197..433d447 100644 --- a/src/TortoiseMerge/LeftView.cpp +++ b/src/TortoiseMerge/LeftView.cpp @@ -1,6 +1,6 @@ // TortoiseMerge - a Diff/Patch program -// Copyright (C) 2006-2008 - TortoiseSVN +// Copyright (C) 2006-2009 - TortoiseSVN // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -127,6 +127,7 @@ bool CLeftView::OnContextMenu(CPoint point, int /*nLine*/, DiffStates state) m_pwndBottom->m_pViewData->SetLine(i, m_pViewData->GetLine(i)); bottomstate.linestates[i] = m_pwndBottom->m_pViewData->GetState(i); m_pwndBottom->m_pViewData->SetState(i, m_pViewData->GetState(i)); + m_pwndBottom->m_pViewData->SetLineEnding(i, m_pViewData->GetLineEnding(i)); if (m_pwndBottom->IsLineConflicted(i)) { if (m_pViewData->GetState(i) == DIFFSTATE_CONFLICTEMPTY) @@ -143,14 +144,15 @@ bool CLeftView::OnContextMenu(CPoint point, int /*nLine*/, DiffStates state) { rightstate.difflines[i] = m_pwndRight->m_pViewData->GetLine(i); m_pwndRight->m_pViewData->SetLine(i, m_pViewData->GetLine(i)); - DiffStates state = m_pViewData->GetState(i); - switch (state) + m_pwndRight->m_pViewData->SetLineEnding(i, m_pViewData->GetLineEnding(i)); + DiffStates state2 = m_pViewData->GetState(i); + switch (state2) { case DIFFSTATE_CONFLICTEMPTY: case DIFFSTATE_UNKNOWN: case DIFFSTATE_EMPTY: rightstate.linestates[i] = m_pwndRight->m_pViewData->GetState(i); - m_pwndRight->m_pViewData->SetState(i, state); + m_pwndRight->m_pViewData->SetState(i, state2); break; case DIFFSTATE_YOURSADDED: case DIFFSTATE_IDENTICALADDED: @@ -191,6 +193,7 @@ bool CLeftView::OnContextMenu(CPoint point, int /*nLine*/, DiffStates state) m_pwndBottom->m_pViewData->SetLine(i, m_pViewData->GetLine(i)); bottomstate.linestates[i] = m_pwndBottom->m_pViewData->GetState(i); m_pwndBottom->m_pViewData->SetState(i, m_pViewData->GetState(i)); + m_pwndBottom->m_pViewData->SetLineEnding(i, EOL_AUTOLINE); if (m_pwndBottom->IsLineConflicted(i)) { if (m_pViewData->GetState(i) == DIFFSTATE_CONFLICTEMPTY) @@ -207,8 +210,9 @@ bool CLeftView::OnContextMenu(CPoint point, int /*nLine*/, DiffStates state) { rightstate.difflines[i] = m_pwndRight->m_pViewData->GetLine(i); m_pwndRight->m_pViewData->SetLine(i, m_pViewData->GetLine(i)); - DiffStates state = m_pViewData->GetState(i); - switch (state) + m_pwndRight->m_pViewData->SetLineEnding(i, EOL_AUTOLINE); + DiffStates state2 = m_pViewData->GetState(i); + switch (state2) { case DIFFSTATE_ADDED: case DIFFSTATE_CONFLICTADDED: @@ -222,7 +226,7 @@ bool CLeftView::OnContextMenu(CPoint point, int /*nLine*/, DiffStates state) case DIFFSTATE_YOURSADDED: case DIFFSTATE_EMPTY: rightstate.linestates[i] = m_pwndRight->m_pViewData->GetState(i); - m_pwndRight->m_pViewData->SetState(i, state); + m_pwndRight->m_pViewData->SetState(i, state2); break; case DIFFSTATE_IDENTICALREMOVED: case DIFFSTATE_REMOVED: diff --git a/src/TortoiseMerge/LocatorBar.cpp b/src/TortoiseMerge/LocatorBar.cpp index 883c0b4..1d74b5a 100644 --- a/src/TortoiseMerge/LocatorBar.cpp +++ b/src/TortoiseMerge/LocatorBar.cpp @@ -188,7 +188,6 @@ void CLocatorBar::OnPaint() { identcount = m_arLeftIdent.GetAt(i); state = m_arLeftState.GetAt(i); - COLORREF color, color2; CDiffColors::GetInstance().GetColors((DiffStates)state, color, color2); if ((DiffStates)state != DIFFSTATE_NORMAL) cacheDC.FillSolidRect(rect.left, height*linecount/m_nLines, @@ -206,7 +205,6 @@ void CLocatorBar::OnPaint() { identcount = m_arRightIdent.GetAt(i); state = m_arRightState.GetAt(i); - COLORREF color, color2; CDiffColors::GetInstance().GetColors((DiffStates)state, color, color2); if ((DiffStates)state != DIFFSTATE_NORMAL) cacheDC.FillSolidRect(rect.left + (width*2/3), height*linecount/m_nLines, @@ -223,7 +221,6 @@ void CLocatorBar::OnPaint() { identcount = m_arBottomIdent.GetAt(i); state = m_arBottomState.GetAt(i); - COLORREF color, color2; CDiffColors::GetInstance().GetColors((DiffStates)state, color, color2); if ((DiffStates)state != DIFFSTATE_NORMAL) cacheDC.FillSolidRect(rect.left + (width/3), height*linecount/m_nLines, @@ -257,7 +254,7 @@ void CLocatorBar::OnPaint() { for (int j=fishstart; jm_nTopLine : -1; int nOldLineNumber = m_pwndLeftView && m_pwndLeftView->m_pViewData ? m_pwndLeftView->m_pViewData->GetLineNumber(m_pwndLeftView->m_nTopLine) : -1; @@ -761,22 +764,30 @@ bool CMainFrame::LoadViews(bool bRetainPosition) UpdateLayout(); SetActiveView(pwndActiveView); - if (bRetainPosition && pwndActiveView->m_pViewData && nOldLineNumber >= 0) + if (bRetainPosition && m_pwndLeftView->m_pViewData) { - if (int n = pwndActiveView->m_pViewData->FindLineNumber(nOldLineNumber)) - { - pwndActiveView->ScrollAllToLine(n); - POINT p; - p.x = 0; - p.y = n; - pwndActiveView->SetCaretPosition(p); - } + int n = nOldLineNumber; + if (n >= 0) + n = m_pwndLeftView->m_pViewData->FindLineNumber(n); + if (n < 0) + n = nOldLine; + + m_pwndLeftView->ScrollAllToLine(n); + POINT p; + p.x = 0; + p.y = n; + m_pwndLeftView->SetCaretPosition(p); } else { bool bGoFirstDiff = (0 != (DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\FirstDiffOnLoad"), TRUE)); - if (bGoFirstDiff) + if (bGoFirstDiff) { pwndActiveView->GoToFirstDifference(); + // Ignore the first few Mouse Move messages, so that the line diff stays on + // the first diff line until the user actually moves the mouse + m_nMoveMovesToIgnore = 3; + } + } // Avoid incorrect rendering of active pane. m_pwndBottomView->ScrollToChar(0); @@ -812,11 +823,11 @@ void CMainFrame::UpdateLayout() void CMainFrame::OnSize(UINT nType, int cx, int cy) { - if (m_bInitSplitter && nType != SIZE_MINIMIZED) - { + if (m_bInitSplitter && nType != SIZE_MINIMIZED) + { UpdateLayout(); - } - CFrameWndEx::OnSize(nType, cx, cy); + } + CFrameWndEx::OnSize(nType, cx, cy); } void CMainFrame::OnViewWhitespaces() @@ -873,6 +884,24 @@ void CMainFrame::OnViewOnewaydiff() LoadViews(true); } +void CMainFrame::ShowDiffBar(bool bShow) +{ + if (bShow) + { + // restore the line diff bar + m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true); + m_wndLineDiffBar.DocumentUpdated(); + m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true); + m_wndLocatorBar.DocumentUpdated(); + } + else + { + // in one way view, hide the line diff bar + m_wndLineDiffBar.ShowPane(false, false, true); + m_wndLineDiffBar.DocumentUpdated(); + } +} + int CMainFrame::CheckResolved() { //only in three way diffs can be conflicts! @@ -934,7 +963,7 @@ int CMainFrame::SaveFile(const CString& sFilePath) do { last++; - } while(lastGetCount() && (pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)); + } while((lastGetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED))); file.Add(_T("<<<<<<< .mine"), EOL_NOENDING); for (int j=first; j (GetNumberOfFiles()/3)) return subpath; } -#endif // if a patch file only contains newly added files // we can't really find the correct path. diff --git a/src/TortoiseMerge/RightView.cpp b/src/TortoiseMerge/RightView.cpp index d3e44c7..30a1a1f 100644 --- a/src/TortoiseMerge/RightView.cpp +++ b/src/TortoiseMerge/RightView.cpp @@ -1,6 +1,6 @@ // TortoiseMerge - a Diff/Patch program -// Copyright (C) 2006-2008 - TortoiseSVN +// Copyright (C) 2006-2009 - TortoiseSVN // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -182,6 +182,7 @@ void CRightView::UseFile(bool refreshViews /* = true */) m_pwndBottom->m_pViewData->SetLine(i, m_pViewData->GetLine(i)); bottomstate.linestates[i] = m_pwndBottom->m_pViewData->GetState(i); m_pwndBottom->m_pViewData->SetState(i, m_pViewData->GetState(i)); + m_pwndBottom->m_pViewData->SetLineEnding(i, m_pViewData->GetLineEnding(i)); if (m_pwndBottom->IsLineConflicted(i)) m_pwndBottom->m_pViewData->SetState(i, DIFFSTATE_CONFLICTRESOLVED); } @@ -193,6 +194,7 @@ void CRightView::UseFile(bool refreshViews /* = true */) { rightstate.difflines[i] = m_pViewData->GetLine(i); m_pViewData->SetLine(i, m_pwndLeft->m_pViewData->GetLine(i)); + m_pViewData->SetLineEnding(i, m_pwndLeft->m_pViewData->GetLineEnding(i)); DiffStates state = m_pwndLeft->m_pViewData->GetState(i); switch (state) { @@ -248,6 +250,7 @@ void CRightView::UseBlock(bool refreshViews /* = true */) m_pwndBottom->m_pViewData->SetLine(i, m_pViewData->GetLine(i)); bottomstate.linestates[i] = m_pwndBottom->m_pViewData->GetState(i); m_pwndBottom->m_pViewData->SetState(i, m_pViewData->GetState(i)); + m_pwndBottom->m_pViewData->SetLineEnding(i, EOL_AUTOLINE); if (m_pwndBottom->IsLineConflicted(i)) { if (m_pViewData->GetState(i) == DIFFSTATE_CONFLICTEMPTY) @@ -264,6 +267,7 @@ void CRightView::UseBlock(bool refreshViews /* = true */) { rightstate.difflines[i] = m_pViewData->GetLine(i); m_pViewData->SetLine(i, m_pwndLeft->m_pViewData->GetLine(i)); + m_pViewData->SetLineEnding(i, EOL_AUTOLINE); DiffStates state = m_pwndLeft->m_pViewData->GetState(i); switch (state) { diff --git a/src/TortoiseMerge/SetMainPage.cpp b/src/TortoiseMerge/SetMainPage.cpp index 0e13672..1541657 100644 --- a/src/TortoiseMerge/SetMainPage.cpp +++ b/src/TortoiseMerge/SetMainPage.cpp @@ -19,7 +19,7 @@ #include "stdafx.h" #include "TortoiseMerge.h" #include "DirFileEnum.h" -#include "..\\version.h" +#include "version.h" #include "AppUtils.h" #include "PathUtils.h" #include "SetMainPage.h" diff --git a/src/TortoiseMerge/TortoiseMerge.cpp b/src/TortoiseMerge/TortoiseMerge.cpp index 5c00d9c..151883d 100644 --- a/src/TortoiseMerge/TortoiseMerge.cpp +++ b/src/TortoiseMerge/TortoiseMerge.cpp @@ -1,6 +1,6 @@ // TortoiseMerge - a Diff/Patch program -// Copyright (C) 2006-2008 - TortoiseSVN +// Copyright (C) 2006-2009 - TortoiseSVN // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -22,10 +22,11 @@ #include "MainFrm.h" #include "AboutDlg.h" #include "CmdLineParser.h" -#include "..\\version.h" +#include "version.h" #include "AppUtils.h" #include "PathUtils.h" #include "BrowseFolder.h" +#include "DirFileEnum.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -47,7 +48,7 @@ CTortoiseMergeApp::CTortoiseMergeApp() // The one and only CTortoiseMergeApp object CTortoiseMergeApp theApp; -//CCrashReport g_crasher("crashreports@tortoisesvn.tigris.org", "Crash Report for TortoiseMerge " APP_X64_STRING " : " STRPRODUCTVER, TRUE); +CCrashReport g_crasher("tortoisesvn@gmail.com", "Crash Report for TortoiseMerge " APP_X64_STRING " : " STRPRODUCTVER, TRUE); // CTortoiseMergeApp initialization BOOL CTortoiseMergeApp::InitInstance() @@ -55,7 +56,7 @@ BOOL CTortoiseMergeApp::InitInstance() CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows)); CMFCButton::EnableWindowsTheming(); //set the resource dll for the required language - CRegDWORD loc = CRegDWORD(_T("Software\\TortoiseGit\\LanguageID"), 1033); + CRegDWORD loc = CRegDWORD(_T("Software\\TortoiseSVN\\LanguageID"), 1033); long langId = loc; CString langDll; HINSTANCE hInst = NULL; @@ -97,7 +98,7 @@ BOOL CTortoiseMergeApp::InitInstance() sHelppath = CPathUtils::GetAppParentDirectory() + _T("Languages\\TortoiseMerge_en.chm"); do { - GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, sizeof(buf)); + GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, sizeof(buf)/sizeof(TCHAR)); CString sLang = _T("_"); sLang += buf; sHelppath.Replace(_T("_en"), sLang); @@ -108,7 +109,7 @@ BOOL CTortoiseMergeApp::InitInstance() break; } sHelppath.Replace(sLang, _T("_en")); - GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, sizeof(buf)); + GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, sizeof(buf)/sizeof(TCHAR)); sLang += _T("_"); sLang += buf; sHelppath.Replace(_T("_en"), sLang); @@ -130,6 +131,10 @@ BOOL CTortoiseMergeApp::InitInstance() langId = 0; } while (langId); setlocale(LC_ALL, ""); + // We need to explicitly set the thread locale to the system default one to avoid possible problems with saving files in its original codepage + // The problems occures when the language of OS differs from the regional settings + // See the details here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100887 + SetThreadLocale(LOCALE_SYSTEM_DEFAULT); // InitCommonControls() is required on Windows XP if an application // manifest specifies use of ComCtl32.dll version 6 or later to enable @@ -427,11 +432,13 @@ BOOL CTortoiseMergeApp::InitInstance() pFrame->ActivateFrame(); pFrame->ShowWindow(SW_SHOW); pFrame->UpdateWindow(); + pFrame->ShowDiffBar(!pFrame->m_bOneWay); if (!pFrame->m_Data.IsBaseFileInUse() && pFrame->m_Data.m_sPatchPath.IsEmpty() && pFrame->m_Data.m_sDiffFile.IsEmpty()) { pFrame->OnFileOpen(); return TRUE; } + return pFrame->LoadViews(); } @@ -462,7 +469,7 @@ CTortoiseMergeApp::CreatePatchFileOpenHook(HWND hDlg, UINT uiMsg, WPARAM wParam, TCHAR * path = new TCHAR[len+1]; TCHAR * tempF = new TCHAR[len+100]; GetTempPath (len+1, path); - GetTempFileName (path, TEXT("svn"), 0, tempF); + GetTempFileName (path, TEXT("tsm"), 0, tempF); std::wstring sTempFile = std::wstring(tempF); delete [] path; delete [] tempF; @@ -486,3 +493,43 @@ CTortoiseMergeApp::CreatePatchFileOpenHook(HWND hDlg, UINT uiMsg, WPARAM wParam, } return 0; } + +int CTortoiseMergeApp::ExitInstance() +{ + // Look for temporary files left around by TortoiseMerge and + // remove them. But only delete 'old' files + DWORD len = ::GetTempPath(0, NULL); + TCHAR * path = new TCHAR[len + 100]; + len = ::GetTempPath (len+100, path); + if (len != 0) + { + CSimpleFileFind finder = CSimpleFileFind(path, _T("*tsm*.*")); + FILETIME systime_; + ::GetSystemTimeAsFileTime(&systime_); + __int64 systime = (((_int64)systime_.dwHighDateTime)<<32) | ((__int64)systime_.dwLowDateTime); + while (finder.FindNextFileNoDirectories()) + { + CString filepath = finder.GetFilePath(); + HANDLE hFile = ::CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + FILETIME createtime_; + if (::GetFileTime(hFile, &createtime_, NULL, NULL)) + { + ::CloseHandle(hFile); + __int64 createtime = (((_int64)createtime_.dwHighDateTime)<<32) | ((__int64)createtime_.dwLowDateTime); + if ((createtime + 864000000000) < systime) //only delete files older than a day + { + ::SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL); + ::DeleteFile(filepath); + } + } + else + ::CloseHandle(hFile); + } + } + } + delete[] path; + + return CWinAppEx::ExitInstance(); +} diff --git a/src/TortoiseMerge/TortoiseMerge.h b/src/TortoiseMerge/TortoiseMerge.h index 3367e9b..fc10ccb 100644 --- a/src/TortoiseMerge/TortoiseMerge.h +++ b/src/TortoiseMerge/TortoiseMerge.h @@ -23,7 +23,7 @@ #endif #include "resource.h" // main symbols -//#include "CrashReport.h" +#include "CrashReport.h" /** @@ -39,6 +39,7 @@ public: // Overrides public: virtual BOOL InitInstance(); + virtual int ExitInstance(); // Implementation UINT m_nAppLook; @@ -53,4 +54,4 @@ private: }; extern CTortoiseMergeApp theApp; -//extern CCrashReport g_crasher; +extern CCrashReport g_crasher; diff --git a/src/TortoiseMerge/TortoiseMerge.vcproj b/src/TortoiseMerge/TortoiseMerge.vcproj index 8e87ef4..4372f49 100644 --- a/src/TortoiseMerge/TortoiseMerge.vcproj +++ b/src/TortoiseMerge/TortoiseMerge.vcproj @@ -21,8 +21,8 @@ + + @@ -1013,6 +1017,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/TortoiseMerge/libsvn_diff/SVNLineDiff.cpp b/src/TortoiseMerge/libsvn_diff/SVNLineDiff.cpp new file mode 100644 index 0000000..6ef0099 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/SVNLineDiff.cpp @@ -0,0 +1,296 @@ +// TortoiseMerge - a Diff/Patch program + +// Copyright (C) 2006-2008 - TortoiseSVN + +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +#include "StdAfx.h" +#include "SVNLineDiff.h" + +const svn_diff_fns_t SVNLineDiff::SVNLineDiff_vtable = +{ + SVNLineDiff::datasource_open, + SVNLineDiff::datasource_close, + SVNLineDiff::next_token, + SVNLineDiff::compare_token, + SVNLineDiff::discard_token, + SVNLineDiff::discard_all_token +}; + +#define SVNLINEDIFF_CHARTYPE_NONE 0 +#define SVNLINEDIFF_CHARTYPE_ALPHANUMERIC 1 +#define SVNLINEDIFF_CHARTYPE_SPACE 2 +#define SVNLINEDIFF_CHARTYPE_OTHER 3 + +typedef void (*LineParser)(LPCTSTR line, unsigned long lineLength, std::vector &tokens); + +void SVNLineDiff::ParseLineWords( + LPCTSTR line, unsigned long lineLength, std::vector &tokens) +{ + std::wstring token; + int prevCharType = SVNLINEDIFF_CHARTYPE_NONE; + for (unsigned long i = 0; i < lineLength; ++i) + { + int charType = + IsCharAlphaNumeric(line[i]) ? SVNLINEDIFF_CHARTYPE_ALPHANUMERIC : + IsCharWhiteSpace(line[i]) ? SVNLINEDIFF_CHARTYPE_SPACE : + SVNLINEDIFF_CHARTYPE_OTHER; + + // Token is a sequence of either alphanumeric or whitespace characters. + // Treat all other characters as a separate tokens. + if (charType == prevCharType && charType != SVNLINEDIFF_CHARTYPE_OTHER) + token += line[i]; + else + { + if (!token.empty()) + tokens.push_back(token); + token = line[i]; + } + prevCharType = charType; + } + if (!token.empty()) + tokens.push_back(token); +} + +void SVNLineDiff::ParseLineChars( + LPCTSTR line, unsigned long lineLength, std::vector &tokens) +{ + std::wstring token; + for (unsigned long i = 0; i < lineLength; ++i) + { + token = line[i]; + tokens.push_back(token); + } +} + +svn_error_t * SVNLineDiff::datasource_open(void * baton, svn_diff_datasource_e datasource) +{ + SVNLineDiff * linediff = (SVNLineDiff *)baton; + LineParser parser = linediff->m_bWordDiff ? ParseLineWords : ParseLineChars; + switch (datasource) + { + case svn_diff_datasource_original: + parser(linediff->m_line1, linediff->m_line1length, linediff->m_line1tokens); + break; + case svn_diff_datasource_modified: + parser(linediff->m_line2, linediff->m_line2length, linediff->m_line2tokens); + break; + } + return SVN_NO_ERROR; +} + +svn_error_t * SVNLineDiff::datasource_close(void * /*baton*/, svn_diff_datasource_e /*datasource*/) +{ + return SVN_NO_ERROR; +} + +void SVNLineDiff::NextTokenWords( + apr_uint32_t* hash, void** token, unsigned long& linePos, const std::vector& tokens) +{ + if (linePos < tokens.size()) + { + *token = (void*)tokens[linePos].c_str(); + *hash = SVNLineDiff::Adler32(0, tokens[linePos].c_str(), tokens[linePos].size()); + linePos++; + } +} + +void SVNLineDiff::NextTokenChars( + apr_uint32_t* hash, void** token, unsigned long& linePos, LPCTSTR line, unsigned long lineLength) +{ + if (linePos < lineLength) + { + *token = (void*)&line[linePos]; + *hash = line[linePos]; + linePos++; + } +} + +svn_error_t * SVNLineDiff::next_token( + apr_uint32_t * hash, void ** token, void * baton, svn_diff_datasource_e datasource) +{ + SVNLineDiff * linediff = (SVNLineDiff *)baton; + *token = NULL; + switch (datasource) + { + case svn_diff_datasource_original: + if (linediff->m_bWordDiff) + NextTokenWords(hash, token, linediff->m_line1pos, linediff->m_line1tokens); + else + NextTokenChars(hash, token, linediff->m_line1pos, linediff->m_line1, linediff->m_line1length); + break; + case svn_diff_datasource_modified: + if (linediff->m_bWordDiff) + NextTokenWords(hash, token, linediff->m_line2pos, linediff->m_line2tokens); + else + NextTokenChars(hash, token, linediff->m_line2pos, linediff->m_line2, linediff->m_line2length); + break; + } + return SVN_NO_ERROR; +} + +svn_error_t * SVNLineDiff::compare_token(void * baton, void * token1, void * token2, int * compare) +{ + SVNLineDiff * linediff = (SVNLineDiff *)baton; + if (linediff->m_bWordDiff) + { + LPCTSTR s1 = (LPCTSTR)token1; + LPCTSTR s2 = (LPCTSTR)token2; + if (s1 && s2) + { + *compare = _tcscmp(s1, s2); + } + } + else + { + TCHAR * c1 = (TCHAR *)token1; + TCHAR * c2 = (TCHAR *)token2; + if (c1 && c2) + { + if (*c1 == *c2) + *compare = 0; + else if (*c1 < *c2) + *compare = -1; + else + *compare = 1; + } + } + return SVN_NO_ERROR; +} + +void SVNLineDiff::discard_token(void * /*baton*/, void * /*token*/) +{ +} + +void SVNLineDiff::discard_all_token(void * /*baton*/) +{ +} + +SVNLineDiff::SVNLineDiff() + : m_pool(NULL) + , m_subpool(NULL) + , m_line1(NULL) + , m_line1length(0) + , m_line2(NULL) + , m_line2length(0) + , m_line1pos(0) + , m_line2pos(0) + , m_bWordDiff(false) +{ + m_pool = svn_pool_create(NULL); +} + +SVNLineDiff::~SVNLineDiff() +{ + svn_pool_destroy(m_pool); +}; + +bool SVNLineDiff::Diff(svn_diff_t **diff, LPCTSTR line1, int len1, LPCTSTR line2, int len2, bool bWordDiff) +{ + if (m_subpool) + svn_pool_clear(m_subpool); + else + m_subpool = svn_pool_create(m_pool); + + if (m_subpool == NULL) + return false; + + m_bWordDiff = bWordDiff; + m_line1 = line1; + m_line2 = line2; + m_line1length = len1 ? len1 : _tcslen(m_line1); + m_line2length = len2 ? len2 : _tcslen(m_line2); + + m_line1pos = 0; + m_line2pos = 0; + m_line1tokens.clear(); + m_line2tokens.clear(); + svn_error_t * err = svn_diff_diff(diff, this, &SVNLineDiff_vtable, m_subpool); + if (err) + { + svn_error_clear(err); + svn_pool_clear(m_subpool); + return false; + } + return true; +} + +#define ADLER_MOD_BASE 65521 +#define ADLER_MOD_BLOCK_SIZE 5552 + +apr_uint32_t SVNLineDiff::Adler32(apr_uint32_t checksum, const WCHAR *data, apr_size_t len) +{ + const unsigned char * input = (const unsigned char *)data; + apr_uint32_t s1 = checksum & 0xFFFF; + apr_uint32_t s2 = checksum >> 16; + apr_uint32_t b; + len *= 2; + apr_size_t blocks = len / ADLER_MOD_BLOCK_SIZE; + + len %= ADLER_MOD_BLOCK_SIZE; + + while (blocks--) + { + int count = ADLER_MOD_BLOCK_SIZE; + while (count--) + { + b = *input++; + s1 += b; + s2 += s1; + } + + s1 %= ADLER_MOD_BASE; + s2 %= ADLER_MOD_BASE; + } + + while (len--) + { + b = *input++; + s1 += b; + s2 += s1; + } + + return ((s2 % ADLER_MOD_BASE) << 16) | (s1 % ADLER_MOD_BASE); +} + +bool SVNLineDiff::IsCharWhiteSpace(TCHAR c) +{ + return (c == ' ') || (c == '\t'); +} + +bool SVNLineDiff::ShowInlineDiff(svn_diff_t* diff) +{ + svn_diff_t* tempdiff = diff; + int diffcounts = 0; + int origcounts = 0; + apr_off_t origsize = 0; + apr_off_t diffsize = 0; + while (tempdiff) + { + if (tempdiff->type == svn_diff__type_common) + { + origcounts++; + origsize += tempdiff->original_length; + } + else + { + diffcounts++; + diffsize += tempdiff->original_length; + diffsize += tempdiff->modified_length; + } + tempdiff = tempdiff->next; + } + return (origcounts >= diffcounts) && (origsize > diffsize); +} diff --git a/src/TortoiseMerge/libsvn_diff/adler32.c b/src/TortoiseMerge/libsvn_diff/adler32.c new file mode 100644 index 0000000..b7b3f5c --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/adler32.c @@ -0,0 +1,48 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c,v 1.1 2003/05/23 21:05:30 steveking Exp $ */ + +#include "zlib.h" + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} diff --git a/src/TortoiseMerge/libsvn_diff/checksum.c b/src/TortoiseMerge/libsvn_diff/checksum.c new file mode 100644 index 0000000..4d1f5bb --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/checksum.c @@ -0,0 +1,334 @@ +/* + * checksum.c: checksum routines + * + * ==================================================================== + * Copyright (c) 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + + +#include + +#include +#include + +#include "svn_checksum.h" +#include "svn_error.h" + +#include "sha1.h" +#include "md5.h" + + + +/* Returns the digest size of it's argument. */ +#define DIGESTSIZE(k) ((k) == svn_checksum_md5 ? APR_MD5_DIGESTSIZE : \ + (k) == svn_checksum_sha1 ? APR_SHA1_DIGESTSIZE : 0) + + +/* Check to see if KIND is something we recognize. If not, return + * SVN_ERR_BAD_CHECKSUM_KIND */ +static svn_error_t * +validate_kind(svn_checksum_kind_t kind) +{ + if (kind == svn_checksum_md5 || kind == svn_checksum_sha1) + return SVN_NO_ERROR; + else + return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL); +} + + +svn_checksum_t * +svn_checksum_create(svn_checksum_kind_t kind, + apr_pool_t *pool) +{ + svn_checksum_t *checksum; + + switch (kind) + { + case svn_checksum_md5: + case svn_checksum_sha1: + checksum = apr_pcalloc(pool, sizeof(*checksum) + DIGESTSIZE(kind)); + checksum->digest = (unsigned char *)checksum + sizeof(*checksum); + checksum->kind = kind; + return checksum; + + default: + return NULL; + } +} + +svn_checksum_t * +svn_checksum__from_digest(const unsigned char *digest, + svn_checksum_kind_t kind, + apr_pool_t *result_pool) +{ + svn_checksum_t *checksum = svn_checksum_create(kind, result_pool); + + memcpy((unsigned char *)checksum->digest, digest, DIGESTSIZE(kind)); + return checksum; +} + +svn_error_t * +svn_checksum_clear(svn_checksum_t *checksum) +{ + SVN_ERR(validate_kind(checksum->kind)); + + memset((unsigned char *) checksum->digest, 0, DIGESTSIZE(checksum->kind)); + return SVN_NO_ERROR; +} + +svn_boolean_t +svn_checksum_match(const svn_checksum_t *checksum1, + const svn_checksum_t *checksum2) +{ + if (checksum1 == NULL || checksum2 == NULL) + return TRUE; + + if (checksum1->kind != checksum2->kind) + return FALSE; + + switch (checksum1->kind) + { + case svn_checksum_md5: + return svn_md5__digests_match(checksum1->digest, checksum2->digest); + case svn_checksum_sha1: + return svn_sha1__digests_match(checksum1->digest, checksum2->digest); + default: + /* We really shouldn't get here, but if we do... */ + return FALSE; + } +} + +const char * +svn_checksum_to_cstring_display(const svn_checksum_t *checksum, + apr_pool_t *pool) +{ + switch (checksum->kind) + { + case svn_checksum_md5: + return svn_md5__digest_to_cstring_display(checksum->digest, pool); + case svn_checksum_sha1: + return svn_sha1__digest_to_cstring_display(checksum->digest, pool); + default: + /* We really shouldn't get here, but if we do... */ + return NULL; + } +} + +const char * +svn_checksum_to_cstring(const svn_checksum_t *checksum, + apr_pool_t *pool) +{ + switch (checksum->kind) + { + case svn_checksum_md5: + return svn_md5__digest_to_cstring(checksum->digest, pool); + case svn_checksum_sha1: + return svn_sha1__digest_to_cstring(checksum->digest, pool); + default: + /* We really shouldn't get here, but if we do... */ + return NULL; + } +} + +svn_error_t * +svn_checksum_parse_hex(svn_checksum_t **checksum, + svn_checksum_kind_t kind, + const char *hex, + apr_pool_t *pool) +{ + int len; + int i; + unsigned char is_zeros = '\0'; + + if (hex == NULL) + { + *checksum = NULL; + return SVN_NO_ERROR; + } + + SVN_ERR(validate_kind(kind)); + + *checksum = svn_checksum_create(kind, pool); + len = DIGESTSIZE(kind); + + for (i = 0; i < len; i++) + { + if ((! isxdigit(hex[i * 2])) || (! isxdigit(hex[i * 2 + 1]))) + return svn_error_create(SVN_ERR_BAD_CHECKSUM_PARSE, NULL, NULL); + + ((unsigned char *)(*checksum)->digest)[i] = + (( isalpha(hex[i*2]) ? hex[i*2] - 'a' + 10 : hex[i*2] - '0') << 4) | + ( isalpha(hex[i*2+1]) ? hex[i*2+1] - 'a' + 10 : hex[i*2+1] - '0'); + is_zeros |= (*checksum)->digest[i]; + } + + if (is_zeros == '\0') + *checksum = NULL; + + return SVN_NO_ERROR; +} + +svn_checksum_t * +svn_checksum_dup(const svn_checksum_t *checksum, + apr_pool_t *pool) +{ + /* The duplicate of a NULL checksum is a NULL... */ + if (checksum == NULL) + return NULL; + + return svn_checksum__from_digest(checksum->digest, checksum->kind, pool); +} + +svn_error_t * +svn_checksum(svn_checksum_t **checksum, + svn_checksum_kind_t kind, + const void *data, + apr_size_t len, + apr_pool_t *pool) +{ + apr_sha1_ctx_t sha1_ctx; + + SVN_ERR(validate_kind(kind)); + *checksum = svn_checksum_create(kind, pool); + + switch (kind) + { + case svn_checksum_md5: + apr_md5((unsigned char *)(*checksum)->digest, data, len); + break; + + case svn_checksum_sha1: + apr_sha1_init(&sha1_ctx); + apr_sha1_update(&sha1_ctx, data, len); + apr_sha1_final((unsigned char *)(*checksum)->digest, &sha1_ctx); + break; + + default: + /* We really shouldn't get here, but if we do... */ + return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL); + } + + return SVN_NO_ERROR; +} + + +svn_checksum_t * +svn_checksum_empty_checksum(svn_checksum_kind_t kind, + apr_pool_t *pool) +{ + const unsigned char *digest; + + switch (kind) + { + case svn_checksum_md5: + digest = svn_md5__empty_string_digest(); + break; + + case svn_checksum_sha1: + digest = svn_sha1__empty_string_digest(); + break; + + default: + /* We really shouldn't get here, but if we do... */ + return NULL; + } + + return svn_checksum__from_digest(digest, kind, pool); +} + +struct svn_checksum_ctx_t +{ + void *apr_ctx; + svn_checksum_kind_t kind; +}; + +svn_checksum_ctx_t * +svn_checksum_ctx_create(svn_checksum_kind_t kind, + apr_pool_t *pool) +{ + svn_checksum_ctx_t *ctx = apr_palloc(pool, sizeof(*ctx)); + + ctx->kind = kind; + switch (kind) + { + case svn_checksum_md5: + ctx->apr_ctx = apr_palloc(pool, sizeof(apr_md5_ctx_t)); + apr_md5_init(ctx->apr_ctx); + break; + + case svn_checksum_sha1: + ctx->apr_ctx = apr_palloc(pool, sizeof(apr_sha1_ctx_t)); + apr_sha1_init(ctx->apr_ctx); + break; + + default: + return NULL; + } + + return ctx; +} + +svn_error_t * +svn_checksum_update(svn_checksum_ctx_t *ctx, + const void *data, + apr_size_t len) +{ + switch (ctx->kind) + { + case svn_checksum_md5: + apr_md5_update(ctx->apr_ctx, data, len); + break; + + case svn_checksum_sha1: + apr_sha1_update(ctx->apr_ctx, data, len); + break; + + default: + /* We really shouldn't get here, but if we do... */ + return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL); + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_checksum_final(svn_checksum_t **checksum, + const svn_checksum_ctx_t *ctx, + apr_pool_t *pool) +{ + *checksum = svn_checksum_create(ctx->kind, pool); + + switch (ctx->kind) + { + case svn_checksum_md5: + apr_md5_final((unsigned char *)(*checksum)->digest, ctx->apr_ctx); + break; + + case svn_checksum_sha1: + apr_sha1_final((unsigned char *)(*checksum)->digest, ctx->apr_ctx); + break; + + default: + /* We really shouldn't get here, but if we do... */ + return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL); + } + + return SVN_NO_ERROR; +} + +apr_size_t +svn_checksum_size(const svn_checksum_t *checksum) +{ + return DIGESTSIZE(checksum->kind); +} diff --git a/src/TortoiseMerge/libsvn_diff/cmdline.c b/src/TortoiseMerge/libsvn_diff/cmdline.c new file mode 100644 index 0000000..c77b002 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/cmdline.c @@ -0,0 +1,617 @@ +/* + * cmdline.c : Helpers for command-line programs. + * + * ==================================================================== + * Copyright (c) 2003-2009 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + + +#include /* for atexit() */ +#include /* for setvbuf() */ +#include /* for setlocale() */ + +#ifndef WIN32 +#include +#include +#include +#include +#endif + +#include /* for apr_strerror */ +#include /* for apr_initialize/apr_terminate */ +#include /* for apr_atomic_init */ +#include /* for apr_snprintf */ +#include + +#include "svn_cmdline.h" +#include "svn_dso.h" +#include "svn_path.h" +#include "svn_pools.h" +#include "svn_error.h" +#include "svn_nls.h" +#include "svn_utf.h" +#include "svn_auth.h" +#include "svn_version.h" +#include "svn_xml.h" +#include "svn_base64.h" +#include "svn_config.h" + +//#include "private/svn_cmdline_private.h" +//#include "private/svn_utf_private.h" + +//#include "svn_private_config.h" + +//#include "win32_crashrpt.h" + +/* The stdin encoding. If null, it's the same as the native encoding. */ +static const char *input_encoding = NULL; + +/* The stdout encoding. If null, it's the same as the native encoding. */ +static const char *output_encoding = NULL; + +#if 0 +int +svn_cmdline_init(const char *progname, FILE *error_stream) +{ + apr_status_t status; + apr_pool_t *pool; + svn_error_t *err; + +#ifndef WIN32 + { + struct stat st; + + /* The following makes sure that file descriptors 0 (stdin), 1 + (stdout) and 2 (stderr) will not be "reused", because if + e.g. file descriptor 2 would be reused when opening a file, a + write to stderr would write to that file and most likely + corrupt it. */ + if ((fstat(0, &st) == -1 && open("/dev/null", O_RDONLY) == -1) || + (fstat(1, &st) == -1 && open("/dev/null", O_WRONLY) == -1) || + (fstat(2, &st) == -1 && open("/dev/null", O_WRONLY) == -1)) + { + if (error_stream) + fprintf(error_stream, "%s: error: cannot open '/dev/null'\n", + progname); + return EXIT_FAILURE; + } + } +#endif + + /* Ignore any errors encountered while attempting to change stream + buffering, as the streams should retain their default buffering + modes. */ + if (error_stream) + setvbuf(error_stream, NULL, _IONBF, 0); +#ifndef WIN32 + setvbuf(stdout, NULL, _IOLBF, 0); +#endif + +#ifdef WIN32 +#if _MSC_VER < 1400 + /* Initialize the input and output encodings. */ + { + static char input_encoding_buffer[16]; + static char output_encoding_buffer[16]; + + apr_snprintf(input_encoding_buffer, sizeof input_encoding_buffer, + "CP%u", (unsigned) GetConsoleCP()); + input_encoding = input_encoding_buffer; + + apr_snprintf(output_encoding_buffer, sizeof output_encoding_buffer, + "CP%u", (unsigned) GetConsoleOutputCP()); + output_encoding = output_encoding_buffer; + } +#endif /* _MSC_VER < 1400 */ + +#ifdef SVN_USE_WIN32_CRASHHANDLER + /* Attach (but don't load) the crash handler */ + SetUnhandledExceptionFilter(svn__unhandled_exception_filter); +#endif + +#endif /* WIN32 */ + + /* C programs default to the "C" locale. But because svn is supposed + to be i18n-aware, it should inherit the default locale of its + environment. */ + if (!setlocale(LC_ALL, "") + && !setlocale(LC_CTYPE, "")) + { + if (error_stream) + { + const char *env_vars[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL }; + const char **env_var = &env_vars[0], *env_val = NULL; + while (*env_var) + { + env_val = getenv(*env_var); + if (env_val && env_val[0]) + break; + ++env_var; + } + + if (!*env_var) + { + /* Unlikely. Can setlocale fail if no env vars are set? */ + --env_var; + env_val = "not set"; + } + + fprintf(error_stream, + "%s: warning: cannot set LC_CTYPE locale\n" + "%s: warning: environment variable %s is %s\n" + "%s: warning: please check that your locale name is correct\n", + progname, progname, *env_var, env_val, progname); + } + } + + /* Initialize the APR subsystem, and register an atexit() function + to Uninitialize that subsystem at program exit. */ + status = apr_initialize(); + if (status) + { + if (error_stream) + { + char buf[1024]; + apr_strerror(status, buf, sizeof(buf) - 1); + fprintf(error_stream, + "%s: error: cannot initialize APR: %s\n", + progname, buf); + } + return EXIT_FAILURE; + } + + /* This has to happen before any pools are created. */ + if ((err = svn_dso_initialize2())) + { + if (error_stream && err->message) + fprintf(error_stream, "%s", err->message); + + svn_error_clear(err); + return EXIT_FAILURE; + } + + if (0 > atexit(apr_terminate)) + { + if (error_stream) + fprintf(error_stream, + "%s: error: atexit registration failed\n", + progname); + return EXIT_FAILURE; + } + + /* Create a pool for use by the UTF-8 routines. It will be cleaned + up by APR at exit time. */ + pool = svn_pool_create(NULL); + svn_utf_initialize(pool); + + if ((err = svn_nls_init())) + { + if (error_stream && err->message) + fprintf(error_stream, "%s", err->message); + + svn_error_clear(err); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} +#endif + +svn_error_t * +svn_cmdline_cstring_from_utf8(const char **dest, + const char *src, + apr_pool_t *pool) +{ + if (output_encoding == NULL) + return svn_utf_cstring_from_utf8(dest, src, pool); + else + return svn_utf_cstring_from_utf8_ex2(dest, src, output_encoding, pool); +} + +const char * +svn_cmdline_cstring_from_utf8_fuzzy(const char *src, + apr_pool_t *pool) +{ + return svn_utf__cstring_from_utf8_fuzzy(src, pool, + svn_cmdline_cstring_from_utf8); +} + + +svn_error_t * +svn_cmdline_cstring_to_utf8(const char **dest, + const char *src, + apr_pool_t *pool) +{ + if (input_encoding == NULL) + return svn_utf_cstring_to_utf8(dest, src, pool); + else + return svn_utf_cstring_to_utf8_ex2(dest, src, input_encoding, pool); +} + +#if 0 +svn_error_t * +svn_cmdline_path_local_style_from_utf8(const char **dest, + const char *src, + apr_pool_t *pool) +{ + return svn_cmdline_cstring_from_utf8(dest, + svn_path_local_style(src, pool), + pool); +} + +svn_error_t * +svn_cmdline_printf(apr_pool_t *pool, const char *fmt, ...) +{ + const char *message; + va_list ap; + + /* A note about encoding issues: + * APR uses the execution character set, but here we give it UTF-8 strings, + * both the fmt argument and any other string arguments. Since apr_pvsprintf + * only cares about and produces ASCII characters, this works under the + * assumption that all supported platforms use an execution character set + * with ASCII as a subset. + */ + + va_start(ap, fmt); + message = apr_pvsprintf(pool, fmt, ap); + va_end(ap); + + return svn_cmdline_fputs(message, stdout, pool); +} +#endif +svn_error_t * +svn_cmdline_fprintf(FILE *stream, apr_pool_t *pool, const char *fmt, ...) +{ + const char *message; + va_list ap; + + /* See svn_cmdline_printf () for a note about character encoding issues. */ + + va_start(ap, fmt); + message = apr_pvsprintf(pool, fmt, ap); + va_end(ap); + + return svn_cmdline_fputs(message, stream, pool); +} + +svn_error_t * +svn_cmdline_fputs(const char *string, FILE* stream, apr_pool_t *pool) +{ + svn_error_t *err; + const char *out; + + err = svn_cmdline_cstring_from_utf8(&out, string, pool); + + if (err) + { + svn_error_clear(err); + out = svn_cmdline_cstring_from_utf8_fuzzy(string, pool); + } + + /* On POSIX systems, errno will be set on an error in fputs, but this might + not be the case on other platforms. We reset errno and only + use it if it was set by the below fputs call. Else, we just return + a generic error. */ + errno = 0; + + if (fputs(out, stream) == EOF) + { + if (errno) + return svn_error_wrap_apr(errno, _("Write error")); + else + return svn_error_create + (SVN_ERR_IO_WRITE_ERROR, NULL, NULL); + } + + return SVN_NO_ERROR; +} +#if 0 +svn_error_t * +svn_cmdline_fflush(FILE *stream) +{ + /* See comment in svn_cmdline_fputs about use of errno and stdio. */ + errno = 0; + if (fflush(stream) == EOF) + { + if (errno) + return svn_error_wrap_apr(errno, _("Write error")); + else + return svn_error_create(SVN_ERR_IO_WRITE_ERROR, NULL, NULL); + } + + return SVN_NO_ERROR; +} + +const char *svn_cmdline_output_encoding(apr_pool_t *pool) +{ + if (output_encoding) + return apr_pstrdup(pool, output_encoding); + else + return SVN_APR_LOCALE_CHARSET; +} + +int +svn_cmdline_handle_exit_error(svn_error_t *err, + apr_pool_t *pool, + const char *prefix) +{ + svn_handle_error2(err, stderr, FALSE, prefix); + svn_error_clear(err); + if (pool) + svn_pool_destroy(pool); + return EXIT_FAILURE; +} + +/* This implements 'svn_auth_ssl_server_trust_prompt_func_t'. + + Don't actually prompt. Instead, set *CRED_P to valid credentials + iff FAILURES is empty or is exactly SVN_AUTH_SSL_UNKNOWNCA. If + there are any other failure bits, then set *CRED_P to null (that + is, reject the cert). + + Ignore MAY_SAVE; we don't save certs we never prompted for. + + Ignore BATON, REALM, and CERT_INFO, + + Ignore any further films by George Lucas. */ +static svn_error_t * +ssl_trust_unknown_server_cert + (svn_auth_cred_ssl_server_trust_t **cred_p, + void *baton, + const char *realm, + apr_uint32_t failures, + const svn_auth_ssl_server_cert_info_t *cert_info, + svn_boolean_t may_save, + apr_pool_t *pool) +{ + *cred_p = NULL; + + if (failures == 0 || failures == SVN_AUTH_SSL_UNKNOWNCA) + { + *cred_p = apr_pcalloc(pool, sizeof(**cred_p)); + (*cred_p)->may_save = FALSE; + (*cred_p)->accepted_failures = failures; + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_cmdline_create_auth_baton(svn_auth_baton_t **ab, + svn_boolean_t non_interactive, + const char *auth_username, + const char *auth_password, + const char *config_dir, + svn_boolean_t no_auth_cache, + svn_boolean_t trust_server_cert, + svn_config_t *cfg, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool) +{ + svn_boolean_t store_password_val = TRUE; + svn_boolean_t store_auth_creds_val = TRUE; + svn_auth_provider_object_t *provider; + svn_cmdline_prompt_baton2_t *pb = NULL; + + /* The whole list of registered providers */ + apr_array_header_t *providers; + + /* Populate the registered providers with the platform-specific providers */ + SVN_ERR(svn_auth_get_platform_specific_client_providers + (&providers, cfg, pool)); + + /* If we have a cancellation function, cram it and the stuff it + needs into the prompt baton. */ + if (cancel_func) + { + pb = apr_palloc(pool, sizeof(*pb)); + pb->cancel_func = cancel_func; + pb->cancel_baton = cancel_baton; + pb->config_dir = config_dir; + } + + if (non_interactive == FALSE) + { + /* This provider doesn't prompt the user in order to get creds; + it prompts the user regarding the caching of creds. */ + svn_auth_get_simple_provider2(&provider, + svn_cmdline_auth_plaintext_prompt, + pb, pool); + } + else + { + svn_auth_get_simple_provider2(&provider, NULL, NULL, pool); + } + + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + svn_auth_get_username_provider(&provider, pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + + /* The server-cert, client-cert, and client-cert-password providers. */ + SVN_ERR(svn_auth_get_platform_specific_provider(&provider, + "windows", + "ssl_server_trust", + pool)); + + if (provider) + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + + svn_auth_get_ssl_server_trust_file_provider(&provider, pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + svn_auth_get_ssl_client_cert_file_provider(&provider, pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + + if (non_interactive == FALSE) + { + /* This provider doesn't prompt the user in order to get creds; + it prompts the user regarding the caching of creds. */ + svn_auth_get_ssl_client_cert_pw_file_provider2 + (&provider, svn_cmdline_auth_plaintext_passphrase_prompt, + pb, pool); + } + else + { + svn_auth_get_ssl_client_cert_pw_file_provider2(&provider, NULL, NULL, + pool); + } + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + + if (non_interactive == FALSE) + { + /* Two basic prompt providers: username/password, and just username. */ + svn_auth_get_simple_prompt_provider(&provider, + svn_cmdline_auth_simple_prompt, + pb, + 2, /* retry limit */ + pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + + svn_auth_get_username_prompt_provider + (&provider, svn_cmdline_auth_username_prompt, pb, + 2, /* retry limit */ pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + + /* Three ssl prompt providers, for server-certs, client-certs, + and client-cert-passphrases. */ + svn_auth_get_ssl_server_trust_prompt_provider + (&provider, svn_cmdline_auth_ssl_server_trust_prompt, pb, pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + + svn_auth_get_ssl_client_cert_prompt_provider + (&provider, svn_cmdline_auth_ssl_client_cert_prompt, pb, 2, pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + + svn_auth_get_ssl_client_cert_pw_prompt_provider + (&provider, svn_cmdline_auth_ssl_client_cert_pw_prompt, pb, 2, pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + } + else if (trust_server_cert) + { + /* Remember, only register this provider if non_interactive. */ + svn_auth_get_ssl_server_trust_prompt_provider + (&provider, ssl_trust_unknown_server_cert, NULL, pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + } + + /* Build an authentication baton to give to libsvn_client. */ + svn_auth_open(ab, providers, pool); + + /* Place any default --username or --password credentials into the + auth_baton's run-time parameter hash. */ + if (auth_username) + svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_DEFAULT_USERNAME, + auth_username); + if (auth_password) + svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_DEFAULT_PASSWORD, + auth_password); + + /* Same with the --non-interactive option. */ + if (non_interactive) + svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_NON_INTERACTIVE, ""); + + if (config_dir) + svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_CONFIG_DIR, + config_dir); + + /* Determine whether storing passwords in any form is allowed. + * This is the deprecated location for this option, the new + * location is SVN_CONFIG_CATEGORY_SERVERS. The RA layer may + * override the value we set here. */ + SVN_ERR(svn_config_get_bool(cfg, &store_password_val, + SVN_CONFIG_SECTION_AUTH, + SVN_CONFIG_OPTION_STORE_PASSWORDS, + SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS)); + + if (! store_password_val) + svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, ""); + + /* Determine whether we are allowed to write to the auth/ area. + * This is the deprecated location for this option, the new + * location is SVN_CONFIG_CATEGORY_SERVERS. The RA layer may + * override the value we set here. */ + SVN_ERR(svn_config_get_bool(cfg, &store_auth_creds_val, + SVN_CONFIG_SECTION_AUTH, + SVN_CONFIG_OPTION_STORE_AUTH_CREDS, + SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS)); + + if (no_auth_cache || ! store_auth_creds_val) + svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_NO_AUTH_CACHE, ""); + +#ifdef SVN_HAVE_GNOME_KEYRING + svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC, + &svn_cmdline__auth_gnome_keyring_unlock_prompt); +#endif /* SVN_HAVE_GNOME_KEYRING */ + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_cmdline__getopt_init(apr_getopt_t **os, + int argc, + const char *argv[], + apr_pool_t *pool) +{ + apr_status_t apr_err = apr_getopt_init(os, pool, argc, argv); + if (apr_err) + return svn_error_wrap_apr(apr_err, + _("Error initializing command line arguments")); + return SVN_NO_ERROR; +} + + +void +svn_cmdline__print_xml_prop(svn_stringbuf_t **outstr, + const char* propname, + svn_string_t *propval, + apr_pool_t *pool) +{ + const char *xml_safe; + const char *encoding = NULL; + + if (*outstr == NULL) + *outstr = svn_stringbuf_create("", pool); + + if (svn_xml_is_xml_safe(propval->data, propval->len)) + { + svn_stringbuf_t *xml_esc = NULL; + svn_xml_escape_cdata_string(&xml_esc, propval, pool); + xml_safe = xml_esc->data; + } + else + { + const svn_string_t *base64ed = svn_base64_encode_string2(propval, TRUE, + pool); + encoding = "base64"; + xml_safe = base64ed->data; + } + + if (encoding) + svn_xml_make_open_tag(outstr, pool, svn_xml_protect_pcdata, + "property", "name", propname, + "encoding", encoding, NULL); + else + svn_xml_make_open_tag(outstr, pool, svn_xml_protect_pcdata, + "property", "name", propname, NULL); + + svn_stringbuf_appendcstr(*outstr, xml_safe); + + svn_xml_make_close_tag(outstr, pool, "property"); + + return; +} + + +#endif \ No newline at end of file diff --git a/src/TortoiseMerge/libsvn_diff/compress.c b/src/TortoiseMerge/libsvn_diff/compress.c new file mode 100644 index 0000000..7a6b62c --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/compress.c @@ -0,0 +1,68 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: compress.c,v 1.1 2003/05/23 21:05:30 steveking Exp $ */ + +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} diff --git a/src/TortoiseMerge/libsvn_diff/crc32.c b/src/TortoiseMerge/libsvn_diff/crc32.c new file mode 100644 index 0000000..92d670b --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/crc32.c @@ -0,0 +1,162 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: crc32.c,v 1.1 2003/05/23 21:05:30 steveking Exp $ */ + +#include "zlib.h" + +#define local static + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local uLongf crc_table[256]; +local void make_crc_table OF((void)); + +/* + Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all + the information needed to generate CRC's on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +local void make_crc_table() +{ + uLong c; + int n, k; + uLong poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(Byte); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (uLong)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + crc_table_empty = 0; +} +#else +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +local const uLongf crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; +#endif + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const uLongf * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif + return (const uLongf *)crc_table; +} + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +uLong ZEXPORT crc32(crc, buf, len) + uLong crc; + const Bytef *buf; + uInt len; +{ + if (buf == Z_NULL) return 0L; +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif + crc = crc ^ 0xffffffffL; + while (len >= 8) + { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffL; +} diff --git a/src/TortoiseMerge/libsvn_diff/ctype.c b/src/TortoiseMerge/libsvn_diff/ctype.c new file mode 100644 index 0000000..a698472 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/ctype.c @@ -0,0 +1,314 @@ +/* + * ctype.c: Character classification routines + * + * ==================================================================== + * Copyright (c) 2000-2004 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + + + +#include "svn_ctype.h" + +const apr_uint32_t svn_ctype_table_internal[256] = + { + /* **** DO NOT EDIT! **** + This table was generated by genctype.py, make changes there. */ + /* nul */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* soh */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* stx */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* etx */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* eot */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* enq */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* ack */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* bel */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* bs */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* ht */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL | SVN_CTYPE_SPACE, + /* nl */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL | SVN_CTYPE_SPACE, + /* vt */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL | SVN_CTYPE_SPACE, + /* np */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL | SVN_CTYPE_SPACE, + /* cr */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL | SVN_CTYPE_SPACE, + /* so */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* si */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* dle */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* dc1 */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* dc2 */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* dc3 */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* dc4 */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* nak */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* syn */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* etb */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* can */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* em */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* sub */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* esc */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* fs */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* gs */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* rs */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* us */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* sp */ SVN_CTYPE_ASCII | SVN_CTYPE_SPACE, + /* ! */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* " */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* # */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* $ */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* % */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* & */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* ' */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* ( */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* ) */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* * */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* + */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* , */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* - */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* . */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* / */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* 0 */ SVN_CTYPE_ASCII | SVN_CTYPE_DIGIT, + /* 1 */ SVN_CTYPE_ASCII | SVN_CTYPE_DIGIT, + /* 2 */ SVN_CTYPE_ASCII | SVN_CTYPE_DIGIT, + /* 3 */ SVN_CTYPE_ASCII | SVN_CTYPE_DIGIT, + /* 4 */ SVN_CTYPE_ASCII | SVN_CTYPE_DIGIT, + /* 5 */ SVN_CTYPE_ASCII | SVN_CTYPE_DIGIT, + /* 6 */ SVN_CTYPE_ASCII | SVN_CTYPE_DIGIT, + /* 7 */ SVN_CTYPE_ASCII | SVN_CTYPE_DIGIT, + /* 8 */ SVN_CTYPE_ASCII | SVN_CTYPE_DIGIT, + /* 9 */ SVN_CTYPE_ASCII | SVN_CTYPE_DIGIT, + /* : */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* ; */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* < */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* = */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* > */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* ? */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* @ */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* A */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER | SVN_CTYPE_XALPHA, + /* B */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER | SVN_CTYPE_XALPHA, + /* C */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER | SVN_CTYPE_XALPHA, + /* D */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER | SVN_CTYPE_XALPHA, + /* E */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER | SVN_CTYPE_XALPHA, + /* F */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER | SVN_CTYPE_XALPHA, + /* G */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* H */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* I */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* J */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* K */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* L */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* M */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* N */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* O */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* P */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* Q */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* R */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* S */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* T */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* U */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* V */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* W */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* X */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* Y */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* Z */ SVN_CTYPE_ASCII | SVN_CTYPE_UPPER, + /* [ */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* \ */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* ] */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* ^ */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* _ */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* ` */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* a */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER | SVN_CTYPE_XALPHA, + /* b */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER | SVN_CTYPE_XALPHA, + /* c */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER | SVN_CTYPE_XALPHA, + /* d */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER | SVN_CTYPE_XALPHA, + /* e */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER | SVN_CTYPE_XALPHA, + /* f */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER | SVN_CTYPE_XALPHA, + /* g */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* h */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* i */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* j */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* k */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* l */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* m */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* n */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* o */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* p */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* q */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* r */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* s */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* t */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* u */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* v */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* w */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* x */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* y */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* z */ SVN_CTYPE_ASCII | SVN_CTYPE_LOWER, + /* { */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* | */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* } */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* ~ */ SVN_CTYPE_ASCII | SVN_CTYPE_PUNCT, + /* del */ SVN_CTYPE_ASCII | SVN_CTYPE_CNTRL, + /* x80 */ SVN_CTYPE_UTF8CONT, + /* x81 */ SVN_CTYPE_UTF8CONT, + /* x82 */ SVN_CTYPE_UTF8CONT, + /* x83 */ SVN_CTYPE_UTF8CONT, + /* x84 */ SVN_CTYPE_UTF8CONT, + /* x85 */ SVN_CTYPE_UTF8CONT, + /* x86 */ SVN_CTYPE_UTF8CONT, + /* x87 */ SVN_CTYPE_UTF8CONT, + /* x88 */ SVN_CTYPE_UTF8CONT, + /* x89 */ SVN_CTYPE_UTF8CONT, + /* x8a */ SVN_CTYPE_UTF8CONT, + /* x8b */ SVN_CTYPE_UTF8CONT, + /* x8c */ SVN_CTYPE_UTF8CONT, + /* x8d */ SVN_CTYPE_UTF8CONT, + /* x8e */ SVN_CTYPE_UTF8CONT, + /* x8f */ SVN_CTYPE_UTF8CONT, + /* x90 */ SVN_CTYPE_UTF8CONT, + /* x91 */ SVN_CTYPE_UTF8CONT, + /* x92 */ SVN_CTYPE_UTF8CONT, + /* x93 */ SVN_CTYPE_UTF8CONT, + /* x94 */ SVN_CTYPE_UTF8CONT, + /* x95 */ SVN_CTYPE_UTF8CONT, + /* x96 */ SVN_CTYPE_UTF8CONT, + /* x97 */ SVN_CTYPE_UTF8CONT, + /* x98 */ SVN_CTYPE_UTF8CONT, + /* x99 */ SVN_CTYPE_UTF8CONT, + /* x9a */ SVN_CTYPE_UTF8CONT, + /* x9b */ SVN_CTYPE_UTF8CONT, + /* x9c */ SVN_CTYPE_UTF8CONT, + /* x9d */ SVN_CTYPE_UTF8CONT, + /* x9e */ SVN_CTYPE_UTF8CONT, + /* x9f */ SVN_CTYPE_UTF8CONT, + /* xa0 */ SVN_CTYPE_UTF8CONT, + /* xa1 */ SVN_CTYPE_UTF8CONT, + /* xa2 */ SVN_CTYPE_UTF8CONT, + /* xa3 */ SVN_CTYPE_UTF8CONT, + /* xa4 */ SVN_CTYPE_UTF8CONT, + /* xa5 */ SVN_CTYPE_UTF8CONT, + /* xa6 */ SVN_CTYPE_UTF8CONT, + /* xa7 */ SVN_CTYPE_UTF8CONT, + /* xa8 */ SVN_CTYPE_UTF8CONT, + /* xa9 */ SVN_CTYPE_UTF8CONT, + /* xaa */ SVN_CTYPE_UTF8CONT, + /* xab */ SVN_CTYPE_UTF8CONT, + /* xac */ SVN_CTYPE_UTF8CONT, + /* xad */ SVN_CTYPE_UTF8CONT, + /* xae */ SVN_CTYPE_UTF8CONT, + /* xaf */ SVN_CTYPE_UTF8CONT, + /* xb0 */ SVN_CTYPE_UTF8CONT, + /* xb1 */ SVN_CTYPE_UTF8CONT, + /* xb2 */ SVN_CTYPE_UTF8CONT, + /* xb3 */ SVN_CTYPE_UTF8CONT, + /* xb4 */ SVN_CTYPE_UTF8CONT, + /* xb5 */ SVN_CTYPE_UTF8CONT, + /* xb6 */ SVN_CTYPE_UTF8CONT, + /* xb7 */ SVN_CTYPE_UTF8CONT, + /* xb8 */ SVN_CTYPE_UTF8CONT, + /* xb9 */ SVN_CTYPE_UTF8CONT, + /* xba */ SVN_CTYPE_UTF8CONT, + /* xbb */ SVN_CTYPE_UTF8CONT, + /* xbc */ SVN_CTYPE_UTF8CONT, + /* xbd */ SVN_CTYPE_UTF8CONT, + /* xbe */ SVN_CTYPE_UTF8CONT, + /* xbf */ SVN_CTYPE_UTF8CONT, + /* xc0 */ 0, + /* xc1 */ SVN_CTYPE_UTF8LEAD, + /* xc2 */ SVN_CTYPE_UTF8LEAD, + /* xc3 */ SVN_CTYPE_UTF8LEAD, + /* xc4 */ SVN_CTYPE_UTF8LEAD, + /* xc5 */ SVN_CTYPE_UTF8LEAD, + /* xc6 */ SVN_CTYPE_UTF8LEAD, + /* xc7 */ SVN_CTYPE_UTF8LEAD, + /* xc8 */ SVN_CTYPE_UTF8LEAD, + /* xc9 */ SVN_CTYPE_UTF8LEAD, + /* xca */ SVN_CTYPE_UTF8LEAD, + /* xcb */ SVN_CTYPE_UTF8LEAD, + /* xcc */ SVN_CTYPE_UTF8LEAD, + /* xcd */ SVN_CTYPE_UTF8LEAD, + /* xce */ SVN_CTYPE_UTF8LEAD, + /* xcf */ SVN_CTYPE_UTF8LEAD, + /* xd0 */ SVN_CTYPE_UTF8LEAD, + /* xd1 */ SVN_CTYPE_UTF8LEAD, + /* xd2 */ SVN_CTYPE_UTF8LEAD, + /* xd3 */ SVN_CTYPE_UTF8LEAD, + /* xd4 */ SVN_CTYPE_UTF8LEAD, + /* xd5 */ SVN_CTYPE_UTF8LEAD, + /* xd6 */ SVN_CTYPE_UTF8LEAD, + /* xd7 */ SVN_CTYPE_UTF8LEAD, + /* xd8 */ SVN_CTYPE_UTF8LEAD, + /* xd9 */ SVN_CTYPE_UTF8LEAD, + /* xda */ SVN_CTYPE_UTF8LEAD, + /* xdb */ SVN_CTYPE_UTF8LEAD, + /* xdc */ SVN_CTYPE_UTF8LEAD, + /* xdd */ SVN_CTYPE_UTF8LEAD, + /* xde */ SVN_CTYPE_UTF8LEAD, + /* xdf */ SVN_CTYPE_UTF8LEAD, + /* xe0 */ 0, + /* xe1 */ SVN_CTYPE_UTF8LEAD, + /* xe2 */ SVN_CTYPE_UTF8LEAD, + /* xe3 */ SVN_CTYPE_UTF8LEAD, + /* xe4 */ SVN_CTYPE_UTF8LEAD, + /* xe5 */ SVN_CTYPE_UTF8LEAD, + /* xe6 */ SVN_CTYPE_UTF8LEAD, + /* xe7 */ SVN_CTYPE_UTF8LEAD, + /* xe8 */ SVN_CTYPE_UTF8LEAD, + /* xe9 */ SVN_CTYPE_UTF8LEAD, + /* xea */ SVN_CTYPE_UTF8LEAD, + /* xeb */ SVN_CTYPE_UTF8LEAD, + /* xec */ SVN_CTYPE_UTF8LEAD, + /* xed */ SVN_CTYPE_UTF8LEAD, + /* xee */ SVN_CTYPE_UTF8LEAD, + /* xef */ SVN_CTYPE_UTF8LEAD, + /* xf0 */ 0, + /* xf1 */ SVN_CTYPE_UTF8LEAD, + /* xf2 */ SVN_CTYPE_UTF8LEAD, + /* xf3 */ SVN_CTYPE_UTF8LEAD, + /* xf4 */ SVN_CTYPE_UTF8LEAD, + /* xf5 */ SVN_CTYPE_UTF8LEAD, + /* xf6 */ SVN_CTYPE_UTF8LEAD, + /* xf7 */ SVN_CTYPE_UTF8LEAD, + /* xf8 */ 0, + /* xf9 */ SVN_CTYPE_UTF8LEAD, + /* xfa */ SVN_CTYPE_UTF8LEAD, + /* xfb */ SVN_CTYPE_UTF8LEAD, + /* xfc */ 0, + /* xfd */ SVN_CTYPE_UTF8LEAD, + /* xfe */ 0, + /* xff */ 0 + }; + +const apr_uint32_t *const svn_ctype_table = svn_ctype_table_internal; + +static const unsigned char casefold_table[256] = + { + /* Identity, except {97:122} => {65:90} */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 + }; + +int +svn_ctype_casecmp(int a, int b) +{ + const int A = casefold_table[(unsigned char)a]; + const int B = casefold_table[(unsigned char)b]; + return A - B; +} diff --git a/src/TortoiseMerge/libsvn_diff/deflate.c b/src/TortoiseMerge/libsvn_diff/deflate.c new file mode 100644 index 0000000..ff57852 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/deflate.c @@ -0,0 +1,1350 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in ftp://ds.internic.net/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id: deflate.c,v 1.1 2003/05/23 21:05:30 steveking Exp $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.1.4 Copyright 1995-2002 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +local block_state deflate_slow OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int noheader = 0; + static const char* my_version = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == Z_NULL) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == Z_NULL) strm->zfree = zcfree; + + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#ifdef FASTEST + level = 1; +#endif + + if (windowBits < 0) { /* undocumented feature: suppress zlib header */ + noheader = 1; + windowBits = -windowBits; + } + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->noheader = noheader; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->status != INIT_STATE) return Z_STREAM_ERROR; + + s = strm->state; + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->noheader < 0) { + s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ + } + s->status = s->noheader ? BUSY_STATE : INIT_STATE; + strm->adler = 1; + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + + if (level == Z_DEFAULT_COMPRESSION) { + level = 6; + } + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the zlib header */ + if (s->status == INIT_STATE) { + + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags = (s->level-1) >> 1; + + if (level_flags > 3) level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = 1L; + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUFF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->noheader) return Z_STREAM_END; + + /* Write the zlib trailer (adler32) */ + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + s->noheader = -1; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (!strm->state->noheader) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +#ifndef FASTEST +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} + +#else /* FASTEST */ +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return len <= s->lookahead ? len : s->lookahead; +} +#endif /* FASTEST */ +#endif /* ASMV */ + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + } else if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in hash table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED || + (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} diff --git a/src/TortoiseMerge/libsvn_diff/deflate.h b/src/TortoiseMerge/libsvn_diff/deflate.h new file mode 100644 index 0000000..26d2b88 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/deflate.h @@ -0,0 +1,318 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2002 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h,v 1.1 2003/05/23 21:05:30 steveking Exp $ */ + +#ifndef _DEFLATE_H +#define _DEFLATE_H + +#include "zutil.h" + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int noheader; /* suppress zlib header and adler32 */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif diff --git a/src/TortoiseMerge/libsvn_diff/deprecated.c b/src/TortoiseMerge/libsvn_diff/deprecated.c index a6ad595..3c5e04b 100644 --- a/src/TortoiseMerge/libsvn_diff/deprecated.c +++ b/src/TortoiseMerge/libsvn_diff/deprecated.c @@ -27,6 +27,10 @@ deprecated functions in this file. */ #define SVN_DEPRECATED +#include "svn_error.h" +#include "svn_version.h" +#include "svn_io.h" + #include "svn_diff.h" #include "svn_utf.h" diff --git a/src/TortoiseMerge/libsvn_diff/diff.c b/src/TortoiseMerge/libsvn_diff/diff.c index 627cec3..2c21143 100644 --- a/src/TortoiseMerge/libsvn_diff/diff.c +++ b/src/TortoiseMerge/libsvn_diff/diff.c @@ -20,6 +20,9 @@ #include #include #include +#include "svn_error.h" +#include "svn_version.h" +#include "svn_io.h" #include "svn_pools.h" #include "svn_error.h" diff --git a/src/TortoiseMerge/libsvn_diff/diff3.c b/src/TortoiseMerge/libsvn_diff/diff3.c index 6602328..269cb4d 100644 --- a/src/TortoiseMerge/libsvn_diff/diff3.c +++ b/src/TortoiseMerge/libsvn_diff/diff3.c @@ -20,6 +20,9 @@ #include //#include #include +#include "svn_error.h" +#include "svn_version.h" +#include "svn_io.h" #include "svn_pools.h" #include "svn_error.h" diff --git a/src/TortoiseMerge/libsvn_diff/diff4.c b/src/TortoiseMerge/libsvn_diff/diff4.c index f57eece..2219ef8 100644 --- a/src/TortoiseMerge/libsvn_diff/diff4.c +++ b/src/TortoiseMerge/libsvn_diff/diff4.c @@ -21,6 +21,11 @@ //#include #include +#include +#include "svn_error.h" +#include "svn_version.h" +#include "svn_io.h" + #include "svn_pools.h" #include "svn_error.h" #include "svn_diff.h" diff --git a/src/TortoiseMerge/libsvn_diff/diff_file.c b/src/TortoiseMerge/libsvn_diff/diff_file.c index 0d24ef6..8d09703 100644 --- a/src/TortoiseMerge/libsvn_diff/diff_file.c +++ b/src/TortoiseMerge/libsvn_diff/diff_file.c @@ -26,6 +26,12 @@ #include #include +#include +#include "svn_error.h" +#include "svn_version.h" +#include "svn_io.h" +#include "svn_ctype.h" + #include "svn_error.h" #include "svn_types.h" @@ -1111,7 +1117,7 @@ output_unified_diff_modified(void *baton, return SVN_NO_ERROR; } -#if 0 + /* Set *HEADER to a new string consisting of PATH, a tab, and PATH's mtime. */ static svn_error_t * output_unified_default_hdr(const char **header, const char *path, @@ -1132,7 +1138,7 @@ output_unified_default_hdr(const char **header, const char *path, return SVN_NO_ERROR; } -#endif + static const svn_diff_output_fns_t svn_diff__file_output_unified_vtable = { diff --git a/src/TortoiseMerge/libsvn_diff/diff_memory.c b/src/TortoiseMerge/libsvn_diff/diff_memory.c index be2b1cf..ee25b6f 100644 --- a/src/TortoiseMerge/libsvn_diff/diff_memory.c +++ b/src/TortoiseMerge/libsvn_diff/diff_memory.c @@ -22,13 +22,19 @@ #include #include +#include +#include "svn_error.h" +#include "svn_version.h" +#include "svn_io.h" +#include "svn_ctype.h" + #include "svn_diff.h" #include "svn_pools.h" #include "svn_types.h" #include "svn_string.h" #include "svn_utf.h" #include "diff.h" -#include "svn_private_config.h" +//#include "svn_private_config.h" typedef struct source_tokens_t { diff --git a/src/TortoiseMerge/libsvn_diff/dirent_uri.c b/src/TortoiseMerge/libsvn_diff/dirent_uri.c new file mode 100644 index 0000000..4b07a89 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/dirent_uri.c @@ -0,0 +1,1199 @@ +/* + * dirent_uri.c: a library to manipulate URIs and directory entries. + * + * ==================================================================== + * Copyright (c) 2008-2009 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + + + +#include +#include +#include + +#include + +//#include "svn_private_config.h" +#include "svn_string.h" +#include "svn_dirent_uri.h" +#include "svn_path.h" + +//#include "private_uri.h" +#define SVN_PATH_LOCAL_SEPARATOR '\\' +const char * +svn_uri_canonicalize(const char *uri, apr_pool_t *pool); + +/* The canonical empty path. Can this be changed? Well, change the empty + test below and the path library will work, not so sure about the fs/wc + libraries. */ +#define SVN_EMPTY_PATH "" + +/* TRUE if s is the canonical empty path, FALSE otherwise */ +#define SVN_PATH_IS_EMPTY(s) ((s)[0] == '\0') + +/* TRUE if s,n is the platform's empty path ("."), FALSE otherwise. Can + this be changed? Well, the path library will work, not so sure about + the OS! */ +#define SVN_PATH_IS_PLATFORM_EMPTY(s,n) ((n) == 1 && (s)[0] == '.') + +/* Path type definition. Used only by internal functions. */ +typedef enum { + type_uri, + type_dirent +} path_type_t; + + +/**** Internal implementation functions *****/ + +/* Return an internal-style new path based on PATH, allocated in POOL. + * Pass type_uri for TYPE if PATH is a uri and type_dirent if PATH + * is a regular path. + * + * "Internal-style" means that separators are all '/', and the new + * path is canonicalized. + */ +static const char * +internal_style(path_type_t type, const char *path, apr_pool_t *pool) +{ +#if '/' != SVN_PATH_LOCAL_SEPARATOR + { + char *p = apr_pstrdup(pool, path); + path = p; + + /* Convert all local-style separators to the canonical ones. */ + for (; *p != '\0'; ++p) + if (*p == SVN_PATH_LOCAL_SEPARATOR) + *p = '/'; + } +#endif + + return type == type_uri ? svn_uri_canonicalize(path, pool) + : svn_dirent_canonicalize(path, pool); + /* FIXME: Should also remove trailing /.'s, if the style says so. */ +} + +/* Return a local-style new path based on PATH, allocated in POOL. + * Pass type_uri for TYPE if PATH is a uri and type_dirent if PATH + * is a regular path. + * + * "Local-style" means a path that looks like what users are + * accustomed to seeing, including native separators. The new path + * will still be canonicalized. + */ +static const char * +local_style(path_type_t type, const char *path, apr_pool_t *pool) +{ + path = type == type_uri ? svn_uri_canonicalize(path, pool) + : svn_dirent_canonicalize(path, pool); + /* FIXME: Should also remove trailing /.'s, if the style says so. */ + + /* Internally, Subversion represents the current directory with the + empty string. But users like to see "." . */ + if (SVN_PATH_IS_EMPTY(path)) + return "."; + + /* If PATH is a URL, the "local style" is the same as the input. */ + if (type == type_uri && svn_path_is_url(path)) + return apr_pstrdup(pool, path); + +#if '/' != SVN_PATH_LOCAL_SEPARATOR + { + char *p = apr_pstrdup(pool, path); + path = p; + + /* Convert all canonical separators to the local-style ones. */ + for (; *p != '\0'; ++p) + if (*p == '/') + *p = SVN_PATH_LOCAL_SEPARATOR; + } +#endif + + return path; +} + +/* Locale insensitive tolower() for converting parts of dirents and urls + while canonicalizing */ +static char +canonicalize_to_lower(char c) +{ + if (c < 'A' || c > 'Z') + return c; + else + return c - 'A' + 'a'; +} +#if defined(WIN32) || defined(__CYGWIN__) +/* Locale insensitive toupper() for converting parts of dirents and urls + while canonicalizing */ +static char +canonicalize_to_upper(char c) +{ + if (c < 'a' || c > 'z') + return c; + else + return c - 'a' + 'A'; +} +#endif + +/* Return the length of substring necessary to encompass the entire + * previous dirent segment in DIRENT, which should be a LEN byte string. + * + * A trailing slash will not be included in the returned length except + * in the case in which DIRENT is absolute and there are no more + * previous segments. + */ +static apr_size_t +dirent_previous_segment(const char *dirent, + apr_size_t len) +{ + if (len == 0) + return 0; + + --len; + while (len > 0 && dirent[len] != '/' +#if defined(WIN32) || defined(__CYGWIN__) + && dirent[len] != ':' +#endif /* WIN32 or Cygwin */ + ) + --len; + + /* check if the remaining segment including trailing '/' is a root dirent */ + if (svn_dirent_is_root(dirent, len + 1)) + return len + 1; + else + return len; +} + +/* Return the length of substring necessary to encompass the entire + * previous uri segment in URI, which should be a LEN byte string. + * + * A trailing slash will not be included in the returned length except + * in the case in which URI is absolute and there are no more + * previous segments. + */ +static apr_size_t +uri_previous_segment(const char *uri, + apr_size_t len) +{ + /* ### Still the old path segment code, should start checking scheme specific format */ + if (len == 0) + return 0; + + --len; + while (len > 0 && uri[len] != '/') + --len; + + /* check if the remaining segment including trailing '/' is a root dirent */ + if (svn_uri_is_root(uri, len + 1)) + return len + 1; + else + return len; +} + +/* Return the canonicalized version of PATH, allocated in POOL. + * Pass type_uri for TYPE if PATH is a uri and type_dirent if PATH + * is a regular path. + */ +static const char * +canonicalize(path_type_t type, const char *path, apr_pool_t *pool) +{ + char *canon, *dst; + const char *src; + apr_size_t seglen; + apr_size_t schemelen = 0; + apr_size_t canon_segments = 0; + svn_boolean_t url = FALSE; + + /* "" is already canonical, so just return it; note that later code + depends on path not being zero-length. */ + if (SVN_PATH_IS_EMPTY(path)) + return path; + + dst = canon = apr_pcalloc(pool, strlen(path) + 1); + + /* Try to parse the path as an URI. */ + url = FALSE; + src = path; + + if (type == type_uri && *src != '/') + { + while (*src && (*src != '/') && (*src != ':')) + src++; + + if (*src == ':' && *(src+1) == '/' && *(src+2) == '/') + { + const char *seg; + + url = TRUE; + + /* Found a scheme, convert to lowercase and copy to dst. */ + src = path; + while (*src != ':') + { + *(dst++) = canonicalize_to_lower((*src++)); + schemelen++; + } + *(dst++) = ':'; + *(dst++) = '/'; + *(dst++) = '/'; + src += 3; + schemelen += 3; + + /* This might be the hostname */ + seg = src; + while (*src && (*src != '/') && (*src != '@')) + src++; + + if (*src == '@') + { + /* Copy the username & password. */ + seglen = src - seg + 1; + memcpy(dst, seg, seglen); + dst += seglen; + src++; + } + else + src = seg; + + /* Found a hostname, convert to lowercase and copy to dst. */ + while (*src && (*src != '/')) + *(dst++) = canonicalize_to_lower((*src++)); + + /* Copy trailing slash, or null-terminator. */ + *(dst) = *(src); + + /* Move src and dst forward only if we are not + * at null-terminator yet. */ + if (*src) + { + src++; + dst++; + } + + canon_segments = 1; + } + } + + if (! url) + { + src = path; + /* If this is an absolute path, then just copy over the initial + separator character. */ + if (*src == '/') + { + *(dst++) = *(src++); + +#if defined(WIN32) || defined(__CYGWIN__) + /* On Windows permit two leading separator characters which means an + * UNC path. */ + if ((type == type_dirent) && *src == '/') + *(dst++) = *(src++); +#endif /* WIN32 or Cygwin */ + } + } + + while (*src) + { + /* Parse each segment, find the closing '/' */ + const char *next = src; + while (*next && (*next != '/')) + ++next; + + seglen = next - src; + + if (seglen == 0 || (seglen == 1 && src[0] == '.')) + { + /* Noop segment, so do nothing. */ + } +#if defined(WIN32) || defined(__CYGWIN__) + /* If this is the first path segment of a file:// URI and it contains a + windows drive letter, convert the drive letter to upper case. */ + else if (url && canon_segments == 1 && seglen == 2 && + (strncmp(canon, "file:", 5) == 0) && + src[0] >= 'a' && src[0] <= 'z' && src[1] == ':') + { + *(dst++) = canonicalize_to_upper(src[0]); + *(dst++) = ':'; + if (*next) + *(dst++) = *next; + canon_segments++; + } +#endif /* WIN32 or Cygwin */ + else + { + /* An actual segment, append it to the destination path */ + if (*next) + seglen++; + memcpy(dst, src, seglen); + dst += seglen; + canon_segments++; + } + + /* Skip over trailing slash to the next segment. */ + src = next; + if (*src) + src++; + } + + /* Remove the trailing slash if there was at least one + * canonical segment and the last segment ends with a slash. + * + * But keep in mind that, for URLs, the scheme counts as a + * canonical segment -- so if path is ONLY a scheme (such + * as "https://") we should NOT remove the trailing slash. */ + if ((canon_segments > 0 && *(dst - 1) == '/') + && ! (url && path[schemelen] == '\0')) + { + dst --; + } + + *dst = '\0'; + +#if defined(WIN32) || defined(__CYGWIN__) + /* Skip leading double slashes when there are less than 2 + * canon segments. UNC paths *MUST* have two segments. */ + if ((type == type_dirent) && canon[0] == '/' && canon[1] == '/') + { + if (canon_segments < 2) + return canon + 1; + else + { + /* Now we're sure this is a valid UNC path, convert the server name + (the first path segment) to lowercase as Windows treats it as case + insensitive. + Note: normally the share name is treated as case insensitive too, + but it seems to be possible to configure Samba to treat those as + case sensitive, so better leave that alone. */ + dst = canon + 2; + while (*dst && *dst != '/') + *(dst++) = canonicalize_to_lower(*dst); + } + } +#endif /* WIN32 or Cygwin */ + + return canon; +} + +/* Return the string length of the longest common ancestor of PATH1 and PATH2. + * Pass type_uri for TYPE if PATH1 and PATH2 are URIs, and type_dirent if + * PATH1 and PATH2 are regular paths. + * + * If the two paths do not share a common ancestor, return 0. + * + * New strings are allocated in POOL. + */ +static apr_size_t +get_longest_ancestor_length(path_type_t types, + const char *path1, + const char *path2, + apr_pool_t *pool) +{ + apr_size_t path1_len, path2_len; + apr_size_t i = 0; + apr_size_t last_dirsep = 0; +#if defined(WIN32) || defined(__CYGWIN__) + svn_boolean_t unc = FALSE; +#endif + + path1_len = strlen(path1); + path2_len = strlen(path2); + + if (SVN_PATH_IS_EMPTY(path1) || SVN_PATH_IS_EMPTY(path2)) + return 0; + + while (path1[i] == path2[i]) + { + /* Keep track of the last directory separator we hit. */ + if (path1[i] == '/') + last_dirsep = i; + + i++; + + /* If we get to the end of either path, break out. */ + if ((i == path1_len) || (i == path2_len)) + break; + } + + /* two special cases: + 1. '/' is the longest common ancestor of '/' and '/foo' */ + if (i == 1 && path1[0] == '/' && path2[0] == '/') + return 1; + /* 2. '' is the longest common ancestor of any non-matching + * strings 'foo' and 'bar' */ + if (types == type_dirent && i == 0) + return 0; + + /* Handle some windows specific cases */ +#if defined(WIN32) || defined(__CYGWIN__) + if (types == type_dirent) + { + /* don't count the '//' from UNC paths */ + if (last_dirsep == 1 && path1[0] == '/' && path1[1] == '/') + { + last_dirsep = 0; + unc = TRUE; + } + + /* X:/ and X:/foo */ + if (i == 3 && path1[2] == '/' && path1[1] == ':') + return i; + + /* Cannot use SVN_ERR_ASSERT here, so we'll have to crash, sorry. + * Note that this assertion triggers only if the code above has + * been broken. The code below relies on this assertion, because + * it uses [i - 1] as index. */ + assert(i > 0); + + /* X: and X:/ */ + if ((path1[i - 1] == ':' && path2[i] == '/') || + (path2[i - 1] == ':' && path1[i] == '/')) + return 0; + /* X: and X:foo */ + if (path1[i - 1] == ':' || path2[i - 1] == ':') + return i; + } +#endif /* WIN32 or Cygwin */ + + /* last_dirsep is now the offset of the last directory separator we + crossed before reaching a non-matching byte. i is the offset of + that non-matching byte, and is guaranteed to be <= the length of + whichever path is shorter. + If one of the paths is the common part return that. */ + if (((i == path1_len) && (path2[i] == '/')) + || ((i == path2_len) && (path1[i] == '/')) + || ((i == path1_len) && (i == path2_len))) + return i; + else + { + /* Nothing in common but the root folder '/' or 'X:/' for Windows + dirents. */ +#if defined(WIN32) || defined(__CYGWIN__) + if (! unc) + { + /* X:/foo and X:/bar returns X:/ */ + if ((types == type_dirent) && + last_dirsep == 2 && path1[1] == ':' && path1[2] == '/' + && path2[1] == ':' && path2[2] == '/') + return 3; +#endif + if (last_dirsep == 0 && path1[0] == '/' && path2[0] == '/') + return 1; +#if defined(WIN32) || defined(__CYGWIN__) + } +#endif + } + + return last_dirsep; +} + +/* Determine whether PATH2 is a child of PATH1. + * + * PATH2 is a child of PATH1 if + * 1) PATH1 is empty, and PATH2 is not empty and not an absolute path. + * or + * 2) PATH2 is has n components, PATH1 has x < n components, + * and PATH1 matches PATH2 in all its x components. + * Components are separated by a slash, '/'. + * + * Pass type_uri for TYPE if PATH1 and PATH2 are URIs, and type_dirent if + * PATH1 and PATH2 are regular paths. + * + * If PATH2 is not a child of PATH1, return NULL. + * + * If PATH2 is a child of PATH1, and POOL is not NULL, allocate a copy + * of the child part of PATH2 in POOL and return a pointer to the + * newly allocated child part. + * + * If PATH2 is a child of PATH1, and POOL is NULL, return a pointer + * pointing to the child part of PATH2. + * */ +static const char * +is_child(path_type_t type, const char *path1, const char *path2, + apr_pool_t *pool) +{ + apr_size_t i; + + /* Allow "" and "foo" or "H:foo" to be parent/child */ + if (SVN_PATH_IS_EMPTY(path1)) /* "" is the parent */ + { + if (SVN_PATH_IS_EMPTY(path2)) /* "" not a child */ + return NULL; + + /* check if this is an absolute path */ + if ((type == type_uri && svn_uri_is_absolute(path2)) || + (type == type_dirent && svn_dirent_is_absolute(path2))) + return NULL; + else + /* everything else is child */ + return pool ? apr_pstrdup(pool, path2) : path2; + } + + /* Reach the end of at least one of the paths. How should we handle + things like path1:"foo///bar" and path2:"foo/bar/baz"? It doesn't + appear to arise in the current Subversion code, it's not clear to me + if they should be parent/child or not. */ + /* Hmmm... aren't paths assumed to be canonical in this function? + * How can "foo///bar" even happen if the paths are canonical? */ + for (i = 0; path1[i] && path2[i]; i++) + if (path1[i] != path2[i]) + return NULL; + + /* FIXME: This comment does not really match + * the checks made in the code it refers to: */ + /* There are two cases that are parent/child + ... path1[i] == '\0' + .../foo path2[i] == '/' + or + / path1[i] == '\0' + /foo path2[i] != '/' + + Other root paths (like X:/) fall under the former case: + X:/ path1[i] == '\0' + X:/foo path2[i] != '/' + + Check for '//' to avoid matching '/' and '//srv'. + */ + if (path1[i] == '\0' && path2[i]) + { + if (path1[i - 1] == '/' +#if defined(WIN32) || defined(__CYGWIN__) + || ((type == type_dirent) && path1[i - 1] == ':') +#endif /* WIN32 or Cygwin */ + ) + { + if (path2[i] == '/') + /* .../ + * ..../ + * i */ + return NULL; + else + /* .../ + * .../foo + * i */ + return pool ? apr_pstrdup(pool, path2 + i) : path2 + i; + } + else if (path2[i] == '/') + { + if (path2[i + 1]) + /* ... + * .../foo + * i */ + return pool ? apr_pstrdup(pool, path2 + i + 1) : path2 + i + 1; + else + /* ... + * .../ + * i */ + return NULL; + } + } + + /* Otherwise, path2 isn't a child. */ + return NULL; +} + +/* FIXME: no doc string */ +static svn_boolean_t +is_ancestor(path_type_t type, const char *path1, const char *path2) +{ + apr_size_t path1_len; + + /* If path1 is empty and path2 is not absolute, then path1 is an ancestor. */ + if (SVN_PATH_IS_EMPTY(path1)) + { + return type == type_uri ? ! svn_uri_is_absolute(path2) + : ! svn_dirent_is_absolute(path2); + } + + /* If path1 is a prefix of path2, then: + - If path1 ends in a path separator, + - If the paths are of the same length + OR + - path2 starts a new path component after the common prefix, + then path1 is an ancestor. */ + path1_len = strlen(path1); + if (strncmp(path1, path2, path1_len) == 0) + return path1[path1_len - 1] == '/' +#if defined(WIN32) || defined(__CYGWIN__) + || ((type == type_dirent) && path1[path1_len - 1] == ':') +#endif /* WIN32 or Cygwin */ + || (path2[path1_len] == '/' || path2[path1_len] == '\0'); + + return FALSE; +} + + +/**** Public API functions ****/ + +const char * +svn_dirent_internal_style(const char *dirent, apr_pool_t *pool) +{ + return internal_style(type_dirent, dirent, pool); +} + +const char * +svn_dirent_local_style(const char *dirent, apr_pool_t *pool) +{ + return local_style(type_dirent, dirent, pool); +} + +const char * +svn_uri_internal_style(const char *uri, apr_pool_t *pool) +{ + return internal_style(type_uri, uri, pool); +} + +const char * +svn_uri_local_style(const char *uri, apr_pool_t *pool) +{ + return local_style(type_uri, uri, pool); +} + +/* We decided against using apr_filepath_root here because of the negative + performance impact (creating a pool and converting strings ). */ +svn_boolean_t +svn_dirent_is_root(const char *dirent, apr_size_t len) +{ + /* directory is root if it's equal to '/' */ + if (len == 1 && dirent[0] == '/') + return TRUE; + +#if defined(WIN32) || defined(__CYGWIN__) + /* On Windows and Cygwin, 'H:' or 'H:/' (where 'H' is any letter) + are also root directories */ + if ((len == 2 || len == 3) && + (dirent[1] == ':') && + ((dirent[0] >= 'A' && dirent[0] <= 'Z') || + (dirent[0] >= 'a' && dirent[0] <= 'z')) && + (len == 2 || (dirent[2] == '/' && len == 3))) + return TRUE; + + /* On Windows and Cygwin, both //drive and //server/share are root + directories */ + if (len >= 2 && dirent[0] == '/' && dirent[1] == '/' + && dirent[len - 1] != '/') + { + int segments = 0; + int i; + for (i = len; i >= 2; i--) + { + if (dirent[i] == '/') + { + segments ++; + if (segments > 1) + return FALSE; + } + } + return (segments <= 1); + } +#endif /* WIN32 or Cygwin */ + + return FALSE; +} + +svn_boolean_t +svn_uri_is_root(const char *uri, apr_size_t len) +{ + /* directory is root if it's equal to '/' */ + if (len == 1 && uri[0] == '/') + return TRUE; + + return FALSE; +} + +char *svn_dirent_join(const char *base, + const char *component, + apr_pool_t *pool) +{ + apr_size_t blen = strlen(base); + apr_size_t clen = strlen(component); + char *dirent; + int add_separator; + + assert(svn_dirent_is_canonical(base, pool)); + assert(svn_dirent_is_canonical(component, pool)); + + /* If the component is absolute, then return it. */ + if (svn_dirent_is_absolute(component)) + return apr_pmemdup(pool, component, clen + 1); + + /* If either is empty return the other */ + if (SVN_PATH_IS_EMPTY(base)) + return apr_pmemdup(pool, component, clen + 1); + if (SVN_PATH_IS_EMPTY(component)) + return apr_pmemdup(pool, base, blen + 1); + + /* if last character of base is already a separator, don't add a '/' */ + add_separator = 1; + if (base[blen - 1] == '/' +#if defined(WIN32) || defined(__CYGWIN__) + || base[blen - 1] == ':' +#endif /* WIN32 or Cygwin */ + ) + add_separator = 0; + + /* Construct the new, combined dirent. */ + dirent = apr_palloc(pool, blen + add_separator + clen + 1); + memcpy(dirent, base, blen); + if (add_separator) + dirent[blen] = '/'; + memcpy(dirent + blen + add_separator, component, clen + 1); + + return dirent; +} + +char *svn_dirent_join_many(apr_pool_t *pool, const char *base, ...) +{ +#define MAX_SAVED_LENGTHS 10 + apr_size_t saved_lengths[MAX_SAVED_LENGTHS]; + apr_size_t total_len; + int nargs; + va_list va; + const char *s; + apr_size_t len; + char *dirent; + char *p; + int add_separator; + int base_arg = 0; + + total_len = strlen(base); + + assert(svn_dirent_is_canonical(base, pool)); + + /* if last character of base is already a separator, don't add a '/' */ + add_separator = 1; + if (total_len == 0 + || base[total_len - 1] == '/' +#if defined(WIN32) || defined(__CYGWIN__) + || base[total_len - 1] == ':' +#endif /* WIN32 or Cygwin */ + ) + add_separator = 0; + + saved_lengths[0] = total_len; + + /* Compute the length of the resulting string. */ + + nargs = 0; + va_start(va, base); + while ((s = va_arg(va, const char *)) != NULL) + { + len = strlen(s); + + assert(svn_dirent_is_canonical(s, pool)); + + if (SVN_PATH_IS_EMPTY(s)) + continue; + + if (nargs++ < MAX_SAVED_LENGTHS) + saved_lengths[nargs] = len; + + if (svn_dirent_is_absolute(s)) + { + /* an absolute dirent. skip all components to this point and reset + the total length. */ + total_len = len; + base_arg = nargs; + add_separator = 1; + if (s[len - 1] == '/' + #if defined(WIN32) || defined(__CYGWIN__) + || s[len - 1] == ':' + #endif /* WIN32 or Cygwin */ + ) + add_separator = 0; + } + else if (nargs == base_arg + 1) + { + total_len += add_separator + len; + } + else + { + total_len += 1 + len; + } + } + va_end(va); + + /* base == "/" and no further components. just return that. */ + if (add_separator == 0 && total_len == 1) + return apr_pmemdup(pool, "/", 2); + + /* we got the total size. allocate it, with room for a NULL character. */ + dirent = p = apr_palloc(pool, total_len + 1); + + /* if we aren't supposed to skip forward to an absolute component, and if + this is not an empty base that we are skipping, then copy the base + into the output. */ + if (base_arg == 0 && ! (SVN_PATH_IS_EMPTY(base))) + { + if (SVN_PATH_IS_EMPTY(base)) + memcpy(p, SVN_EMPTY_PATH, len = saved_lengths[0]); + else + memcpy(p, base, len = saved_lengths[0]); + p += len; + } + + nargs = 0; + va_start(va, base); + while ((s = va_arg(va, const char *)) != NULL) + { + if (SVN_PATH_IS_EMPTY(s)) + continue; + + if (++nargs < base_arg) + continue; + + if (nargs < MAX_SAVED_LENGTHS) + len = saved_lengths[nargs]; + else + len = strlen(s); + + /* insert a separator if we aren't copying in the first component + (which can happen when base_arg is set). also, don't put in a slash + if the prior character is a slash (occurs when prior component + is "/"). */ + if (p != dirent && + ( ! (nargs - 1 == base_arg) || add_separator)) + *p++ = '/'; + + /* copy the new component and advance the pointer */ + memcpy(p, s, len); + p += len; + } + va_end(va); + + *p = '\0'; + assert((apr_size_t)(p - dirent) == total_len); + + return dirent; +} + +char * +svn_dirent_dirname(const char *dirent, apr_pool_t *pool) +{ + apr_size_t len = strlen(dirent); + + assert(svn_dirent_is_canonical(dirent, pool)); + + if (svn_dirent_is_root(dirent, len)) + return apr_pstrmemdup(pool, dirent, len); + else + return apr_pstrmemdup(pool, dirent, dirent_previous_segment(dirent, len)); +} + +char * +svn_uri_dirname(const char *uri, apr_pool_t *pool) +{ + apr_size_t len = strlen(uri); + + assert(svn_uri_is_canonical(uri, pool)); + + if (svn_uri_is_root(uri, len)) + return apr_pstrmemdup(pool, uri, len); + else + return apr_pstrmemdup(pool, uri, uri_previous_segment(uri, len)); +} + +char * +svn_dirent_get_longest_ancestor(const char *dirent1, + const char *dirent2, + apr_pool_t *pool) +{ + return apr_pstrndup(pool, dirent1, + get_longest_ancestor_length(type_dirent, dirent1, + dirent2, pool)); +} + +char * +svn_uri_get_longest_ancestor(const char *uri1, + const char *uri2, + apr_pool_t *pool) +{ + svn_boolean_t uri1_is_url, uri2_is_url; + uri1_is_url = svn_path_is_url(uri1); + uri2_is_url = svn_path_is_url(uri2); + + if (uri1_is_url && uri2_is_url) + { + apr_size_t uri_ancestor_len; + apr_size_t i = 0; + + /* Find ':' */ + while (1) + { + /* No shared protocol => no common prefix */ + if (uri1[i] != uri2[i]) + return apr_pmemdup(pool, SVN_EMPTY_PATH, + sizeof(SVN_EMPTY_PATH)); + + if (uri1[i] == ':') + break; + + /* They're both URLs, so EOS can't come before ':' */ + assert((uri1[i] != '\0') && (uri2[i] != '\0')); + + i++; + } + + i += 3; /* Advance past '://' */ + + uri_ancestor_len = get_longest_ancestor_length(type_uri, uri1 + i, + uri2 + i, pool); + + if (uri_ancestor_len == 0 || + (uri_ancestor_len == 1 && (uri1 + i)[0] == '/')) + return apr_pmemdup(pool, SVN_EMPTY_PATH, sizeof(SVN_EMPTY_PATH)); + else + return apr_pstrndup(pool, uri1, uri_ancestor_len + i); + } + + else if ((! uri1_is_url) && (! uri2_is_url)) + { + return apr_pstrndup(pool, uri1, + get_longest_ancestor_length(type_uri, uri1, uri2, + pool)); + } + + else + { + /* A URL and a non-URL => no common prefix */ + return apr_pmemdup(pool, SVN_EMPTY_PATH, sizeof(SVN_EMPTY_PATH)); + } +} + +const char * +svn_dirent_is_child(const char *dirent1, + const char *dirent2, + apr_pool_t *pool) +{ + return is_child(type_dirent, dirent1, dirent2, pool); +} + +const char * +svn_uri_is_child(const char *uri1, + const char *uri2, + apr_pool_t *pool) +{ + return is_child(type_uri, uri1, uri2, pool); +} + +svn_boolean_t +svn_dirent_is_ancestor(const char *dirent1, const char *dirent2) +{ + return is_ancestor(type_dirent, dirent1, dirent2); +} + +svn_boolean_t +svn_uri_is_ancestor(const char *uri1, const char *uri2) +{ + return is_ancestor(type_uri, uri1, uri2); +} + +svn_boolean_t +svn_dirent_is_absolute(const char *dirent) +{ + if (! dirent) + return FALSE; + + /* dirent is absolute if it starts with '/' */ + if (dirent[0] == '/') + return TRUE; + + /* On Windows, dirent is also absolute when it starts with 'H:' or 'H:/' + where 'H' is any letter. */ +#if defined(WIN32) || defined(__CYGWIN__) + if (((dirent[0] >= 'A' && dirent[0] <= 'Z') || + (dirent[0] >= 'a' && dirent[0] <= 'z')) && + (dirent[1] == ':')) + return TRUE; +#endif /* WIN32 or Cygwin */ + + return FALSE; +} + +svn_boolean_t +svn_uri_is_absolute(const char *uri) +{ + /* uri is absolute if it starts with '/' */ + if (uri && uri[0] == '/') + return TRUE; + + /* URLs are absolute. */ + return svn_path_is_url(uri); +} + +svn_error_t * +svn_dirent_get_absolute(const char **pabsolute, + const char *relative, + apr_pool_t *pool) +{ + char *buffer; + apr_status_t apr_err; + const char *path_apr; + + /* Merge the current working directory with the relative dirent. */ + SVN_ERR(svn_path_cstring_from_utf8(&path_apr, relative, pool)); + + apr_err = apr_filepath_merge(&buffer, NULL, + path_apr, + APR_FILEPATH_NOTRELATIVE, + pool); + if (apr_err) + return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL, + _("Couldn't determine absolute path of '%s'"), + svn_path_local_style(relative, pool)); + + SVN_ERR(svn_path_cstring_to_utf8(pabsolute, buffer, pool)); + *pabsolute = svn_dirent_canonicalize(*pabsolute, pool); + return SVN_NO_ERROR; +} + +const char * +svn_uri_canonicalize(const char *uri, apr_pool_t *pool) +{ + return canonicalize(type_uri, uri, pool);; +} + +const char * +svn_dirent_canonicalize(const char *dirent, apr_pool_t *pool) +{ + const char *dst = canonicalize(type_dirent, dirent, pool);; + +#if defined(WIN32) || defined(__CYGWIN__) + /* Handle a specific case on Windows where path == "X:/". Here we have to + append the final '/', as svn_path_canonicalize will chop this of. */ + if (((dirent[0] >= 'A' && dirent[0] <= 'Z') || + (dirent[0] >= 'a' && dirent[0] <= 'z')) && + dirent[1] == ':' && dirent[2] == '/' && + dst[3] == '\0') + { + char *dst_slash = apr_pcalloc(pool, 4); + dst_slash[0] = dirent[0]; + dst_slash[1] = ':'; + dst_slash[2] = '/'; + dst_slash[3] = '\0'; + + return dst_slash; + } +#endif /* WIN32 or Cygwin */ + + return dst; +} + +svn_boolean_t +svn_dirent_is_canonical(const char *dirent, apr_pool_t *pool) +{ + return (strcmp(dirent, svn_dirent_canonicalize(dirent, pool)) == 0); +} + +svn_boolean_t +svn_uri_is_canonical(const char *uri, apr_pool_t *pool) +{ + const char *ptr = uri, *seg = uri; + + /* URI is canonical if it has: + * - no '.' segments + * - no closing '/', unless for the root path '/' itself + * - no '//' + * - lowercase URL scheme + * - lowercase URL hostname + */ + + if (*uri == '\0') + return TRUE; + + /* Maybe parse hostname and scheme. */ + if (*ptr != '/') + { + while (*ptr && (*ptr != '/') && (*ptr != ':')) + ptr++; + + if (*ptr == ':' && *(ptr+1) == '/' && *(ptr+2) == '/') + { + /* Found a scheme, check that it's all lowercase. */ + ptr = uri; + while (*ptr != ':') + { + if (*ptr >= 'A' && *ptr <= 'Z') + return FALSE; + ptr++; + } + /* Skip :// */ + ptr += 3; + + /* This might be the hostname */ + seg = ptr; + while (*ptr && (*ptr != '/') && (*ptr != '@')) + ptr++; + + if (! *ptr) + return TRUE; + + if (*ptr == '@') + seg = ptr + 1; + + /* Found a hostname, check that it's all lowercase. */ + ptr = seg; + while (*ptr && *ptr != '/') + { + if (*ptr >= 'A' && *ptr <= 'Z') + return FALSE; + ptr++; + } + } + else + { + /* Didn't find a scheme; finish the segment. */ + while (*ptr && *ptr != '/') + ptr++; + } + } + +#if defined(WIN32) || defined(__CYGWIN__) + if (*ptr == '/') + { + /* If this is a file url, ptr now points to the third '/' in + file:///C:/path. Check that if we have such a URL the drive + letter is in uppercase. */ + if (strncmp(uri, "file:", 5) == 0 && + ! (*(ptr+1) >= 'A' && *(ptr+1) <= 'Z') && + *(ptr+2) == ':') + return FALSE; + } +#endif /* WIN32 or Cygwin */ + + /* Now validate the rest of the URI. */ + while(1) + { + int seglen = ptr - seg; + + if (seglen == 1 && *seg == '.') + return FALSE; /* /./ */ + + if (*ptr == '/' && *(ptr+1) == '/') + return FALSE; /* // */ + + if (! *ptr && *(ptr - 1) == '/' && ptr - 1 != uri) + return FALSE; /* foo/ */ + + if (! *ptr) + break; + + if (*ptr == '/') + ptr++; + seg = ptr; + + while (*ptr && (*ptr != '/')) + ptr++; + } + + return TRUE; +} diff --git a/src/TortoiseMerge/libsvn_diff/dso.c b/src/TortoiseMerge/libsvn_diff/dso.c new file mode 100644 index 0000000..3bcbf36 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/dso.c @@ -0,0 +1,132 @@ +/* + * ==================================================================== + * Copyright (c) 2006 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + +#include +#include + +#include "svn_dso.h" +#include "svn_pools.h" +//#include "svn_private_config.h" + +/* A mutex to protect our global pool and cache. */ +#if APR_HAS_THREADS +static apr_thread_mutex_t *dso_mutex; +#endif + +/* Global pool to allocate DSOs in. */ +static apr_pool_t *dso_pool; + +/* Global cache for storing DSO objects. */ +static apr_hash_t *dso_cache; + +/* Just an arbitrary location in memory... */ +static int not_there_sentinel; + +/* A specific value we store in the dso_cache to indicate that the + library wasn't found. This keeps us from allocating extra memory + from dso_pool when trying to find libraries we already know aren't + there. */ +#define NOT_THERE ((void *) ¬_there_sentinel) + +svn_error_t * +svn_dso_initialize2(void) +{ + apr_status_t status; + if (dso_pool) + return SVN_NO_ERROR; + + dso_pool = svn_pool_create(NULL); + +#if APR_HAS_THREADS + status = apr_thread_mutex_create(&dso_mutex, + APR_THREAD_MUTEX_DEFAULT, dso_pool); + if (status) + return svn_error_wrap_apr(status, _("Can't create DSO mutex")); +#endif + + dso_cache = apr_hash_make(dso_pool); + return SVN_NO_ERROR; +} + +#if APR_HAS_DSO +svn_error_t * +svn_dso_load(apr_dso_handle_t **dso, const char *fname) +{ + apr_status_t status; + + if (! dso_pool) + SVN_ERR(svn_dso_initialize2()); + +#if APR_HAS_THREADS + status = apr_thread_mutex_lock(dso_mutex); + if (status) + return svn_error_wrap_apr(status, _("Can't grab DSO mutex")); +#endif + + *dso = apr_hash_get(dso_cache, fname, APR_HASH_KEY_STRING); + + /* First check to see if we've been through this before... We do this + to avoid calling apr_dso_load multiple times for a given library, + which would result in wasting small amounts of memory each time. */ + if (*dso == NOT_THERE) + { + *dso = NULL; +#if APR_HAS_THREADS + status = apr_thread_mutex_unlock(dso_mutex); + if (status) + return svn_error_wrap_apr(status, _("Can't ungrab DSO mutex")); +#endif + return SVN_NO_ERROR; + } + + /* If we got nothing back from the cache, try and load the library. */ + if (! *dso) + { + status = apr_dso_load(dso, fname, dso_pool); + if (status) + { + *dso = NULL; + + /* It wasn't found, so set the special "we didn't find it" value. */ + apr_hash_set(dso_cache, + apr_pstrdup(dso_pool, fname), + APR_HASH_KEY_STRING, + NOT_THERE); + +#if APR_HAS_THREADS + status = apr_thread_mutex_unlock(dso_mutex); + if (status) + return svn_error_wrap_apr(status, _("Can't ungrab DSO mutex")); +#endif + return SVN_NO_ERROR; + } + + /* Stash the dso so we can use it next time. */ + apr_hash_set(dso_cache, + apr_pstrdup(dso_pool, fname), + APR_HASH_KEY_STRING, + *dso); + } + +#if APR_HAS_THREADS + status = apr_thread_mutex_unlock(dso_mutex); + if (status) + return svn_error_wrap_apr(status, _("Can't ungrab DSO mutex")); +#endif + + return SVN_NO_ERROR; +} +#endif /* APR_HAS_DSO */ diff --git a/src/TortoiseMerge/libsvn_diff/error.c b/src/TortoiseMerge/libsvn_diff/error.c new file mode 100644 index 0000000..c6273a6 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/error.c @@ -0,0 +1,549 @@ +/* error.c: common exception handling for Subversion + * + * ==================================================================== + * Copyright (c) 2000-2007 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + + + +#include + +#include +#include +#include + +//#include "svn_cmdline.h" +#include "svn_error.h" +#include "svn_pools.h" +#include "svn_utf.h" + +#ifdef SVN_DEBUG +/* file_line for the non-debug case. */ +static const char SVN_FILE_LINE_UNDEFINED[] = "svn:"; +#endif /* SVN_DEBUG */ + +//#include "svn_private_config.h" + + +/*** Helpers for creating errors ***/ +#undef svn_error_create +#undef svn_error_createf +#undef svn_error_quick_wrap +#undef svn_error_wrap_apr + + +/* XXX FIXME: These should be protected by a thread mutex. + svn_error__locate and make_error_internal should cooperate + in locking and unlocking it. */ + +/* XXX TODO: Define mutex here #if APR_HAS_THREADS */ +static const char *error_file = NULL; +static long error_line = -1; + +void +svn_error__locate(const char *file, long line) +{ + /* XXX TODO: Lock mutex here */ + error_file = file; + error_line = line; +} + + +/* Cleanup function for errors. svn_error_clear () removes this so + errors that are properly handled *don't* hit this code. */ +#if defined(SVN_DEBUG) +static apr_status_t err_abort(void *data) +{ + svn_error_t *err = data; /* For easy viewing in a debugger */ + err = err; /* Fake a use for the variable to avoid compiler warnings */ + abort(); +} +#endif + + +static svn_error_t * +make_error_internal(apr_status_t apr_err, + svn_error_t *child) +{ + apr_pool_t *pool; + svn_error_t *new_error; + + /* Reuse the child's pool, or create our own. */ + if (child) + pool = child->pool; + else + { + if (apr_pool_create(&pool, NULL)) + abort(); + } + + /* Create the new error structure */ + new_error = apr_pcalloc(pool, sizeof(*new_error)); + + /* Fill 'er up. */ + new_error->apr_err = apr_err; + new_error->child = child; + new_error->pool = pool; + new_error->file = error_file; + new_error->line = error_line; + /* XXX TODO: Unlock mutex here */ + +#if defined(SVN_DEBUG) + if (! child) + apr_pool_cleanup_register(pool, new_error, + err_abort, + apr_pool_cleanup_null); +#endif + + return new_error; +} + + + +/*** Creating and destroying errors. ***/ + +svn_error_t * +svn_error_create(apr_status_t apr_err, + svn_error_t *child, + const char *message) +{ + svn_error_t *err; + + err = make_error_internal(apr_err, child); + + if (message) + err->message = apr_pstrdup(err->pool, message); + + return err; +} + + +svn_error_t * +svn_error_createf(apr_status_t apr_err, + svn_error_t *child, + const char *fmt, + ...) +{ + svn_error_t *err; + va_list ap; + + err = make_error_internal(apr_err, child); + + va_start(ap, fmt); + err->message = apr_pvsprintf(err->pool, fmt, ap); + va_end(ap); + + return err; +} + + +svn_error_t * +svn_error_wrap_apr(apr_status_t status, + const char *fmt, + ...) +{ + svn_error_t *err, *utf8_err; + va_list ap; + char errbuf[255]; + const char *msg_apr, *msg; + + err = make_error_internal(status, NULL); + + if (fmt) + { + /* Grab the APR error message. */ + apr_strerror(status, errbuf, sizeof(errbuf)); + utf8_err = svn_utf_cstring_to_utf8(&msg_apr, errbuf, err->pool); + if (utf8_err) + msg_apr = NULL; + svn_error_clear(utf8_err); + + /* Append it to the formatted message. */ + va_start(ap, fmt); + msg = apr_pvsprintf(err->pool, fmt, ap); + va_end(ap); + err->message = apr_psprintf(err->pool, "%s%s%s", msg, + (msg_apr) ? ": " : "", + (msg_apr) ? msg_apr : ""); + } + + return err; +} + + +svn_error_t * +svn_error_quick_wrap(svn_error_t *child, const char *new_msg) +{ + return svn_error_create(child->apr_err, + child, + new_msg); +} + + +svn_error_t * +svn_error_compose_create(svn_error_t *err1, + svn_error_t *err2) +{ + if (err1 && err2) + { + svn_error_compose(err1, err2); + return err1; + } + return err1 ? err1 : err2; +} + + +void +svn_error_compose(svn_error_t *chain, svn_error_t *new_err) +{ + apr_pool_t *pool = chain->pool; + apr_pool_t *oldpool = new_err->pool; + + while (chain->child) + chain = chain->child; + +#if defined(SVN_DEBUG) + /* Kill existing handler since the end of the chain is going to change */ + apr_pool_cleanup_kill(pool, chain, err_abort); +#endif + + /* Copy the new error chain into the old chain's pool. */ + while (new_err) + { + chain->child = apr_palloc(pool, sizeof(*chain->child)); + chain = chain->child; + *chain = *new_err; + if (chain->message) + chain->message = apr_pstrdup(pool, new_err->message); + chain->pool = pool; +#if defined(SVN_DEBUG) + if (! new_err->child) + apr_pool_cleanup_kill(oldpool, new_err, err_abort); +#endif + new_err = new_err->child; + } + +#if defined(SVN_DEBUG) + apr_pool_cleanup_register(pool, chain, + err_abort, + apr_pool_cleanup_null); +#endif + + /* Destroy the new error chain. */ + svn_pool_destroy(oldpool); +} + +svn_error_t * +svn_error_root_cause(svn_error_t *err) +{ + while (err) + { + if (err->child) + err = err->child; + else + break; + } + + return err; +} + +svn_error_t * +svn_error_dup(svn_error_t *err) +{ + apr_pool_t *pool; + svn_error_t *new_err = NULL, *tmp_err = NULL; + + if (apr_pool_create(&pool, NULL)) + abort(); + + for (; err; err = err->child) + { + if (! new_err) + { + new_err = apr_palloc(pool, sizeof(*new_err)); + tmp_err = new_err; + } + else + { + tmp_err->child = apr_palloc(pool, sizeof(*tmp_err->child)); + tmp_err = tmp_err->child; + } + *tmp_err = *err; + tmp_err->pool = pool; + if (tmp_err->message) + tmp_err->message = apr_pstrdup(pool, tmp_err->message); + } + +#if defined(SVN_DEBUG) + apr_pool_cleanup_register(pool, tmp_err, + err_abort, + apr_pool_cleanup_null); +#endif + + return new_err; +} + +void +svn_error_clear(svn_error_t *err) +{ + if (err) + { +#if defined(SVN_DEBUG) + while (err->child) + err = err->child; + apr_pool_cleanup_kill(err->pool, err, err_abort); +#endif + svn_pool_destroy(err->pool); + } +} + +static void +print_error(svn_error_t *err, FILE *stream, const char *prefix) +{ + char errbuf[256]; + const char *err_string; + svn_error_t *temp_err = NULL; /* ensure initialized even if + err->file == NULL */ + /* Pretty-print the error */ + /* Note: we can also log errors here someday. */ + +#ifdef SVN_DEBUG + /* Note: err->file is _not_ in UTF-8, because it's expanded from + the __FILE__ preprocessor macro. */ + const char *file_utf8; + + if (err->file + && !(temp_err = svn_utf_cstring_to_utf8(&file_utf8, err->file, + err->pool))) + svn_error_clear(svn_cmdline_fprintf(stream, err->pool, + "%s:%ld", err->file, err->line)); + else + { + svn_error_clear(svn_cmdline_fputs(SVN_FILE_LINE_UNDEFINED, + stream, err->pool)); + svn_error_clear(temp_err); + } + + svn_error_clear(svn_cmdline_fprintf(stream, err->pool, + ": (apr_err=%d)\n", err->apr_err)); +#endif /* SVN_DEBUG */ + + /* Only print the same APR error string once. */ + if (err->message) + { + svn_error_clear(svn_cmdline_fprintf(stream, err->pool, "%s%s\n", + prefix, err->message)); + } + else + { + /* Is this a Subversion-specific error code? */ + if ((err->apr_err > APR_OS_START_USEERR) + && (err->apr_err <= APR_OS_START_CANONERR)) + err_string = svn_strerror(err->apr_err, errbuf, sizeof(errbuf)); + /* Otherwise, this must be an APR error code. */ + else if ((temp_err = svn_utf_cstring_to_utf8 + (&err_string, apr_strerror(err->apr_err, errbuf, + sizeof(errbuf)), err->pool))) + { + svn_error_clear(temp_err); + err_string = _("Can't recode error string from APR"); + } + + svn_error_clear(svn_cmdline_fprintf(stream, err->pool, + "%s%s\n", prefix, err_string)); + } +} + +void +svn_handle_error(svn_error_t *err, FILE *stream, svn_boolean_t fatal) +{ + svn_handle_error2(err, stream, fatal, "svn: "); +} + +void +svn_handle_error2(svn_error_t *err, + FILE *stream, + svn_boolean_t fatal, + const char *prefix) +{ + /* In a long error chain, there may be multiple errors with the same + error code and no custom message. We only want to print the + default message for that code once; printing it multiple times + would add no useful information. The 'empties' array below + remembers the codes of empty errors already seen in the chain. + + We could allocate it in err->pool, but there's no telling how + long err will live or how many times it will get handled. So we + use a subpool. */ + apr_pool_t *subpool; + apr_array_header_t *empties; + svn_error_t *tmp_err; + + /* ### The rest of this file carefully avoids using svn_pool_*(), + preferring apr_pool_*() instead. I can't remember why -- it may + be an artifact of r3719, or it may be for some deeper reason -- + but I'm playing it safe and using apr_pool_*() here too. */ + apr_pool_create(&subpool, err->pool); + empties = apr_array_make(subpool, 0, sizeof(apr_status_t)); + + tmp_err = err; + while (tmp_err) + { + int i; + svn_boolean_t printed_already = FALSE; + + if (! tmp_err->message) + { + for (i = 0; i < empties->nelts; i++) + { + if (tmp_err->apr_err == APR_ARRAY_IDX(empties, i, apr_status_t) ) + { + printed_already = TRUE; + break; + } + } + } + + if (! printed_already) + { + print_error(tmp_err, stream, prefix); + if (! tmp_err->message) + { + APR_ARRAY_PUSH(empties, apr_status_t) = tmp_err->apr_err; + } + } + + tmp_err = tmp_err->child; + } + + svn_pool_destroy(subpool); + + fflush(stream); + if (fatal) + { + /* Avoid abort()s in maintainer mode. */ + svn_error_clear(err); + + /* We exit(1) here instead of abort()ing so that atexit handlers + get called. */ + exit(EXIT_FAILURE); + } +} + + +void +svn_handle_warning(FILE *stream, svn_error_t *err) +{ + svn_handle_warning2(stream, err, "svn: "); +} + +void +svn_handle_warning2(FILE *stream, svn_error_t *err, const char *prefix) +{ + char buf[256]; + + svn_error_clear(svn_cmdline_fprintf + (stream, err->pool, + _("%swarning: %s\n"), + prefix, svn_err_best_message(err, buf, sizeof(buf)))); + fflush(stream); +} + +const char * +svn_err_best_message(svn_error_t *err, char *buf, apr_size_t bufsize) +{ + if (err->message) + return err->message; + else + return svn_strerror(err->apr_err, buf, bufsize); +} + + +/* svn_strerror() and helpers */ + +typedef struct { + svn_errno_t errcode; + const char *errdesc; +} err_defn; + +/* To understand what is going on here, read svn_error_codes.h. */ +#define SVN_ERROR_BUILD_ARRAY +#include "svn_error_codes.h" + +char * +svn_strerror(apr_status_t statcode, char *buf, apr_size_t bufsize) +{ + const err_defn *defn; + + for (defn = error_table; defn->errdesc != NULL; ++defn) + if (defn->errcode == (svn_errno_t)statcode) + { + apr_cpystrn(buf, _(defn->errdesc), bufsize); + return buf; + } + + return apr_strerror(statcode, buf, bufsize); +} + +svn_error_t * +svn_error_raise_on_malfunction(svn_boolean_t can_return, + const char *file, int line, + const char *expr) +{ + if (!can_return) + abort(); /* Nothing else we can do as a library */ + + if (expr) + return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL, + _("In file '%s' line %d: assertion failed (%s)"), + file, line, expr); + else + return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL, + _("In file '%s' line %d: internal malfunction"), + file, line); +} + +svn_error_t * +svn_error_abort_on_malfunction(svn_boolean_t can_return, + const char *file, int line, + const char *expr) +{ + svn_error_t *err = svn_error_raise_on_malfunction(TRUE, file, line, expr); + + svn_handle_error2(err, stderr, FALSE, "svn: "); + abort(); + return err; /* Not reached. */ +} + +/* The current handler for reporting malfunctions, and its default setting. */ +static svn_error_malfunction_handler_t malfunction_handler + = svn_error_abort_on_malfunction; + +svn_error_malfunction_handler_t +svn_error_set_malfunction_handler(svn_error_malfunction_handler_t func) +{ + svn_error_malfunction_handler_t old_malfunction_handler + = malfunction_handler; + + malfunction_handler = func; + return old_malfunction_handler; +} + +svn_error_t * +svn_error__malfunction(svn_boolean_t can_return, + const char *file, int line, + const char *expr) +{ + return malfunction_handler(can_return, file, line, expr); +} diff --git a/src/TortoiseMerge/libsvn_diff/gzio.c b/src/TortoiseMerge/libsvn_diff/gzio.c new file mode 100644 index 0000000..0e41081 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/gzio.c @@ -0,0 +1,875 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_DEFLATE to avoid the compression code. + */ + +/* @(#) $Id: gzio.c,v 1.1 2003/05/23 21:05:30 steveking Exp $ */ + +#include + +#include "zutil.h" + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + long startpos; /* start of compressed data in file (header skipped) */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open return NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_DEFLATE + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->startpos = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * startpos anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->startpos = (ftell(s->file) - s->stream.avail_in); + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Check the gzip magic header */ + for (len = 0; len < 2; len++) { + c = get_byte(s); + if (c != gz_magic[len]) { + if (len != 0) s->stream.avail_in++, s->stream.next_in--; + if (c != EOF) { + s->stream.avail_in++, s->stream.next_in--; + s->transparent = 1; + } + s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; + return; + } + } + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_DEFLATE + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->stream.total_in += (uLong)len; + s->stream.total_out += (uLong)len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may + * be different from s->stream.total_out) in case of + * concatenated .gz files. Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + uLong total_in = s->stream.total_in; + uLong total_out = s->stream.total_out; + + inflateReset(&(s->stream)); + s->stream.total_in = total_in; + s->stream.total_out = total_out; + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_DEFLATE +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + const voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + va_start(va, format); +#ifdef HAS_vsnprintf + (void)vsnprintf(buf, sizeof(buf), format, va); +#else + (void)vsprintf(buf, format, va); +#endif + va_end(va); + len = strlen(buf); /* some *sprintf don't return the nb of bytes written */ + if (len <= 0) return 0; + + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + +#ifdef HAS_snprintf + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +#else + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +#endif + len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */ + if (len <= 0) return 0; + + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->z_err = deflate(&(s->stream), flush); + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_DEFLATE */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_DEFLATE + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->stream.total_in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return (z_off_t)s->stream.total_in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->stream.total_out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->stream.total_in = s->stream.total_out = (uLong)offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if ((uLong)offset >= s->stream.total_out) { + offset -= s->stream.total_out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return (z_off_t)s->stream.total_out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + + if (s->startpos == 0) { /* not a compressed file */ + rewind(s->file); + return 0; + } + + (void) inflateReset(&s->stream); + return fseek(s->file, s->startpos, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + return (s == NULL || s->mode != 'r') ? 0 : s->z_eof; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_DEFLATE + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, s->stream.total_in); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char* ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} diff --git a/src/TortoiseMerge/libsvn_diff/infblock.c b/src/TortoiseMerge/libsvn_diff/infblock.c new file mode 100644 index 0000000..943e849 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/infblock.c @@ -0,0 +1,403 @@ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +local const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(s, z, c) +inflate_blocks_statef *s; +z_streamp z; +uLongf *c; +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); + Tracev((stderr, "inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z, c, w) +z_streamp z; +check_func c; +uInt w; +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + r = t; + if (r == Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + } + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + } + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + ZFREE(z, s->sub.trees.blens); + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(s, z) +inflate_blocks_statef *s; +z_streamp z; +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(s, d, n) +inflate_blocks_statef *s; +const Bytef *d; +uInt n; +{ + zmemcpy(s->window, d, n); + s->read = s->write = s->window + n; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL + */ +int inflate_blocks_sync_point(s) +inflate_blocks_statef *s; +{ + return s->mode == LENS; +} diff --git a/src/TortoiseMerge/libsvn_diff/infblock.h b/src/TortoiseMerge/libsvn_diff/infblock.h new file mode 100644 index 0000000..4cf0fa9 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/infblock.h @@ -0,0 +1,39 @@ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Bytef *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); diff --git a/src/TortoiseMerge/libsvn_diff/infcodes.c b/src/TortoiseMerge/libsvn_diff/infcodes.c new file mode 100644 index 0000000..aa7b3a0 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/infcodes.c @@ -0,0 +1,251 @@ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" +#include "inffast.h" + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +z_streamp z; +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ + f = q - c->sub.copy.dist; + while (f < s->window) /* modulo window size-"while" instead */ + f += s->end - s->window; /* of "if" handles invalid distances */ + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +void inflate_codes_free(c, z) +inflate_codes_statef *c; +z_streamp z; +{ + ZFREE(z, c); + Tracev((stderr, "inflate: codes free\n")); +} diff --git a/src/TortoiseMerge/libsvn_diff/infcodes.h b/src/TortoiseMerge/libsvn_diff/infcodes.h new file mode 100644 index 0000000..531d419 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/infcodes.h @@ -0,0 +1,27 @@ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + diff --git a/src/TortoiseMerge/libsvn_diff/inffast.c b/src/TortoiseMerge/libsvn_diff/inffast.c new file mode 100644 index 0000000..655eaf0 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/inffast.c @@ -0,0 +1,183 @@ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" +#include "inffast.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(bl, bd, tl, td, s, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +inflate_blocks_statef *s; +z_streamp z; +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Bytef *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + r = q - d; + if (r < s->window) /* wrap if needed */ + { + do { + r += s->end - s->window; /* force pointer in window */ + } while (r < s->window); /* covers invalid distances */ + e = s->end - r; + if (c > e) + { + c -= e; /* wrapped copy */ + do { + *q++ = *r++; + } while (--e); + r = s->window; + do { + *q++ = *r++; + } while (--c); + } + else /* normal copy */ + { + *q++ = *r++; c--; + *q++ = *r++; c--; + do { + *q++ = *r++; + } while (--c); + } + } + else /* normal copy */ + { + *q++ = *r++; c--; + *q++ = *r++; c--; + do { + *q++ = *r++; + } while (--c); + } + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} diff --git a/src/TortoiseMerge/libsvn_diff/inffast.h b/src/TortoiseMerge/libsvn_diff/inffast.h new file mode 100644 index 0000000..ac643b3 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/inffast.h @@ -0,0 +1,17 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_streamp )); diff --git a/src/TortoiseMerge/libsvn_diff/inffixed.h b/src/TortoiseMerge/libsvn_diff/inffixed.h new file mode 100644 index 0000000..e997507 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/inffixed.h @@ -0,0 +1,151 @@ +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +local uInt fixed_bl = 9; +local uInt fixed_bd = 5; +local inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +local inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; diff --git a/src/TortoiseMerge/libsvn_diff/inflate.c b/src/TortoiseMerge/libsvn_diff/inflate.c new file mode 100644 index 0000000..5577e02 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/inflate.c @@ -0,0 +1,366 @@ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" + +struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ + +typedef enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + DICT4, /* four dictionary check bytes to go */ + DICT3, /* three dictionary check bytes to go */ + DICT2, /* two dictionary check bytes to go */ + DICT1, /* one dictionary check byte to go */ + DICT0, /* waiting for inflateSetDictionary */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int ZEXPORT inflateReset(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + + +int ZEXPORT inflateEnd(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + + +int ZEXPORT inflateInit2_(z, w, version, stream_size) +z_streamp z; +int w; +const char *version; +int stream_size; +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = zcalloc; + z->opaque = (voidpf)0; + } + if (z->zfree == Z_NULL) z->zfree = zcfree; + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int ZEXPORT inflateInit_(z, version, stream_size) +z_streamp z; +const char *version; +int stream_size; +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define NEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int ZEXPORT inflate(z, f) +z_streamp z; +int f; +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = BAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + b = NEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = BLOCKS; + break; + } + z->state->mode = DICT4; + case DICT4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = DICT3; + case DICT3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = DICT2; + case DICT2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = DICT1; + case DICT1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z->state->mode = BAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +int ZEXPORT inflateSetDictionary(z, dictionary, dictLength) +z_streamp z; +const Bytef *dictionary; +uInt dictLength; +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = BLOCKS; + return Z_OK; +} + + +int ZEXPORT inflateSync(z) +z_streamp z; +{ + uInt n; /* number of bytes to look at */ + Bytef *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != BAD) + { + z->state->mode = BAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + static const Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = BLOCKS; + return Z_OK; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(z->state->blocks); +} diff --git a/src/TortoiseMerge/libsvn_diff/inftrees.c b/src/TortoiseMerge/libsvn_diff/inftrees.c new file mode 100644 index 0000000..f89e801 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/inftrees.c @@ -0,0 +1,454 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#if !defined(BUILDFIXED) && !defined(STDC) +# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */ +#endif + +const char inflate_copyright[] = + " inflate 1.1.4 Copyright 1995-2002 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ +struct internal_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uIntf *, /* list of base values for non-simple codes */ + const uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uIntf * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +local int huft_build(b, n, s, d, e, t, m, hp, hn, v) +uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ +uInt n; /* number of codes (assumed <= 288) */ +uInt s; /* number of simple-valued codes (0..s-1) */ +const uIntf *d; /* list of base values for non-simple codes */ +const uIntf *e; /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t; /* result: starting table */ +uIntf *m; /* maximum lookup bits, returns actual */ +inflate_huft *hp; /* space for trees */ +uInt *hn; /* hufts used in space */ +uIntf *v; /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), or Z_DATA_ERROR if the input is invalid. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_DATA_ERROR; /* overflow of MANY */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(c, bb, tb, hp, z) +uIntf *c; /* 19 code lengths */ +uIntf *bb; /* bits tree desired/actual depth */ +inflate_huft * FAR *tb; /* bits tree result */ +inflate_huft *hp; /* space for trees */ +z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ + + if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z) +uInt nl; /* number of literal/length codes */ +uInt nd; /* number of distance codes */ +uIntf *c; /* that many (total) code lengths */ +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +inflate_huft *hp; /* space for trees */ +z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +#ifdef BUILDFIXED +local int fixed_built = 0; +#define FIXEDH 544 /* number of hufts used by fixed tables */ +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; +#else +#include "inffixed.h" +#endif + + +int inflate_trees_fixed(bl, bd, tl, td, z) +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +z_streamp z; /* for memory allocation */ +{ +#ifdef BUILDFIXED + /* build fixed tables if not already */ + if (!fixed_built) + { + int k; /* temporary variable */ + uInt f = 0; /* number of hufts used in fixed_mem */ + uIntf *c; /* length list for huft_build */ + uIntf *v; /* work area for huft_build */ + + /* allocate memory */ + if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + { + ZFREE(z, c); + return Z_MEM_ERROR; + } + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 9; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, + fixed_mem, &f, v); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, + fixed_mem, &f, v); + + /* done */ + ZFREE(z, v); + ZFREE(z, c); + fixed_built = 1; + } +#endif + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} diff --git a/src/TortoiseMerge/libsvn_diff/inftrees.h b/src/TortoiseMerge/libsvn_diff/inftrees.h new file mode 100644 index 0000000..affbb3b --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/inftrees.h @@ -0,0 +1,58 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +extern int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_streamp)); /* for memory allocation */ diff --git a/src/TortoiseMerge/libsvn_diff/infutil.c b/src/TortoiseMerge/libsvn_diff/infutil.c new file mode 100644 index 0000000..976d5e5 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/infutil.c @@ -0,0 +1,87 @@ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt n; + Bytef *p; + Bytef *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} diff --git a/src/TortoiseMerge/libsvn_diff/infutil.h b/src/TortoiseMerge/libsvn_diff/infutil.h new file mode 100644 index 0000000..0c0ace3 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/infutil.h @@ -0,0 +1,98 @@ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#endif diff --git a/src/TortoiseMerge/libsvn_diff/io.c b/src/TortoiseMerge/libsvn_diff/io.c new file mode 100644 index 0000000..2fb3936 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/io.c @@ -0,0 +1,3491 @@ +/* + * io.c: shared file reading, writing, and probing code. + * + * ==================================================================== + * Copyright (c) 2000-2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + + + +#include + +#ifndef WIN32 +#include +#endif + +#ifndef APR_STATUS_IS_EPERM +#include +#ifdef EPERM +#define APR_STATUS_IS_EPERM(s) ((s) == EPERM) +#else +#define APR_STATUS_IS_EPERM(s) (0) +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svn_types.h" +#include "svn_path.h" +#include "svn_string.h" +#include "svn_error.h" +#include "svn_io.h" +#include "svn_pools.h" +#include "svn_utf.h" +#include "svn_config.h" +//#include "svn_private_config.h" + +#define SVN_SLEEP_ENV_VAR "SVN_I_LOVE_CORRUPTED_WORKING_COPIES_SO_DISABLE_SLEEP_FOR_TIMESTAMPS" + +/* + Windows is 'aided' by a number of types of applications that + follow other applications around and open up files they have + changed for various reasons (the most intrusive are virus + scanners). So, if one of these other apps has glommed onto + our file we may get an 'access denied' error. + + This retry loop does not completely solve the problem (who + knows how long the other app is going to hold onto it for), but + goes a long way towards minimizing it. It is not an infinite + loop because there might really be an error. + + Another reason for retrying delete operations on Windows + is that they are asynchronous -- the file or directory is not + actually deleted until the last handle to it is closed. The + retry loop cannot completely solve this problem either, but can + help mitigate it. +*/ +#ifdef WIN32 +#define WIN32_RETRY_LOOP(err, expr) \ + do \ + { \ + apr_status_t os_err = APR_TO_OS_ERROR(err); \ + int sleep_count = 1000; \ + int retries; \ + for (retries = 0; \ + retries < 100 && (os_err == ERROR_ACCESS_DENIED \ + || os_err == ERROR_SHARING_VIOLATION \ + || os_err == ERROR_DIR_NOT_EMPTY); \ + ++retries, os_err = APR_TO_OS_ERROR(err)) \ + { \ + apr_sleep(sleep_count); \ + if (sleep_count < 128000) \ + sleep_count *= 2; \ + (err) = (expr); \ + } \ + } \ + while (0) +#else +#define WIN32_RETRY_LOOP(err, expr) ((void)0) +#endif + +/* Local wrapper of svn_path_cstring_to_utf8() that does no copying on + * operating systems where APR always uses utf-8 as native path format */ +static svn_error_t * +cstring_to_utf8(const char **path_utf8, + const char *path_apr, + apr_pool_t *pool) +{ +#if defined(WIN32) || defined(DARWIN) + pool; /* Unused */ + *path_utf8 = path_apr; + return SVN_NO_ERROR; +#else + return svn_path_cstring_to_utf8(path_utf8, path_apr, pool); +#endif +} + +/* Local wrapper of svn_path_cstring_from_utf8() that does no copying on + * operating systems where APR always uses utf-8 as native path format */ +static svn_error_t * +cstring_from_utf8(const char **path_apr, + const char *path_utf8, + apr_pool_t *pool) +{ +#if defined(WIN32) || defined(DARWIN) + pool; /* Unused */ + *path_apr = path_utf8; + return SVN_NO_ERROR; +#else + return svn_path_cstring_from_utf8(path_apr, path_utf8, pool); +#endif +} + + +/* Set *NAME_P to the UTF-8 representation of directory entry NAME. + * NAME is in the the internal encoding used by APR; PARENT is in + * UTF-8 and in internal (not local) style. + * + * Use PARENT only for generating an error string if the conversion + * fails because NAME could not be represented in UTF-8. In that + * case, return a two-level error in which the outer error's message + * mentions PARENT, but the inner error's message does not mention + * NAME (except possibly in hex) since NAME may not be printable. + * Such a compound error at least allows the user to go looking in the + * right directory for the problem. + * + * If there is any other error, just return that error directly. + * + * If there is any error, the effect on *NAME_P is undefined. + * + * *NAME_P and NAME may refer to the same storage. + */ +static svn_error_t * +entry_name_to_utf8(const char **name_p, + const char *name, + const char *parent, + apr_pool_t *pool) +{ + svn_error_t *err = svn_path_cstring_to_utf8(name_p, name, pool); + if (err && err->apr_err == APR_EINVAL) + { + return svn_error_createf(err->apr_err, err, + _("Error converting entry " + "in directory '%s' to UTF-8"), + svn_path_local_style(parent, pool)); + } + return err; +} + + + +static void +map_apr_finfo_to_node_kind(svn_node_kind_t *kind, + svn_boolean_t *is_special, + apr_finfo_t *finfo) +{ + *is_special = FALSE; + + if (finfo->filetype == APR_REG) + *kind = svn_node_file; + else if (finfo->filetype == APR_DIR) + *kind = svn_node_dir; + else if (finfo->filetype == APR_LNK) + { + *is_special = TRUE; + *kind = svn_node_file; + } + else + *kind = svn_node_unknown; +} + +/* Helper for svn_io_check_path() and svn_io_check_resolved_path(); + essentially the same semantics as those two, with the obvious + interpretation for RESOLVE_SYMLINKS. */ +static svn_error_t * +io_check_path(const char *path, + svn_boolean_t resolve_symlinks, + svn_boolean_t *is_special_p, + svn_node_kind_t *kind, + apr_pool_t *pool) +{ + apr_int32_t flags; + apr_finfo_t finfo; + apr_status_t apr_err; + const char *path_apr; + svn_boolean_t is_special = FALSE; + + if (path[0] == '\0') + path = "."; + + /* Not using svn_io_stat() here because we want to check the + apr_err return explicitly. */ + SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); + + flags = resolve_symlinks ? APR_FINFO_MIN : (APR_FINFO_MIN | APR_FINFO_LINK); + apr_err = apr_stat(&finfo, path_apr, flags, pool); + + if (APR_STATUS_IS_ENOENT(apr_err)) + *kind = svn_node_none; + else if (APR_STATUS_IS_ENOTDIR(apr_err)) + *kind = svn_node_none; + else if (apr_err) + return svn_error_wrap_apr(apr_err, _("Can't check path '%s'"), + svn_path_local_style(path, pool)); + else + map_apr_finfo_to_node_kind(kind, &is_special, &finfo); + + *is_special_p = is_special; + + return SVN_NO_ERROR; +} + + +/* Wrapper for apr_file_open(). */ +static apr_status_t +file_open(apr_file_t **f, + const char *fname, + apr_int32_t flag, + apr_fileperms_t perm, + svn_boolean_t retry_on_failure, + apr_pool_t *pool) +{ + apr_status_t status = apr_file_open(f, fname, flag, perm, pool); + + if (retry_on_failure) + { + WIN32_RETRY_LOOP(status, apr_file_open(f, fname, flag, perm, pool)); + } + return status; +} + + +svn_error_t * +svn_io_check_resolved_path(const char *path, + svn_node_kind_t *kind, + apr_pool_t *pool) +{ + svn_boolean_t ignored; + return io_check_path(path, TRUE, &ignored, kind, pool); +} + +svn_error_t * +svn_io_check_path(const char *path, + svn_node_kind_t *kind, + apr_pool_t *pool) +{ + svn_boolean_t ignored; + return io_check_path(path, FALSE, &ignored, kind, pool); +} + +svn_error_t * +svn_io_check_special_path(const char *path, + svn_node_kind_t *kind, + svn_boolean_t *is_special, + apr_pool_t *pool) +{ + return io_check_path(path, FALSE, is_special, kind, pool); +} + +struct temp_file_cleanup_s +{ + apr_pool_t *pool; + const char *name; +}; + + +static apr_status_t +temp_file_plain_cleanup_handler(void *baton) +{ + struct temp_file_cleanup_s *b = baton; + apr_status_t apr_err = APR_SUCCESS; + + if (b->name) + { + apr_err = apr_file_remove(b->name, b->pool); + WIN32_RETRY_LOOP(apr_err, apr_file_remove(b->name, b->pool)); + } + + return apr_err; +} + + +static apr_status_t +temp_file_child_cleanup_handler(void *baton) +{ + struct temp_file_cleanup_s *b = baton; + + apr_pool_cleanup_kill(b->pool, b, + temp_file_plain_cleanup_handler); + + return APR_SUCCESS; +} + + +svn_error_t * +svn_io_open_uniquely_named(apr_file_t **file, + const char **unique_path, + const char *dirpath, + const char *filename, + const char *suffix, + svn_io_file_del_t delete_when, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + const char *path; + unsigned int i; + struct temp_file_cleanup_s *baton = NULL; + + SVN_ERR_ASSERT(file || unique_path); + + if (dirpath == NULL) + SVN_ERR(svn_io_temp_dir(&dirpath, scratch_pool)); + if (filename == NULL) + filename = "tempfile"; + if (suffix == NULL) + suffix = ".tmp"; + + path = svn_path_join(dirpath, filename, scratch_pool); + + if (delete_when == svn_io_file_del_on_pool_cleanup) + { + baton = apr_palloc(result_pool, sizeof(*baton)); + + baton->pool = result_pool; + baton->name = NULL; + + /* Because cleanups are run LIFO, we need to make sure to register + our cleanup before the apr_file_close cleanup: + + On Windows, you can't remove an open file. + */ + apr_pool_cleanup_register(result_pool, baton, + temp_file_plain_cleanup_handler, + temp_file_child_cleanup_handler); + } + + for (i = 1; i <= 99999; i++) + { + const char *unique_name; + const char *unique_name_apr; + apr_file_t *try_file; + apr_status_t apr_err; + apr_int32_t flag = (APR_READ | APR_WRITE | APR_CREATE | APR_EXCL + | APR_BUFFERED | APR_BINARY); + + if (delete_when == svn_io_file_del_on_close) + flag |= APR_DELONCLOSE; + + /* Special case the first attempt -- if we can avoid having a + generated numeric portion at all, that's best. So first we + try with just the suffix; then future tries add a number + before the suffix. (A do-while loop could avoid the repeated + conditional, but it's not worth the clarity loss.) + + If the first attempt fails, the first number will be "2". + This is good, since "1" would misleadingly imply that + the second attempt was actually the first... and if someone's + got conflicts on their conflicts, we probably don't want to + add to their confusion :-). */ + /* ### could alloc in scratch, then copy to result.. but "meh" */ + if (i == 1) + unique_name = apr_psprintf(result_pool, "%s%s", path, suffix); + else + unique_name = apr_psprintf(result_pool, "%s.%u%s", path, i, suffix); + + /* Hmmm. Ideally, we would append to a native-encoding buf + before starting iteration, then convert back to UTF-8 for + return. But I suppose that would make the appending code + sensitive to i18n in a way it shouldn't be... Oh well. */ + /* ### could alloc in scratch, then copy to result in baton... */ + SVN_ERR(cstring_from_utf8(&unique_name_apr, unique_name, result_pool)); + + apr_err = file_open(&try_file, unique_name_apr, flag, + APR_OS_DEFAULT, FALSE, result_pool); + + if (APR_STATUS_IS_EEXIST(apr_err)) + continue; + else if (apr_err) + { + /* On Win32, CreateFile fails with an "Access Denied" error + code, rather than "File Already Exists", if the colliding + name belongs to a directory. */ + if (APR_STATUS_IS_EACCES(apr_err)) + { + apr_finfo_t finfo; + apr_status_t apr_err_2 = apr_stat(&finfo, unique_name_apr, + APR_FINFO_TYPE, scratch_pool); + + if (!apr_err_2 && finfo.filetype == APR_DIR) + continue; + +#if WIN32 + apr_err_2 = APR_TO_OS_ERROR(apr_err); + + if (apr_err_2 == ERROR_ACCESS_DENIED || + apr_err_2 == ERROR_SHARING_VIOLATION) + { + /* The file is in use by another process or is hidden; + create a new name, but don't do this 99999 times in + case the folder is not writable */ + i += 797; + continue; + } +#endif + + /* Else fall through and return the original error. */ + } + + if (file) *file = NULL; + if (unique_path) *unique_path = NULL; + return svn_error_wrap_apr(apr_err, _("Can't open '%s'"), + svn_path_local_style(unique_name, + scratch_pool)); + } + else + { + if (delete_when == svn_io_file_del_on_pool_cleanup) + baton->name = unique_name_apr; + + if (file) + *file = try_file; + else + apr_file_close(try_file); + if (unique_path) *unique_path = unique_name; + + return SVN_NO_ERROR; + } + } + + if (file) *file = NULL; + if (unique_path) *unique_path = NULL; + return svn_error_createf(SVN_ERR_IO_UNIQUE_NAMES_EXHAUSTED, + NULL, + _("Unable to make name for '%s'"), + svn_path_local_style(path, scratch_pool)); +} + +svn_error_t * +svn_io_open_unique_file3(apr_file_t **file, + const char **temp_path, + const char *dirpath, + svn_io_file_del_t delete_when, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_io_open_uniquely_named(file, temp_path, + dirpath, "tempfile", ".tmp", + delete_when, result_pool, scratch_pool); +} + +svn_error_t * +svn_io_create_unique_link(const char **unique_name_p, + const char *path, + const char *dest, + const char *suffix, + apr_pool_t *pool) +{ +#ifdef HAVE_SYMLINK + unsigned int i; + const char *unique_name; + const char *unique_name_apr; + const char *dest_apr; + int rv; + + SVN_ERR(cstring_from_utf8(&dest_apr, dest, pool)); + for (i = 1; i <= 99999; i++) + { + apr_status_t apr_err; + + /* Special case the first attempt -- if we can avoid having a + generated numeric portion at all, that's best. So first we + try with just the suffix; then future tries add a number + before the suffix. (A do-while loop could avoid the repeated + conditional, but it's not worth the clarity loss.) + + If the first attempt fails, the first number will be "2". + This is good, since "1" would misleadingly imply that + the second attempt was actually the first... and if someone's + got conflicts on their conflicts, we probably don't want to + add to their confusion :-). */ + if (i == 1) + unique_name = apr_psprintf(pool, "%s%s", path, suffix); + else + unique_name = apr_psprintf(pool, "%s.%u%s", path, i, suffix); + + /* Hmmm. Ideally, we would append to a native-encoding buf + before starting iteration, then convert back to UTF-8 for + return. But I suppose that would make the appending code + sensitive to i18n in a way it shouldn't be... Oh well. */ + SVN_ERR(cstring_from_utf8(&unique_name_apr, unique_name, pool)); + do { + rv = symlink(dest_apr, unique_name_apr); + } while (rv == -1 && APR_STATUS_IS_EINTR(apr_get_os_error())); + + apr_err = apr_get_os_error(); + + if (rv == -1 && APR_STATUS_IS_EEXIST(apr_err)) + continue; + else if (rv == -1 && apr_err) + { + /* On Win32, CreateFile fails with an "Access Denied" error + code, rather than "File Already Exists", if the colliding + name belongs to a directory. */ + if (APR_STATUS_IS_EACCES(apr_err)) + { + apr_finfo_t finfo; + apr_status_t apr_err_2 = apr_stat(&finfo, unique_name_apr, + APR_FINFO_TYPE, pool); + + if (!apr_err_2 + && (finfo.filetype == APR_DIR)) + continue; + + /* Else ignore apr_err_2; better to fall through and + return the original error. */ + } + + *unique_name_p = NULL; + return svn_error_wrap_apr(apr_err, + _("Can't create symbolic link '%s'"), + svn_path_local_style(unique_name, pool)); + } + else + { + *unique_name_p = unique_name; + return SVN_NO_ERROR; + } + } + + *unique_name_p = NULL; + return svn_error_createf(SVN_ERR_IO_UNIQUE_NAMES_EXHAUSTED, + NULL, + _("Unable to make name for '%s'"), + svn_path_local_style(path, pool)); +#else + return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, + _("Symbolic links are not supported on this " + "platform")); +#endif +} + +svn_error_t * +svn_io_read_link(svn_string_t **dest, + const char *path, + apr_pool_t *pool) +{ +#ifdef HAVE_READLINK + svn_string_t dest_apr; + const char *path_apr; + char buf[1025]; + int rv; + + SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); + do { + rv = readlink(path_apr, buf, sizeof(buf) - 1); + } while (rv == -1 && APR_STATUS_IS_EINTR(apr_get_os_error())); + + if (rv == -1) + return svn_error_wrap_apr + (apr_get_os_error(), _("Can't read contents of link")); + + buf[rv] = '\0'; + dest_apr.data = buf; + dest_apr.len = rv; + + /* ### Cast needed, one of these interfaces is wrong */ + return svn_utf_string_to_utf8((const svn_string_t **)dest, &dest_apr, pool); +#else + return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, + _("Symbolic links are not supported on this " + "platform")); +#endif +} + + +svn_error_t * +svn_io_copy_link(const char *src, + const char *dst, + apr_pool_t *pool) + +{ +#ifdef HAVE_READLINK + svn_string_t *link_dest; + const char *dst_tmp; + + /* Notice what the link is pointing at... */ + SVN_ERR(svn_io_read_link(&link_dest, src, pool)); + + /* Make a tmp-link pointing at the same thing. */ + SVN_ERR(svn_io_create_unique_link(&dst_tmp, dst, link_dest->data, + ".tmp", pool)); + + /* Move the tmp-link to link. */ + return svn_io_file_rename(dst_tmp, dst, pool); + +#else + return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, + _("Symbolic links are not supported on this " + "platform")); +#endif +} + + +svn_error_t * +svn_io_temp_dir(const char **dir, + apr_pool_t *pool) +{ + apr_status_t apr_err = apr_temp_dir_get(dir, pool); + + if (apr_err) + return svn_error_wrap_apr(apr_err, _("Can't find a temporary directory")); + + SVN_ERR(cstring_to_utf8(dir, *dir, pool)); + + *dir = svn_path_canonicalize(*dir, pool); + + return SVN_NO_ERROR; +} + + + + +/*** Creating, copying and appending files. ***/ + +/* Transfer the contents of FROM_FILE to TO_FILE, using POOL for temporary + * allocations. + * + * NOTE: We don't use apr_copy_file() for this, since it takes filenames + * as parameters. Since we want to copy to a temporary file + * and rename for atomicity (see below), this would require an extra + * close/open pair, which can be expensive, especially on + * remote file systems. + */ +static apr_status_t +copy_contents(apr_file_t *from_file, + apr_file_t *to_file, + apr_pool_t *pool) +{ + /* Copy bytes till the cows come home. */ + while (1) + { + char buf[SVN__STREAM_CHUNK_SIZE]; + apr_size_t bytes_this_time = sizeof(buf); + apr_status_t read_err; + apr_status_t write_err; + + /* Read 'em. */ + read_err = apr_file_read(from_file, buf, &bytes_this_time); + if (read_err && !APR_STATUS_IS_EOF(read_err)) + { + return read_err; + } + + /* Write 'em. */ + write_err = apr_file_write_full(to_file, buf, bytes_this_time, NULL); + if (write_err) + { + return write_err; + } + + if (read_err && APR_STATUS_IS_EOF(read_err)) + { + /* Return the results of this close: an error, or success. */ + return APR_SUCCESS; + } + } + /* NOTREACHED */ +} + + +svn_error_t * +svn_io_copy_file(const char *src, + const char *dst, + svn_boolean_t copy_perms, + apr_pool_t *pool) +{ + apr_file_t *from_file, *to_file; + apr_status_t apr_err; + const char *src_apr, *dst_tmp_apr; + const char *dst_tmp; + svn_error_t *err, *err2; + + /* ### NOTE: sometimes src == dst. In this case, because we copy to a + ### temporary file, and then rename over the top of the destination, + ### the net result is resetting the permissions on src/dst. + ### + ### Note: specifically, this can happen during a switch when the desired + ### permissions for a file change from one branch to another. See + ### switch_tests 17. + ### + ### ... yes, we should avoid copying to the same file, and we should + ### make the "reset perms" explicit. The switch *happens* to work + ### because of this copy-to-temp-then-rename implementation. If it + ### weren't for that, the switch would break. + */ +#ifdef CHECK_FOR_SAME_FILE + if (strcmp(src, dst) == 0) + return SVN_NO_ERROR; +#endif + + SVN_ERR(cstring_from_utf8(&src_apr, src, pool)); + + SVN_ERR(svn_io_file_open(&from_file, src, APR_READ | APR_BINARY, + APR_OS_DEFAULT, pool)); + + /* For atomicity, we copy to a tmp file and then rename the tmp + file over the real destination. */ + + SVN_ERR(svn_io_open_unique_file3(&to_file, &dst_tmp, + svn_path_dirname(dst, pool), + svn_io_file_del_none, pool, pool)); + SVN_ERR(cstring_from_utf8(&dst_tmp_apr, dst_tmp, pool)); + + apr_err = copy_contents(from_file, to_file, pool); + + if (apr_err) + { + err = svn_error_wrap_apr + (apr_err, _("Can't copy '%s' to '%s'"), + svn_path_local_style(src, pool), + svn_path_local_style(dst_tmp, pool)); + } + else + err = NULL; + + err2 = svn_io_file_close(from_file, pool); + if (! err) + err = err2; + else + svn_error_clear(err2); + err2 = svn_io_file_close(to_file, pool); + if (! err) + err = err2; + else + svn_error_clear(err2); + if (err) + { + apr_err = apr_file_remove(dst_tmp_apr, pool); + WIN32_RETRY_LOOP(apr_err, apr_file_remove(dst_tmp_apr, pool)); + return err; + } + + /* If copying perms, set the perms on dst_tmp now, so they will be + atomically inherited in the upcoming rename. But note that we + had to wait until now to set perms, because if they say + read-only, then we'd have failed filling dst_tmp's contents. */ + if (copy_perms) + SVN_ERR(svn_io_copy_perms(src, dst_tmp, pool)); + + return svn_io_file_rename(dst_tmp, dst, pool); +} + + +svn_error_t * +svn_io_copy_perms(const char *src, + const char *dst, + apr_pool_t *pool) +{ + /* ### FIXME: apr_file_copy with perms may fail on Win32. We need a + platform-specific implementation to get the permissions right. */ + +#ifndef WIN32 + { + apr_file_t *src_file; + apr_finfo_t finfo; + const char *dst_apr; + apr_status_t apr_err; + + SVN_ERR(svn_io_file_open(&src_file, src, APR_READ, APR_OS_DEFAULT, pool)); + SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_PROT, src_file, pool)); + SVN_ERR(svn_io_file_close(src_file, pool)); + + SVN_ERR(cstring_from_utf8(&dst_apr, dst, pool)); + apr_err = apr_file_perms_set(dst_apr, finfo.protection); + + /* We shouldn't be able to get APR_INCOMPLETE or APR_ENOTIMPL + here under normal circumstances, because the perms themselves + came from a call to apr_file_info_get(), and we already know + this is the non-Win32 case. But if it does happen, it's not + an error. */ + if (apr_err != APR_SUCCESS + && apr_err != APR_INCOMPLETE + && apr_err != APR_ENOTIMPL) + { + return svn_error_wrap_apr(apr_err, _("Can't set permissions on '%s'"), + svn_path_local_style(dst, pool)); + } + } +#endif /* ! WIN32 */ + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_append_file(const char *src, const char *dst, apr_pool_t *pool) +{ + apr_status_t apr_err; + const char *src_apr, *dst_apr; + + SVN_ERR(cstring_from_utf8(&src_apr, src, pool)); + SVN_ERR(cstring_from_utf8(&dst_apr, dst, pool)); + + apr_err = apr_file_append(src_apr, dst_apr, APR_OS_DEFAULT, pool); + + if (apr_err) + return svn_error_wrap_apr(apr_err, _("Can't append '%s' to '%s'"), + svn_path_local_style(src, pool), + svn_path_local_style(dst, pool)); + + return SVN_NO_ERROR; +} + + +svn_error_t *svn_io_copy_dir_recursively(const char *src, + const char *dst_parent, + const char *dst_basename, + svn_boolean_t copy_perms, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool) +{ + svn_node_kind_t kind; + apr_status_t status; + const char *dst_path; + apr_dir_t *this_dir; + apr_finfo_t this_entry; + apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME; + + /* Make a subpool for recursion */ + apr_pool_t *subpool = svn_pool_create(pool); + + /* The 'dst_path' is simply dst_parent/dst_basename */ + dst_path = svn_path_join(dst_parent, dst_basename, pool); + + /* Sanity checks: SRC and DST_PARENT are directories, and + DST_BASENAME doesn't already exist in DST_PARENT. */ + SVN_ERR(svn_io_check_path(src, &kind, subpool)); + if (kind != svn_node_dir) + return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, + _("Source '%s' is not a directory"), + svn_path_local_style(src, pool)); + + SVN_ERR(svn_io_check_path(dst_parent, &kind, subpool)); + if (kind != svn_node_dir) + return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, + _("Destination '%s' is not a directory"), + svn_path_local_style(dst_parent, pool)); + + SVN_ERR(svn_io_check_path(dst_path, &kind, subpool)); + if (kind != svn_node_none) + return svn_error_createf(SVN_ERR_ENTRY_EXISTS, NULL, + _("Destination '%s' already exists"), + svn_path_local_style(dst_path, pool)); + + /* Create the new directory. */ + /* ### TODO: copy permissions (needs apr_file_attrs_get()) */ + SVN_ERR(svn_io_dir_make(dst_path, APR_OS_DEFAULT, pool)); + + /* Loop over the dirents in SRC. ('.' and '..' are auto-excluded) */ + SVN_ERR(svn_io_dir_open(&this_dir, src, subpool)); + + for (status = apr_dir_read(&this_entry, flags, this_dir); + status == APR_SUCCESS; + status = apr_dir_read(&this_entry, flags, this_dir)) + { + if ((this_entry.name[0] == '.') + && ((this_entry.name[1] == '\0') + || ((this_entry.name[1] == '.') + && (this_entry.name[2] == '\0')))) + { + continue; + } + else + { + const char *src_target, *entryname_utf8; + + if (cancel_func) + SVN_ERR(cancel_func(cancel_baton)); + + SVN_ERR(entry_name_to_utf8(&entryname_utf8, this_entry.name, + src, subpool)); + src_target = svn_path_join(src, entryname_utf8, subpool); + + if (this_entry.filetype == APR_REG) /* regular file */ + { + const char *dst_target = svn_path_join(dst_path, entryname_utf8, + subpool); + SVN_ERR(svn_io_copy_file(src_target, dst_target, + copy_perms, subpool)); + } + else if (this_entry.filetype == APR_LNK) /* symlink */ + { + const char *dst_target = svn_path_join(dst_path, entryname_utf8, + subpool); + SVN_ERR(svn_io_copy_link(src_target, dst_target, + subpool)); + } + else if (this_entry.filetype == APR_DIR) /* recurse */ + { + /* Prevent infinite recursion by filtering off our + newly created destination path. */ + if (strcmp(src, dst_parent) == 0 + && strcmp(entryname_utf8, dst_basename) == 0) + continue; + + SVN_ERR(svn_io_copy_dir_recursively + (src_target, + dst_path, + entryname_utf8, + copy_perms, + cancel_func, + cancel_baton, + subpool)); + } + /* ### support other APR node types someday?? */ + + } + } + + if (! (APR_STATUS_IS_ENOENT(status))) + return svn_error_wrap_apr(status, _("Can't read directory '%s'"), + svn_path_local_style(src, pool)); + + status = apr_dir_close(this_dir); + if (status) + return svn_error_wrap_apr(status, _("Error closing directory '%s'"), + svn_path_local_style(src, pool)); + + /* Free any memory used by recursion */ + svn_pool_destroy(subpool); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_make_dir_recursively(const char *path, apr_pool_t *pool) +{ + const char *path_apr; + apr_status_t apr_err; + + if (svn_path_is_empty(path)) + /* Empty path (current dir) is assumed to always exist, + so we do nothing, per docs. */ + return SVN_NO_ERROR; + + SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); + + apr_err = apr_dir_make_recursive(path_apr, APR_OS_DEFAULT, pool); + WIN32_RETRY_LOOP(apr_err, apr_dir_make_recursive(path_apr, + APR_OS_DEFAULT, pool)); + + if (apr_err) + return svn_error_wrap_apr(apr_err, _("Can't make directory '%s'"), + svn_path_local_style(path, pool)); + + return SVN_NO_ERROR; +} + +svn_error_t *svn_io_file_create(const char *file, + const char *contents, + apr_pool_t *pool) +{ + apr_file_t *f; + apr_size_t written; + + SVN_ERR(svn_io_file_open(&f, file, + (APR_WRITE | APR_CREATE | APR_EXCL), + APR_OS_DEFAULT, + pool)); + SVN_ERR(svn_io_file_write_full(f, contents, strlen(contents), + &written, pool)); + return svn_io_file_close(f, pool); +} + +svn_error_t *svn_io_dir_file_copy(const char *src_path, + const char *dest_path, + const char *file, + apr_pool_t *pool) +{ + const char *file_dest_path = svn_path_join(dest_path, file, pool); + const char *file_src_path = svn_path_join(src_path, file, pool); + + return svn_io_copy_file(file_src_path, file_dest_path, TRUE, pool); +} + + +/*** Modtime checking. ***/ + +svn_error_t * +svn_io_file_affected_time(apr_time_t *apr_time, + const char *path, + apr_pool_t *pool) +{ + apr_finfo_t finfo; + + SVN_ERR(svn_io_stat(&finfo, path, APR_FINFO_MIN | APR_FINFO_LINK, pool)); + + *apr_time = finfo.mtime; + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_set_file_affected_time(apr_time_t apr_time, + const char *path, + apr_pool_t *pool) +{ + apr_status_t status; + const char *native_path; + + SVN_ERR(cstring_from_utf8(&native_path, path, pool)); + status = apr_file_mtime_set(native_path, apr_time, pool); + + if (status) + return svn_error_wrap_apr + (status, _("Can't set access time of '%s'"), + svn_path_local_style(path, pool)); + + return SVN_NO_ERROR; +} + + +void +svn_io_sleep_for_timestamps(const char *path, apr_pool_t *pool) +{ + apr_time_t now, then; + svn_error_t *err; + char *sleep_env_var; + + sleep_env_var = getenv(SVN_SLEEP_ENV_VAR); + + if (sleep_env_var && apr_strnatcasecmp(sleep_env_var, "yes") == 0) + return; /* Allow skipping for testing */ + + now = apr_time_now(); + + /* Calculate 0.02 seconds after the next second wallclock tick. */ + then = apr_time_make(apr_time_sec(now) + 1, APR_USEC_PER_SEC / 50); + + /* Worst case is waiting one second, so we can use that time to determine + if we can sleep shorter than that */ + if (path) + { + apr_finfo_t finfo; + + err = svn_io_stat(&finfo, path, APR_FINFO_MTIME | APR_FINFO_LINK, pool); + + if (err) + { + svn_error_clear(err); /* Fall back on original behavior */ + } + else if (finfo.mtime % APR_USEC_PER_SEC) + { + /* Very simplistic but safe approach: + If the filesystem has < sec mtime we can be reasonably sure + that the filesystem has <= millisecond precision. + + ## Perhaps find a better algorithm here. This will fail once + in every 1000 cases on a millisecond precision filesystem. + + But better to fail once in every thousand cases than every + time, like we did before. + (All tested filesystems I know have at least microsecond precision.) + + Note for further research on algorithm: + FAT32 has < 1 sec precision on ctime, but 2 sec on mtime */ + + /* Sleep for at least 1 millisecond. + (t < 1000 will be round to 0 in apr) */ + apr_sleep(1000); + + return; + } + + now = apr_time_now(); /* Extract the time used for the path stat */ + + if (now >= then) + return; /* Passing negative values may suspend indefinately (Windows) */ + } + + apr_sleep(then - now); +} + + +svn_error_t * +svn_io_filesizes_different_p(svn_boolean_t *different_p, + const char *file1, + const char *file2, + apr_pool_t *pool) +{ + apr_finfo_t finfo1; + apr_finfo_t finfo2; + apr_status_t status; + const char *file1_apr, *file2_apr; + + /* Not using svn_io_stat() because don't want to generate + svn_error_t objects for non-error conditions. */ + + SVN_ERR(cstring_from_utf8(&file1_apr, file1, pool)); + SVN_ERR(cstring_from_utf8(&file2_apr, file2, pool)); + + /* Stat both files */ + status = apr_stat(&finfo1, file1_apr, APR_FINFO_MIN, pool); + if (status) + { + /* If we got an error stat'ing a file, it could be because the + file was removed... or who knows. Whatever the case, we + don't know if the filesizes are definitely different, so + assume that they're not. */ + *different_p = FALSE; + return SVN_NO_ERROR; + } + + status = apr_stat(&finfo2, file2_apr, APR_FINFO_MIN, pool); + if (status) + { + /* See previous comment. */ + *different_p = FALSE; + return SVN_NO_ERROR; + } + + /* Examine file sizes */ + if (finfo1.size == finfo2.size) + *different_p = FALSE; + else + *different_p = TRUE; + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_file_checksum2(svn_checksum_t **checksum, + const char *file, + svn_checksum_kind_t kind, + apr_pool_t *pool) +{ + svn_stream_t *file_stream; + svn_stream_t *checksum_stream; + apr_file_t* f; + + SVN_ERR(svn_io_file_open(&f, file, APR_READ, APR_OS_DEFAULT, pool)); + file_stream = svn_stream_from_aprfile2(f, FALSE, pool); + checksum_stream = svn_stream_checksummed2(file_stream, checksum, NULL, kind, + TRUE, pool); + + /* Because the checksummed stream will force the reading (and + checksumming) of all the file's bytes, we can just close the stream + and let its magic work. */ + return svn_stream_close(checksum_stream); +} + + +svn_error_t * +svn_io_file_checksum(unsigned char digest[], + const char *file, + apr_pool_t *pool) +{ + svn_checksum_t *checksum; + + SVN_ERR(svn_io_file_checksum2(&checksum, file, svn_checksum_md5, pool)); + memcpy(digest, checksum->digest, APR_MD5_DIGESTSIZE); + + return SVN_NO_ERROR; +} + + + +/*** Permissions and modes. ***/ + +#ifndef WIN32 +/* Given the file specified by PATH, attempt to create an + identical version of it owned by the current user. This is done by + moving it to a temporary location, copying the file back to its old + path, then deleting the temporarily moved version. All temporary + allocations are done in POOL. */ +static svn_error_t * +reown_file(const char *path, + apr_pool_t *pool) +{ + const char *unique_name; + + SVN_ERR(svn_io_open_unique_file3(NULL, &unique_name, + svn_path_dirname(path, pool), + svn_io_file_del_none, pool, pool)); + SVN_ERR(svn_io_file_rename(path, unique_name, pool)); + SVN_ERR(svn_io_copy_file(unique_name, path, TRUE, pool)); + return svn_io_remove_file(unique_name, pool); +} + +/* Determine what the read-write PERMS for PATH should be by ORing + together the permissions of PATH and the permissions of a temporary + file that we create. Unfortunately, this is the only way to + determine which combination of write bits (User/Group/World) should + be set to restore a file from read-only to read-write. Make + temporary allocations in POOL. */ +static svn_error_t * +get_default_file_perms(const char *path, apr_fileperms_t *perms, + apr_pool_t *pool) +{ + apr_status_t status; + apr_finfo_t tmp_finfo, finfo; + apr_file_t *fd; + const char *tmp_path; + const char *apr_path; + + /* Get the perms for a newly created file to find out what write + bits should be set. + + NOTE: normally del_on_close can be problematic because APR might + delete the file if we spawned any child processes. In this case, + the lifetime of this file handle is about 3 lines of code, so + we can safely use del_on_close here. + + NOTE: not so fast, shorty. if some other thread forks off a child, + then the APR cleanups run, and the file will disappear. sigh. + */ + SVN_ERR(svn_io_open_unique_file3(&fd, &tmp_path, + svn_path_dirname(path, pool), + svn_io_file_del_on_pool_cleanup, + pool, pool)); + status = apr_stat(&tmp_finfo, tmp_path, APR_FINFO_PROT, pool); + if (status) + return svn_error_wrap_apr(status, _("Can't get default file perms " + "for file at '%s' (file stat error)"), + path); + apr_file_close(fd); + + /* Get the perms for the original file so we'll have any other bits + * that were already set (like the execute bits, for example). */ + SVN_ERR(cstring_from_utf8(&apr_path, path, pool)); + status = apr_file_open(&fd, apr_path, APR_READ | APR_BINARY, + APR_OS_DEFAULT, pool); + if (status) + return svn_error_wrap_apr(status, _("Can't open file at '%s'"), path); + + status = apr_stat(&finfo, apr_path, APR_FINFO_PROT, pool); + if (status) + return svn_error_wrap_apr(status, _("Can't get file perms for file at " + "'%s' (file stat error)"), path); + apr_file_close(fd); + + /* Glom the perms together. */ + *perms = tmp_finfo.protection | finfo.protection; + return SVN_NO_ERROR; +} + +/* This is a helper function for the svn_io_set_file_read* functions + that attempts to honor the users umask when dealing with + permission changes. It is a no-op when invoked on a symlink. */ +static svn_error_t * +io_set_file_perms(const char *path, + svn_boolean_t change_readwrite, + svn_boolean_t enable_write, + svn_boolean_t change_executable, + svn_boolean_t executable, + svn_boolean_t ignore_enoent, + apr_pool_t *pool) +{ + apr_status_t status; + const char *path_apr; + apr_finfo_t finfo; + apr_fileperms_t perms_to_set; + + SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); + + /* Try to change only a minimal amount of the perms first + by getting the current perms and adding bits + only on where read perms are granted. If this fails + fall through to just setting file attributes. */ + status = apr_stat(&finfo, path_apr, APR_FINFO_PROT | APR_FINFO_LINK, pool); + if (status) + { + if (ignore_enoent && APR_STATUS_IS_ENOENT(status)) + return SVN_NO_ERROR; + else if (status != APR_ENOTIMPL) + return svn_error_wrap_apr(status, + _("Can't change perms of file '%s'"), + svn_path_local_style(path, pool)); + return SVN_NO_ERROR; + } + + if (finfo.filetype == APR_LNK) + return SVN_NO_ERROR; + + perms_to_set = finfo.protection; + if (change_readwrite) + { + if (enable_write) /* Make read-write. */ + SVN_ERR(get_default_file_perms(path, &perms_to_set, pool)); + else + { + if (finfo.protection & APR_UREAD) + perms_to_set &= ~APR_UWRITE; + if (finfo.protection & APR_GREAD) + perms_to_set &= ~APR_GWRITE; + if (finfo.protection & APR_WREAD) + perms_to_set &= ~APR_WWRITE; + } + } + + if (change_executable) + { + if (executable) + { + if (finfo.protection & APR_UREAD) + perms_to_set |= APR_UEXECUTE; + if (finfo.protection & APR_GREAD) + perms_to_set |= APR_GEXECUTE; + if (finfo.protection & APR_WREAD) + perms_to_set |= APR_WEXECUTE; + } + else + { + if (finfo.protection & APR_UREAD) + perms_to_set &= ~APR_UEXECUTE; + if (finfo.protection & APR_GREAD) + perms_to_set &= ~APR_GEXECUTE; + if (finfo.protection & APR_WREAD) + perms_to_set &= ~APR_WEXECUTE; + } + } + + /* If we aren't changing anything then just return, this saves + some system calls and helps with shared working copies */ + if (perms_to_set == finfo.protection) + return SVN_NO_ERROR; + + status = apr_file_perms_set(path_apr, perms_to_set); + if (!status) + return SVN_NO_ERROR; + + if (APR_STATUS_IS_EPERM(status)) + { + /* We don't have permissions to change the + permissions! Try a move, copy, and delete + workaround to see if we can get the file owned by + us. If these succeed, try the permissions set + again. + + Note that we only attempt this in the + stat-available path. This assumes that the + move-copy workaround will only be helpful on + platforms that implement apr_stat. */ + SVN_ERR(reown_file(path, pool)); + status = apr_file_perms_set(path_apr, perms_to_set); + } + + if (!status) + return SVN_NO_ERROR; + + if (ignore_enoent && APR_STATUS_IS_ENOENT(status)) + return SVN_NO_ERROR; + else if (status == APR_ENOTIMPL) + { + /* At least try to set the attributes. */ + apr_fileattrs_t attrs = 0; + apr_fileattrs_t attrs_values = 0; + + if (change_readwrite) + { + attrs = APR_FILE_ATTR_READONLY; + if (!enable_write) + attrs_values = APR_FILE_ATTR_READONLY; + } + if (change_executable) + { + attrs = APR_FILE_ATTR_EXECUTABLE; + if (executable) + attrs_values = APR_FILE_ATTR_EXECUTABLE; + } + status = apr_file_attrs_set(path_apr, attrs, attrs_values, pool); + } + + return svn_error_wrap_apr(status, + _("Can't change perms of file '%s'"), + svn_path_local_style(path, pool)); +} +#endif /* !WIN32 */ + + +svn_error_t * +svn_io_set_file_read_write_carefully(const char *path, + svn_boolean_t enable_write, + svn_boolean_t ignore_enoent, + apr_pool_t *pool) +{ + if (enable_write) + return svn_io_set_file_read_write(path, ignore_enoent, pool); + return svn_io_set_file_read_only(path, ignore_enoent, pool); +} + +svn_error_t * +svn_io_set_file_read_only(const char *path, + svn_boolean_t ignore_enoent, + apr_pool_t *pool) +{ + /* On Windows, just set the file attributes -- on unix call + our internal function which attempts to honor the umask. */ +#ifndef WIN32 + return io_set_file_perms(path, TRUE, FALSE, FALSE, FALSE, + ignore_enoent, pool); +#else + apr_status_t status; + const char *path_apr; + + SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); + + status = apr_file_attrs_set(path_apr, + APR_FILE_ATTR_READONLY, + APR_FILE_ATTR_READONLY, + pool); + + if (status && status != APR_ENOTIMPL) + if (!ignore_enoent || !APR_STATUS_IS_ENOENT(status)) + return svn_error_wrap_apr(status, + _("Can't set file '%s' read-only"), + svn_path_local_style(path, pool)); + + return SVN_NO_ERROR; +#endif +} + + +svn_error_t * +svn_io_set_file_read_write(const char *path, + svn_boolean_t ignore_enoent, + apr_pool_t *pool) +{ + /* On Windows, just set the file attributes -- on unix call + our internal function which attempts to honor the umask. */ +#ifndef WIN32 + return io_set_file_perms(path, TRUE, TRUE, FALSE, FALSE, + ignore_enoent, pool); +#else + apr_status_t status; + const char *path_apr; + + SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); + + status = apr_file_attrs_set(path_apr, + 0, + APR_FILE_ATTR_READONLY, + pool); + + if (status && status != APR_ENOTIMPL) + if (!ignore_enoent || !APR_STATUS_IS_ENOENT(status)) + return svn_error_wrap_apr(status, + _("Can't set file '%s' read-write"), + svn_path_local_style(path, pool)); + + return SVN_NO_ERROR; +#endif +} + +svn_error_t * +svn_io_set_file_executable(const char *path, + svn_boolean_t executable, + svn_boolean_t ignore_enoent, + apr_pool_t *pool) +{ + /* On Windows, just exit -- on unix call our internal function + which attempts to honor the umask. */ +#ifndef WIN32 + return io_set_file_perms(path, FALSE, FALSE, TRUE, executable, + ignore_enoent, pool); +#else + return SVN_NO_ERROR; +#endif +} + + +svn_error_t * +svn_io_is_file_executable(svn_boolean_t *executable, + const char *path, + apr_pool_t *pool) +{ +#if defined(APR_HAS_USER) && !defined(WIN32) + apr_finfo_t file_info; + apr_status_t apr_err; + apr_uid_t uid; + apr_gid_t gid; + + *executable = FALSE; + + /* Get file and user info. */ + SVN_ERR(svn_io_stat(&file_info, path, + (APR_FINFO_PROT | APR_FINFO_OWNER), + pool)); + apr_err = apr_uid_current(&uid, &gid, pool); + + if (apr_err) + return svn_error_wrap_apr(apr_err, _("Error getting UID of process")); + + /* Check executable bit for current user. */ + if (apr_uid_compare(uid, file_info.user) == APR_SUCCESS) + *executable = (file_info.protection & APR_UEXECUTE); + + else if (apr_gid_compare(gid, file_info.group) == APR_SUCCESS) + *executable = (file_info.protection & APR_GEXECUTE); + + else + *executable = (file_info.protection & APR_WEXECUTE); + +#else /* defined(WIN32) || !defined(APR_HAS_USER) */ + *executable = FALSE; +#endif + + return SVN_NO_ERROR; +} + + +/*** File locking. ***/ +/* Clear all outstanding locks on ARG, an open apr_file_t *. */ +static apr_status_t +svn_io__file_clear_and_close(void *arg) +{ + apr_status_t apr_err; + apr_file_t *f = arg; + + /* Remove locks. */ + apr_err = apr_file_unlock(f); + if (apr_err) + return apr_err; + + /* Close the file. */ + apr_err = apr_file_close(f); + if (apr_err) + return apr_err; + + return 0; +} + + +svn_error_t *svn_io_file_lock(const char *lock_file, + svn_boolean_t exclusive, + apr_pool_t *pool) +{ + return svn_io_file_lock2(lock_file, exclusive, FALSE, pool); +} + +svn_error_t *svn_io_file_lock2(const char *lock_file, + svn_boolean_t exclusive, + svn_boolean_t nonblocking, + apr_pool_t *pool) +{ + int locktype = APR_FLOCK_SHARED; + apr_file_t *lockfile_handle; + apr_int32_t flags; + apr_status_t apr_err; + + if (exclusive == TRUE) + locktype = APR_FLOCK_EXCLUSIVE; + + flags = APR_READ; + if (locktype == APR_FLOCK_EXCLUSIVE) + flags |= APR_WRITE; + + if (nonblocking == TRUE) + locktype |= APR_FLOCK_NONBLOCK; + + SVN_ERR(svn_io_file_open(&lockfile_handle, lock_file, flags, + APR_OS_DEFAULT, + pool)); + + /* Get lock on the filehandle. */ + apr_err = apr_file_lock(lockfile_handle, locktype); + if (apr_err) + { + switch (locktype & APR_FLOCK_TYPEMASK) + { + case APR_FLOCK_SHARED: + return svn_error_wrap_apr + (apr_err, _("Can't get shared lock on file '%s'"), + svn_path_local_style(lock_file, pool)); + case APR_FLOCK_EXCLUSIVE: + return svn_error_wrap_apr + (apr_err, _("Can't get exclusive lock on file '%s'"), + svn_path_local_style(lock_file, pool)); + default: + SVN_ERR_MALFUNCTION(); + } + } + + apr_pool_cleanup_register(pool, lockfile_handle, + svn_io__file_clear_and_close, + apr_pool_cleanup_null); + + return SVN_NO_ERROR; +} + + + +/* Data consistency/coherency operations. */ + +static svn_error_t * +do_io_file_wrapper_cleanup(apr_file_t *file, apr_status_t status, + const char *msg, const char *msg_no_name, + apr_pool_t *pool); + +svn_error_t *svn_io_file_flush_to_disk(apr_file_t *file, + apr_pool_t *pool) +{ + apr_os_file_t filehand; + + /* First make sure that any user-space buffered data is flushed. */ + SVN_ERR(do_io_file_wrapper_cleanup(file, apr_file_flush(file), + N_("Can't flush file '%s'"), + N_("Can't flush stream"), + pool)); + + apr_os_file_get(&filehand, file); + + /* Call the operating system specific function to actually force the + data to disk. */ + { +#ifdef WIN32 + + if (! FlushFileBuffers(filehand)) + return svn_error_wrap_apr + (apr_get_os_error(), _("Can't flush file to disk")); + +#else + int rv; + + do { + rv = fsync(filehand); + } while (rv == -1 && APR_STATUS_IS_EINTR(apr_get_os_error())); + + /* If the file is in a memory filesystem, fsync() may return + EINVAL. Presumably the user knows the risks, and we can just + ignore the error. */ + if (rv == -1 && APR_STATUS_IS_EINVAL(apr_get_os_error())) + return SVN_NO_ERROR; + + if (rv == -1) + return svn_error_wrap_apr + (apr_get_os_error(), _("Can't flush file to disk")); + +#endif + } + return SVN_NO_ERROR; +} + + + +/* TODO write test for these two functions, then refactor. */ + +svn_error_t * +svn_stringbuf_from_file2(svn_stringbuf_t **result, + const char *filename, + apr_pool_t *pool) +{ + apr_file_t *f; + + if (filename[0] == '-' && filename[1] == '\0') + { + apr_status_t apr_err; + if ((apr_err = apr_file_open_stdin(&f, pool))) + return svn_error_wrap_apr(apr_err, _("Can't open stdin")); + } + else + { + SVN_ERR(svn_io_file_open(&f, filename, APR_READ, APR_OS_DEFAULT, pool)); + } + + /* ### ugh. we should stat() the file, get its length, and read that + ### much data into memory. the _from_aprfile() function uses a + ### realloc-style that chews up memory needlessly. */ + + SVN_ERR(svn_stringbuf_from_aprfile(result, f, pool)); + return svn_io_file_close(f, pool); +} + + +svn_error_t * +svn_stringbuf_from_file(svn_stringbuf_t **result, + const char *filename, + apr_pool_t *pool) +{ + if (filename[0] == '-' && filename[1] == '\0') + return svn_error_create + (SVN_ERR_UNSUPPORTED_FEATURE, NULL, + _("Reading from stdin is disallowed")); + return svn_stringbuf_from_file2(result, filename, pool); +} + + +/* Get the name of FILE, or NULL if FILE is an unnamed stream. */ +static svn_error_t * +file_name_get(const char **fname_utf8, apr_file_t *file, apr_pool_t *pool) +{ + apr_status_t apr_err; + const char *fname; + + apr_err = apr_file_name_get(&fname, file); + if (apr_err) + return svn_error_wrap_apr(apr_err, _("Can't get file name")); + + if (fname) + SVN_ERR(svn_path_cstring_to_utf8(fname_utf8, fname, pool)); + else + *fname_utf8 = NULL; + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_stringbuf_from_aprfile(svn_stringbuf_t **result, + apr_file_t *file, + apr_pool_t *pool) +{ + apr_size_t len; + svn_error_t *err; + svn_stringbuf_t *res = svn_stringbuf_create_ensure(SVN__STREAM_CHUNK_SIZE, + pool); + char *buf = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); + + /* XXX: We should check the incoming data for being of type binary. */ + + /* apr_file_read will not return data and eof in the same call. So this loop + * is safe from missing read data. */ + len = SVN__STREAM_CHUNK_SIZE; + err = svn_io_file_read(file, buf, &len, pool); + while (! err) + { + svn_stringbuf_appendbytes(res, buf, len); + len = SVN__STREAM_CHUNK_SIZE; + err = svn_io_file_read(file, buf, &len, pool); + } + + /* Having read all the data we *expect* EOF */ + if (err && !APR_STATUS_IS_EOF(err->apr_err)) + return err; + svn_error_clear(err); + + *result = res; + return SVN_NO_ERROR; +} + + + +/* Deletion. */ + +svn_error_t * +svn_io_remove_file(const char *path, apr_pool_t *pool) +{ + apr_status_t apr_err; + const char *path_apr; + +#ifdef WIN32 + /* Set the file writable but only on Windows, because Windows + will not allow us to remove files that are read-only. */ + SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool)); +#endif /* WIN32 */ + + SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); + + apr_err = apr_file_remove(path_apr, pool); +#ifdef WIN32 + if (apr_err) + { + /* Check to make sure we aren't trying to delete a directory */ + if (APR_TO_OS_ERROR(apr_err) == ERROR_ACCESS_DENIED) + { + apr_finfo_t finfo; + + if (apr_stat(&finfo, path_apr, APR_FINFO_TYPE, pool) == APR_SUCCESS + && finfo.filetype == APR_REG) + { + WIN32_RETRY_LOOP(apr_err, apr_file_remove(path_apr, pool)); + } + } + + /* Just return the delete error */ + } +#endif + if (apr_err) + return svn_error_wrap_apr(apr_err, _("Can't remove file '%s'"), + svn_path_local_style(path, pool)); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_remove_dir(const char *path, apr_pool_t *pool) +{ + return svn_io_remove_dir2(path, FALSE, NULL, NULL, pool); +} + +/* + Mac OS X has a bug where if you're readding the contents of a + directory via readdir in a loop, and you remove one of the entries in + the directory and the directory has 338 or more files in it you will + skip over some of the entries in the directory. Needless to say, + this causes problems if you are using this kind of loop inside a + function that is recursively deleting a directory, because when you + get around to removing the directory it will still have something in + it. + + Similar problem has been observed on FreeBSD. + + See http://subversion.tigris.org/issues/show_bug.cgi?id=1896 for more + discussion and an initial solution. + + To work around the problem, we do a rewinddir after we delete all files + and see if there's anything left. We repeat the steps untill there's + nothing left to delete. + + This workaround causes issues on Windows where delete's are asynchronous, + however, so we never rewind if we're on Windows (the delete says it is + complete, we rewind, we see the same file and try to delete it again, + we fail. +*/ + +/* Neither windows nor unix allows us to delete a non-empty + directory. + + This is a function to perform the equivalent of 'rm -rf'. */ +svn_error_t * +svn_io_remove_dir2(const char *path, svn_boolean_t ignore_enoent, + svn_cancel_func_t cancel_func, void *cancel_baton, + apr_pool_t *pool) +{ + apr_status_t status; + apr_dir_t *this_dir; + apr_finfo_t this_entry; + apr_pool_t *subpool; + apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME; + const char *path_apr; + int need_rewind; + + /* Check for pending cancellation request. + If we need to bail out, do so early. */ + + if (cancel_func) + SVN_ERR((*cancel_func)(cancel_baton)); + + /* Convert path to native here and call apr_dir_open directly, + instead of just using svn_io_dir_open, because we're going to + need path_apr later anyway when we remove the dir itself. */ + + if (path[0] == '\0') + /* APR doesn't like "" directories; use "." instead. */ + SVN_ERR(cstring_from_utf8(&path_apr, ".", pool)); + else + SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); + + status = apr_dir_open(&this_dir, path_apr, pool); + if (status) + { + /* if the directory doesn't exist, our mission is accomplished */ + if (ignore_enoent && APR_STATUS_IS_ENOENT(status)) + return SVN_NO_ERROR; + else + return svn_error_wrap_apr(status, + _("Can't open directory '%s'"), + svn_path_local_style(path, pool)); + } + + subpool = svn_pool_create(pool); + + do + { + need_rewind = FALSE; + + for (status = apr_dir_read(&this_entry, flags, this_dir); + status == APR_SUCCESS; + status = apr_dir_read(&this_entry, flags, this_dir)) + { + svn_pool_clear(subpool); + if ((this_entry.filetype == APR_DIR) + && ((this_entry.name[0] == '.') + && ((this_entry.name[1] == '\0') + || ((this_entry.name[1] == '.') + && (this_entry.name[2] == '\0'))))) + { + continue; + } + else /* something other than "." or "..", so proceed */ + { + const char *fullpath, *entry_utf8; + +#ifndef WIN32 + need_rewind = TRUE; +#endif + + SVN_ERR(entry_name_to_utf8(&entry_utf8, this_entry.name, + path_apr, subpool)); + + fullpath = svn_path_join(path, entry_utf8, subpool); + + if (this_entry.filetype == APR_DIR) + { + /* Don't check for cancellation, the callee + will immediately do so */ + SVN_ERR(svn_io_remove_dir2(fullpath, FALSE, + cancel_func, cancel_baton, + subpool)); + } + else + { + svn_error_t *err; + + if (cancel_func) + SVN_ERR((*cancel_func)(cancel_baton)); + + err = svn_io_remove_file(fullpath, subpool); + if (err) + return svn_error_createf + (err->apr_err, err, _("Can't remove '%s'"), + svn_path_local_style(fullpath, subpool)); + } + } + } + + if (need_rewind) + { + status = apr_dir_rewind(this_dir); + if (status) + return svn_error_wrap_apr(status, _("Can't rewind directory '%s'"), + svn_path_local_style (path, pool)); + } + } + while (need_rewind); + + svn_pool_destroy(subpool); + + if (!APR_STATUS_IS_ENOENT(status)) + return svn_error_wrap_apr(status, _("Can't read directory '%s'"), + svn_path_local_style(path, pool)); + + status = apr_dir_close(this_dir); + if (status) + return svn_error_wrap_apr(status, _("Error closing directory '%s'"), + svn_path_local_style(path, pool)); + + status = apr_dir_remove(path_apr, pool); + WIN32_RETRY_LOOP(status, apr_dir_remove(path_apr, pool)); + if (status) + return svn_error_wrap_apr(status, _("Can't remove '%s'"), + svn_path_local_style(path, pool)); + + return APR_SUCCESS; +} + +svn_error_t * +svn_io_get_dir_filenames(apr_hash_t **dirents, + const char *path, + apr_pool_t *pool) +{ + apr_status_t status; + apr_dir_t *this_dir; + apr_finfo_t this_entry; + apr_int32_t flags = APR_FINFO_NAME; + + *dirents = apr_hash_make(pool); + + SVN_ERR(svn_io_dir_open(&this_dir, path, pool)); + + for (status = apr_dir_read(&this_entry, flags, this_dir); + status == APR_SUCCESS; + status = apr_dir_read(&this_entry, flags, this_dir)) + { + if ((this_entry.name[0] == '.') + && ((this_entry.name[1] == '\0') + || ((this_entry.name[1] == '.') + && (this_entry.name[2] == '\0')))) + { + continue; + } + else + { + const char *name; + SVN_ERR(entry_name_to_utf8(&name, this_entry.name, path, pool)); + apr_hash_set(*dirents, name, APR_HASH_KEY_STRING, name); + } + } + + if (! (APR_STATUS_IS_ENOENT(status))) + return svn_error_wrap_apr(status, _("Can't read directory '%s'"), + svn_path_local_style(path, pool)); + + status = apr_dir_close(this_dir); + if (status) + return svn_error_wrap_apr(status, _("Error closing directory '%s'"), + svn_path_local_style(path, pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_io_get_dirents2(apr_hash_t **dirents, + const char *path, + apr_pool_t *pool) +{ + apr_status_t status; + apr_dir_t *this_dir; + apr_finfo_t this_entry; + apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME; + + *dirents = apr_hash_make(pool); + + SVN_ERR(svn_io_dir_open(&this_dir, path, pool)); + + for (status = apr_dir_read(&this_entry, flags, this_dir); + status == APR_SUCCESS; + status = apr_dir_read(&this_entry, flags, this_dir)) + { + if ((this_entry.name[0] == '.') + && ((this_entry.name[1] == '\0') + || ((this_entry.name[1] == '.') + && (this_entry.name[2] == '\0')))) + { + continue; + } + else + { + const char *name; + svn_io_dirent_t *dirent = apr_palloc(pool, sizeof(*dirent)); + + SVN_ERR(entry_name_to_utf8(&name, this_entry.name, path, pool)); + + map_apr_finfo_to_node_kind(&(dirent->kind), + &(dirent->special), + &this_entry); + + apr_hash_set(*dirents, name, APR_HASH_KEY_STRING, dirent); + } + } + + if (! (APR_STATUS_IS_ENOENT(status))) + return svn_error_wrap_apr(status, _("Can't read directory '%s'"), + svn_path_local_style(path, pool)); + + status = apr_dir_close(this_dir); + if (status) + return svn_error_wrap_apr(status, _("Error closing directory '%s'"), + svn_path_local_style(path, pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_io_get_dirents(apr_hash_t **dirents, + const char *path, + apr_pool_t *pool) +{ + /* Note that in C, padding is not allowed at the beginning of structs, + so this is actually portable, since the kind field of svn_io_dirent_t + is first in that struct. */ + return svn_io_get_dirents2(dirents, path, pool); +} + +/* Pool userdata key for the error file passed to svn_io_start_cmd(). */ +#define ERRFILE_KEY "svn-io-start-cmd-errfile" + +/* Handle an error from the child process (before command execution) by + printing DESC and the error string corresponding to STATUS to stderr. */ +static void +handle_child_process_error(apr_pool_t *pool, apr_status_t status, + const char *desc) +{ + char errbuf[256]; + apr_file_t *errfile; + void *p; + + /* We can't do anything if we get an error here, so just return. */ + if (apr_pool_userdata_get(&p, ERRFILE_KEY, pool)) + return; + errfile = p; + + if (errfile) + /* What we get from APR is in native encoding. */ + apr_file_printf(errfile, "%s: %s", + desc, apr_strerror(status, errbuf, + sizeof(errbuf))); +} + + +svn_error_t * +svn_io_start_cmd(apr_proc_t *cmd_proc, + const char *path, + const char *cmd, + const char *const *args, + svn_boolean_t inherit, + apr_file_t *infile, + apr_file_t *outfile, + apr_file_t *errfile, + apr_pool_t *pool) +{ + apr_status_t apr_err; + apr_procattr_t *cmdproc_attr; + int num_args; + const char **args_native; + const char *cmd_apr; + + /* Create the process attributes. */ + apr_err = apr_procattr_create(&cmdproc_attr, pool); + if (apr_err) + return svn_error_wrap_apr + (apr_err, _("Can't create process '%s' attributes"), cmd); + + /* Make sure we invoke cmd directly, not through a shell. */ + apr_err = apr_procattr_cmdtype_set(cmdproc_attr, + inherit?APR_PROGRAM_PATH:APR_PROGRAM); + if (apr_err) + return svn_error_wrap_apr(apr_err, _("Can't set process '%s' cmdtype"), + cmd); + + /* Set the process's working directory. */ + if (path) + { + const char *path_apr; + + SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); + apr_err = apr_procattr_dir_set(cmdproc_attr, path_apr); + if (apr_err) + return svn_error_wrap_apr + (apr_err, _("Can't set process '%s' directory"), cmd); + } + + /* Use requested inputs and outputs. + + ### Unfortunately each of these apr functions creates a pipe and then + overwrites the pipe file descriptor with the descriptor we pass + in. The pipes can then never be closed. This is an APR bug. */ + if (infile) + { + apr_err = apr_procattr_child_in_set(cmdproc_attr, infile, NULL); + if (apr_err) + return svn_error_wrap_apr + (apr_err, _("Can't set process '%s' child input"), cmd); + } + if (outfile) + { + apr_err = apr_procattr_child_out_set(cmdproc_attr, outfile, NULL); + if (apr_err) + return svn_error_wrap_apr + (apr_err, _("Can't set process '%s' child outfile"), cmd); + } + if (errfile) + { + apr_err = apr_procattr_child_err_set(cmdproc_attr, errfile, NULL); + if (apr_err) + return svn_error_wrap_apr + (apr_err, _("Can't set process '%s' child errfile"), cmd); + } + + /* Have the child print any problems executing its program to errfile. */ + apr_err = apr_pool_userdata_set(errfile, ERRFILE_KEY, NULL, pool); + if (apr_err) + return svn_error_wrap_apr + (apr_err, _("Can't set process '%s' child errfile for error handler"), + cmd); + apr_err = apr_procattr_child_errfn_set(cmdproc_attr, + handle_child_process_error); + if (apr_err) + return svn_error_wrap_apr + (apr_err, _("Can't set process '%s' error handler"), cmd); + + /* Convert cmd and args from UTF-8 */ + SVN_ERR(cstring_from_utf8(&cmd_apr, cmd, pool)); + for (num_args = 0; args[num_args]; num_args++) + ; + args_native = apr_palloc(pool, (num_args + 1) * sizeof(char *)); + args_native[num_args] = NULL; + while (num_args--) + { + /* ### Well, it turns out that on APR on Windows expects all + program args to be in UTF-8. Callers of svn_io_run_cmd + should be aware of that. */ + SVN_ERR(cstring_from_utf8(&args_native[num_args], + args[num_args], pool)); + } + + + /* Start the cmd command. */ + apr_err = apr_proc_create(cmd_proc, cmd_apr, args_native, NULL, + cmdproc_attr, pool); + if (apr_err) + return svn_error_wrap_apr(apr_err, _("Can't start process '%s'"), cmd); + + return SVN_NO_ERROR; +} + +#undef ERRFILE_KEY + +svn_error_t * +svn_io_wait_for_cmd(apr_proc_t *cmd_proc, + const char *cmd, + int *exitcode, + apr_exit_why_e *exitwhy, + apr_pool_t *pool) +{ + apr_status_t apr_err; + apr_exit_why_e exitwhy_val; + int exitcode_val; + + /* The Win32 apr_proc_wait doesn't set this... */ + exitwhy_val = APR_PROC_EXIT; + + /* Wait for the cmd command to finish. */ + apr_err = apr_proc_wait(cmd_proc, &exitcode_val, &exitwhy_val, APR_WAIT); + if (!APR_STATUS_IS_CHILD_DONE(apr_err)) + return svn_error_wrap_apr(apr_err, _("Error waiting for process '%s'"), + cmd); + + if (exitwhy) + *exitwhy = exitwhy_val; + else if (! APR_PROC_CHECK_EXIT(exitwhy_val)) + return svn_error_createf + (SVN_ERR_EXTERNAL_PROGRAM, NULL, + _("Process '%s' failed (exitwhy %d)"), cmd, exitwhy_val); + + if (exitcode) + *exitcode = exitcode_val; + else if (exitcode_val != 0) + return svn_error_createf + (SVN_ERR_EXTERNAL_PROGRAM, NULL, + _("Process '%s' returned error exitcode %d"), cmd, exitcode_val); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_run_cmd(const char *path, + const char *cmd, + const char *const *args, + int *exitcode, + apr_exit_why_e *exitwhy, + svn_boolean_t inherit, + apr_file_t *infile, + apr_file_t *outfile, + apr_file_t *errfile, + apr_pool_t *pool) +{ + apr_proc_t cmd_proc; + + SVN_ERR(svn_io_start_cmd(&cmd_proc, path, cmd, args, inherit, + infile, outfile, errfile, pool)); + + return svn_io_wait_for_cmd(&cmd_proc, cmd, exitcode, exitwhy, pool); +} + + +svn_error_t * +svn_io_run_diff2(const char *dir, + const char *const *user_args, + int num_user_args, + const char *label1, + const char *label2, + const char *from, + const char *to, + int *pexitcode, + apr_file_t *outfile, + apr_file_t *errfile, + const char *diff_cmd, + apr_pool_t *pool) +{ + const char **args; + int i; + int exitcode; + int nargs = 4; /* the diff command itself, two paths, plus a trailing NULL */ + apr_pool_t *subpool = svn_pool_create(pool); + + if (pexitcode == NULL) + pexitcode = &exitcode; + + if (user_args != NULL) + nargs += num_user_args; + else + nargs += 1; /* -u */ + + if (label1 != NULL) + nargs += 2; /* the -L and the label itself */ + if (label2 != NULL) + nargs += 2; /* the -L and the label itself */ + + args = apr_palloc(subpool, nargs * sizeof(char *)); + + i = 0; + args[i++] = diff_cmd; + + if (user_args != NULL) + { + int j; + for (j = 0; j < num_user_args; ++j) + args[i++] = user_args[j]; + } + else + args[i++] = "-u"; /* assume -u if the user didn't give us any args */ + + if (label1 != NULL) + { + args[i++] = "-L"; + args[i++] = label1; + } + if (label2 != NULL) + { + args[i++] = "-L"; + args[i++] = label2; + } + + args[i++] = svn_path_local_style(from, subpool); + args[i++] = svn_path_local_style(to, subpool); + args[i++] = NULL; + + SVN_ERR_ASSERT(i == nargs); + + SVN_ERR(svn_io_run_cmd(dir, diff_cmd, args, pexitcode, NULL, TRUE, + NULL, outfile, errfile, subpool)); + + /* The man page for (GNU) diff describes the return value as: + + "An exit status of 0 means no differences were found, 1 means + some differences were found, and 2 means trouble." + + A return value of 2 typically occurs when diff cannot read its input + or write to its output, but in any case we probably ought to return an + error for anything other than 0 or 1 as the output is likely to be + corrupt. + */ + if (*pexitcode != 0 && *pexitcode != 1) + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + _("'%s' returned %d"), + svn_path_local_style(diff_cmd, pool), + *pexitcode); + + svn_pool_destroy(subpool); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_run_diff3_3(int *exitcode, + const char *dir, + const char *mine, + const char *older, + const char *yours, + const char *mine_label, + const char *older_label, + const char *yours_label, + apr_file_t *merged, + const char *diff3_cmd, + const apr_array_header_t *user_args, + apr_pool_t *pool) +{ + const char **args = apr_palloc(pool, + sizeof(char*) * (13 + + (user_args + ? user_args->nelts + : 1))); +#ifndef NDEBUG + int nargs = 12; +#endif + int i = 0; + + /* Labels fall back to sensible defaults if not specified. */ + if (mine_label == NULL) + mine_label = ".working"; + if (older_label == NULL) + older_label = ".old"; + if (yours_label == NULL) + yours_label = ".new"; + + /* Set up diff3 command line. */ + args[i++] = diff3_cmd; + if (user_args) + { + int j; + for (j = 0; j < user_args->nelts; ++j) + args[i++] = APR_ARRAY_IDX(user_args, j, const char *); +#ifndef NDEBUG + nargs += user_args->nelts; +#endif + } + else + { + args[i++] = "-E"; /* We tried "-A" here, but that caused + overlapping identical changes to + conflict. See issue #682. */ +#ifndef NDEBUG + ++nargs; +#endif + } + args[i++] = "-m"; + args[i++] = "-L"; + args[i++] = mine_label; + args[i++] = "-L"; + args[i++] = older_label; /* note: this label is ignored if + using 2-part markers, which is the + case with "-E". */ + args[i++] = "-L"; + args[i++] = yours_label; +#ifdef SVN_DIFF3_HAS_DIFF_PROGRAM_ARG + { + svn_boolean_t has_arg; + + /* ### FIXME: we really shouldn't be reading the config here; + instead, the necessary bits should be passed in by the caller. + But should we add another parameter to this function, when the + whole external diff3 thing might eventually go away? */ + apr_hash_t *config; + svn_config_t *cfg; + + SVN_ERR(svn_config_get_config(&config, pool)); + cfg = config ? apr_hash_get(config, SVN_CONFIG_CATEGORY_CONFIG, + APR_HASH_KEY_STRING) : NULL; + SVN_ERR(svn_config_get_bool(cfg, &has_arg, SVN_CONFIG_SECTION_HELPERS, + SVN_CONFIG_OPTION_DIFF3_HAS_PROGRAM_ARG, + TRUE)); + if (has_arg) + { + const char *diff_cmd, *diff_utf8; + svn_config_get(cfg, &diff_cmd, SVN_CONFIG_SECTION_HELPERS, + SVN_CONFIG_OPTION_DIFF_CMD, SVN_CLIENT_DIFF); + SVN_ERR(cstring_to_utf8(&diff_utf8, diff_cmd, pool)); + args[i++] = apr_pstrcat(pool, "--diff-program=", diff_utf8, NULL); +#ifndef NDEBUG + ++nargs; +#endif + } + } +#endif + args[i++] = svn_path_local_style(mine, pool); + args[i++] = svn_path_local_style(older, pool); + args[i++] = svn_path_local_style(yours, pool); + args[i++] = NULL; +#ifndef NDEBUG + SVN_ERR_ASSERT(i == nargs); +#endif + + /* Run diff3, output the merged text into the scratch file. */ + SVN_ERR(svn_io_run_cmd(dir, diff3_cmd, args, + exitcode, NULL, + TRUE, /* keep environment */ + NULL, merged, NULL, + pool)); + + /* According to the diff3 docs, a '0' means the merge was clean, and + '1' means conflict markers were found. Anything else is real + error. */ + if ((*exitcode != 0) && (*exitcode != 1)) + return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL, + _("Error running '%s': exitcode was %d, " + "args were:" + "\nin directory '%s', basenames:\n%s\n%s\n%s"), + svn_path_local_style(diff3_cmd, pool), + *exitcode, + svn_path_local_style(dir, pool), + /* Don't call svn_path_local_style() on + the basenames. We don't want them to + be absolute, and we don't need the + separator conversion. */ + mine, older, yours); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_io_parse_mimetypes_file(apr_hash_t **type_map, + const char *mimetypes_file, + apr_pool_t *pool) +{ + svn_error_t *err = SVN_NO_ERROR; + apr_hash_t *types = apr_hash_make(pool); + svn_boolean_t eof = FALSE; + svn_stringbuf_t *buf; + apr_pool_t *subpool = svn_pool_create(pool); + apr_file_t *types_file; + svn_stream_t *mimetypes_stream; + + SVN_ERR(svn_io_file_open(&types_file, mimetypes_file, + APR_READ, APR_OS_DEFAULT, pool)); + mimetypes_stream = svn_stream_from_aprfile2(types_file, FALSE, pool); + + while (1) + { + apr_array_header_t *tokens; + const char *type; + int i; + + svn_pool_clear(subpool); + + /* Read a line. */ + if ((err = svn_stream_readline(mimetypes_stream, &buf, + APR_EOL_STR, &eof, subpool))) + break; + + /* Only pay attention to non-empty, non-comment lines. */ + if (buf->len) + { + if (buf->data[0] == '#') + continue; + + /* Tokenize (into our return pool). */ + tokens = svn_cstring_split(buf->data, " \t", TRUE, pool); + if (tokens->nelts < 2) + continue; + + /* The first token in a multi-token line is the media type. + Subsequent tokens are filename extensions associated with + that media type. */ + type = APR_ARRAY_IDX(tokens, 0, const char *); + for (i = 1; i < tokens->nelts; i++) + { + const char *ext = APR_ARRAY_IDX(tokens, i, const char *); + apr_hash_set(types, ext, APR_HASH_KEY_STRING, type); + } + } + if (eof) + break; + } + svn_pool_destroy(subpool); + + /* If there was an error above, close the file (ignoring any error + from *that*) and return the originally error. */ + if (err) + { + svn_error_clear(svn_stream_close(mimetypes_stream)); + return err; + } + + /* Close the stream (which closes the underlying file, too). */ + SVN_ERR(svn_stream_close(mimetypes_stream)); + + *type_map = types; + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_detect_mimetype2(const char **mimetype, + const char *file, + apr_hash_t *mimetype_map, + apr_pool_t *pool) +{ + static const char * const generic_binary = "application/octet-stream"; + + svn_node_kind_t kind; + apr_file_t *fh; + svn_error_t *err; + unsigned char block[1024]; + apr_size_t amt_read = sizeof(block); + + /* Default return value is NULL. */ + *mimetype = NULL; + + /* See if this file even exists, and make sure it really is a file. */ + SVN_ERR(svn_io_check_path(file, &kind, pool)); + if (kind != svn_node_file) + return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL, + _("Can't detect MIME type of non-file '%s'"), + svn_path_local_style(file, pool)); + + /* If there is a mimetype_map provided, we'll first try to look up + our file's extension in the map. Failing that, we'll run the + heuristic. */ + if (mimetype_map) + { + const char *type_from_map, *path_ext; + svn_path_splitext(NULL, &path_ext, file, pool); + if ((type_from_map = apr_hash_get(mimetype_map, path_ext, + APR_HASH_KEY_STRING))) + { + *mimetype = type_from_map; + return SVN_NO_ERROR; + } + } + + SVN_ERR(svn_io_file_open(&fh, file, APR_READ, 0, pool)); + + /* Read a block of data from FILE. */ + err = svn_io_file_read(fh, block, &amt_read, pool); + if (err && ! APR_STATUS_IS_EOF(err->apr_err)) + return err; + svn_error_clear(err); + + /* Now close the file. No use keeping it open any more. */ + SVN_ERR(svn_io_file_close(fh, pool)); + + + /* Right now, this function is going to be really stupid. It's + going to examine the first block of data, and make sure that 85% + of the bytes are such that their value is in the ranges 0x07-0x0D + or 0x20-0x7F, and that 100% of those bytes is not 0x00. + + If those criteria are not met, we're calling it binary. */ + if (amt_read > 0) + { + apr_size_t i; + int binary_count = 0; + + /* Run through the data we've read, counting the 'binary-ish' + bytes. HINT: If we see a 0x00 byte, we'll set our count to its + max and stop reading the file. */ + for (i = 0; i < amt_read; i++) + { + if (block[i] == 0) + { + binary_count = amt_read; + break; + } + if ((block[i] < 0x07) + || ((block[i] > 0x0D) && (block[i] < 0x20)) + || (block[i] > 0x7F)) + { + binary_count++; + } + } + + if (((binary_count * 1000) / amt_read) > 850) + { + *mimetype = generic_binary; + return SVN_NO_ERROR; + } + } + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_detect_mimetype(const char **mimetype, + const char *file, + apr_pool_t *pool) +{ + return svn_io_detect_mimetype2(mimetype, file, NULL, pool); +} + + +svn_error_t * +svn_io_file_open(apr_file_t **new_file, const char *fname, + apr_int32_t flag, apr_fileperms_t perm, + apr_pool_t *pool) +{ + const char *fname_apr; + apr_status_t status; + + SVN_ERR(cstring_from_utf8(&fname_apr, fname, pool)); + status = file_open(new_file, fname_apr, flag | APR_BINARY, perm, TRUE, + pool); + + if (status) + return svn_error_wrap_apr(status, _("Can't open file '%s'"), + svn_path_local_style(fname, pool)); + else + return SVN_NO_ERROR; +} + + +static svn_error_t * +do_io_file_wrapper_cleanup(apr_file_t *file, apr_status_t status, + const char *msg, const char *msg_no_name, + apr_pool_t *pool) +{ + const char *name; + svn_error_t *err; + + if (! status) + return SVN_NO_ERROR; + + err = file_name_get(&name, file, pool); + if (err) + name = NULL; + svn_error_clear(err); + + if (name) + return svn_error_wrap_apr(status, _(msg), + svn_path_local_style(name, pool)); + else + return svn_error_wrap_apr(status, _(msg_no_name)); +} + + +svn_error_t * +svn_io_file_close(apr_file_t *file, apr_pool_t *pool) +{ + return do_io_file_wrapper_cleanup + (file, apr_file_close(file), + N_("Can't close file '%s'"), + N_("Can't close stream"), + pool); +} + + +svn_error_t * +svn_io_file_getc(char *ch, apr_file_t *file, apr_pool_t *pool) +{ + return do_io_file_wrapper_cleanup + (file, apr_file_getc(ch, file), + N_("Can't read file '%s'"), + N_("Can't read stream"), + pool); +} + + +svn_error_t * +svn_io_file_info_get(apr_finfo_t *finfo, apr_int32_t wanted, + apr_file_t *file, apr_pool_t *pool) +{ + return do_io_file_wrapper_cleanup + (file, apr_file_info_get(finfo, wanted, file), + N_("Can't get attribute information from file '%s'"), + N_("Can't get attribute information from stream"), + pool); +} + + +svn_error_t * +svn_io_file_read(apr_file_t *file, void *buf, + apr_size_t *nbytes, apr_pool_t *pool) +{ + return do_io_file_wrapper_cleanup + (file, apr_file_read(file, buf, nbytes), + N_("Can't read file '%s'"), + N_("Can't read stream"), + pool); +} + + +svn_error_t * +svn_io_file_read_full(apr_file_t *file, void *buf, + apr_size_t nbytes, apr_size_t *bytes_read, + apr_pool_t *pool) +{ + return do_io_file_wrapper_cleanup + (file, apr_file_read_full(file, buf, nbytes, bytes_read), + N_("Can't read file '%s'"), + N_("Can't read stream"), + pool); +} + + +svn_error_t * +svn_io_file_seek(apr_file_t *file, apr_seek_where_t where, + apr_off_t *offset, apr_pool_t *pool) +{ + return do_io_file_wrapper_cleanup + (file, apr_file_seek(file, where, offset), + N_("Can't set position pointer in file '%s'"), + N_("Can't set position pointer in stream"), + pool); +} + + +svn_error_t * +svn_io_file_write(apr_file_t *file, const void *buf, + apr_size_t *nbytes, apr_pool_t *pool) +{ + return do_io_file_wrapper_cleanup + (file, apr_file_write(file, buf, nbytes), + N_("Can't write to file '%s'"), + N_("Can't write to stream"), + pool); +} + + +svn_error_t * +svn_io_file_write_full(apr_file_t *file, const void *buf, + apr_size_t nbytes, apr_size_t *bytes_written, + apr_pool_t *pool) +{ + apr_status_t rv = apr_file_write_full(file, buf, nbytes, bytes_written); + +#ifdef WIN32 +#define MAXBUFSIZE 30*1024 + if (rv == APR_FROM_OS_ERROR(ERROR_NOT_ENOUGH_MEMORY) + && nbytes > MAXBUFSIZE) + { + apr_size_t bw = 0; + *bytes_written = 0; + + do { + rv = apr_file_write_full(file, buf, + nbytes > MAXBUFSIZE ? MAXBUFSIZE : nbytes, &bw); + *bytes_written += bw; + buf = (char *)buf + bw; + nbytes -= bw; + } while (rv == APR_SUCCESS && nbytes > 0); + } +#undef MAXBUFSIZE +#endif + + return do_io_file_wrapper_cleanup + (file, rv, + N_("Can't write to file '%s'"), + N_("Can't write to stream"), + pool); +} + + +svn_error_t * +svn_io_write_unique(const char **tmp_path, + const char *dirpath, + const void *buf, + apr_size_t nbytes, + svn_io_file_del_t delete_when, + apr_pool_t *pool) +{ + apr_file_t *new_file; + + SVN_ERR(svn_io_open_unique_file3(&new_file, tmp_path, dirpath, + delete_when, pool, pool)); + SVN_ERR(svn_io_file_write_full(new_file, buf, nbytes, NULL, pool)); + SVN_ERR(svn_io_file_flush_to_disk(new_file, pool)); + return svn_io_file_close(new_file, pool); +} + + +svn_error_t * +svn_io_file_trunc(apr_file_t *file, apr_off_t offset, apr_pool_t *pool) +{ + return do_io_file_wrapper_cleanup + (file, apr_file_trunc(file, offset), + N_("Can't truncate file '%s'"), + N_("Can't truncate stream"), + pool); +} + + +svn_error_t * +svn_io_read_length_line(apr_file_t *file, char *buf, apr_size_t *limit, + apr_pool_t *pool) +{ + const char *name; + svn_error_t *err; + apr_size_t i; + char c; + + for (i = 0; i < *limit; i++) + { + SVN_ERR(svn_io_file_getc(&c, file, pool)); + /* Note: this error could be APR_EOF, which + is totally fine. The caller should be aware of + this. */ + + if (c == '\n') + { + buf[i] = '\0'; + *limit = i; + return SVN_NO_ERROR; + } + else + { + buf[i] = c; + } + } + + err = file_name_get(&name, file, pool); + if (err) + name = NULL; + svn_error_clear(err); + + if (name) + return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, + _("Can't read length line in file '%s'"), + svn_path_local_style(name, pool)); + else + return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL, + _("Can't read length line in stream")); +} + + +svn_error_t * +svn_io_stat(apr_finfo_t *finfo, const char *fname, + apr_int32_t wanted, apr_pool_t *pool) +{ + apr_status_t status; + const char *fname_apr; + + /* APR doesn't like "" directories */ + if (fname[0] == '\0') + fname = "."; + + SVN_ERR(cstring_from_utf8(&fname_apr, fname, pool)); + + status = apr_stat(finfo, fname_apr, wanted, pool); + if (status) + return svn_error_wrap_apr(status, _("Can't stat '%s'"), + svn_path_local_style(fname, pool)); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_file_rename(const char *from_path, const char *to_path, + apr_pool_t *pool) +{ + apr_status_t status = APR_SUCCESS; + const char *from_path_apr, *to_path_apr; + + SVN_ERR(cstring_from_utf8(&from_path_apr, from_path, pool)); + SVN_ERR(cstring_from_utf8(&to_path_apr, to_path, pool)); + + status = apr_file_rename(from_path_apr, to_path_apr, pool); + +#ifdef WIN32 + if (status) + { + /* Set the destination file writable because Windows will not + allow us to rename over files that are read-only. */ + SVN_ERR(svn_io_set_file_read_write(to_path, TRUE, pool)); + + status = apr_file_rename(from_path_apr, to_path_apr, pool); + + WIN32_RETRY_LOOP(status, + apr_file_rename(from_path_apr, to_path_apr, pool)); + } +#endif /* WIN32 */ + + if (status) + return svn_error_wrap_apr(status, _("Can't move '%s' to '%s'"), + svn_path_local_style(from_path, pool), + svn_path_local_style(to_path, pool)); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_file_move(const char *from_path, const char *to_path, + apr_pool_t *pool) +{ + svn_error_t *err = svn_io_file_rename(from_path, to_path, pool); + + if (err && APR_STATUS_IS_EXDEV(err->apr_err)) + { + const char *tmp_to_path; + + svn_error_clear(err); + + SVN_ERR(svn_io_open_unique_file3(NULL, &tmp_to_path, + svn_path_dirname(to_path, pool), + svn_io_file_del_none, + pool, pool)); + + err = svn_io_copy_file(from_path, tmp_to_path, TRUE, pool); + if (err) + goto failed_tmp; + + err = svn_io_file_rename(tmp_to_path, to_path, pool); + if (err) + goto failed_tmp; + + err = svn_io_remove_file(from_path, pool); + if (! err) + return SVN_NO_ERROR; + + svn_error_clear(svn_io_remove_file(to_path, pool)); + + return err; + + failed_tmp: + svn_error_clear(svn_io_remove_file(tmp_to_path, pool)); + } + + return err; +} + +/* Common implementation of svn_io_dir_make and svn_io_dir_make_hidden. + HIDDEN determines if the hidden attribute + should be set on the newly created directory. */ +static svn_error_t * +dir_make(const char *path, apr_fileperms_t perm, + svn_boolean_t hidden, svn_boolean_t sgid, apr_pool_t *pool) +{ + apr_status_t status; + const char *path_apr; + + SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); + + /* APR doesn't like "" directories */ + if (path_apr[0] == '\0') + path_apr = "."; + +#if (APR_OS_DEFAULT & APR_WSTICKY) + /* The APR shipped with httpd 2.0.50 contains a bug where + APR_OS_DEFAULT encompasses the setuid, setgid, and sticky bits. + There is a special case for file creation, but not directory + creation, so directories wind up getting created with the sticky + bit set. (There is no such thing as a setuid directory, and the + setgid bit is apparently ignored at mkdir() time.) If we detect + this problem, work around it by unsetting those bits if we are + passed APR_OS_DEFAULT. */ + if (perm == APR_OS_DEFAULT) + perm &= ~(APR_USETID | APR_GSETID | APR_WSTICKY); +#endif + + status = apr_dir_make(path_apr, perm, pool); + WIN32_RETRY_LOOP(status, apr_dir_make(path_apr, perm, pool)); + + if (status) + return svn_error_wrap_apr(status, _("Can't create directory '%s'"), + svn_path_local_style(path, pool)); + +#ifdef APR_FILE_ATTR_HIDDEN + if (hidden) + { + status = apr_file_attrs_set(path_apr, + APR_FILE_ATTR_HIDDEN, + APR_FILE_ATTR_HIDDEN, + pool); + if (status) + return svn_error_wrap_apr(status, _("Can't hide directory '%s'"), + svn_path_local_style(path, pool)); + } +#endif + +/* Windows does not implement sgid. Skip here because retrieving + the file permissions via APR_FINFO_PROT | APR_FINFO_OWNER is documented + to be 'incredibly expensive'. */ +#ifndef WIN32 + if (sgid) + { + apr_finfo_t finfo; + + /* Per our contract, don't do error-checking. Some filesystems + * don't support the sgid bit, and that's okay. */ + status = apr_stat(&finfo, path_apr, APR_FINFO_PROT, pool); + + if (!status) + apr_file_perms_set(path_apr, finfo.protection | APR_GSETID); + } +#endif + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_io_dir_make(const char *path, apr_fileperms_t perm, apr_pool_t *pool) +{ + return dir_make(path, perm, FALSE, FALSE, pool); +} + +svn_error_t * +svn_io_dir_make_hidden(const char *path, apr_fileperms_t perm, + apr_pool_t *pool) +{ + return dir_make(path, perm, TRUE, FALSE, pool); +} + +svn_error_t * +svn_io_dir_make_sgid(const char *path, apr_fileperms_t perm, + apr_pool_t *pool) +{ + return dir_make(path, perm, FALSE, TRUE, pool); +} + + +svn_error_t * +svn_io_dir_open(apr_dir_t **new_dir, const char *dirname, apr_pool_t *pool) +{ + apr_status_t status; + const char *dirname_apr; + + /* APR doesn't like "" directories */ + if (dirname[0] == '\0') + dirname = "."; + + SVN_ERR(cstring_from_utf8(&dirname_apr, dirname, pool)); + + status = apr_dir_open(new_dir, dirname_apr, pool); + if (status) + return svn_error_wrap_apr(status, _("Can't open directory '%s'"), + svn_path_local_style(dirname, pool)); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_dir_remove_nonrecursive(const char *dirname, apr_pool_t *pool) +{ + apr_status_t status; + const char *dirname_apr; + + SVN_ERR(cstring_from_utf8(&dirname_apr, dirname, pool)); + + status = apr_dir_remove(dirname_apr, pool); + WIN32_RETRY_LOOP(status, apr_dir_remove(dirname_apr, pool)); + if (status) + return svn_error_wrap_apr(status, _("Can't remove directory '%s'"), + svn_path_local_style(dirname, pool)); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_dir_read(apr_finfo_t *finfo, + apr_int32_t wanted, + apr_dir_t *thedir, + apr_pool_t *pool) +{ + apr_status_t status; + + status = apr_dir_read(finfo, wanted, thedir); + + if (status) + return svn_error_wrap_apr(status, _("Can't read directory")); + + /* It would be nice to use entry_name_to_utf8() below, but can we + get the dir's path out of an apr_dir_t? I don't see a reliable + way to do it. */ + + if (finfo->fname) + SVN_ERR(svn_path_cstring_to_utf8(&finfo->fname, finfo->fname, pool)); + + if (finfo->name) + SVN_ERR(svn_path_cstring_to_utf8(&finfo->name, finfo->name, pool)); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_io_dir_walk(const char *dirname, + apr_int32_t wanted, + svn_io_walk_func_t walk_func, + void *walk_baton, + apr_pool_t *pool) +{ + apr_status_t apr_err; + apr_dir_t *handle; + apr_pool_t *subpool; + const char *dirname_apr; + apr_finfo_t finfo; + + wanted |= APR_FINFO_TYPE | APR_FINFO_NAME; + + /* The documentation for apr_dir_read used to state that "." and ".." + will be returned as the first two files, but it doesn't + work that way in practice, in particular ext3 on Linux-2.6 doesn't + follow the rules. For details see + http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=56666 + + If APR ever does implement "dot-first" then it would be possible to + remove the svn_io_stat and walk_func calls and use the walk_func + inside the loop. + + Note: apr_stat doesn't handle FINFO_NAME but svn_io_dir_walk is + documented to provide it, so we have to do a bit extra. */ + SVN_ERR(svn_io_stat(&finfo, dirname, wanted & ~APR_FINFO_NAME, pool)); + SVN_ERR(cstring_from_utf8(&finfo.name, + svn_path_basename(dirname, pool), + pool)); + finfo.valid |= APR_FINFO_NAME; + SVN_ERR((*walk_func)(walk_baton, dirname, &finfo, pool)); + + SVN_ERR(cstring_from_utf8(&dirname_apr, dirname, pool)); + + apr_err = apr_dir_open(&handle, dirname_apr, pool); + if (apr_err) + return svn_error_wrap_apr(apr_err, _("Can't open directory '%s'"), + svn_path_local_style(dirname, pool)); + + /* iteration subpool */ + subpool = svn_pool_create(pool); + + while (1) + { + const char *name_utf8; + const char *full_path; + + svn_pool_clear(subpool); + + apr_err = apr_dir_read(&finfo, wanted, handle); + if (APR_STATUS_IS_ENOENT(apr_err)) + break; + else if (apr_err) + { + return svn_error_wrap_apr + (apr_err, _("Can't read directory entry in '%s'"), + svn_path_local_style(dirname, pool)); + } + + if (finfo.filetype == APR_DIR) + { + if (finfo.name[0] == '.' + && (finfo.name[1] == '\0' + || (finfo.name[1] == '.' && finfo.name[2] == '\0'))) + /* skip "." and ".." */ + continue; + + /* some other directory. recurse. it will be passed to the + callback inside the recursion. */ + SVN_ERR(entry_name_to_utf8(&name_utf8, finfo.name, dirname, + subpool)); + full_path = svn_path_join(dirname, name_utf8, subpool); + SVN_ERR(svn_io_dir_walk(full_path, + wanted, + walk_func, + walk_baton, + subpool)); + } + else if (finfo.filetype == APR_REG) + { + /* some other directory. pass it to the callback. */ + SVN_ERR(entry_name_to_utf8(&name_utf8, finfo.name, dirname, + subpool)); + full_path = svn_path_join(dirname, name_utf8, subpool); + SVN_ERR((*walk_func)(walk_baton, + full_path, + &finfo, + subpool)); + } + /* else: + some other type of file; skip it. + */ + + } + + svn_pool_destroy(subpool); + + apr_err = apr_dir_close(handle); + if (apr_err) + return svn_error_wrap_apr(apr_err, _("Error closing directory '%s'"), + svn_path_local_style(dirname, pool)); + + return SVN_NO_ERROR; +} + + + +/** + * Determine if a directory is empty or not. + * @param Return APR_SUCCESS if the dir is empty, else APR_ENOTEMPTY if not. + * @param path The directory. + * @param pool Used for temporary allocation. + * @remark If path is not a directory, or some other error occurs, + * then return the appropriate apr status code. + * + * (This function is written in APR style, in anticipation of + * perhaps someday being moved to APR as 'apr_dir_is_empty'.) + */ +static apr_status_t +dir_is_empty(const char *dir, apr_pool_t *pool) +{ + apr_status_t apr_err; + apr_dir_t *dir_handle; + apr_finfo_t finfo; + apr_status_t retval = APR_SUCCESS; + + /* APR doesn't like "" directories */ + if (dir[0] == '\0') + dir = "."; + + apr_err = apr_dir_open(&dir_handle, dir, pool); + if (apr_err != APR_SUCCESS) + return apr_err; + + for (apr_err = apr_dir_read(&finfo, APR_FINFO_NAME, dir_handle); + apr_err == APR_SUCCESS; + apr_err = apr_dir_read(&finfo, APR_FINFO_NAME, dir_handle)) + { + /* Ignore entries for this dir and its parent, robustly. + (APR promises that they'll come first, so technically + this guard could be moved outside the loop. But Ryan Bloom + says he doesn't believe it, and I believe him. */ + if (! (finfo.name[0] == '.' + && (finfo.name[1] == '\0' + || (finfo.name[1] == '.' && finfo.name[2] == '\0')))) + { + retval = APR_ENOTEMPTY; + break; + } + } + + /* Make sure we broke out of the loop for the right reason. */ + if (apr_err && ! APR_STATUS_IS_ENOENT(apr_err)) + return apr_err; + + apr_err = apr_dir_close(dir_handle); + if (apr_err != APR_SUCCESS) + return apr_err; + + return retval; +} + + +svn_error_t * +svn_io_dir_empty(svn_boolean_t *is_empty_p, + const char *path, + apr_pool_t *pool) +{ + apr_status_t status; + const char *path_apr; + + SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); + + status = dir_is_empty(path_apr, pool); + + if (!status) + *is_empty_p = TRUE; + else if (APR_STATUS_IS_ENOTEMPTY(status)) + *is_empty_p = FALSE; + else + return svn_error_wrap_apr(status, _("Can't check directory '%s'"), + svn_path_local_style(path, pool)); + + return SVN_NO_ERROR; +} + + + +/*** Version/format files ***/ + +svn_error_t * +svn_io_write_version_file(const char *path, + int version, + apr_pool_t *pool) +{ + const char *path_tmp; + const char *format_contents = apr_psprintf(pool, "%d\n", version); + + SVN_ERR_ASSERT(version >= 0); + + SVN_ERR(svn_io_write_unique(&path_tmp, + svn_path_dirname(path, pool), + format_contents, strlen(format_contents), + svn_io_file_del_none, pool)); + +#ifdef WIN32 + /* make the destination writable, but only on Windows, because + Windows does not let us replace read-only files. */ + SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool)); +#endif /* WIN32 */ + + /* rename the temp file as the real destination */ + SVN_ERR(svn_io_file_rename(path_tmp, path, pool)); + + /* And finally remove the perms to make it read only */ + return svn_io_set_file_read_only(path, FALSE, pool); +} + + +svn_error_t * +svn_io_read_version_file(int *version, + const char *path, + apr_pool_t *pool) +{ + apr_file_t *format_file; + char buf[80]; + apr_size_t len; + + /* Read a chunk of data from PATH */ + SVN_ERR(svn_io_file_open(&format_file, path, APR_READ, + APR_OS_DEFAULT, pool)); + len = sizeof(buf); + SVN_ERR(svn_io_file_read(format_file, buf, &len, pool)); + + /* Close the file. */ + SVN_ERR(svn_io_file_close(format_file, pool)); + + /* If there was no data in PATH, return an error. */ + if (len == 0) + return svn_error_createf(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL, + _("Reading '%s'"), + svn_path_local_style(path, pool)); + + /* Check that the first line contains only digits. */ + { + apr_size_t i; + + for (i = 0; i < len; ++i) + { + char c = buf[i]; + + if (i > 0 && (c == '\r' || c == '\n')) + break; + if (! apr_isdigit(c)) + return svn_error_createf + (SVN_ERR_BAD_VERSION_FILE_FORMAT, NULL, + _("First line of '%s' contains non-digit"), + svn_path_local_style(path, pool)); + } + } + + /* Convert to integer. */ + *version = atoi(buf); + + return SVN_NO_ERROR; +} + + + +/* Do a byte-for-byte comparison of FILE1 and FILE2. */ +static svn_error_t * +contents_identical_p(svn_boolean_t *identical_p, + const char *file1, + const char *file2, + apr_pool_t *pool) +{ + svn_error_t *err1; + svn_error_t *err2; + apr_size_t bytes_read1, bytes_read2; + char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); + char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); + apr_file_t *file1_h = NULL; + apr_file_t *file2_h = NULL; + + SVN_ERR(svn_io_file_open(&file1_h, file1, APR_READ, APR_OS_DEFAULT, + pool)); + SVN_ERR(svn_io_file_open(&file2_h, file2, APR_READ, APR_OS_DEFAULT, + pool)); + + *identical_p = TRUE; /* assume TRUE, until disproved below */ + do + { + err1 = svn_io_file_read_full(file1_h, buf1, + SVN__STREAM_CHUNK_SIZE, &bytes_read1, pool); + if (err1 && !APR_STATUS_IS_EOF(err1->apr_err)) + return err1; + + err2 = svn_io_file_read_full(file2_h, buf2, + SVN__STREAM_CHUNK_SIZE, &bytes_read2, pool); + if (err2 && !APR_STATUS_IS_EOF(err2->apr_err)) + { + svn_error_clear(err1); + return err2; + } + + if ((bytes_read1 != bytes_read2) + || (memcmp(buf1, buf2, bytes_read1))) + { + *identical_p = FALSE; + break; + } + } while (! err1 && ! err2); + + svn_error_clear(err1); + svn_error_clear(err2); + + SVN_ERR(svn_io_file_close(file1_h, pool)); + return svn_io_file_close(file2_h, pool); +} + + + +svn_error_t * +svn_io_files_contents_same_p(svn_boolean_t *same, + const char *file1, + const char *file2, + apr_pool_t *pool) +{ + svn_boolean_t q; + + SVN_ERR(svn_io_filesizes_different_p(&q, file1, file2, pool)); + + if (q) + { + *same = 0; + return SVN_NO_ERROR; + } + + SVN_ERR(contents_identical_p(&q, file1, file2, pool)); + + if (q) + *same = 1; + else + *same = 0; + + return SVN_NO_ERROR; +} diff --git a/src/TortoiseMerge/libsvn_diff/lcs.c b/src/TortoiseMerge/libsvn_diff/lcs.c index 4154b15..0d4a63e 100644 --- a/src/TortoiseMerge/libsvn_diff/lcs.c +++ b/src/TortoiseMerge/libsvn_diff/lcs.c @@ -21,6 +21,11 @@ #include #include +#include +#include "svn_error.h" +#include "svn_version.h" +#include "svn_io.h" + #include "diff.h" diff --git a/src/TortoiseMerge/libsvn_diff/maketree.c b/src/TortoiseMerge/libsvn_diff/maketree.c new file mode 100644 index 0000000..c64de51 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/maketree.c @@ -0,0 +1,85 @@ +/* maketree.c -- make inffixed.h table for decoding fixed codes + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* This program is included in the distribution for completeness. + You do not need to compile or run this program since inffixed.h + is already included in the distribution. To use this program + you need to compile zlib with BUILDFIXED defined and then compile + and link this program with the zlib library. Then the output of + this program can be piped to inffixed.h. */ + +#include +#include +#include "zutil.h" +#include "inftrees.h" + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* generate initialization table for an inflate_huft structure array */ +void maketree(uInt b, inflate_huft *t) +{ + int i, e; + + i = 0; + while (1) + { + e = t[i].exop; + if (e && (e & (16+64)) == 0) /* table pointer */ + { + fprintf(stderr, "maketree: cannot initialize sub-tables!\n"); + exit(1); + } + if (i % 4 == 0) + printf("\n "); + printf(" {{{%u,%u}},%u}", t[i].exop, t[i].bits, t[i].base); + if (++i == (1< +#include "md5.h" +#include "svn_md5.h" + + + +/* The MD5 digest for the empty string. */ +static const unsigned char svn_md5__empty_string_digest_array[] = { + 212, 29, 140, 217, 143, 0, 178, 4, 233, 128, 9, 152, 236, 248, 66, 126 +}; + +const unsigned char * +svn_md5__empty_string_digest(void) +{ + return svn_md5__empty_string_digest_array; +} + + +const char * +svn_md5__digest_to_cstring_display(const unsigned char digest[], + apr_pool_t *pool) +{ + static const char *hex = "0123456789abcdef"; + char *str = apr_palloc(pool, (APR_MD5_DIGESTSIZE * 2) + 1); + int i; + + for (i = 0; i < APR_MD5_DIGESTSIZE; i++) + { + str[i*2] = hex[digest[i] >> 4]; + str[i*2+1] = hex[digest[i] & 0x0f]; + } + str[i*2] = '\0'; + + return str; +} + + +const char * +svn_md5__digest_to_cstring(const unsigned char digest[], apr_pool_t *pool) +{ + static const unsigned char zeros_digest[APR_MD5_DIGESTSIZE] = { 0 }; + + if (memcmp(digest, zeros_digest, APR_MD5_DIGESTSIZE) != 0) + return svn_md5__digest_to_cstring_display(digest, pool); + else + return NULL; +} + + +svn_boolean_t +svn_md5__digests_match(const unsigned char d1[], const unsigned char d2[]) +{ + static const unsigned char zeros[APR_MD5_DIGESTSIZE] = { 0 }; + + return ((memcmp(d1, zeros, APR_MD5_DIGESTSIZE) == 0) + || (memcmp(d2, zeros, APR_MD5_DIGESTSIZE) == 0) + || (memcmp(d1, d2, APR_MD5_DIGESTSIZE) == 0)); +} + +/* These are all deprecated, and just wrap the internal functions defined + above. */ +const unsigned char * +svn_md5_empty_string_digest(void) +{ + return svn_md5__empty_string_digest(); +} + +const char * +svn_md5_digest_to_cstring_display(const unsigned char digest[], + apr_pool_t *pool) +{ + return svn_md5__digest_to_cstring_display(digest, pool); +} + +const char * +svn_md5_digest_to_cstring(const unsigned char digest[], apr_pool_t *pool) +{ + return svn_md5__digest_to_cstring(digest, pool); +} + +svn_boolean_t +svn_md5_digests_match(const unsigned char d1[], const unsigned char d2[]) +{ + return svn_md5__digests_match(d1, d2); +} diff --git a/src/TortoiseMerge/libsvn_diff/md5.h b/src/TortoiseMerge/libsvn_diff/md5.h new file mode 100644 index 0000000..7fb3242 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/md5.h @@ -0,0 +1,66 @@ +/* + * md5.h: Converting and comparing MD5 checksums + * + * ==================================================================== + * Copyright (c) 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + +#ifndef SVN_LIBSVN_SUBR_MD5_H +#define SVN_LIBSVN_SUBR_MD5_H + +#include + +#include "svn_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +/* The MD5 digest for the empty string. */ +const unsigned char * +svn_md5__empty_string_digest(void); + + +/* Return the hex representation of DIGEST, which must be + * APR_MD5_DIGESTSIZE bytes long, allocating the string in POOL. + */ +const char * +svn_md5__digest_to_cstring_display(const unsigned char digest[], + apr_pool_t *pool); + + +/* Return the hex representation of DIGEST, which must be + * APR_MD5_DIGESTSIZE bytes long, allocating the string in POOL. + * If DIGEST is all zeros, then return NULL. + */ +const char * +svn_md5__digest_to_cstring(const unsigned char digest[], + apr_pool_t *pool); + + +/** Compare digests D1 and D2, each APR_MD5_DIGESTSIZE bytes long. + * If neither is all zeros, and they do not match, then return FALSE; + * else return TRUE. + */ +svn_boolean_t +svn_md5__digests_match(const unsigned char d1[], + const unsigned char d2[]); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_LIBSVN_SUBR_MD5_H */ diff --git a/src/TortoiseMerge/libsvn_diff/path.c b/src/TortoiseMerge/libsvn_diff/path.c new file mode 100644 index 0000000..daac8a1 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/path.c @@ -0,0 +1,1203 @@ +/* + * paths.c: a path manipulation library using svn_stringbuf_t + * + * ==================================================================== + * Copyright (c) 2000-2007, 2009 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + + + +#include +#include + +#include +#include +#include + +#include "svn_string.h" +//#include "svn_dirent_uri.h" +#include "svn_path.h" +//#include "svn_private_config.h" /* for SVN_PATH_LOCAL_SEPARATOR */ +#include "svn_utf.h" +#include "svn_io.h" /* for svn_io_stat() */ +#include "svn_ctype.h" + +//#include "private_uri.h" + +/* The canonical empty path. Can this be changed? Well, change the empty + test below and the path library will work, not so sure about the fs/wc + libraries. */ +#define SVN_EMPTY_PATH "" + +/* TRUE if s is the canonical empty path, FALSE otherwise */ +#define SVN_PATH_IS_EMPTY(s) ((s)[0] == '\0') + +/* TRUE if s,n is the platform's empty path ("."), FALSE otherwise. Can + this be changed? Well, the path library will work, not so sure about + the OS! */ +#define SVN_PATH_IS_PLATFORM_EMPTY(s,n) ((n) == 1 && (s)[0] == '.') + + +const char * +svn_path_internal_style(const char *path, apr_pool_t *pool) +{ +#if defined(WIN32) || defined(__CYGWIN__) + if ((path[0] == '/' || path[0] == '\\') && path[1] == path[0]) + return svn_dirent_internal_style(path, pool); +#endif + return svn_uri_internal_style(path, pool); +} + + +const char * +svn_path_local_style(const char *path, apr_pool_t *pool) +{ +#if defined(WIN32) || defined(__CYGWIN__) + if (path[0] == '/' && path[1] == '/') + return svn_dirent_local_style(path, pool); +#endif + return svn_uri_local_style(path, pool); +} + + +#ifndef NDEBUG +/* This function is an approximation of svn_path_is_canonical. + * It is supposed to be used in functions that do not have access + * to a pool, but still want to assert that a path is canonical. + * + * PATH with length LEN is assumed to be canonical if it isn't + * the platform's empty path (see definition of SVN_PATH_IS_PLATFORM_EMPTY), + * and does not contain "/./", and any one of the following + * conditions is also met: + * + * 1. PATH has zero length + * 2. PATH is the root directory (what exactly a root directory is + * depends on the platform) + * 3. PATH is not a root directory and does not end with '/' + * + * If possible, please use svn_path_is_canonical instead. + */ +static svn_boolean_t +is_canonical(const char *path, + apr_size_t len) +{ + return (! SVN_PATH_IS_PLATFORM_EMPTY(path, len) + && strstr(path, "/./") == NULL + && (len == 0 + || svn_dirent_is_root(path, len) + /* The len > 0 check is redundant, but here to make + * sure we never ever end up indexing with -1. */ + || (len > 0 && path[len-1] != '/'))); +} +#endif + + +char *svn_path_join(const char *base, + const char *component, + apr_pool_t *pool) +{ + apr_size_t blen = strlen(base); + apr_size_t clen = strlen(component); + char *path; + + assert(svn_path_is_canonical(base, pool)); + assert(svn_path_is_canonical(component, pool)); + + /* If the component is absolute, then return it. */ + if (*component == '/') + return apr_pmemdup(pool, component, clen + 1); + + /* If either is empty return the other */ + if (SVN_PATH_IS_EMPTY(base)) + return apr_pmemdup(pool, component, clen + 1); + if (SVN_PATH_IS_EMPTY(component)) + return apr_pmemdup(pool, base, blen + 1); + + if (blen == 1 && base[0] == '/') + blen = 0; /* Ignore base, just return separator + component */ + + /* Construct the new, combined path. */ + path = apr_palloc(pool, blen + 1 + clen + 1); + memcpy(path, base, blen); + path[blen] = '/'; + memcpy(path + blen + 1, component, clen + 1); + + return path; +} + +char *svn_path_join_many(apr_pool_t *pool, const char *base, ...) +{ +#define MAX_SAVED_LENGTHS 10 + apr_size_t saved_lengths[MAX_SAVED_LENGTHS]; + apr_size_t total_len; + int nargs; + va_list va; + const char *s; + apr_size_t len; + char *path; + char *p; + svn_boolean_t base_is_empty = FALSE, base_is_root = FALSE; + int base_arg = 0; + + total_len = strlen(base); + + assert(svn_path_is_canonical(base, pool)); + + if (total_len == 1 && *base == '/') + base_is_root = TRUE; + else if (SVN_PATH_IS_EMPTY(base)) + { + total_len = sizeof(SVN_EMPTY_PATH) - 1; + base_is_empty = TRUE; + } + + saved_lengths[0] = total_len; + + /* Compute the length of the resulting string. */ + + nargs = 0; + va_start(va, base); + while ((s = va_arg(va, const char *)) != NULL) + { + len = strlen(s); + + assert(svn_path_is_canonical(s, pool)); + + if (SVN_PATH_IS_EMPTY(s)) + continue; + + if (nargs++ < MAX_SAVED_LENGTHS) + saved_lengths[nargs] = len; + + if (*s == '/') + { + /* an absolute path. skip all components to this point and reset + the total length. */ + total_len = len; + base_arg = nargs; + base_is_root = len == 1; + base_is_empty = FALSE; + } + else if (nargs == base_arg + || (nargs == base_arg + 1 && base_is_root) + || base_is_empty) + { + /* if we have skipped everything up to this arg, then the base + and all prior components are empty. just set the length to + this component; do not add a separator. If the base is empty + we can now ignore it. */ + if (base_is_empty) + { + base_is_empty = FALSE; + total_len = 0; + } + total_len += len; + } + else + { + total_len += 1 + len; + } + } + va_end(va); + + /* base == "/" and no further components. just return that. */ + if (base_is_root && total_len == 1) + return apr_pmemdup(pool, "/", 2); + + /* we got the total size. allocate it, with room for a NULL character. */ + path = p = apr_palloc(pool, total_len + 1); + + /* if we aren't supposed to skip forward to an absolute component, and if + this is not an empty base that we are skipping, then copy the base + into the output. */ + if (base_arg == 0 && ! (SVN_PATH_IS_EMPTY(base) && ! base_is_empty)) + { + if (SVN_PATH_IS_EMPTY(base)) + memcpy(p, SVN_EMPTY_PATH, len = saved_lengths[0]); + else + memcpy(p, base, len = saved_lengths[0]); + p += len; + } + + nargs = 0; + va_start(va, base); + while ((s = va_arg(va, const char *)) != NULL) + { + if (SVN_PATH_IS_EMPTY(s)) + continue; + + if (++nargs < base_arg) + continue; + + if (nargs < MAX_SAVED_LENGTHS) + len = saved_lengths[nargs]; + else + len = strlen(s); + + /* insert a separator if we aren't copying in the first component + (which can happen when base_arg is set). also, don't put in a slash + if the prior character is a slash (occurs when prior component + is "/"). */ + if (p != path && p[-1] != '/') + *p++ = '/'; + + /* copy the new component and advance the pointer */ + memcpy(p, s, len); + p += len; + } + va_end(va); + + *p = '\0'; + assert((apr_size_t)(p - path) == total_len); + + return path; +} + + + +apr_size_t +svn_path_component_count(const char *path) +{ + apr_size_t count = 0; + + assert(is_canonical(path, strlen(path))); + + while (*path) + { + const char *start; + + while (*path == '/') + ++path; + + start = path; + + while (*path && *path != '/') + ++path; + + if (path != start) + ++count; + } + + return count; +} + + +/* Return the length of substring necessary to encompass the entire + * previous path segment in PATH, which should be a LEN byte string. + * + * A trailing slash will not be included in the returned length except + * in the case in which PATH is absolute and there are no more + * previous segments. + */ +static apr_size_t +previous_segment(const char *path, + apr_size_t len) +{ + if (len == 0) + return 0; + + while (len > 0 && path[--len] != '/') + ; + + if (len == 0 && path[0] == '/') + return 1; + else + return len; +} + + +void +svn_path_add_component(svn_stringbuf_t *path, + const char *component) +{ + apr_size_t len = strlen(component); + + assert(is_canonical(path->data, path->len)); + assert(is_canonical(component, strlen(component))); + + /* Append a dir separator, but only if this path is neither empty + nor consists of a single dir separator already. */ + if ((! SVN_PATH_IS_EMPTY(path->data)) + && (! ((path->len == 1) && (*(path->data) == '/')))) + { + char dirsep = '/'; + svn_stringbuf_appendbytes(path, &dirsep, sizeof(dirsep)); + } + + svn_stringbuf_appendbytes(path, component, len); +} + + +void +svn_path_remove_component(svn_stringbuf_t *path) +{ + assert(is_canonical(path->data, path->len)); + + path->len = previous_segment(path->data, path->len); + path->data[path->len] = '\0'; +} + + +void +svn_path_remove_components(svn_stringbuf_t *path, apr_size_t n) +{ + while (n > 0) + { + svn_path_remove_component(path); + n--; + } +} + + +char * +svn_path_dirname(const char *path, apr_pool_t *pool) +{ + apr_size_t len = strlen(path); + + assert(svn_path_is_canonical(path, pool)); + + return apr_pstrmemdup(pool, path, previous_segment(path, len)); +} + + +char * +svn_path_basename(const char *path, apr_pool_t *pool) +{ + apr_size_t len = strlen(path); + apr_size_t start; + + assert(svn_path_is_canonical(path, pool)); + + if (len == 1 && path[0] == '/') + start = 0; + else + { + start = len; + while (start > 0 && path[start - 1] != '/') + --start; + } + + return apr_pstrmemdup(pool, path + start, len - start); +} + + +void +svn_path_split(const char *path, + const char **dirpath, + const char **base_name, + apr_pool_t *pool) +{ + assert(dirpath != base_name); + + if (dirpath) + *dirpath = svn_path_dirname(path, pool); + + if (base_name) + *base_name = svn_path_basename(path, pool); +} + + +int +svn_path_is_empty(const char *path) +{ + assert(is_canonical(path, strlen(path))); + + if (SVN_PATH_IS_EMPTY(path)) + return 1; + + return 0; +} + +int +svn_path_compare_paths(const char *path1, + const char *path2) +{ + apr_size_t path1_len = strlen(path1); + apr_size_t path2_len = strlen(path2); + apr_size_t min_len = ((path1_len < path2_len) ? path1_len : path2_len); + apr_size_t i = 0; + + assert(is_canonical(path1, strlen(path1))); + assert(is_canonical(path2, strlen(path2))); + + /* Skip past common prefix. */ + while (i < min_len && path1[i] == path2[i]) + ++i; + + /* Are the paths exactly the same? */ + if ((path1_len == path2_len) && (i >= min_len)) + return 0; + + /* Children of paths are greater than their parents, but less than + greater siblings of their parents. */ + if ((path1[i] == '/') && (path2[i] == 0)) + return 1; + if ((path2[i] == '/') && (path1[i] == 0)) + return -1; + if (path1[i] == '/') + return -1; + if (path2[i] == '/') + return 1; + + /* Common prefix was skipped above, next character is compared to + determine order. We need to use an unsigned comparison, though, + so a "next character" of NULL (0x00) sorts numerically + smallest. */ + return (unsigned char)(path1[i]) < (unsigned char)(path2[i]) ? -1 : 1; +} + +char * +svn_path_get_longest_ancestor(const char *path1, + const char *path2, + apr_pool_t *pool) +{ + return svn_uri_get_longest_ancestor(path1, path2, pool); +} + +const char * +svn_path_is_child(const char *path1, + const char *path2, + apr_pool_t *pool) +{ + return svn_uri_is_child(path1, path2, pool); +} + + +svn_boolean_t +svn_path_is_ancestor(const char *path1, const char *path2) +{ + return svn_uri_is_ancestor(path1, path2); +} + + +apr_array_header_t * +svn_path_decompose(const char *path, + apr_pool_t *pool) +{ + apr_size_t i, oldi; + + apr_array_header_t *components = + apr_array_make(pool, 1, sizeof(const char *)); + + assert(svn_path_is_canonical(path, pool)); + + if (SVN_PATH_IS_EMPTY(path)) + return components; /* ### Should we return a "" component? */ + + /* If PATH is absolute, store the '/' as the first component. */ + i = oldi = 0; + if (path[i] == '/') + { + char dirsep = '/'; + + APR_ARRAY_PUSH(components, const char *) + = apr_pstrmemdup(pool, &dirsep, sizeof(dirsep)); + + i++; + oldi++; + if (path[i] == '\0') /* path is a single '/' */ + return components; + } + + do + { + if ((path[i] == '/') || (path[i] == '\0')) + { + if (SVN_PATH_IS_PLATFORM_EMPTY(path + oldi, i - oldi)) + APR_ARRAY_PUSH(components, const char *) = SVN_EMPTY_PATH; + else + APR_ARRAY_PUSH(components, const char *) + = apr_pstrmemdup(pool, path + oldi, i - oldi); + + i++; + oldi = i; /* skipping past the dirsep */ + continue; + } + i++; + } + while (path[i-1]); + + return components; +} + + +const char * +svn_path_compose(const apr_array_header_t *components, + apr_pool_t *pool) +{ + apr_size_t *lengths = apr_palloc(pool, components->nelts*sizeof(*lengths)); + apr_size_t max_length = components->nelts; + char *path; + char *p; + int i; + + /* Get the length of each component so a total length can be + calculated. */ + for (i = 0; i < components->nelts; ++i) + { + apr_size_t l = strlen(APR_ARRAY_IDX(components, i, const char *)); + lengths[i] = l; + max_length += l; + } + + path = apr_palloc(pool, max_length + 1); + p = path; + + for (i = 0; i < components->nelts; ++i) + { + /* Append a '/' to the path. Handle the case with an absolute + path where a '/' appears in the first component. Only append + a '/' if the component is the second component that does not + follow a "/" first component; or it is the third or later + component. */ + if (i > 1 || + (i == 1 && strcmp("/", APR_ARRAY_IDX(components, + 0, + const char *)) != 0)) + { + *p++ = '/'; + } + + memcpy(p, APR_ARRAY_IDX(components, i, const char *), lengths[i]); + p += lengths[i]; + } + + *p = '\0'; + + return path; +} + + +svn_boolean_t +svn_path_is_single_path_component(const char *name) +{ + assert(is_canonical(name, strlen(name))); + + /* Can't be empty or `..' */ + if (SVN_PATH_IS_EMPTY(name) + || (name[0] == '.' && name[1] == '.' && name[2] == '\0')) + return FALSE; + + /* Slashes are bad, m'kay... */ + if (strchr(name, '/') != NULL) + return FALSE; + + /* It is valid. */ + return TRUE; +} + + +svn_boolean_t +svn_path_is_dotpath_present(const char *path) +{ + int len; + + /* The empty string does not have a dotpath */ + if (path[0] == '\0') + return FALSE; + + /* Handle "." or a leading "./" */ + if (path[0] == '.' && (path[1] == '\0' || path[1] == '/')) + return TRUE; + + /* Paths of length 1 (at this point) have no dotpath present. */ + if (path[1] == '\0') + return FALSE; + + /* If any segment is "/./", then a dotpath is present. */ + if (strstr(path, "/./") != NULL) + return TRUE; + + /* Does the path end in "/." ? */ + len = strlen(path); + return path[len - 2] == '/' && path[len - 1] == '.'; +} + +svn_boolean_t +svn_path_is_backpath_present(const char *path) +{ + int len; + + /* 0 and 1-length paths do not have a backpath */ + if (path[0] == '\0' || path[1] == '\0') + return FALSE; + + /* Handle ".." or a leading "../" */ + if (path[0] == '.' && path[1] == '.' && (path[2] == '\0' || path[2] == '/')) + return TRUE; + + /* Paths of length 2 (at this point) have no backpath present. */ + if (path[2] == '\0') + return FALSE; + + /* If any segment is "..", then a backpath is present. */ + if (strstr(path, "/../") != NULL) + return TRUE; + + /* Does the path end in "/.." ? */ + len = strlen(path); + return path[len - 3] == '/' && path[len - 2] == '.' && path[len - 1] == '.'; +} + + +/*** URI Stuff ***/ + +/* Examine PATH as a potential URI, and return a substring of PATH + that immediately follows the (scheme):// portion of the URI, or + NULL if PATH doesn't appear to be a valid URI. The returned value + is not alloced -- it shares memory with PATH. */ +static const char * +skip_uri_scheme(const char *path) +{ + apr_size_t j; + + /* A scheme is terminated by a : and cannot contain any /'s. */ + for (j = 0; path[j] && path[j] != ':'; ++j) + if (path[j] == '/') + return NULL; + + if (j > 0 && path[j] == ':' && path[j+1] == '/' && path[j+2] == '/') + return path + j + 3; + + return NULL; +} + + +svn_boolean_t +svn_path_is_url(const char *path) +{ + /* ### This function is reaaaaaaaaaaaaaally stupid right now. + We're just going to look for: + + (scheme)://(optional_stuff) + + Where (scheme) has no ':' or '/' characters. + + Someday it might be nice to have an actual URI parser here. + */ + return skip_uri_scheme(path) != NULL; +} + + + +/* Here is the BNF for path components in a URI. "pchar" is a + character in a path component. + + pchar = unreserved | escaped | + ":" | "@" | "&" | "=" | "+" | "$" | "," + unreserved = alphanum | mark + mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" + + Note that "escaped" doesn't really apply to what users can put in + their paths, so that really means the set of characters is: + + alphanum | mark | ":" | "@" | "&" | "=" | "+" | "$" | "," +*/ +static const char uri_char_validity[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, + + /* 64 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, + + /* 128 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /* 192 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + + +svn_boolean_t +svn_path_is_uri_safe(const char *path) +{ + apr_size_t i; + + /* Skip the URI scheme. */ + path = skip_uri_scheme(path); + + /* No scheme? Get outta here. */ + if (! path) + return FALSE; + + /* Skip to the first slash that's after the URI scheme. */ + path = strchr(path, '/'); + + /* If there's no first slash, then there's only a host portion; + therefore there couldn't be any uri-unsafe characters after the + host... so return true. */ + if (path == NULL) + return TRUE; + + for (i = 0; path[i]; i++) + { + /* Allow '%XX' (where each X is a hex digit) */ + if (path[i] == '%') + { + if (apr_isxdigit(path[i + 1]) && apr_isxdigit(path[i + 2])) + { + i += 2; + continue; + } + return FALSE; + } + else if (! uri_char_validity[((unsigned char)path[i])]) + { + return FALSE; + } + } + + return TRUE; +} + + +/* URI-encode each character c in PATH for which TABLE[c] is 0. + If no encoding was needed, return PATH, else return a new string allocated + in POOL. */ +static const char * +uri_escape(const char *path, const char table[], apr_pool_t *pool) +{ + svn_stringbuf_t *retstr; + apr_size_t i, copied = 0; + int c; + + retstr = svn_stringbuf_create_ensure(strlen(path), pool); + for (i = 0; path[i]; i++) + { + c = (unsigned char)path[i]; + if (table[c]) + continue; + + /* If we got here, we're looking at a character that isn't + supported by the (or at least, our) URI encoding scheme. We + need to escape this character. */ + + /* First things first, copy all the good stuff that we haven't + yet copied into our output buffer. */ + if (i - copied) + svn_stringbuf_appendbytes(retstr, path + copied, + i - copied); + + /* Now, sprintf() in our escaped character, making sure our + buffer is big enough to hold the '%' and two digits. We cast + the C to unsigned char here because the 'X' format character + will be tempted to treat it as an unsigned int...which causes + problem when messing with 0x80-0xFF chars. We also need space + for a null as sprintf will write one. */ + svn_stringbuf_ensure(retstr, retstr->len + 4); + sprintf(retstr->data + retstr->len, "%%%02X", (unsigned char)c); + retstr->len += 3; + + /* Finally, update our copy counter. */ + copied = i + 1; + } + + /* If we didn't encode anything, we don't need to duplicate the string. */ + if (retstr->len == 0) + return path; + + /* Anything left to copy? */ + if (i - copied) + svn_stringbuf_appendbytes(retstr, path + copied, i - copied); + + /* retstr is null-terminated either by sprintf or the svn_stringbuf + functions. */ + + return retstr->data; +} + + +const char * +svn_path_uri_encode(const char *path, apr_pool_t *pool) +{ + const char *ret; + + ret = uri_escape(path, uri_char_validity, pool); + + /* Our interface guarantees a copy. */ + if (ret == path) + return apr_pstrdup(pool, path); + else + return ret; +} + +static const char iri_escape_chars[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + /* 128 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const char * +svn_path_uri_from_iri(const char *iri, apr_pool_t *pool) +{ + return uri_escape(iri, iri_escape_chars, pool); +} + +static const char uri_autoescape_chars[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, + + /* 64 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, + + /* 128 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + /* 192 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; + +const char * +svn_path_uri_autoescape(const char *uri, apr_pool_t *pool) +{ + return uri_escape(uri, uri_autoescape_chars, pool); +} + +const char * +svn_path_uri_decode(const char *path, apr_pool_t *pool) +{ + svn_stringbuf_t *retstr; + apr_size_t i; + svn_boolean_t query_start = FALSE; + + /* avoid repeated realloc */ + retstr = svn_stringbuf_create_ensure(strlen(path) + 1, pool); + + retstr->len = 0; + for (i = 0; path[i]; i++) + { + char c = path[i]; + + if (c == '?') + { + /* Mark the start of the query string, if it exists. */ + query_start = TRUE; + } + else if (c == '+' && query_start) + { + /* Only do this if we are into the query string. + * RFC 2396, section 3.3 */ + c = ' '; + } + else if (c == '%' && apr_isxdigit(path[i + 1]) + && apr_isxdigit(path[i+2])) + { + char digitz[3]; + digitz[0] = path[++i]; + digitz[1] = path[++i]; + digitz[2] = '\0'; + c = (char)(strtol(digitz, NULL, 16)); + } + + retstr->data[retstr->len++] = c; + } + + /* Null-terminate this bad-boy. */ + retstr->data[retstr->len] = 0; + + return retstr->data; +} + + +const char * +svn_path_url_add_component2(const char *url, + const char *component, + apr_pool_t *pool) +{ + assert(svn_path_is_canonical(url, pool)); + + return svn_path_join(url, svn_path_uri_encode(component, pool), pool); +} + +svn_error_t * +svn_path_get_absolute(const char **pabsolute, + const char *relative, + apr_pool_t *pool) +{ + if (svn_path_is_url(relative)) + { + *pabsolute = apr_pstrdup(pool, relative); + return SVN_NO_ERROR; + } + + return svn_dirent_get_absolute(pabsolute, relative, pool); +} + + +svn_error_t * +svn_path_split_if_file(const char *path, + const char **pdirectory, + const char **pfile, + apr_pool_t *pool) +{ + apr_finfo_t finfo; + svn_error_t *err; + + SVN_ERR_ASSERT(svn_path_is_canonical(path, pool)); + + err = svn_io_stat(&finfo, path, APR_FINFO_TYPE, pool); + if (err && ! APR_STATUS_IS_ENOENT(err->apr_err)) + return err; + + if (err || finfo.filetype == APR_REG) + { + svn_error_clear(err); + svn_path_split(path, pdirectory, pfile, pool); + } + else if (finfo.filetype == APR_DIR) + { + *pdirectory = path; + *pfile = SVN_EMPTY_PATH; + } + else + { + return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL, + _("'%s' is neither a file nor a directory name"), + svn_path_local_style(path, pool)); + } + + return SVN_NO_ERROR; +} + + +const char * +svn_path_canonicalize(const char *path, apr_pool_t *pool) +{ +#if defined(WIN32) || defined(__CYGWIN__) + if (path[0] == '/' && path[1] == '/') + return svn_dirent_canonicalize(path, pool); +#endif + return svn_uri_canonicalize(path, pool); +} + +svn_boolean_t +svn_path_is_canonical(const char *path, apr_pool_t *pool) +{ + return svn_uri_is_canonical(path, pool) +#if defined(WIN32) || defined(__CYGWIN__) + || (path[0] == '/' && path[1] == '/' && + svn_dirent_is_canonical(path, pool)) +#endif + ; +} + + +/** Get APR's internal path encoding. */ +static svn_error_t * +get_path_encoding(svn_boolean_t *path_is_utf8, apr_pool_t *pool) +{ + apr_status_t apr_err; + int encoding_style; + + apr_err = apr_filepath_encoding(&encoding_style, pool); + if (apr_err) + return svn_error_wrap_apr(apr_err, + _("Can't determine the native path encoding")); + + /* ### What to do about APR_FILEPATH_ENCODING_UNKNOWN? + Well, for now we'll just punt to the svn_utf_ functions; + those will at least do the ASCII-subset check. */ + *path_is_utf8 = (encoding_style == APR_FILEPATH_ENCODING_UTF8); + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_path_cstring_from_utf8(const char **path_apr, + const char *path_utf8, + apr_pool_t *pool) +{ + svn_boolean_t path_is_utf8; + SVN_ERR(get_path_encoding(&path_is_utf8, pool)); + if (path_is_utf8) + { + *path_apr = apr_pstrdup(pool, path_utf8); + return SVN_NO_ERROR; + } + else + return svn_utf_cstring_from_utf8(path_apr, path_utf8, pool); +} + + +svn_error_t * +svn_path_cstring_to_utf8(const char **path_utf8, + const char *path_apr, + apr_pool_t *pool) +{ + svn_boolean_t path_is_utf8; + SVN_ERR(get_path_encoding(&path_is_utf8, pool)); + if (path_is_utf8) + { + *path_utf8 = apr_pstrdup(pool, path_apr); + return SVN_NO_ERROR; + } + else + return svn_utf_cstring_to_utf8(path_utf8, path_apr, pool); +} + + +/* Return a copy of PATH, allocated from POOL, for which control + characters have been escaped using the form \NNN (where NNN is the + octal representation of the byte's ordinal value). */ +static const char * +illegal_path_escape(const char *path, apr_pool_t *pool) +{ + svn_stringbuf_t *retstr; + apr_size_t i, copied = 0; + int c; + + /* At least one control character: + strlen - 1 (control) + \ + N + N + N + null . */ + retstr = svn_stringbuf_create_ensure(strlen(path) + 4, pool); + for (i = 0; path[i]; i++) + { + c = (unsigned char)path[i]; + if (! svn_ctype_iscntrl(c)) + continue; + + /* If we got here, we're looking at a character that isn't + supported by the (or at least, our) URI encoding scheme. We + need to escape this character. */ + + /* First things first, copy all the good stuff that we haven't + yet copied into our output buffer. */ + if (i - copied) + svn_stringbuf_appendbytes(retstr, path + copied, + i - copied); + + /* Make sure buffer is big enough for '\' 'N' 'N' 'N' null */ + svn_stringbuf_ensure(retstr, retstr->len + 5); + /*### The backslash separator doesn't work too great with Windows, + but it's what we'll use for consistency with invalid utf8 + formatting (until someone has a better idea) */ + sprintf(retstr->data + retstr->len, "\\%03o", (unsigned char)c); + retstr->len += 4; + + /* Finally, update our copy counter. */ + copied = i + 1; + } + + /* If we didn't encode anything, we don't need to duplicate the string. */ + if (retstr->len == 0) + return path; + + /* Anything left to copy? */ + if (i - copied) + svn_stringbuf_appendbytes(retstr, path + copied, i - copied); + + /* retstr is null-terminated either by sprintf or the svn_stringbuf + functions. */ + + return retstr->data; +} + +svn_error_t * +svn_path_check_valid(const char *path, apr_pool_t *pool) +{ + const char *c; + + for (c = path; *c; c++) + { + if (svn_ctype_iscntrl(*c)) + { + return svn_error_createf + (SVN_ERR_FS_PATH_SYNTAX, NULL, + _("Invalid control character '0x%02x' in path '%s'"), + (unsigned char)*c, + illegal_path_escape(svn_path_local_style(path, pool), pool)); + } + } + + return SVN_NO_ERROR; +} + +void +svn_path_splitext(const char **path_root, + const char **path_ext, + const char *path, + apr_pool_t *pool) +{ + const char *last_dot, *last_slash; + + /* Easy out -- why do all the work when there's no way to report it? */ + if (! (path_root || path_ext)) + return; + + /* Do we even have a period in this thing? And if so, is there + anything after it? We look for the "rightmost" period in the + string. */ + last_dot = strrchr(path, '.'); + if (last_dot && (last_dot + 1 != '\0')) + { + /* If we have a period, we need to make sure it occurs in the + final path component -- that there's no path separator + between the last period and the end of the PATH -- otherwise, + it doesn't count. Also, we want to make sure that our period + isn't the first character of the last component. */ + last_slash = strrchr(path, '/'); + if ((last_slash && (last_dot > (last_slash + 1))) + || ((! last_slash) && (last_dot > path))) + { + if (path_root) + *path_root = apr_pstrmemdup(pool, path, + (last_dot - path + 1) * sizeof(*path)); + if (path_ext) + *path_ext = apr_pstrdup(pool, last_dot + 1); + return; + } + } + /* If we get here, we never found a suitable separator character, so + there's no split. */ + if (path_root) + *path_root = apr_pstrdup(pool, path); + if (path_ext) + *path_ext = ""; +} diff --git a/src/TortoiseMerge/libsvn_diff/pool.c b/src/TortoiseMerge/libsvn_diff/pool.c new file mode 100644 index 0000000..dc1994b --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/pool.c @@ -0,0 +1,94 @@ +/* pool.c: pool wrappers for Subversion + * + * ==================================================================== + * Copyright (c) 2000-2007 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + + + +#include +#include +#include + +#include +#include + +#include "svn_pools.h" + + +#if APR_POOL_DEBUG +/* file_line for the non-debug case. */ +static const char SVN_FILE_LINE_UNDEFINED[] = "svn:"; +#endif /* APR_POOL_DEBUG */ + + + +/*-----------------------------------------------------------------*/ + + +/* Pool allocation handler which just aborts, since we aren't generally + prepared to deal with out-of-memory errors. + */ +static int +abort_on_pool_failure(int retcode) +{ + /* Don't translate this string! It requires memory allocation to do so! + And we don't have any of it... */ + printf("Out of memory - terminating application.\n"); + abort(); +} + + +#if APR_POOL_DEBUG +#undef svn_pool_create_ex +#endif /* APR_POOL_DEBUG */ + +#if !APR_POOL_DEBUG + +apr_pool_t * +svn_pool_create_ex(apr_pool_t *parent_pool, apr_allocator_t *allocator) +{ + apr_pool_t *pool; + apr_pool_create_ex(&pool, parent_pool, abort_on_pool_failure, allocator); + return pool; +} + +/* Wrapper that ensures binary compatibility */ +apr_pool_t * +svn_pool_create_ex_debug(apr_pool_t *pool, apr_allocator_t *allocator, + const char *file_line) +{ + return svn_pool_create_ex(pool, allocator); +} + +#else /* APR_POOL_DEBUG */ + +apr_pool_t * +svn_pool_create_ex_debug(apr_pool_t *parent_pool, apr_allocator_t *allocator, + const char *file_line) +{ + apr_pool_t *pool; + apr_pool_create_ex_debug(&pool, parent_pool, abort_on_pool_failure, + allocator, file_line); + return pool; +} + +/* Wrapper that ensures binary compatibility */ +apr_pool_t * +svn_pool_create_ex(apr_pool_t *pool, apr_allocator_t *allocator) +{ + return svn_pool_create_ex_debug(pool, allocator, SVN_FILE_LINE_UNDEFINED); +} + +#endif /* APR_POOL_DEBUG */ diff --git a/src/TortoiseMerge/libsvn_diff/porting.c b/src/TortoiseMerge/libsvn_diff/porting.c deleted file mode 100644 index ad2f2ec..0000000 --- a/src/TortoiseMerge/libsvn_diff/porting.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include - -void * apr_palloc(apr_pool_t *p, apr_size_t size) -{ - if(p->start+size> p->size) - return NULL; - - else - { - p->start+=size; - return (void*)(p->data+p->start); - } -} - -void * apr_pcalloc(apr_pool_t *p, apr_size_t size) -{ - void *p1=apr_palloc(p,size); - memset(p1,0,size); - return p1; -} -apr_pool_t * svn_pool_create(apr_pool_t *p) -{ - return malloc(4096); -} - -void svn_pool_destroy(apr_pool_t *p) -{ - free(p); -} - -void svn_pool_clear(apr_pool_t *p) -{ - p->start=0; -} - -void svn_error__malfunction(char * error, int x, void* p) -{ -} - -void svn_error_clear() -{ -} \ No newline at end of file diff --git a/src/TortoiseMerge/libsvn_diff/readme.txt b/src/TortoiseMerge/libsvn_diff/readme.txt new file mode 100644 index 0000000..6e510b7 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/readme.txt @@ -0,0 +1,37 @@ + +UnZip 0.15 additionnal library + + + This unzip package allow extract file from .ZIP file, compatible with +PKZip 2.04g, WinZip, InfoZip tools and compatible. + + Multi volume ZipFile (span) are not supported, and old compression used by old +PKZip 1.x are not supported. + +See probdesc.zip from PKWare for specification of .ZIP format. + +What is Unzip + The Zlib library support the deflate compression and the creation of gzip (.gz) +file. Zlib is free and small. + The .Zip format, which can contain several compressed files (.gz can containt +only one file) is a very popular format. This is why I've written a package for reading file compressed in Zipfile. + +Using Unzip package + +You need source of Zlib (get zlib111.zip and read zlib.h). +Get unzlb015.zip and read unzip.h (whith documentation of unzip functions) + +The Unzip package is only two file : unzip.h and unzip.c. But it use the Zlib + files. +unztst.c is a simple sample program, which list file in a zipfile and display + README.TXT or FILE_ID.DIZ (if these files are found). +miniunz.c is a mini unzip program. + +I'm also currenlyt writing a zipping portion (zip.h, zip.c and test with minizip.c) + +Please email me for feedback. +I hope my source is compatible with Unix system, but I need your help for be sure + +Latest revision : Mar 04th, 1998 + +Check http://www.winimage.com/zLibDll/unzip.html for up to date info. diff --git a/src/TortoiseMerge/libsvn_diff/sha1.c b/src/TortoiseMerge/libsvn_diff/sha1.c new file mode 100644 index 0000000..f9bc551 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/sha1.c @@ -0,0 +1,77 @@ +/* + * sha1.c: SHA1 checksum routines + * + * ==================================================================== + * Copyright (c) 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + +#include + +#include "sha1.h" + + + +/* The SHA1 digest for the empty string. */ +static const unsigned char svn_sha1__empty_string_digest_array[] = { + 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, + 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 +}; + +const unsigned char * +svn_sha1__empty_string_digest(void) +{ + return svn_sha1__empty_string_digest_array; +} + + +const char * +svn_sha1__digest_to_cstring_display(const unsigned char digest[], + apr_pool_t *pool) +{ + static const char *hex = "0123456789abcdef"; + char *str = apr_palloc(pool, (APR_SHA1_DIGESTSIZE * 2) + 1); + int i; + + for (i = 0; i < APR_SHA1_DIGESTSIZE; i++) + { + str[i*2] = hex[digest[i] >> 4]; + str[i*2+1] = hex[digest[i] & 0x0f]; + } + str[i*2] = '\0'; + + return str; +} + + +const char * +svn_sha1__digest_to_cstring(const unsigned char digest[], apr_pool_t *pool) +{ + static const unsigned char zeros_digest[APR_SHA1_DIGESTSIZE] = { 0 }; + + if (memcmp(digest, zeros_digest, APR_SHA1_DIGESTSIZE) != 0) + return svn_sha1__digest_to_cstring_display(digest, pool); + else + return NULL; +} + + +svn_boolean_t +svn_sha1__digests_match(const unsigned char d1[], const unsigned char d2[]) +{ + static const unsigned char zeros[APR_SHA1_DIGESTSIZE] = { 0 }; + + return ((memcmp(d1, zeros, APR_SHA1_DIGESTSIZE) == 0) + || (memcmp(d2, zeros, APR_SHA1_DIGESTSIZE) == 0) + || (memcmp(d1, d2, APR_SHA1_DIGESTSIZE) == 0)); +} diff --git a/src/TortoiseMerge/libsvn_diff/sha1.h b/src/TortoiseMerge/libsvn_diff/sha1.h new file mode 100644 index 0000000..cdb5080 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/sha1.h @@ -0,0 +1,65 @@ +/* + * sha1.h: Converting and comparing SHA1 checksums + * + * ==================================================================== + * Copyright (c) 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + +#ifndef SVN_LIBSVN_SUBR_SHA1_H +#define SVN_LIBSVN_SUBR_SHA1_H + +#include +#include "svn_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +/* The SHA1 digest for the empty string. */ +const unsigned char * +svn_sha1__empty_string_digest(void); + + +/* Return the hex representation of DIGEST, which must be + * APR_SHA1_DIGESTSIZE bytes long, allocating the string in POOL. + */ +const char * +svn_sha1__digest_to_cstring_display(const unsigned char digest[], + apr_pool_t *pool); + + +/* Return the hex representation of DIGEST, which must be + * APR_SHA1_DIGESTSIZE bytes long, allocating the string in POOL. + * If DIGEST is all zeros, then return NULL. + */ +const char * +svn_sha1__digest_to_cstring(const unsigned char digest[], + apr_pool_t *pool); + + +/** Compare digests D1 and D2, each APR_SHA1_DIGESTSIZE bytes long. + * If neither is all zeros, and they do not match, then return FALSE; + * else return TRUE. + */ +svn_boolean_t +svn_sha1__digests_match(const unsigned char d1[], + const unsigned char d2[]); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_LIBSVN_SUBR_SHA1_H */ diff --git a/src/TortoiseMerge/libsvn_diff/stream.c b/src/TortoiseMerge/libsvn_diff/stream.c new file mode 100644 index 0000000..3c1967e --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/stream.c @@ -0,0 +1,1093 @@ +/* + * stream.c: svn_stream operations + * + * ==================================================================== + * Copyright (c) 2000-2004, 2006 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + +//#include "svn_private_config.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "svn_pools.h" +#include "svn_io.h" +#include "svn_error.h" +#include "svn_string.h" +#include "svn_utf.h" +#include "svn_checksum.h" +#include "svn_path.h" + + +struct svn_stream_t { + void *baton; + svn_read_fn_t read_fn; + svn_write_fn_t write_fn; + svn_close_fn_t close_fn; +}; + + + +/*** Generic streams. ***/ + +svn_stream_t * +svn_stream_create(void *baton, apr_pool_t *pool) +{ + svn_stream_t *stream; + + stream = apr_palloc(pool, sizeof(*stream)); + stream->baton = baton; + stream->read_fn = NULL; + stream->write_fn = NULL; + stream->close_fn = NULL; + return stream; +} + + +void +svn_stream_set_baton(svn_stream_t *stream, void *baton) +{ + stream->baton = baton; +} + + +void +svn_stream_set_read(svn_stream_t *stream, svn_read_fn_t read_fn) +{ + stream->read_fn = read_fn; +} + + +void +svn_stream_set_write(svn_stream_t *stream, svn_write_fn_t write_fn) +{ + stream->write_fn = write_fn; +} + + +void +svn_stream_set_close(svn_stream_t *stream, svn_close_fn_t close_fn) +{ + stream->close_fn = close_fn; +} + + +svn_error_t * +svn_stream_read(svn_stream_t *stream, char *buffer, apr_size_t *len) +{ + SVN_ERR_ASSERT(stream->read_fn != NULL); + return stream->read_fn(stream->baton, buffer, len); +} + + +svn_error_t * +svn_stream_write(svn_stream_t *stream, const char *data, apr_size_t *len) +{ + SVN_ERR_ASSERT(stream->write_fn != NULL); + return stream->write_fn(stream->baton, data, len); +} + + +svn_error_t * +svn_stream_close(svn_stream_t *stream) +{ + if (stream->close_fn == NULL) + return SVN_NO_ERROR; + return stream->close_fn(stream->baton); +} + + +svn_error_t * +svn_stream_printf(svn_stream_t *stream, + apr_pool_t *pool, + const char *fmt, + ...) +{ + const char *message; + va_list ap; + apr_size_t len; + + va_start(ap, fmt); + message = apr_pvsprintf(pool, fmt, ap); + va_end(ap); + + len = strlen(message); + return svn_stream_write(stream, message, &len); +} + + +svn_error_t * +svn_stream_printf_from_utf8(svn_stream_t *stream, + const char *encoding, + apr_pool_t *pool, + const char *fmt, + ...) +{ + const char *message, *translated; + va_list ap; + apr_size_t len; + + va_start(ap, fmt); + message = apr_pvsprintf(pool, fmt, ap); + va_end(ap); + + SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding, + pool)); + + len = strlen(translated); + + return svn_stream_write(stream, translated, &len); +} + + +svn_error_t * +svn_stream_readline(svn_stream_t *stream, + svn_stringbuf_t **stringbuf, + const char *eol, + svn_boolean_t *eof, + apr_pool_t *pool) +{ + apr_size_t numbytes; + const char *match; + char c; + /* Since we're reading one character at a time, let's at least + optimize for the 90% case. 90% of the time, we can avoid the + stringbuf ever having to realloc() itself if we start it out at + 80 chars. */ + svn_stringbuf_t *str = svn_stringbuf_create_ensure(80, pool); + + match = eol; + while (*match) + { + numbytes = 1; + SVN_ERR(svn_stream_read(stream, &c, &numbytes)); + if (numbytes != 1) + { + /* a 'short' read means the stream has run out. */ + *eof = TRUE; + *stringbuf = str; + return SVN_NO_ERROR; + } + + if (c == *match) + match++; + else + match = eol; + + svn_stringbuf_appendbytes(str, &c, 1); + } + + *eof = FALSE; + svn_stringbuf_chop(str, match - eol); + *stringbuf = str; + return SVN_NO_ERROR; +} + + +svn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool) +{ + char *buf = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE); + svn_error_t *err; + svn_error_t *err2; + + /* Read and write chunks until we get a short read, indicating the + end of the stream. (We can't get a short write without an + associated error.) */ + while (1) + { + apr_size_t len = SVN__STREAM_CHUNK_SIZE; + + if (cancel_func) + SVN_ERR(cancel_func(cancel_baton)); + + SVN_ERR(svn_stream_read(from, buf, &len)); + if (len > 0) + SVN_ERR(svn_stream_write(to, buf, &len)); + if (len != SVN__STREAM_CHUNK_SIZE) + break; + } + + err = svn_stream_close(from); + err2 = svn_stream_close(to); + if (err) + { + /* ### it would be nice to compose the two errors in some way */ + svn_error_clear(err2); /* note: might be NULL */ + return err; + } + return err2; +} + +svn_error_t *svn_stream_copy2(svn_stream_t *from, svn_stream_t *to, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool) +{ + return svn_stream_copy3(svn_stream_disown(from, scratch_pool), + svn_stream_disown(to, scratch_pool), + cancel_func, cancel_baton, scratch_pool); +} + +svn_error_t *svn_stream_copy(svn_stream_t *from, svn_stream_t *to, + apr_pool_t *scratch_pool) +{ + return svn_stream_copy3(svn_stream_disown(from, scratch_pool), + svn_stream_disown(to, scratch_pool), + NULL, NULL, scratch_pool); +} + + +svn_error_t * +svn_stream_contents_same(svn_boolean_t *same, + svn_stream_t *stream1, + svn_stream_t *stream2, + apr_pool_t *pool) +{ + char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); + char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); + apr_size_t bytes_read1 = SVN__STREAM_CHUNK_SIZE; + apr_size_t bytes_read2 = SVN__STREAM_CHUNK_SIZE; + + *same = TRUE; /* assume TRUE, until disproved below */ + while (bytes_read1 == SVN__STREAM_CHUNK_SIZE + && bytes_read2 == SVN__STREAM_CHUNK_SIZE) + { + SVN_ERR(svn_stream_read(stream1, buf1, &bytes_read1)); + SVN_ERR(svn_stream_read(stream2, buf2, &bytes_read2)); + + if ((bytes_read1 != bytes_read2) + || (memcmp(buf1, buf2, bytes_read1))) + { + *same = FALSE; + break; + } + } + + return SVN_NO_ERROR; +} + + + +/*** Generic readable empty stream ***/ + +static svn_error_t * +read_handler_empty(void *baton, char *buffer, apr_size_t *len) +{ + *len = 0; + return SVN_NO_ERROR; +} + + +static svn_error_t * +write_handler_empty(void *baton, const char *data, apr_size_t *len) +{ + return SVN_NO_ERROR; +} + + +svn_stream_t * +svn_stream_empty(apr_pool_t *pool) +{ + svn_stream_t *stream; + + stream = svn_stream_create(NULL, pool); + svn_stream_set_read(stream, read_handler_empty); + svn_stream_set_write(stream, write_handler_empty); + return stream; +} + + + + +/*** Ownership detaching stream ***/ + +static svn_error_t * +read_handler_disown(void *baton, char *buffer, apr_size_t *len) +{ + return svn_stream_read((svn_stream_t *)baton, buffer, len); +} + +static svn_error_t * +write_handler_disown(void *baton, const char *buffer, apr_size_t *len) +{ + return svn_stream_write((svn_stream_t *)baton, buffer, len); +} + + +svn_stream_t * +svn_stream_disown(svn_stream_t *stream, apr_pool_t *pool) +{ + svn_stream_t *s = svn_stream_create(stream, pool); + + svn_stream_set_read(s, read_handler_disown); + svn_stream_set_write(s, write_handler_disown); + + return s; +} + + + +/*** Generic stream for APR files ***/ +struct baton_apr { + apr_file_t *file; + apr_pool_t *pool; +}; + + +static svn_error_t * +read_handler_apr(void *baton, char *buffer, apr_size_t *len) +{ + struct baton_apr *btn = baton; + svn_error_t *err; + + err = svn_io_file_read_full(btn->file, buffer, *len, len, btn->pool); + if (err && APR_STATUS_IS_EOF(err->apr_err)) + { + svn_error_clear(err); + err = SVN_NO_ERROR; + } + + return err; +} + + +static svn_error_t * +write_handler_apr(void *baton, const char *data, apr_size_t *len) +{ + struct baton_apr *btn = baton; + + return svn_io_file_write_full(btn->file, data, *len, len, btn->pool); +} + +static svn_error_t * +close_handler_apr(void *baton) +{ + struct baton_apr *btn = baton; + + return svn_io_file_close(btn->file, btn->pool); +} + + +svn_error_t * +svn_stream_open_readonly(svn_stream_t **stream, + const char *path, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_file_t *file; + + SVN_ERR(svn_io_file_open(&file, path, APR_READ | APR_BUFFERED | APR_BINARY, + APR_OS_DEFAULT, result_pool)); + *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_stream_open_writable(svn_stream_t **stream, + const char *path, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_file_t *file; + + SVN_ERR(svn_io_file_open(&file, path, + APR_WRITE + | APR_BUFFERED + | APR_BINARY + | APR_CREATE + | APR_EXCL, + APR_OS_DEFAULT, result_pool)); + *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_stream_open_unique(svn_stream_t **stream, + const char **temp_path, + const char *dirpath, + svn_io_file_del_t delete_when, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_file_t *file; + + SVN_ERR(svn_io_open_unique_file3(&file, temp_path, dirpath, + delete_when, result_pool, scratch_pool)); + *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); + + return SVN_NO_ERROR; +} + + +svn_stream_t * +svn_stream_from_aprfile2(apr_file_t *file, + svn_boolean_t disown, + apr_pool_t *pool) +{ + struct baton_apr *baton; + svn_stream_t *stream; + + if (file == NULL) + return svn_stream_empty(pool); + + baton = apr_palloc(pool, sizeof(*baton)); + baton->file = file; + baton->pool = pool; + stream = svn_stream_create(baton, pool); + svn_stream_set_read(stream, read_handler_apr); + svn_stream_set_write(stream, write_handler_apr); + + if (! disown) + svn_stream_set_close(stream, close_handler_apr); + + return stream; +} + +svn_stream_t * +svn_stream_from_aprfile(apr_file_t *file, apr_pool_t *pool) +{ + return svn_stream_from_aprfile2(file, TRUE, pool); +} + + + +/* Compressed stream support */ + +#define ZBUFFER_SIZE 4096 /* The size of the buffer the + compressed stream uses to read from + the substream. Basically an + arbitrary value, picked to be about + page-sized. */ + +struct zbaton { + z_stream *in; /* compressed stream for reading */ + z_stream *out; /* compressed stream for writing */ + svn_read_fn_t read; /* substream's read function */ + svn_write_fn_t write; /* substream's write function */ + svn_close_fn_t close; /* substream's close function */ + void *read_buffer; /* buffer used for reading from + substream */ + int read_flush; /* what flush mode to use while + reading */ + apr_pool_t *pool; /* The pool this baton is allocated + on */ + void *subbaton; /* The substream's baton */ +}; + +/* zlib alloc function. opaque is the pool we need. */ +static voidpf +zalloc(voidpf opaque, uInt items, uInt size) +{ + apr_pool_t *pool = opaque; + + return apr_palloc(pool, items * size); +} + +/* zlib free function */ +static void +zfree(voidpf opaque, voidpf address) +{ + /* Empty, since we allocate on the pool */ +} + +/* Converts a zlib error to an svn_error_t. zerr is the error code, + function is the function name, and stream is the z_stream we are + using. */ +static svn_error_t * +zerr_to_svn_error(int zerr, const char *function, z_stream *stream) +{ + apr_status_t status; + const char *message; + + if (zerr == Z_OK) + return SVN_NO_ERROR; + + switch (zerr) + { + case Z_STREAM_ERROR: + status = SVN_ERR_STREAM_MALFORMED_DATA; + message = "stream error"; + break; + + case Z_MEM_ERROR: + status = APR_ENOMEM; + message = "out of memory"; + break; + + case Z_BUF_ERROR: + status = APR_ENOMEM; + message = "buffer error"; + break; + + case Z_VERSION_ERROR: + status = SVN_ERR_STREAM_UNRECOGNIZED_DATA; + message = "version error"; + break; + + case Z_DATA_ERROR: + status = SVN_ERR_STREAM_MALFORMED_DATA; + message = "corrupted data"; + break; + + default: + status = SVN_ERR_STREAM_UNRECOGNIZED_DATA; + message = "error"; + break; + } + + if (stream->msg != NULL) + return svn_error_createf(status, NULL, "zlib (%s): %s: %s", function, + message, stream->msg); + else + return svn_error_createf(status, NULL, "zlib (%s): %s", function, + message); +} + +/* Helper function to figure out the sync mode */ +static svn_error_t * +read_helper_gz(svn_read_fn_t read_fn, + void *baton, + char *buffer, + uInt *len, int *zflush) +{ + uInt orig_len = *len; + + /* There's no reason this value should grow bigger than the range of + uInt, but Subversion's API requires apr_size_t. */ + apr_size_t apr_len = (apr_size_t) *len; + + SVN_ERR((*read_fn)(baton, buffer, &apr_len)); + + /* Type cast back to uInt type that zlib uses. On LP64 platforms + apr_size_t will be bigger than uInt. */ + *len = (uInt) apr_len; + + /* I wanted to use Z_FINISH here, but we need to know our buffer is + big enough */ + *zflush = (*len) < orig_len ? Z_SYNC_FLUSH : Z_SYNC_FLUSH; + + return SVN_NO_ERROR; +} + +/* Handle reading from a compressed stream */ +static svn_error_t * +read_handler_gz(void *baton, char *buffer, apr_size_t *len) +{ + struct zbaton *btn = baton; + int zerr; + + if (btn->in == NULL) + { + btn->in = apr_palloc(btn->pool, sizeof(z_stream)); + btn->in->zalloc = zalloc; + btn->in->zfree = zfree; + btn->in->opaque = btn->pool; + btn->read_buffer = apr_palloc(btn->pool, ZBUFFER_SIZE); + btn->in->next_in = btn->read_buffer; + btn->in->avail_in = ZBUFFER_SIZE; + + SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer, + &btn->in->avail_in, &btn->read_flush)); + + zerr = inflateInit(btn->in); + SVN_ERR(zerr_to_svn_error(zerr, "inflateInit", btn->in)); + } + + btn->in->next_out = (Bytef *) buffer; + btn->in->avail_out = *len; + + while (btn->in->avail_out > 0) + { + if (btn->in->avail_in <= 0) + { + btn->in->avail_in = ZBUFFER_SIZE; + btn->in->next_in = btn->read_buffer; + SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer, + &btn->in->avail_in, &btn->read_flush)); + } + + zerr = inflate(btn->in, btn->read_flush); + if (zerr == Z_STREAM_END) + break; + else if (zerr != Z_OK) + return zerr_to_svn_error(zerr, "inflate", btn->in); + } + + *len -= btn->in->avail_out; + return SVN_NO_ERROR; +} + +/* Compress data and write it to the substream */ +static svn_error_t * +write_handler_gz(void *baton, const char *buffer, apr_size_t *len) +{ + struct zbaton *btn = baton; + apr_pool_t *subpool; + void *write_buf; + apr_size_t buf_size, write_len; + int zerr; + + if (btn->out == NULL) + { + btn->out = apr_palloc(btn->pool, sizeof(z_stream)); + btn->out->zalloc = zalloc; + btn->out->zfree = zfree; + btn->out->opaque = btn->pool; + + zerr = deflateInit(btn->out, Z_DEFAULT_COMPRESSION); + SVN_ERR(zerr_to_svn_error(zerr, "deflateInit", btn->out)); + } + + /* The largest buffer we should need is 0.1% larger than the + compressed data, + 12 bytes. This info comes from zlib.h. */ + buf_size = *len + (*len / 1000) + 13; + subpool = svn_pool_create(btn->pool); + write_buf = apr_palloc(subpool, buf_size); + + btn->out->next_in = (Bytef *) buffer; /* Casting away const! */ + btn->out->avail_in = *len; + + while (btn->out->avail_in > 0) + { + btn->out->next_out = write_buf; + btn->out->avail_out = buf_size; + + zerr = deflate(btn->out, Z_NO_FLUSH); + SVN_ERR(zerr_to_svn_error(zerr, "deflate", btn->out)); + write_len = buf_size - btn->out->avail_out; + if (write_len > 0) + SVN_ERR(btn->write(btn->subbaton, write_buf, &write_len)); + } + + svn_pool_destroy(subpool); + + return SVN_NO_ERROR; +} + +/* Handle flushing and closing the stream */ +static svn_error_t * +close_handler_gz(void *baton) +{ + struct zbaton *btn = baton; + int zerr; + + if (btn->in != NULL) + { + zerr = inflateEnd(btn->in); + SVN_ERR(zerr_to_svn_error(zerr, "inflateEnd", btn->in)); + } + + if (btn->out != NULL) + { + void *buf; + apr_size_t write_len; + + buf = apr_palloc(btn->pool, ZBUFFER_SIZE); + + while (TRUE) + { + btn->out->next_out = buf; + btn->out->avail_out = ZBUFFER_SIZE; + + zerr = deflate(btn->out, Z_FINISH); + if (zerr != Z_STREAM_END && zerr != Z_OK) + return zerr_to_svn_error(zerr, "deflate", btn->out); + write_len = ZBUFFER_SIZE - btn->out->avail_out; + if (write_len > 0) + SVN_ERR(btn->write(btn->subbaton, buf, &write_len)); + if (zerr == Z_STREAM_END) + break; + } + + zerr = deflateEnd(btn->out); + SVN_ERR(zerr_to_svn_error(zerr, "deflateEnd", btn->out)); + } + + if (btn->close != NULL) + return btn->close(btn->subbaton); + else + return SVN_NO_ERROR; +} + + +svn_stream_t * +svn_stream_compressed(svn_stream_t *stream, apr_pool_t *pool) +{ + struct svn_stream_t *zstream; + struct zbaton *baton; + + assert(stream != NULL); + + baton = apr_palloc(pool, sizeof(*baton)); + baton->in = baton->out = NULL; + baton->read = stream->read_fn; + baton->write = stream->write_fn; + baton->close = stream->close_fn; + baton->subbaton = stream->baton; + baton->pool = pool; + baton->read_buffer = NULL; + baton->read_flush = Z_SYNC_FLUSH; + + zstream = svn_stream_create(baton, pool); + svn_stream_set_read(zstream, read_handler_gz); + svn_stream_set_write(zstream, write_handler_gz); + svn_stream_set_close(zstream, close_handler_gz); + + return zstream; +} + + +/* Checksummed stream support */ + +struct checksum_stream_baton +{ + svn_checksum_ctx_t *read_ctx, *write_ctx; + svn_checksum_t **read_checksum; /* Output value. */ + svn_checksum_t **write_checksum; /* Output value. */ + svn_stream_t *proxy; + + /* True if more data should be read when closing the stream. */ + svn_boolean_t read_more; + + /* Pool to allocate read buffer and output values from. */ + apr_pool_t *pool; +}; + +static svn_error_t * +read_handler_checksum(void *baton, char *buffer, apr_size_t *len) +{ + struct checksum_stream_baton *btn = baton; + apr_size_t saved_len = *len; + + SVN_ERR(svn_stream_read(btn->proxy, buffer, len)); + + if (btn->read_checksum) + SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len)); + + if (saved_len != *len) + btn->read_more = FALSE; + + return SVN_NO_ERROR; +} + + +static svn_error_t * +write_handler_checksum(void *baton, const char *buffer, apr_size_t *len) +{ + struct checksum_stream_baton *btn = baton; + + if (btn->write_checksum && *len > 0) + SVN_ERR(svn_checksum_update(btn->write_ctx, buffer, *len)); + + return svn_stream_write(btn->proxy, buffer, len); +} + + +static svn_error_t * +close_handler_checksum(void *baton) +{ + struct checksum_stream_baton *btn = baton; + + /* If we're supposed to drain the stream, do so before finalizing the + checksum. */ + if (btn->read_more) + { + char *buf = apr_palloc(btn->pool, SVN__STREAM_CHUNK_SIZE); + apr_size_t len = SVN__STREAM_CHUNK_SIZE; + + do + { + SVN_ERR(read_handler_checksum(baton, buf, &len)); + } + while (btn->read_more); + } + + if (btn->read_ctx) + SVN_ERR(svn_checksum_final(btn->read_checksum, btn->read_ctx, btn->pool)); + + if (btn->write_ctx) + SVN_ERR(svn_checksum_final(btn->write_checksum, btn->write_ctx, btn->pool)); + + return svn_stream_close(btn->proxy); +} + + +svn_stream_t * +svn_stream_checksummed2(svn_stream_t *stream, + svn_checksum_t **read_checksum, + svn_checksum_t **write_checksum, + svn_checksum_kind_t checksum_kind, + svn_boolean_t read_all, + apr_pool_t *pool) +{ + svn_stream_t *s; + struct checksum_stream_baton *baton; + + if (read_checksum == NULL && write_checksum == NULL) + return stream; + + baton = apr_palloc(pool, sizeof(*baton)); + if (read_checksum) + baton->read_ctx = svn_checksum_ctx_create(checksum_kind, pool); + else + baton->read_ctx = NULL; + + if (write_checksum) + baton->write_ctx = svn_checksum_ctx_create(checksum_kind, pool); + else + baton->write_ctx = NULL; + + baton->read_checksum = read_checksum; + baton->write_checksum = write_checksum; + baton->proxy = stream; + baton->read_more = read_all; + baton->pool = pool; + + s = svn_stream_create(baton, pool); + svn_stream_set_read(s, read_handler_checksum); + svn_stream_set_write(s, write_handler_checksum); + svn_stream_set_close(s, close_handler_checksum); + return s; +} + +struct md5_stream_baton +{ + const unsigned char **read_digest; + const unsigned char **write_digest; + svn_checksum_t *read_checksum; + svn_checksum_t *write_checksum; + svn_stream_t *proxy; + apr_pool_t *pool; +}; + +static svn_error_t * +read_handler_md5(void *baton, char *buffer, apr_size_t *len) +{ + struct md5_stream_baton *btn = baton; + return svn_stream_read(btn->proxy, buffer, len); +} + +static svn_error_t * +write_handler_md5(void *baton, const char *buffer, apr_size_t *len) +{ + struct md5_stream_baton *btn = baton; + return svn_stream_write(btn->proxy, buffer, len); +} + +static svn_error_t * +close_handler_md5(void *baton) +{ + struct md5_stream_baton *btn = baton; + + SVN_ERR(svn_stream_close(btn->proxy)); + + if (btn->read_digest) + *btn->read_digest + = apr_pmemdup(btn->pool, btn->read_checksum->digest, + APR_MD5_DIGESTSIZE); + + if (btn->write_digest) + *btn->write_digest + = apr_pmemdup(btn->pool, btn->write_checksum->digest, + APR_MD5_DIGESTSIZE); + + return SVN_NO_ERROR; +} + + +svn_stream_t * +svn_stream_checksummed(svn_stream_t *stream, + const unsigned char **read_digest, + const unsigned char **write_digest, + svn_boolean_t read_all, + apr_pool_t *pool) +{ + svn_stream_t *s; + struct md5_stream_baton *baton; + + if (! read_digest && ! write_digest) + return stream; + + baton = apr_palloc(pool, sizeof(*baton)); + baton->read_digest = read_digest; + baton->write_digest = write_digest; + baton->pool = pool; + + /* Set BATON->proxy to a stream that will fill in BATON->read_checksum + * and BATON->write_checksum (if we want them) when it is closed. */ + baton->proxy + = svn_stream_checksummed2(stream, + read_digest ? &baton->read_checksum : NULL, + write_digest ? &baton->write_checksum : NULL, + svn_checksum_md5, + read_all, pool); + + /* Create a stream that will forward its read/write/close operations to + * BATON->proxy and will fill in *READ_DIGEST and *WRITE_DIGEST (if we + * want them) after it closes BATON->proxy. */ + s = svn_stream_create(baton, pool); + svn_stream_set_read(s, read_handler_md5); + svn_stream_set_write(s, write_handler_md5); + svn_stream_set_close(s, close_handler_md5); + return s; +} + + + + +/* Miscellaneous stream functions. */ +struct stringbuf_stream_baton +{ + svn_stringbuf_t *str; + apr_size_t amt_read; +}; + +static svn_error_t * +read_handler_stringbuf(void *baton, char *buffer, apr_size_t *len) +{ + struct stringbuf_stream_baton *btn = baton; + apr_size_t left_to_read = btn->str->len - btn->amt_read; + + *len = (*len > left_to_read) ? left_to_read : *len; + memcpy(buffer, btn->str->data + btn->amt_read, *len); + btn->amt_read += *len; + return SVN_NO_ERROR; +} + +static svn_error_t * +write_handler_stringbuf(void *baton, const char *data, apr_size_t *len) +{ + struct stringbuf_stream_baton *btn = baton; + + svn_stringbuf_appendbytes(btn->str, data, *len); + return SVN_NO_ERROR; +} + +svn_stream_t * +svn_stream_from_stringbuf(svn_stringbuf_t *str, + apr_pool_t *pool) +{ + svn_stream_t *stream; + struct stringbuf_stream_baton *baton; + + if (! str) + return svn_stream_empty(pool); + + baton = apr_palloc(pool, sizeof(*baton)); + baton->str = str; + baton->amt_read = 0; + stream = svn_stream_create(baton, pool); + svn_stream_set_read(stream, read_handler_stringbuf); + svn_stream_set_write(stream, write_handler_stringbuf); + return stream; +} + +struct string_stream_baton +{ + const svn_string_t *str; + apr_size_t amt_read; +}; + +static svn_error_t * +read_handler_string(void *baton, char *buffer, apr_size_t *len) +{ + struct string_stream_baton *btn = baton; + apr_size_t left_to_read = btn->str->len - btn->amt_read; + + *len = (*len > left_to_read) ? left_to_read : *len; + memcpy(buffer, btn->str->data + btn->amt_read, *len); + btn->amt_read += *len; + return SVN_NO_ERROR; +} + +svn_stream_t * +svn_stream_from_string(const svn_string_t *str, + apr_pool_t *pool) +{ + svn_stream_t *stream; + struct string_stream_baton *baton; + + if (! str) + return svn_stream_empty(pool); + + baton = apr_palloc(pool, sizeof(*baton)); + baton->str = str; + baton->amt_read = 0; + stream = svn_stream_create(baton, pool); + svn_stream_set_read(stream, read_handler_string); + return stream; +} + + +svn_error_t * +svn_stream_for_stdout(svn_stream_t **out, apr_pool_t *pool) +{ + apr_file_t *stdout_file; + apr_status_t apr_err; + + apr_err = apr_file_open_stdout(&stdout_file, pool); + if (apr_err) + return svn_error_wrap_apr(apr_err, "Can't open stdout"); + + *out = svn_stream_from_aprfile2(stdout_file, TRUE, pool); + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_string_from_stream(svn_string_t **result, + svn_stream_t *stream, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_stringbuf_t *work = svn_stringbuf_create_ensure(SVN__STREAM_CHUNK_SIZE, + result_pool); + char *buffer = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE); + + while (1) + { + apr_size_t len = SVN__STREAM_CHUNK_SIZE; + + SVN_ERR(svn_stream_read(stream, buffer, &len)); + svn_stringbuf_appendbytes(work, buffer, len); + + if (len < SVN__STREAM_CHUNK_SIZE) + break; + } + + SVN_ERR(svn_stream_close(stream)); + + *result = apr_palloc(result_pool, sizeof(**result)); + (*result)->data = work->data; + (*result)->len = work->len; + + return SVN_NO_ERROR; +} diff --git a/src/TortoiseMerge/libsvn_diff/svn_base64.h b/src/TortoiseMerge/libsvn_diff/svn_base64.h new file mode 100644 index 0000000..64ed530 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/svn_base64.h @@ -0,0 +1,118 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2004, 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_base64.h + * @brief Base64 encoding and decoding functions + */ + +#ifndef SVN_BASE64_H +#define SVN_BASE64_H + +#include + +#include "svn_types.h" +#include "svn_io.h" /* for svn_stream_t */ +#include "svn_string.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * + * + * @defgroup base64 Base64 encoding/decoding functions + * + * @{ + */ + +/** Return a writable generic stream which will encode binary data in + * base64 format and write the encoded data to @c output. Be sure to + * close the stream when done writing in order to squeeze out the last + * bit of encoded data. The stream is allocated in @c pool. + */ +svn_stream_t * +svn_base64_encode(svn_stream_t *output, + apr_pool_t *pool); + +/** Return a writable generic stream which will decode base64-encoded + * data and write the decoded data to @c output. The stream is allocated + * in @c pool. + */ +svn_stream_t * +svn_base64_decode(svn_stream_t *output, + apr_pool_t *pool); + + +/** Encode an @c svn_stringbuf_t into base64. + * + * A simple interface for encoding base64 data assuming we have all of + * it present at once. If @a break_lines is true, newlines will be + * inserted periodically; otherwise the string will only consist of + * base64 encoding characters. The returned string will be allocated + * from @c pool. + * + * @since New in 1.6. + */ +const svn_string_t * +svn_base64_encode_string2(const svn_string_t *str, + svn_boolean_t break_lines, + apr_pool_t *pool); + +/** + * Same as svn_base64_encode_string2, but with @a break_lines always + * TRUE. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +const svn_string_t * +svn_base64_encode_string(const svn_string_t *str, + apr_pool_t *pool); + +/** Decode an @c svn_stringbuf_t from base64. + * + * A simple interface for decoding base64 data assuming we have all of + * it present at once. The returned string will be allocated from @c + * pool. + * + */ +const svn_string_t * +svn_base64_decode_string(const svn_string_t *str, + apr_pool_t *pool); + + +/** Return a base64-encoded checksum for finalized @c digest. + * + * @c digest contains @c APR_MD5_DIGESTSIZE bytes of finalized data. + * Allocate the returned checksum in @c pool. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_stringbuf_t * +svn_base64_from_md5(unsigned char digest[], + apr_pool_t *pool); + + +/** @} end group: Base64 encoding/decoding functions */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_BASE64_H */ diff --git a/src/TortoiseMerge/libsvn_diff/svn_cmdline.h b/src/TortoiseMerge/libsvn_diff/svn_cmdline.h new file mode 100644 index 0000000..be808b6 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/svn_cmdline.h @@ -0,0 +1,383 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2004, 2008-2009 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_cmdline.h + * @brief Support functions for command line programs + */ + + + + +#ifndef SVN_CMDLINE_H +#define SVN_CMDLINE_H + +#include +#include + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +#define APR_WANT_STDIO +#endif +#include + +#include "svn_types.h" +#include "svn_auth.h" +#include "svn_config.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/** Set up the locale for character conversion, and initialize APR. + * If @a error_stream is non-NULL, print error messages to the stream, + * using @a progname as the program name. Attempt to set @c stdout to + * line-buffered mode, and @a error_stream to unbuffered mode. Return + * @c EXIT_SUCCESS if successful, otherwise @c EXIT_FAILURE. + * + * @note This function should be called exactly once at program startup, + * before calling any other APR or Subversion functions. + */ +int +svn_cmdline_init(const char *progname, + FILE *error_stream); + + +/** Set @a *dest to an output-encoded C string from UTF-8 C string @a + * src; allocate @a *dest in @a pool. + */ +svn_error_t * +svn_cmdline_cstring_from_utf8(const char **dest, + const char *src, + apr_pool_t *pool); + +/** Like svn_utf_cstring_from_utf8_fuzzy(), but converts to an + * output-encoded C string. */ +const char * +svn_cmdline_cstring_from_utf8_fuzzy(const char *src, + apr_pool_t *pool); + +/** Set @a *dest to a UTF-8-encoded C string from input-encoded C + * string @a src; allocate @a *dest in @a pool. + */ +svn_error_t * +svn_cmdline_cstring_to_utf8(const char **dest, + const char *src, + apr_pool_t *pool); + +/** Set @a *dest to an output-encoded natively-formatted path string + * from canonical path @a src; allocate @a *dest in @a pool. + */ +svn_error_t * +svn_cmdline_path_local_style_from_utf8(const char **dest, + const char *src, + apr_pool_t *pool); + +/** Write to stdout, using a printf-like format string @a fmt, passed + * through apr_pvsprintf(). All string arguments are in UTF-8; the output + * is converted to the output encoding. Use @a pool for temporary + * allocation. + * + * @since New in 1.1. + */ +svn_error_t * +svn_cmdline_printf(apr_pool_t *pool, + const char *fmt, + ...) + __attribute__((format(printf, 2, 3))); + +/** Write to the stdio @a stream, using a printf-like format string @a fmt, + * passed through apr_pvsprintf(). All string arguments are in UTF-8; + * the output is converted to the output encoding. Use @a pool for + * temporary allocation. + * + * @since New in 1.1. + */ +svn_error_t * +svn_cmdline_fprintf(FILE *stream, + apr_pool_t *pool, + const char *fmt, + ...) + __attribute__((format(printf, 3, 4))); + +/** Output the @a string to the stdio @a stream, converting from UTF-8 + * to the output encoding. Use @a pool for temporary allocation. + * + * @since New in 1.1. + */ +svn_error_t * +svn_cmdline_fputs(const char *string, + FILE *stream, + apr_pool_t *pool); + +/** Flush output buffers of the stdio @a stream, returning an error if that + * fails. This is just a wrapper for the standard fflush() function for + * consistent error handling. + * + * @since New in 1.1. + */ +svn_error_t * +svn_cmdline_fflush(FILE *stream); + +/** Return the name of the output encoding allocated in @a pool, or @c + * APR_LOCALE_CHARSET if the output encoding is the same as the locale + * encoding. + * + * @since New in 1.3. + */ +const char * +svn_cmdline_output_encoding(apr_pool_t *pool); + +/** Handle @a error in preparation for immediate exit from a + * command-line client. Specifically: + * + * Call svn_handle_error2(@a error, stderr, FALSE, @a prefix), clear + * @a error, destroy @a pool iff it is non-NULL, and return EXIT_FAILURE. + * + * @since New in 1.3. + */ +int +svn_cmdline_handle_exit_error(svn_error_t *error, + apr_pool_t *pool, + const char *prefix); + +/** A cancellation function/baton pair, and the path to the configuration + * directory. To be passed as the baton argument to the + * @c svn_cmdline_*_prompt functions. + * + * @since New in 1.6. + */ +typedef struct svn_cmdline_prompt_baton2_t { + svn_cancel_func_t cancel_func; + void *cancel_baton; + const char *config_dir; +} svn_cmdline_prompt_baton2_t; + +/** Like svn_cmdline_prompt_baton2_t, but without the path to the + * configuration directory. + * + * @since New in 1.4. + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +typedef struct svn_cmdline_prompt_baton_t { + svn_cancel_func_t cancel_func; + void *cancel_baton; +} svn_cmdline_prompt_baton_t; + +/** Prompt the user for input, using @a prompt_str for the prompt and + * @a baton (which may be @c NULL) for cancellation, and returning the + * user's response in @a result, allocated in @a pool. + * + * @since New in 1.5. + */ +svn_error_t * +svn_cmdline_prompt_user2(const char **result, + const char *prompt_str, + svn_cmdline_prompt_baton_t *baton, + apr_pool_t *pool); + +/** Similar to svn_cmdline_prompt_user2, but without cancellation + * support. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_cmdline_prompt_user(const char **result, + const char *prompt_str, + apr_pool_t *pool); + +/** An implementation of @c svn_auth_simple_prompt_func_t that prompts + * the user for keyboard input on the command line. + * + * @since New in 1.4. + * + * Expects a @c svn_cmdline_prompt_baton_t to be passed as @a baton. + */ +svn_error_t * +svn_cmdline_auth_simple_prompt(svn_auth_cred_simple_t **cred_p, + void *baton, + const char *realm, + const char *username, + svn_boolean_t may_save, + apr_pool_t *pool); + + +/** An implementation of @c svn_auth_username_prompt_func_t that prompts + * the user for their username via the command line. + * + * @since New in 1.4. + * + * Expects a @c svn_cmdline_prompt_baton_t to be passed as @a baton. + */ +svn_error_t * +svn_cmdline_auth_username_prompt(svn_auth_cred_username_t **cred_p, + void *baton, + const char *realm, + svn_boolean_t may_save, + apr_pool_t *pool); + + +/** An implementation of @c svn_auth_ssl_server_trust_prompt_func_t that + * asks the user if they trust a specific ssl server via the command line. + * + * @since New in 1.4. + * + * Expects a @c svn_cmdline_prompt_baton_t to be passed as @a baton. + */ +svn_error_t * +svn_cmdline_auth_ssl_server_trust_prompt + (svn_auth_cred_ssl_server_trust_t **cred_p, + void *baton, + const char *realm, + apr_uint32_t failures, + const svn_auth_ssl_server_cert_info_t *cert_info, + svn_boolean_t may_save, + apr_pool_t *pool); + + +/** An implementation of @c svn_auth_ssl_client_cert_prompt_func_t that + * prompts the user for the filename of their SSL client certificate via + * the command line. + * + * Records absolute path of the SSL client certificate file. + * + * @since New in 1.4. + * + * Expects a @c svn_cmdline_prompt_baton_t to be passed as @a baton. + */ +svn_error_t * +svn_cmdline_auth_ssl_client_cert_prompt + (svn_auth_cred_ssl_client_cert_t **cred_p, + void *baton, + const char *realm, + svn_boolean_t may_save, + apr_pool_t *pool); + + +/** An implementation of @c svn_auth_ssl_client_cert_pw_prompt_func_t that + * prompts the user for their SSL certificate password via the command line. + * + * @since New in 1.4. + * + * Expects a @c svn_cmdline_prompt_baton_t to be passed as @a baton. + */ +svn_error_t * +svn_cmdline_auth_ssl_client_cert_pw_prompt + (svn_auth_cred_ssl_client_cert_pw_t **cred_p, + void *baton, + const char *realm, + svn_boolean_t may_save, + apr_pool_t *pool); + +/** An implementation of @c svn_auth_plaintext_prompt_func_t that + * prompts the user whether storing unencypted passwords to disk is OK. + * + * Expects a @c svn_cmdline_prompt_baton2_t to be passed as @a baton. + * + * @since New in 1.6. + */ +svn_error_t * +svn_cmdline_auth_plaintext_prompt(svn_boolean_t *may_save_plaintext, + const char *realmstring, + void *baton, + apr_pool_t *pool); + +/** An implementation of @c svn_auth_plaintext_passphrase_prompt_func_t that + * prompts the user whether storing unencypted passphrase to disk is OK. + * + * Expects a @c svn_cmdline_prompt_baton2_t to be passed as @a baton. + * + * @since New in 1.6. + */ +svn_error_t * +svn_cmdline_auth_plaintext_passphrase_prompt(svn_boolean_t *may_save_plaintext, + const char *realmstring, + void *baton, + apr_pool_t *pool); + + +/** Set @a *ab to an authentication baton allocated from @a pool and + * initialized with the standard set of authentication providers used + * by the command line client. + * + * @a non_interactive, @a username, @a password, @a config_dir, + * @a no_auth_cache, and @a trust_server_cert are the values of the + * command line options of the corresponding names. + * + * @a cfg is the @c SVN_CONFIG_CATEGORY_CONFIG configuration, and + * @a cancel_func and @a cancel_baton control the cancellation of the + * prompting providers that are initialized. + * + * Use @a pool for all allocations. + * + * @since New in 1.6. + */ +svn_error_t * +svn_cmdline_create_auth_baton(svn_auth_baton_t **ab, + svn_boolean_t non_interactive, + const char *username, + const char *password, + const char *config_dir, + svn_boolean_t no_auth_cache, + svn_boolean_t trust_server_cert, + svn_config_t *cfg, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** Similar to svn_cmdline_create_auth_baton(), but with + * @a trust_server_cert always set to false. + * + * @since New in 1.4. + * @deprecated Provided for backward compatibility with the 1.5 API. + * Use svn_cmdline_create_auth_baton() instead. + * + * @note This deprecation does not follow the usual pattern of putting + * a new number on end of the function's name. Instead, the new + * function name is distinguished from the old by a grammatical + * improvement: the verb "create" instead of the noun "setup". + */ +SVN_DEPRECATED +svn_error_t * +svn_cmdline_setup_auth_baton(svn_auth_baton_t **ab, + svn_boolean_t non_interactive, + const char *username, + const char *password, + const char *config_dir, + svn_boolean_t no_auth_cache, + svn_config_t *cfg, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** Wrapper for apr_getopt_init(), which see. + * + * @since New in 1.4. + * + * This is a private API for Subversion's own use. + */ +svn_error_t * +svn_cmdline__getopt_init(apr_getopt_t **os, + int argc, + const char *argv[], + apr_pool_t *pool); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_CMDLINE_H */ diff --git a/src/TortoiseMerge/libsvn_diff/svn_dirent_uri.h b/src/TortoiseMerge/libsvn_diff/svn_dirent_uri.h new file mode 100644 index 0000000..92ef985 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/svn_dirent_uri.h @@ -0,0 +1,225 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_dirent_uri.h + * @brief A library to manipulate URIs and directory entries. + * + * This library makes a clear distinction between directory entries (dirents) + * and URIs where: + * - a dirent is a path on (local) disc or a UNC path (Windows) + * examples: "/foo/bar", "X:/temp", "//server/share" + * - a URI is a path in a repository or a URL + * examples: "/trunk/README", "http://hostname/svn/repos" + * + * This distinction is needed because on Windows we have to handle some + * dirents and URIs differently. Since it's not possible to determine from + * the path string if it's a dirent or a URI, it's up to the API user to + * make this choice. See also issue #2028. + * + * Nearly all the @c svn_dirent_xxx functions expect paths passed into them + * to be in canonical form. The only functions which do *not* have such + * expectations are: + * + * - @c svn_dirent_canonicalize() + * - @c svn_dirent_is_canonical() + * - @c svn_dirent_internal_style() + * - @c svn_dirent_local_style() + * + * ### TODO: add description in line with svn_path.h, once more functions + * are moved. + * ### END TODO + */ + +#ifndef SVN_DIRENT_URI_H +#define SVN_DIRENT_URI_H + +#include +#include +#include + +#include "svn_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/** Convert @a dirent from the local style to the canonical internal style. + * + * @since New in 1.6. + */ +const char * +svn_dirent_internal_style(const char *dirent, + apr_pool_t *pool); + +/** Convert @a dirent from the canonical internal style to the local style. + * + * @since New in 1.6. + */ +const char * +svn_dirent_local_style(const char *dirent, + apr_pool_t *pool); + +/** Join a base dirent (@a base) with a component (@a component), allocated in + * @a pool. + * + * If either @a base or @a component is the empty string, then the other + * argument will be copied and returned. If both are the empty string then + * empty string is returned. + * + * If the @a component is an absolute dirent, then it is copied and returned. + * The platform specific rules for joining paths are used to join the components. + * + * This function is NOT appropriate for native (local) file + * dirents. Only for "internal" canonicalized dirents, since it uses '/' + * for the separator. + * + * @since New in 1.6. + */ +char * +svn_dirent_join(const char *base, + const char *component, + apr_pool_t *pool); + +/** Join multiple components onto a @a base dirent, allocated in @a pool. The + * components are terminated by a @c NULL. + * + * If any component is the empty string, it will be ignored. + * + * If any component is an absolute dirent, then it resets the base and + * further components will be appended to it. + * + * See svn_dirent_join() for further notes about joining dirents. + * + * @since New in 1.6. + */ +char * +svn_dirent_join_many(apr_pool_t *pool, + const char *base, + ...); + +/** Get the dirname of the specified canonicalized @a dirent, defined as + * the dirent with its basename removed. + * + * If @a dirent is root ("/", "X:/", "//server/share/"), it is returned + * unchanged. + * + * The returned dirname will be allocated in @a pool. + * + * @since New in 1.6. + */ +char * +svn_dirent_dirname(const char *dirent, + apr_pool_t *pool); + +/** Return TRUE if @a dirent is considered absolute on the platform at + * hand. E.g. '/foo' on posix or 'X:/foo', '//server/share/foo' + * on Windows. + * + * @since New in 1.6. + */ +svn_boolean_t +svn_dirent_is_absolute(const char *dirent); + +/** Return TRUE if @a dirent is considered a root directory on the platform + * at hand. E.g. '/' on posix platforms or 'X:/', '//server/share' + * on Windows. + * + * @since New in 1.5. + */ +svn_boolean_t +svn_dirent_is_root(const char *dirent, + apr_size_t len); + +/** Return a new dirent like @a dirent, but transformed such that some types + * of dirent specification redundancies are removed. + * + * This involves collapsing redundant "/./" elements, removing + * multiple adjacent separator characters, removing trailing + * separator characters, and possibly other semantically inoperative + * transformations. + * + * Convert the server name of UNC paths lowercase on Windows. + * + * The returned dirent may be statically allocated, equal to @a dirent, or + * allocated from @a pool. + * + * @since New in 1.6. + */ +const char * +svn_dirent_canonicalize(const char *dirent, + apr_pool_t *pool); + +/** Return @c TRUE iff @a dirent is canonical. Use @a pool for temporary + * allocations. + * + * @note The test for canonicalization is currently defined as + * "looks exactly the same as @c svn_dirent_canonicalize() would make + * it look". + * + * @since New in 1.6. + */ +svn_boolean_t +svn_dirent_is_canonical(const char *dirent, + apr_pool_t *pool); + +/** Return the longest common dirent shared by two canonicalized dirents, + * @a dirent1 and @a dirent2. If there's no common ancestor, return the + * empty path. + * + * @since New in 1.6. + */ +char * +svn_dirent_get_longest_ancestor(const char *dirent1, + const char *dirent2, + apr_pool_t *pool); + +/** Convert @a relative canonicalized dirent to an absolute dirent and + * return the results in @a *pabsolute, allocated in @a pool. + * + * @since New in 1.6. + */ +svn_error_t * +svn_dirent_get_absolute(const char **pabsolute, + const char *relative, + apr_pool_t *pool); + +/** + * This function is similar as @c svn_path_is_child, except that it supports + * Windows dirents and UNC paths on Windows. + * + * @since New in 1.6. + */ +const char * +svn_dirent_is_child(const char *dirent1, + const char *dirent2, + apr_pool_t *pool); + +/** Return TRUE if @a dirent1 is an ancestor of @a dirent2 or the dirents are + * equal and FALSE otherwise. + * + * @since New in 1.6. + */ +svn_boolean_t +svn_dirent_is_ancestor(const char *path1, + const char *path2); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_DIRENT_URI_H */ diff --git a/src/TortoiseMerge/libsvn_diff/svn_md5.h b/src/TortoiseMerge/libsvn_diff/svn_md5.h new file mode 100644 index 0000000..8bf35c7 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/svn_md5.h @@ -0,0 +1,86 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2004, 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_md5.h + * @brief Converting and comparing MD5 checksums. + */ + +#ifndef SVN_MD5_H +#define SVN_MD5_H + +#include /* for apr_pool_t */ + +#include "svn_types.h" /* for svn_boolean_t */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +/** + * The MD5 digest for the empty string. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + * */ +SVN_DEPRECATED +const unsigned char * +svn_md5_empty_string_digest(void); + + +/** + * Return the hex representation of @a digest, which must be + * @c APR_MD5_DIGESTSIZE bytes long, allocating the string in @a pool. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +const char * +svn_md5_digest_to_cstring_display(const unsigned char digest[], + apr_pool_t *pool); + + +/** + * Return the hex representation of @a digest, which must be + * @c APR_MD5_DIGESTSIZE bytes long, allocating the string in @a pool. + * If @a digest is all zeros, then return NULL. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +const char * +svn_md5_digest_to_cstring(const unsigned char digest[], + apr_pool_t *pool); + + +/** + * Compare digests @a d1 and @a d2, each @c APR_MD5_DIGESTSIZE bytes long. + * If neither is all zeros, and they do not match, then return FALSE; + * else return TRUE. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_boolean_t +svn_md5_digests_match(const unsigned char d1[], + const unsigned char d2[]); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_MD5_H */ diff --git a/src/TortoiseMerge/libsvn_diff/svn_nls.h b/src/TortoiseMerge/libsvn_diff/svn_nls.h new file mode 100644 index 0000000..01be3c2 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/svn_nls.h @@ -0,0 +1,51 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2005, 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_nls.h + * @brief Support functions for NLS programs + */ + + + +#ifndef SVN_NLS_H +#define SVN_NLS_H + +#include "svn_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Set up the NLS. + * Return the error @c APR_EINVAL or @c APR_INCOMPLETE if an + * error occurs. + * + * @note This function is for bindings. You should usually + * use svn_cmdline_init() instead of calling this + * function directly. This function should be called + * after initializing APR. + * + * @since New in 1.3. + */ +svn_error_t * +svn_nls_init(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_NLS_H */ diff --git a/src/TortoiseMerge/libsvn_diff/svn_string.c b/src/TortoiseMerge/libsvn_diff/svn_string.c new file mode 100644 index 0000000..c665eb7 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/svn_string.c @@ -0,0 +1,601 @@ +/* + * svn_string.h: routines to manipulate counted-length strings + * (svn_stringbuf_t and svn_string_t) and C strings. + * + * + * ==================================================================== + * Copyright (c) 2000-2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + + + +#include /* for memcpy(), memcmp(), strlen() */ +#include /* for apr_isspace() */ +#include +#include "svn_string.h" /* loads "svn_types.h" and */ +#include "svn_ctype.h" + + + +/* Our own realloc, since APR doesn't have one. Note: this is a + generic realloc for memory pools, *not* for strings. */ +static void * +my__realloc(char *data, apr_size_t oldsize, apr_size_t request, + apr_pool_t *pool) +{ + void *new_area; + + /* kff todo: it's a pity APR doesn't give us this -- sometimes it + could realloc the block merely by extending in place, sparing us + a memcpy(), but only the pool would know enough to be able to do + this. We should add a realloc() to APR if someone hasn't + already. */ + + /* malloc new area */ + new_area = apr_palloc(pool, request); + + /* copy data to new area */ + memcpy(new_area, data, oldsize); + + /* I'm NOT freeing old area here -- cuz we're using pools, ugh. */ + + /* return new area */ + return new_area; +} + +static APR_INLINE svn_boolean_t +string_compare(const char *str1, + const char *str2, + apr_size_t len1, + apr_size_t len2) +{ + /* easy way out :) */ + if (len1 != len2) + return FALSE; + + /* now the strings must have identical lenghths */ + + if ((memcmp(str1, str2, len1)) == 0) + return TRUE; + else + return FALSE; +} + +static APR_INLINE apr_size_t +string_first_non_whitespace(const char *str, apr_size_t len) +{ + apr_size_t i; + + for (i = 0; i < len; i++) + { + if (! apr_isspace(str[i])) + return i; + } + + /* if we get here, then the string must be entirely whitespace */ + return len; +} + +static APR_INLINE apr_size_t +find_char_backward(const char *str, apr_size_t len, char ch) +{ + apr_size_t i = len; + + while (i != 0) + { + if (str[--i] == ch) + return i; + } + + /* char was not found, return len */ + return len; +} + + +/* svn_string functions */ + +static svn_string_t * +create_string(const char *data, apr_size_t size, + apr_pool_t *pool) +{ + svn_string_t *new_string; + + new_string = apr_palloc(pool, sizeof(*new_string)); + + new_string->data = data; + new_string->len = size; + + return new_string; +} + +svn_string_t * +svn_string_ncreate(const char *bytes, apr_size_t size, apr_pool_t *pool) +{ + char *data; + + data = apr_palloc(pool, size + 1); + memcpy(data, bytes, size); + + /* Null termination is the convention -- even if we suspect the data + to be binary, it's not up to us to decide, it's the caller's + call. Heck, that's why they call it the caller! */ + data[size] = '\0'; + + /* wrap an svn_string_t around the new data */ + return create_string(data, size, pool); +} + + +svn_string_t * +svn_string_create(const char *cstring, apr_pool_t *pool) +{ + return svn_string_ncreate(cstring, strlen(cstring), pool); +} + + +svn_string_t * +svn_string_create_from_buf(const svn_stringbuf_t *strbuf, apr_pool_t *pool) +{ + return svn_string_ncreate(strbuf->data, strbuf->len, pool); +} + + +svn_string_t * +svn_string_createv(apr_pool_t *pool, const char *fmt, va_list ap) +{ + char *data = apr_pvsprintf(pool, fmt, ap); + + /* wrap an svn_string_t around the new data */ + return create_string(data, strlen(data), pool); +} + + +svn_string_t * +svn_string_createf(apr_pool_t *pool, const char *fmt, ...) +{ + svn_string_t *str; + + va_list ap; + va_start(ap, fmt); + str = svn_string_createv(pool, fmt, ap); + va_end(ap); + + return str; +} + + +svn_boolean_t +svn_string_isempty(const svn_string_t *str) +{ + return (str->len == 0); +} + + +svn_string_t * +svn_string_dup(const svn_string_t *original_string, apr_pool_t *pool) +{ + return (svn_string_ncreate(original_string->data, + original_string->len, pool)); +} + + + +svn_boolean_t +svn_string_compare(const svn_string_t *str1, const svn_string_t *str2) +{ + return + string_compare(str1->data, str2->data, str1->len, str2->len); +} + + + +apr_size_t +svn_string_first_non_whitespace(const svn_string_t *str) +{ + return + string_first_non_whitespace(str->data, str->len); +} + + +apr_size_t +svn_string_find_char_backward(const svn_string_t *str, char ch) +{ + return find_char_backward(str->data, str->len, ch); +} + + + +/* svn_stringbuf functions */ + +static svn_stringbuf_t * +create_stringbuf(char *data, apr_size_t size, apr_size_t blocksize, apr_pool_t *pool) +{ + svn_stringbuf_t *new_string; + + new_string = apr_palloc(pool, sizeof(*new_string)); + + new_string->data = data; + new_string->len = size; + new_string->blocksize = blocksize; + new_string->pool = pool; + + return new_string; +} + +svn_stringbuf_t * +svn_stringbuf_create_ensure(apr_size_t blocksize, apr_pool_t *pool) +{ + char *data = apr_palloc(pool, ++blocksize); /* + space for '\0' */ + + data[0] = '\0'; + + /* wrap an svn_stringbuf_t around the new data buffer. */ + return create_stringbuf(data, 0, blocksize, pool); +} + +svn_stringbuf_t * +svn_stringbuf_ncreate(const char *bytes, apr_size_t size, apr_pool_t *pool) +{ + /* Ensure string buffer of size + 1 */ + svn_stringbuf_t *strbuf = svn_stringbuf_create_ensure(size, pool); + + memcpy(strbuf->data, bytes, size); + + /* Null termination is the convention -- even if we suspect the data + to be binary, it's not up to us to decide, it's the caller's + call. Heck, that's why they call it the caller! */ + strbuf->data[size] = '\0'; + strbuf->len = size; + + return strbuf; +} + + +svn_stringbuf_t * +svn_stringbuf_create(const char *cstring, apr_pool_t *pool) +{ + return svn_stringbuf_ncreate(cstring, strlen(cstring), pool); +} + + +svn_stringbuf_t * +svn_stringbuf_create_from_string(const svn_string_t *str, apr_pool_t *pool) +{ + return svn_stringbuf_ncreate(str->data, str->len, pool); +} + + +svn_stringbuf_t * +svn_stringbuf_createv(apr_pool_t *pool, const char *fmt, va_list ap) +{ + char *data = apr_pvsprintf(pool, fmt, ap); + apr_size_t size = strlen(data); + + /* wrap an svn_stringbuf_t around the new data */ + return create_stringbuf(data, size, size + 1, pool); +} + + +svn_stringbuf_t * +svn_stringbuf_createf(apr_pool_t *pool, const char *fmt, ...) +{ + svn_stringbuf_t *str; + + va_list ap; + va_start(ap, fmt); + str = svn_stringbuf_createv(pool, fmt, ap); + va_end(ap); + + return str; +} + + +void +svn_stringbuf_fillchar(svn_stringbuf_t *str, unsigned char c) +{ + memset(str->data, c, str->len); +} + + +void +svn_stringbuf_set(svn_stringbuf_t *str, const char *value) +{ + apr_size_t amt = strlen(value); + + svn_stringbuf_ensure(str, amt + 1); + memcpy(str->data, value, amt + 1); + str->len = amt; +} + +void +svn_stringbuf_setempty(svn_stringbuf_t *str) +{ + if (str->len > 0) + str->data[0] = '\0'; + + str->len = 0; +} + + +void +svn_stringbuf_chop(svn_stringbuf_t *str, apr_size_t nbytes) +{ + if (nbytes > str->len) + str->len = 0; + else + str->len -= nbytes; + + str->data[str->len] = '\0'; +} + + +svn_boolean_t +svn_stringbuf_isempty(const svn_stringbuf_t *str) +{ + return (str->len == 0); +} + + +void +svn_stringbuf_ensure(svn_stringbuf_t *str, apr_size_t minimum_size) +{ + /* Keep doubling capacity until have enough. */ + if (str->blocksize < minimum_size) + { + if (str->blocksize == 0) + str->blocksize = minimum_size; + else + while (str->blocksize < minimum_size) + { + apr_size_t prev_size = str->blocksize; + str->blocksize *= 2; + /* check for apr_size_t overflow */ + if (prev_size > str->blocksize) + { + str->blocksize = minimum_size; + break; + } + } + + str->data = (char *) my__realloc(str->data, + str->len + 1, + /* We need to maintain (and thus copy) + the trailing nul */ + str->blocksize, + str->pool); + } +} + + +void +svn_stringbuf_appendbytes(svn_stringbuf_t *str, const char *bytes, + apr_size_t count) +{ + apr_size_t total_len; + void *start_address; + + total_len = str->len + count; /* total size needed */ + + /* +1 for null terminator. */ + svn_stringbuf_ensure(str, (total_len + 1)); + + /* get address 1 byte beyond end of original bytestring */ + start_address = (str->data + str->len); + + memcpy(start_address, bytes, count); + str->len = total_len; + + str->data[str->len] = '\0'; /* We don't know if this is binary + data or not, but convention is + to null-terminate. */ +} + + +void +svn_stringbuf_appendstr(svn_stringbuf_t *targetstr, + const svn_stringbuf_t *appendstr) +{ + svn_stringbuf_appendbytes(targetstr, appendstr->data, appendstr->len); +} + + +void +svn_stringbuf_appendcstr(svn_stringbuf_t *targetstr, const char *cstr) +{ + svn_stringbuf_appendbytes(targetstr, cstr, strlen(cstr)); +} + + +svn_stringbuf_t * +svn_stringbuf_dup(const svn_stringbuf_t *original_string, apr_pool_t *pool) +{ + return (svn_stringbuf_ncreate(original_string->data, + original_string->len, pool)); +} + + + +svn_boolean_t +svn_stringbuf_compare(const svn_stringbuf_t *str1, + const svn_stringbuf_t *str2) +{ + return string_compare(str1->data, str2->data, str1->len, str2->len); +} + + + +apr_size_t +svn_stringbuf_first_non_whitespace(const svn_stringbuf_t *str) +{ + return string_first_non_whitespace(str->data, str->len); +} + + +void +svn_stringbuf_strip_whitespace(svn_stringbuf_t *str) +{ + /* Find first non-whitespace character */ + apr_size_t offset = svn_stringbuf_first_non_whitespace(str); + + /* Go ahead! Waste some RAM, we've got pools! :) */ + str->data += offset; + str->len -= offset; + str->blocksize -= offset; + + /* Now that we've trimmed the front, trim the end, wasting more RAM. */ + while ((str->len > 0) && apr_isspace(str->data[str->len - 1])) + str->len--; + str->data[str->len] = '\0'; +} + + +apr_size_t +svn_stringbuf_find_char_backward(const svn_stringbuf_t *str, char ch) +{ + return find_char_backward(str->data, str->len, ch); +} + + +svn_boolean_t +svn_string_compare_stringbuf(const svn_string_t *str1, + const svn_stringbuf_t *str2) +{ + return string_compare(str1->data, str2->data, str1->len, str2->len); +} + + + +/*** C string stuff. ***/ + +void +svn_cstring_split_append(apr_array_header_t *array, + const char *input, + const char *sep_chars, + svn_boolean_t chop_whitespace, + apr_pool_t *pool) +{ + char *last; + char *pats; + char *p; + + pats = apr_pstrdup(pool, input); /* strtok wants non-const data */ + p = apr_strtok(pats, sep_chars, &last); + + while (p) + { + if (chop_whitespace) + { + while (apr_isspace(*p)) + p++; + + { + char *e = p + (strlen(p) - 1); + while ((e >= p) && (apr_isspace(*e))) + e--; + *(++e) = '\0'; + } + } + + if (p[0] != '\0') + APR_ARRAY_PUSH(array, const char *) = p; + + p = apr_strtok(NULL, sep_chars, &last); + } + + return; +} + + +apr_array_header_t * +svn_cstring_split(const char *input, + const char *sep_chars, + svn_boolean_t chop_whitespace, + apr_pool_t *pool) +{ + apr_array_header_t *a = apr_array_make(pool, 5, sizeof(input)); + svn_cstring_split_append(a, input, sep_chars, chop_whitespace, pool); + return a; +} + + +svn_boolean_t svn_cstring_match_glob_list(const char *str, + apr_array_header_t *list) +{ + int i; + + for (i = 0; i < list->nelts; i++) + { + const char *this_pattern = APR_ARRAY_IDX(list, i, char *); + + if (apr_fnmatch(this_pattern, str, 0) == APR_SUCCESS) + return TRUE; + } + + return FALSE; +} + +int svn_cstring_count_newlines(const char *msg) +{ + int count = 0; + const char *p; + + for (p = msg; *p; p++) + { + if (*p == '\n') + { + count++; + if (*(p + 1) == '\r') + p++; + } + else if (*p == '\r') + { + count++; + if (*(p + 1) == '\n') + p++; + } + } + + return count; +} + +char * +svn_cstring_join(const apr_array_header_t *strings, + const char *separator, + apr_pool_t *pool) +{ + svn_stringbuf_t *new_str = svn_stringbuf_create("", pool); + int sep_len = strlen(separator); + int i; + + for (i = 0; i < strings->nelts; i++) + { + const char *string = APR_ARRAY_IDX(strings, i, const char *); + svn_stringbuf_appendbytes(new_str, string, strlen(string)); + svn_stringbuf_appendbytes(new_str, separator, sep_len); + } + return new_str->data; +} + +int +svn_cstring_casecmp(const char *str1, const char *str2) +{ + for (;;) + { + const int a = *str1++; + const int b = *str2++; + const int cmp = svn_ctype_casecmp(a, b); + if (cmp || !a || !b) + return cmp; + } +} diff --git a/src/TortoiseMerge/libsvn_diff/svn_utf_private.h b/src/TortoiseMerge/libsvn_diff/svn_utf_private.h new file mode 100644 index 0000000..ebd53f6 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/svn_utf_private.h @@ -0,0 +1,82 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2008-2009 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_utf_private.h + * @brief UTF validation routines + */ + +#ifndef SVN_UTF_PRIVATE_H +#define SVN_UTF_PRIVATE_H + +#include +#include + +#include "svn_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Return TRUE if the string SRC of length LEN is a valid UTF-8 encoding + * according to the rules laid down by the Unicode 4.0 standard, FALSE + * otherwise. This function is faster than svn_utf__last_valid(). + */ +svn_boolean_t +svn_utf__is_valid(const char *src, apr_size_t len); + +/* As for svn_utf__is_valid but SRC is NULL terminated. */ +svn_boolean_t +svn_utf__cstring_is_valid(const char *src); + +/* Return a pointer to the first character after the last valid UTF-8 + * potentially multi-byte character in the string SRC of length LEN. + * Validity of bytes from SRC to SRC+LEN-1, inclusively, is checked. + * If SRC is a valid UTF-8, the return value will point to the byte SRC+LEN, + * otherwise it will point to the start of the first invalid character. + * In either case all the characters between SRC and the return pointer - 1, + * inclusively, are valid UTF-8. + * + * See also svn_utf__is_valid(). + */ +const char * +svn_utf__last_valid(const char *src, apr_size_t len); + +/* As for svn_utf__last_valid but uses a different implementation without + lookup tables. It avoids the table memory use (about 400 bytes) but the + function is longer (about 200 bytes extra) and likely to be slower when + the string is valid. If the string is invalid this function may be + faster since it returns immediately rather than continuing to the end of + the string. The main reason this function exists is to test the table + driven implementation. */ +const char * +svn_utf__last_valid2(const char *src, apr_size_t len); + +const char * +svn_utf__cstring_from_utf8_fuzzy(const char *src, + apr_pool_t *pool, + svn_error_t *(*convert_from_utf8) + (const char **, + const char *, + apr_pool_t *)); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_UTF_PRIVATE_H */ diff --git a/src/TortoiseMerge/libsvn_diff/svn_xml.h b/src/TortoiseMerge/libsvn_diff/svn_xml.h new file mode 100644 index 0000000..45d19d5 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/svn_xml.h @@ -0,0 +1,361 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2006, 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_xml.h + * @brief XML code shared by various Subversion libraries. + */ + +#ifndef SVN_XML_H +#define SVN_XML_H + +#include +#include +#include + +#include "svn_types.h" +#include "svn_string.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** The namespace all Subversion XML uses. */ +#define SVN_XML_NAMESPACE "svn:" + +/** Used as style argument to svn_xml_make_open_tag() and friends. */ +enum svn_xml_open_tag_style { + /** */ + svn_xml_normal = 1, + + /** , no cosmetic newline */ + svn_xml_protect_pcdata, + + /** */ + svn_xml_self_closing +}; + + + +/** Determine if a string of character @a data of length @a len is a + * safe bet for use with the svn_xml_escape_* functions found in this + * header. + * + * Return @c TRUE if it is, @c FALSE otherwise. + * + * Essentially, this function exists to determine whether or not + * simply running a string of bytes through the Subversion XML escape + * routines will produce legitimate XML. It should only be necessary + * for data which might contain bytes that cannot be safely encoded + * into XML (certain control characters, for example). + */ +svn_boolean_t +svn_xml_is_xml_safe(const char *data, + apr_size_t len); + +/** Create or append in @a *outstr an xml-escaped version of @a string, + * suitable for output as character data. + * + * If @a *outstr is @c NULL, set @a *outstr to a new stringbuf allocated + * in @a pool, else append to the existing stringbuf there. + */ +void +svn_xml_escape_cdata_stringbuf(svn_stringbuf_t **outstr, + const svn_stringbuf_t *string, + apr_pool_t *pool); + +/** Same as svn_xml_escape_cdata_stringbuf(), but @a string is an + * @c svn_string_t. + */ +void +svn_xml_escape_cdata_string(svn_stringbuf_t **outstr, + const svn_string_t *string, + apr_pool_t *pool); + +/** Same as svn_xml_escape_cdata_stringbuf(), but @a string is a + * NULL-terminated C string. + */ +void +svn_xml_escape_cdata_cstring(svn_stringbuf_t **outstr, + const char *string, + apr_pool_t *pool); + + +/** Create or append in @a *outstr an xml-escaped version of @a string, + * suitable for output as an attribute value. + * + * If @a *outstr is @c NULL, set @a *outstr to a new stringbuf allocated + * in @a pool, else append to the existing stringbuf there. + */ +void +svn_xml_escape_attr_stringbuf(svn_stringbuf_t **outstr, + const svn_stringbuf_t *string, + apr_pool_t *pool); + +/** Same as svn_xml_escape_attr_stringbuf(), but @a string is an + * @c svn_string_t. + */ +void +svn_xml_escape_attr_string(svn_stringbuf_t **outstr, + const svn_string_t *string, + apr_pool_t *pool); + +/** Same as svn_xml_escape_attr_stringbuf(), but @a string is a + * NULL-terminated C string. + */ +void +svn_xml_escape_attr_cstring(svn_stringbuf_t **outstr, + const char *string, + apr_pool_t *pool); + +/** + * Return UTF-8 string @a string if it contains no characters that are + * unrepresentable in XML. Else, return a copy of @a string, + * allocated in @a pool, with each unrepresentable character replaced + * by "?\uuu", where "uuu" is the three-digit unsigned decimal value + * of that character. + * + * Neither the input nor the output need be valid XML; however, the + * output can always be safely XML-escaped. + * + * @note The current implementation treats all Unicode characters as + * representable, except for most ASCII control characters (the + * exceptions being CR, LF, and TAB, which are valid in XML). There + * may be other UTF-8 characters that are invalid in XML; see + * http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=90591 + * and its thread for details. + * + * @since New in 1.2. + */ +const char * +svn_xml_fuzzy_escape(const char *string, + apr_pool_t *pool); + + +/*---------------------------------------------------------------*/ + +/* Generalized Subversion XML Parsing */ + +/** A generalized Subversion XML parser object */ +typedef struct svn_xml_parser_t svn_xml_parser_t; + +typedef void (*svn_xml_start_elem)(void *baton, + const char *name, + const char **atts); + +typedef void (*svn_xml_end_elem)(void *baton, const char *name); + +/* data is not NULL-terminated. */ +typedef void (*svn_xml_char_data)(void *baton, + const char *data, + apr_size_t len); + + +/** Create a general Subversion XML parser */ +svn_xml_parser_t * +svn_xml_make_parser(void *baton, + svn_xml_start_elem start_handler, + svn_xml_end_elem end_handler, + svn_xml_char_data data_handler, + apr_pool_t *pool); + + +/** Free a general Subversion XML parser */ +void +svn_xml_free_parser(svn_xml_parser_t *svn_parser); + + +/** Push @a len bytes of xml data in @a buf at @a svn_parser. + * + * If this is the final push, @a is_final must be set. + * + * An error will be returned if there was a syntax problem in the XML, + * or if any of the callbacks set an error using + * svn_xml_signal_bailout(). + * + * If an error is returned, the @c svn_xml_parser_t will have been freed + * automatically, so the caller should not call svn_xml_free_parser(). + */ +svn_error_t * +svn_xml_parse(svn_xml_parser_t *svn_parser, + const char *buf, + apr_size_t len, + svn_boolean_t is_final); + + + +/** The way to officially bail out of xml parsing. + * + * Store @a error in @a svn_parser and set all expat callbacks to @c NULL. + */ +void +svn_xml_signal_bailout(svn_error_t *error, + svn_xml_parser_t *svn_parser); + + + + + +/*** Helpers for dealing with the data Expat gives us. ***/ + +/** Return the value associated with @a name in expat attribute array @a atts, + * else return @c NULL. + * + * (There could never be a @c NULL attribute value in the XML, + * although the empty string is possible.) + * + * @a atts is an array of c-strings: even-numbered indexes are names, + * odd-numbers hold values. If all is right, it should end on an + * even-numbered index pointing to @c NULL. + */ +const char * +svn_xml_get_attr_value(const char *name, + const char **atts); + + + +/* Converting between Expat attribute lists and APR hash tables. */ + + +/** Create an attribute hash from @c va_list @a ap. + * + * The contents of @a ap are alternating char * keys and + * char * vals, terminated by a final @c NULL falling on an + * even index (zero-based). + */ +apr_hash_t * +svn_xml_ap_to_hash(va_list ap, + apr_pool_t *pool); + +/** Create a hash that corresponds to Expat xml attribute list @a atts. + * + * The hash's keys and values are char *'s. + * + * @a atts may be NULL, in which case you just get an empty hash back + * (this makes life more convenient for some callers). + */ +apr_hash_t * +svn_xml_make_att_hash(const char **atts, + apr_pool_t *pool); + + +/** Like svn_xml_make_att_hash(), but takes a hash and preserves any + * key/value pairs already in it. + */ +void +svn_xml_hash_atts_preserving(const char **atts, + apr_hash_t *ht, + apr_pool_t *pool); + +/** Like svn_xml_make_att_hash(), but takes a hash and overwrites + * key/value pairs already in it that also appear in @a atts. + */ +void +svn_xml_hash_atts_overlaying(const char **atts, + apr_hash_t *ht, + apr_pool_t *pool); + + + +/* Printing XML */ + +/** Create an XML header and return it in @a *str. + * + * Fully-formed XML documents should start out with a header, + * something like + * \ + * + * This function returns such a header. @a *str must either be @c NULL, in + * which case a new string is created, or it must point to an existing + * string to be appended to. + */ +void +svn_xml_make_header(svn_stringbuf_t **str, + apr_pool_t *pool); + + +/** Store a new xml tag @a tagname in @a *str. + * + * If @a *str is @c NULL, set @a *str to a new stringbuf allocated + * in @a pool, else append to the existing stringbuf there. + * + * Take the tag's attributes from varargs, a NULL-terminated list of + * alternating char * key and char * val. Do xml-escaping + * on each val. + * + * @a style is one of the enumerated styles in @c svn_xml_open_tag_style. + */ +void +svn_xml_make_open_tag(svn_stringbuf_t **str, + apr_pool_t *pool, + enum svn_xml_open_tag_style style, + const char *tagname, + ...); + + +/** Like svn_xml_make_open_tag(), but takes a @c va_list instead of being + * variadic. + */ +void +svn_xml_make_open_tag_v(svn_stringbuf_t **str, + apr_pool_t *pool, + enum svn_xml_open_tag_style style, + const char *tagname, + va_list ap); + + +/** Like svn_xml_make_open_tag(), but takes a hash table of attributes + * (char * keys mapping to char * values). + * + * You might ask, why not just provide svn_xml_make_tag_atts()? + * + * The reason is that a hash table is the most natural interface to an + * attribute list; the fact that Expat uses char ** atts instead is + * certainly a defensible implementation decision, but since we'd have + * to have special code to support such lists throughout Subversion + * anyway, we might as well write that code for the natural interface + * (hashes) and then convert in the few cases where conversion is + * needed. Someday it might even be nice to change expat-lite to work + * with apr hashes. + * + * See conversion functions svn_xml_make_att_hash() and + * svn_xml_make_att_hash_overlaying(). Callers should use those to + * convert Expat attr lists into hashes when necessary. + */ +void +svn_xml_make_open_tag_hash(svn_stringbuf_t **str, + apr_pool_t *pool, + enum svn_xml_open_tag_style style, + const char *tagname, + apr_hash_t *attributes); + + +/** Store an xml close tag @a tagname in @a str. + * + * If @a *str is @c NULL, set @a *str to a new stringbuf allocated + * in @a pool, else append to the existing stringbuf there. + */ +void +svn_xml_make_close_tag(svn_stringbuf_t **str, + apr_pool_t *pool, + const char *tagname); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_XML_H */ diff --git a/src/TortoiseMerge/libsvn_diff/token.c b/src/TortoiseMerge/libsvn_diff/token.c index 47e7963..07ab5d1 100644 --- a/src/TortoiseMerge/libsvn_diff/token.c +++ b/src/TortoiseMerge/libsvn_diff/token.c @@ -20,6 +20,9 @@ #include #include #include +#include "svn_error.h" +#include "svn_version.h" +#include "svn_io.h" #include "diff.h" diff --git a/src/TortoiseMerge/libsvn_diff/trees.c b/src/TortoiseMerge/libsvn_diff/trees.c new file mode 100644 index 0000000..aa75265 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/trees.c @@ -0,0 +1,1214 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2002 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id: trees.c,v 1.1 2003/05/23 21:05:30 steveking Exp $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +#define MAX(a,b) (a >= b ? a : b) +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute first the block length in bytes*/ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/src/TortoiseMerge/libsvn_diff/trees.h b/src/TortoiseMerge/libsvn_diff/trees.h new file mode 100644 index 0000000..1ca868b --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/src/TortoiseMerge/libsvn_diff/uncompr.c b/src/TortoiseMerge/libsvn_diff/uncompr.c new file mode 100644 index 0000000..909ad2a --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/uncompr.c @@ -0,0 +1,58 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: uncompr.c,v 1.1 2003/05/23 21:05:30 steveking Exp $ */ + +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/src/TortoiseMerge/libsvn_diff/unzip.c b/src/TortoiseMerge/libsvn_diff/unzip.c new file mode 100644 index 0000000..67c123f --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/unzip.c @@ -0,0 +1,1294 @@ +/* unzip.c -- IO on .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Read unzip.h for more info +*/ + + +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +const char unz_copyright[] = + " unzip 0.15 Copyright 1998 Gilles Vollant "; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + FILE* file; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + FILE* file; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ +} unz_s; + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unzlocal_getByte(fin,pi) + FILE *fin; + int *pi; +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unzlocal_getShort (fin,pX) + FILE* fin; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unzlocal_getLong (fin,pX) + FILE* fin; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (fileName1,fileName2) + const char* fileName1; + const char* fileName2; +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) + const char* fileName1; + const char* fileName2; + int iCaseSensitivity; +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong unzlocal_SearchCentralDir(fin) + FILE *fin; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen (path) + const char *path; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo (file, + pfile_info, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) + unzFile file; + const char *szFileName; + int iCaseSensitivity; +{ + unz_s* s; + int err; + + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (file, buf, len) + unzFile file; + voidp buf; + unsigned len; +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ + int err=UNZ_OK; + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} diff --git a/src/TortoiseMerge/libsvn_diff/unzip.h b/src/TortoiseMerge/libsvn_diff/unzip.h new file mode 100644 index 0000000..5692cc8 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/unzip.h @@ -0,0 +1,275 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */ diff --git a/src/TortoiseMerge/libsvn_diff/utf.c b/src/TortoiseMerge/libsvn_diff/utf.c new file mode 100644 index 0000000..e7a3d8d --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/utf.c @@ -0,0 +1,957 @@ +/* + * utf.c: UTF-8 conversion routines + * + * ==================================================================== + * Copyright (c) 2000-2007, 2009 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + + + +#include +#include + +#include +#include +#include + +#include "svn_string.h" +#include "svn_error.h" +#include "svn_pools.h" +#include "svn_ctype.h" +#include "svn_utf.h" +//#include "svn_private_config.h" +#include "win32_xlate.h" + +#include "svn_utf_private.h" + + + +#define SVN_UTF_NTOU_XLATE_HANDLE "svn-utf-ntou-xlate-handle" +#define SVN_UTF_UTON_XLATE_HANDLE "svn-utf-uton-xlate-handle" +#define SVN_APR_UTF8_CHARSET "UTF-8" + +#if APR_HAS_THREADS +static apr_thread_mutex_t *xlate_handle_mutex = NULL; +#endif + +/* The xlate handle cache is a global hash table with linked lists of xlate + * handles. In multi-threaded environments, a thread "borrows" an xlate + * handle from the cache during a translation and puts it back afterwards. + * This avoids holding a global lock for all translations. + * If there is no handle for a particular key when needed, a new is + * handle is created and put in the cache after use. + * This means that there will be at most N handles open for a key, where N + * is the number of simultanous handles in use for that key. */ + +typedef struct xlate_handle_node_t { + apr_xlate_t *handle; + /* FALSE if the handle is not valid, since its pool is being + destroyed. */ + svn_boolean_t valid; + /* The name of a char encoding or APR_LOCALE_CHARSET. */ + const char *frompage, *topage; + struct xlate_handle_node_t *next; +} xlate_handle_node_t; + +/* This maps const char * userdata_key strings to xlate_handle_node_t ** + handles to the first entry in the linked list of xlate handles. We don't + store the pointer to the list head directly in the hash table, since we + remove/insert entries at the head in the list in the code below, and + we can't use apr_hash_set() in each character translation because that + function allocates memory in each call where the value is non-NULL. + Since these allocations take place in a global pool, this would be a + memory leak. */ +static apr_hash_t *xlate_handle_hash = NULL; + +/* Clean up the xlate handle cache. */ +static apr_status_t +xlate_cleanup(void *arg) +{ + /* We set the cache variables to NULL so that translation works in other + cleanup functions, even if it isn't cached then. */ +#if APR_HAS_THREADS + apr_thread_mutex_destroy(xlate_handle_mutex); + xlate_handle_mutex = NULL; +#endif + xlate_handle_hash = NULL; + + return APR_SUCCESS; +} + +/* Set the handle of ARG to NULL. */ +static apr_status_t +xlate_handle_node_cleanup(void *arg) +{ + xlate_handle_node_t *node = arg; + + node->valid = FALSE; + return APR_SUCCESS; +} + +void +svn_utf_initialize(apr_pool_t *pool) +{ + apr_pool_t *subpool; +#if APR_HAS_THREADS + apr_thread_mutex_t *mutex; +#endif + + if (!xlate_handle_hash) + { + /* We create our own subpool, which we protect with the mutex. + We can't use the pool passed to us by the caller, since we will + use it for xlate handle allocations, possibly in multiple threads, + and pool allocation is not thread-safe. */ + subpool = svn_pool_create(pool); +#if APR_HAS_THREADS + if (apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, subpool) + == APR_SUCCESS) + xlate_handle_mutex = mutex; + else + return; +#endif + + xlate_handle_hash = apr_hash_make(subpool); + apr_pool_cleanup_register(subpool, NULL, xlate_cleanup, + apr_pool_cleanup_null); + } +} + +/* Return a unique string key based on TOPAGE and FROMPAGE. TOPAGE and + * FROMPAGE can be any valid arguments of the same name to + * apr_xlate_open(). Allocate the returned string in POOL. */ +static const char* +get_xlate_key(const char *topage, + const char *frompage, + apr_pool_t *pool) +{ + /* In the cases of SVN_APR_LOCALE_CHARSET and SVN_APR_DEFAULT_CHARSET + * topage/frompage is really an int, not a valid string. So generate a + * unique key accordingly. */ + if (frompage == SVN_APR_LOCALE_CHARSET) + frompage = "APR_LOCALE_CHARSET"; + else if (frompage == SVN_APR_DEFAULT_CHARSET) + frompage = "APR_DEFAULT_CHARSET"; + + if (topage == SVN_APR_LOCALE_CHARSET) + topage = "APR_LOCALE_CHARSET"; + else if (topage == SVN_APR_DEFAULT_CHARSET) + topage = "APR_DEFAULT_CHARSET"; + + return apr_pstrcat(pool, "svn-utf-", frompage, "to", topage, + "-xlate-handle", NULL); +} + +/* Set *RET to a handle node for converting from FROMPAGE to TOPAGE, + creating the handle node if it doesn't exist in USERDATA_KEY. + If a node is not cached and apr_xlate_open() returns APR_EINVAL or + APR_ENOTIMPL, set (*RET)->handle to NULL. If fail for any other + reason, return the error. + + Allocate *RET and its xlate handle in POOL if svn_utf_initialize() + hasn't been called or USERDATA_KEY is NULL. Else, allocate them + in the pool of xlate_handle_hash. */ +static svn_error_t * +get_xlate_handle_node(xlate_handle_node_t **ret, + const char *topage, const char *frompage, + const char *userdata_key, apr_pool_t *pool) +{ + xlate_handle_node_t **old_node_p; + xlate_handle_node_t *old_node = NULL; + apr_status_t apr_err; + apr_xlate_t *handle; + svn_error_t *err = NULL; + + /* If we already have a handle, just return it. */ + if (userdata_key) + { + if (xlate_handle_hash) + { +#if APR_HAS_THREADS + apr_err = apr_thread_mutex_lock(xlate_handle_mutex); + if (apr_err != APR_SUCCESS) + return svn_error_create(apr_err, NULL, + _("Can't lock charset translation mutex")); +#endif + old_node_p = apr_hash_get(xlate_handle_hash, userdata_key, + APR_HASH_KEY_STRING); + if (old_node_p) + old_node = *old_node_p; + if (old_node) + { + /* Ensure that the handle is still valid. */ + if (old_node->valid) + { + /* Remove from the list. */ + *old_node_p = old_node->next; + old_node->next = NULL; +#if APR_HAS_THREADS + apr_err = apr_thread_mutex_unlock(xlate_handle_mutex); + if (apr_err != APR_SUCCESS) + return svn_error_create(apr_err, NULL, + _("Can't unlock charset " + "translation mutex")); +#endif + *ret = old_node; + return SVN_NO_ERROR; + } + } + } + else + { + void *p; + /* We fall back on a per-pool cache instead. */ + apr_pool_userdata_get(&p, userdata_key, pool); + old_node = p; + /* Ensure that the handle is still valid. */ + if (old_node && old_node->valid) + { + *ret = old_node; + return SVN_NO_ERROR; + } + } + } + + /* Note that we still have the mutex locked (if it is initialized), so we + can use the global pool for creating the new xlate handle. */ + + /* The error handling doesn't support the following cases, since we don't + use them currently. Catch this here. */ + SVN_ERR_ASSERT(frompage != SVN_APR_DEFAULT_CHARSET + && topage != SVN_APR_DEFAULT_CHARSET + && (frompage != SVN_APR_LOCALE_CHARSET + || topage != SVN_APR_LOCALE_CHARSET)); + + /* Use the correct pool for creating the handle. */ + if (userdata_key && xlate_handle_hash) + pool = apr_hash_pool_get(xlate_handle_hash); + + /* Try to create a handle. */ +#if defined(WIN32) + apr_err = svn_subr__win32_xlate_open((win32_xlate_t **)&handle, topage, + frompage, pool); +#else + apr_err = apr_xlate_open(&handle, topage, frompage, pool); +#endif + + if (APR_STATUS_IS_EINVAL(apr_err) || APR_STATUS_IS_ENOTIMPL(apr_err)) + handle = NULL; + else if (apr_err != APR_SUCCESS) + { + const char *errstr; + /* Can't use svn_error_wrap_apr here because it calls functions in + this file, leading to infinite recursion. */ + if (frompage == SVN_APR_LOCALE_CHARSET) + errstr = apr_psprintf(pool, + _("Can't create a character converter from " + "native encoding to '%s'"), topage); + else if (topage == SVN_APR_LOCALE_CHARSET) + errstr = apr_psprintf(pool, + _("Can't create a character converter from " + "'%s' to native encoding"), frompage); + else + errstr = apr_psprintf(pool, + _("Can't create a character converter from " + "'%s' to '%s'"), frompage, topage); + + err = svn_error_create(apr_err, NULL, errstr); + goto cleanup; + } + + /* Allocate and initialize the node. */ + *ret = apr_palloc(pool, sizeof(xlate_handle_node_t)); + (*ret)->handle = handle; + (*ret)->valid = TRUE; + (*ret)->frompage = ((frompage != SVN_APR_LOCALE_CHARSET) + ? apr_pstrdup(pool, frompage) : frompage); + (*ret)->topage = ((topage != SVN_APR_LOCALE_CHARSET) + ? apr_pstrdup(pool, topage) : topage); + (*ret)->next = NULL; + + /* If we are called from inside a pool cleanup handler, the just created + xlate handle will be closed when that handler returns by a newly + registered cleanup handler, however, the handle is still cached by us. + To prevent this, we register a cleanup handler that will reset the valid + flag of our node, so we don't use an invalid handle. */ + if (handle) + apr_pool_cleanup_register(pool, *ret, xlate_handle_node_cleanup, + apr_pool_cleanup_null); + + cleanup: + /* Don't need the lock anymore. */ +#if APR_HAS_THREADS + if (userdata_key && xlate_handle_hash) + { + apr_status_t unlock_err = apr_thread_mutex_unlock(xlate_handle_mutex); + if (unlock_err != APR_SUCCESS) + return svn_error_create(unlock_err, NULL, + _("Can't unlock charset translation mutex")); + } +#endif + + return err; +} + +/* Put back NODE into the xlate handle cache for use by other calls. + If there is no global cache, store the handle in POOL. + Ignore errors related to locking/unlocking the mutex. + ### Mutex errors here are very weird. Should we handle them "correctly" + ### even if that complicates error handling in the routines below? */ +static void +put_xlate_handle_node(xlate_handle_node_t *node, + const char *userdata_key, + apr_pool_t *pool) +{ + assert(node->next == NULL); + if (!userdata_key) + return; + if (xlate_handle_hash) + { + xlate_handle_node_t **node_p; +#if APR_HAS_THREADS + if (apr_thread_mutex_lock(xlate_handle_mutex) != APR_SUCCESS) + SVN_ERR_MALFUNCTION_NO_RETURN(); +#endif + node_p = apr_hash_get(xlate_handle_hash, userdata_key, + APR_HASH_KEY_STRING); + if (node_p == NULL) + { + userdata_key = apr_pstrdup(apr_hash_pool_get(xlate_handle_hash), + userdata_key); + node_p = apr_palloc(apr_hash_pool_get(xlate_handle_hash), + sizeof(*node_p)); + *node_p = NULL; + apr_hash_set(xlate_handle_hash, userdata_key, + APR_HASH_KEY_STRING, node_p); + } + node->next = *node_p; + *node_p = node; +#if APR_HAS_THREADS + if (apr_thread_mutex_unlock(xlate_handle_mutex) != APR_SUCCESS) + SVN_ERR_MALFUNCTION_NO_RETURN(); +#endif + } + else + { + /* Store it in the per-pool cache. */ + apr_pool_userdata_set(node, userdata_key, apr_pool_cleanup_null, pool); + } +} + +/* Return the apr_xlate handle for converting native characters to UTF-8. */ +static svn_error_t * +get_ntou_xlate_handle_node(xlate_handle_node_t **ret, apr_pool_t *pool) +{ + return get_xlate_handle_node(ret, SVN_APR_UTF8_CHARSET, + SVN_APR_LOCALE_CHARSET, + SVN_UTF_NTOU_XLATE_HANDLE, pool); +} + + +/* Return the apr_xlate handle for converting UTF-8 to native characters. + Create one if it doesn't exist. If unable to find a handle, or + unable to create one because apr_xlate_open returned APR_EINVAL, then + set *RET to null and return SVN_NO_ERROR; if fail for some other + reason, return error. */ +static svn_error_t * +get_uton_xlate_handle_node(xlate_handle_node_t **ret, apr_pool_t *pool) +{ + return get_xlate_handle_node(ret, SVN_APR_LOCALE_CHARSET, + SVN_APR_UTF8_CHARSET, + SVN_UTF_UTON_XLATE_HANDLE, pool); +} + + +/* Copy LEN bytes of SRC, converting non-ASCII and zero bytes to ?\nnn + sequences, allocating the result in POOL. */ +static const char * +fuzzy_escape(const char *src, apr_size_t len, apr_pool_t *pool) +{ + const char *src_orig = src, *src_end = src + len; + apr_size_t new_len = 0; + char *new; + const char *new_orig; + + /* First count how big a dest string we'll need. */ + while (src < src_end) + { + if (! svn_ctype_isascii(*src) || *src == '\0') + new_len += 5; /* 5 slots, for "?\XXX" */ + else + new_len += 1; /* one slot for the 7-bit char */ + + src++; + } + + /* Allocate that amount. */ + new = apr_palloc(pool, new_len + 1); + + new_orig = new; + + /* And fill it up. */ + while (src_orig < src_end) + { + if (! svn_ctype_isascii(*src_orig) || src_orig == '\0') + { + /* This is the same format as svn_xml_fuzzy_escape uses, but that + function escapes different characters. Please keep in sync! + ### If we add another fuzzy escape somewhere, we should abstract + ### this out to a common function. */ + sprintf(new, "?\\%03u", (unsigned char) *src_orig); + new += 5; + } + else + { + *new = *src_orig; + new += 1; + } + + src_orig++; + } + + *new = '\0'; + + return new_orig; +} + +/* Convert SRC_LENGTH bytes of SRC_DATA in NODE->handle, store the result + in *DEST, which is allocated in POOL. */ +static svn_error_t * +convert_to_stringbuf(xlate_handle_node_t *node, + const char *src_data, + apr_size_t src_length, + svn_stringbuf_t **dest, + apr_pool_t *pool) +{ +#ifdef WIN32 + apr_status_t apr_err; + + apr_err = svn_subr__win32_xlate_to_stringbuf((win32_xlate_t *) node->handle, + src_data, src_length, + dest, pool); +#else + apr_size_t buflen = src_length * 2; + apr_status_t apr_err; + apr_size_t srclen = src_length; + apr_size_t destlen = buflen; + char *destbuf; + + /* Initialize *DEST to an empty stringbuf. + A 1:2 ratio of input bytes to output bytes (as assigned above) + should be enough for most translations, and if it turns out not + to be enough, we'll grow the buffer again, sizing it based on a + 1:3 ratio of the remainder of the string. */ + *dest = svn_stringbuf_create_ensure(buflen + 1, pool); + destbuf = (*dest)->data; + + /* Not only does it not make sense to convert an empty string, but + apr-iconv is quite unreasonable about not allowing that. */ + if (src_length == 0) + return SVN_NO_ERROR; + + do + { + /* Set up state variables for xlate. */ + destlen = buflen - (*dest)->len; + + /* Attempt the conversion. */ + apr_err = apr_xlate_conv_buffer(node->handle, + src_data + (src_length - srclen), + &srclen, + (*dest)->data + (*dest)->len, + &destlen); + + /* Now, update the *DEST->len to track the amount of output data + churned out so far from this loop. */ + (*dest)->len += ((buflen - (*dest)->len) - destlen); + buflen += srclen * 3; /* 3 is middle ground, 2 wasn't enough + for all characters in the buffer, 4 is + maximum character size (currently) */ + + + } while (apr_err == APR_SUCCESS && srclen != 0); +#endif + + /* If we exited the loop with an error, return the error. */ + if (apr_err) + { + const char *errstr; + svn_error_t *err; + + /* Can't use svn_error_wrap_apr here because it calls functions in + this file, leading to infinite recursion. */ + if (node->frompage == SVN_APR_LOCALE_CHARSET) + errstr = apr_psprintf + (pool, _("Can't convert string from native encoding to '%s':"), + node->topage); + else if (node->topage == SVN_APR_LOCALE_CHARSET) + errstr = apr_psprintf + (pool, _("Can't convert string from '%s' to native encoding:"), + node->frompage); + else + errstr = apr_psprintf + (pool, _("Can't convert string from '%s' to '%s':"), + node->frompage, node->topage); + + err = svn_error_create(apr_err, NULL, fuzzy_escape(src_data, + src_length, pool)); + return svn_error_create(apr_err, err, errstr); + } + /* Else, exited due to success. Trim the result buffer down to the + right length. */ + (*dest)->data[(*dest)->len] = '\0'; + + return SVN_NO_ERROR; +} + + +/* Return APR_EINVAL if the first LEN bytes of DATA contain anything + other than seven-bit, non-control (except for whitespace) ASCII + characters, finding the error pool from POOL. Otherwise, return + SVN_NO_ERROR. */ +static svn_error_t * +check_non_ascii(const char *data, apr_size_t len, apr_pool_t *pool) +{ + const char *data_start = data; + + for (; len > 0; --len, data++) + { + if ((! apr_isascii(*data)) + || ((! apr_isspace(*data)) + && apr_iscntrl(*data))) + { + /* Show the printable part of the data, followed by the + decimal code of the questionable character. Because if a + user ever gets this error, she's going to have to spend + time tracking down the non-ASCII data, so we want to help + as much as possible. And yes, we just call the unsafe + data "non-ASCII", even though the actual constraint is + somewhat more complex than that. */ + + if (data - data_start) + { + const char *error_data + = apr_pstrndup(pool, data_start, (data - data_start)); + + return svn_error_createf + (APR_EINVAL, NULL, + _("Safe data '%s' was followed by non-ASCII byte %d: " + "unable to convert to/from UTF-8"), + error_data, *((const unsigned char *) data)); + } + else + { + return svn_error_createf + (APR_EINVAL, NULL, + _("Non-ASCII character (code %d) detected, " + "and unable to convert to/from UTF-8"), + *((const unsigned char *) data)); + } + } + } + + return SVN_NO_ERROR; +} + +/* Construct an error with code APR_EINVAL and with a suitable message + * to describe the invalid UTF-8 sequence DATA of length LEN (which + * may have embedded NULLs). We can't simply print the data, almost + * by definition we don't really know how it is encoded. + */ +static svn_error_t * +invalid_utf8(const char *data, apr_size_t len, apr_pool_t *pool) +{ + const char *last = svn_utf__last_valid(data, len); + const char *valid_txt = "", *invalid_txt = ""; + int i, valid, invalid; + + /* We will display at most 24 valid octets (this may split a leading + multi-byte character) as that should fit on one 80 character line. */ + valid = last - data; + if (valid > 24) + valid = 24; + for (i = 0; i < valid; ++i) + valid_txt = apr_pstrcat(pool, valid_txt, + apr_psprintf(pool, " %02x", + (unsigned char)last[i-valid]), NULL); + + /* 4 invalid octets will guarantee that the faulty octet is displayed */ + invalid = data + len - last; + if (invalid > 4) + invalid = 4; + for (i = 0; i < invalid; ++i) + invalid_txt = apr_pstrcat(pool, invalid_txt, + apr_psprintf(pool, " %02x", + (unsigned char)last[i]), NULL); + + return svn_error_createf(APR_EINVAL, NULL, + _("Valid UTF-8 data\n(hex:%s)\n" + "followed by invalid UTF-8 sequence\n(hex:%s)"), + valid_txt, invalid_txt); +} + +/* Verify that the sequence DATA of length LEN is valid UTF-8. + If it is not, return an error with code APR_EINVAL. */ +static svn_error_t * +check_utf8(const char *data, apr_size_t len, apr_pool_t *pool) +{ + if (! svn_utf__is_valid(data, len)) + return invalid_utf8(data, len, pool); + return SVN_NO_ERROR; +} + +/* Verify that the NULL terminated sequence DATA is valid UTF-8. + If it is not, return an error with code APR_EINVAL. */ +static svn_error_t * +check_cstring_utf8(const char *data, apr_pool_t *pool) +{ + + if (! svn_utf__cstring_is_valid(data)) + return invalid_utf8(data, strlen(data), pool); + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_utf_stringbuf_to_utf8(svn_stringbuf_t **dest, + const svn_stringbuf_t *src, + apr_pool_t *pool) +{ + xlate_handle_node_t *node; + svn_error_t *err; + + SVN_ERR(get_ntou_xlate_handle_node(&node, pool)); + + if (node->handle) + { + err = convert_to_stringbuf(node, src->data, src->len, dest, pool); + if (! err) + err = check_utf8((*dest)->data, (*dest)->len, pool); + } + else + { + err = check_non_ascii(src->data, src->len, pool); + if (! err) + *dest = svn_stringbuf_dup(src, pool); + } + + put_xlate_handle_node(node, SVN_UTF_NTOU_XLATE_HANDLE, pool); + + return err; +} + + +svn_error_t * +svn_utf_string_to_utf8(const svn_string_t **dest, + const svn_string_t *src, + apr_pool_t *pool) +{ + svn_stringbuf_t *destbuf; + xlate_handle_node_t *node; + svn_error_t *err; + + SVN_ERR(get_ntou_xlate_handle_node(&node, pool)); + + if (node->handle) + { + err = convert_to_stringbuf(node, src->data, src->len, &destbuf, pool); + if (! err) + err = check_utf8(destbuf->data, destbuf->len, pool); + if (! err) + *dest = svn_string_create_from_buf(destbuf, pool); + } + else + { + err = check_non_ascii(src->data, src->len, pool); + if (! err) + *dest = svn_string_dup(src, pool); + } + + put_xlate_handle_node(node, SVN_UTF_NTOU_XLATE_HANDLE, pool); + + return err; +} + + +/* Common implementation for svn_utf_cstring_to_utf8, + svn_utf_cstring_to_utf8_ex, svn_utf_cstring_from_utf8 and + svn_utf_cstring_from_utf8_ex. Convert SRC to DEST using NODE->handle as + the translator and allocating from POOL. */ +static svn_error_t * +convert_cstring(const char **dest, + const char *src, + xlate_handle_node_t *node, + apr_pool_t *pool) +{ + if (node->handle) + { + svn_stringbuf_t *destbuf; + SVN_ERR(convert_to_stringbuf(node, src, strlen(src), + &destbuf, pool)); + *dest = destbuf->data; + } + else + { + apr_size_t len = strlen(src); + SVN_ERR(check_non_ascii(src, len, pool)); + *dest = apr_pstrmemdup(pool, src, len); + } + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_utf_cstring_to_utf8(const char **dest, + const char *src, + apr_pool_t *pool) +{ + xlate_handle_node_t *node; + svn_error_t *err; + + SVN_ERR(get_ntou_xlate_handle_node(&node, pool)); + err = convert_cstring(dest, src, node, pool); + put_xlate_handle_node(node, SVN_UTF_NTOU_XLATE_HANDLE, pool); + SVN_ERR(err); + return check_cstring_utf8(*dest, pool); +} + + +svn_error_t * +svn_utf_cstring_to_utf8_ex2(const char **dest, + const char *src, + const char *frompage, + apr_pool_t *pool) +{ + xlate_handle_node_t *node; + svn_error_t *err; + const char *convset_key = get_xlate_key(SVN_APR_UTF8_CHARSET, frompage, + pool); + + SVN_ERR(get_xlate_handle_node(&node, SVN_APR_UTF8_CHARSET, frompage, + convset_key, pool)); + err = convert_cstring(dest, src, node, pool); + put_xlate_handle_node(node, convset_key, pool); + SVN_ERR(err); + return check_cstring_utf8(*dest, pool); +} + + +svn_error_t * +svn_utf_cstring_to_utf8_ex(const char **dest, + const char *src, + const char *frompage, + const char *convset_key, + apr_pool_t *pool) +{ + return svn_utf_cstring_to_utf8_ex2(dest, src, frompage, pool); +} + + +svn_error_t * +svn_utf_stringbuf_from_utf8(svn_stringbuf_t **dest, + const svn_stringbuf_t *src, + apr_pool_t *pool) +{ + xlate_handle_node_t *node; + svn_error_t *err; + + SVN_ERR(get_uton_xlate_handle_node(&node, pool)); + + if (node->handle) + { + err = check_utf8(src->data, src->len, pool); + if (! err) + err = convert_to_stringbuf(node, src->data, src->len, dest, pool); + } + else + { + err = check_non_ascii(src->data, src->len, pool); + if (! err) + *dest = svn_stringbuf_dup(src, pool); + } + + put_xlate_handle_node(node, SVN_UTF_UTON_XLATE_HANDLE, pool); + + return err; +} + + +svn_error_t * +svn_utf_string_from_utf8(const svn_string_t **dest, + const svn_string_t *src, + apr_pool_t *pool) +{ + svn_stringbuf_t *dbuf; + xlate_handle_node_t *node; + svn_error_t *err; + + SVN_ERR(get_uton_xlate_handle_node(&node, pool)); + + if (node->handle) + { + err = check_utf8(src->data, src->len, pool); + if (! err) + err = convert_to_stringbuf(node, src->data, src->len, + &dbuf, pool); + if (! err) + *dest = svn_string_create_from_buf(dbuf, pool); + } + else + { + err = check_non_ascii(src->data, src->len, pool); + if (! err) + *dest = svn_string_dup(src, pool); + } + + put_xlate_handle_node(node, SVN_UTF_UTON_XLATE_HANDLE, pool); + + return err; +} + + +svn_error_t * +svn_utf_cstring_from_utf8(const char **dest, + const char *src, + apr_pool_t *pool) +{ + xlate_handle_node_t *node; + svn_error_t *err; + + SVN_ERR(check_utf8(src, strlen(src), pool)); + + SVN_ERR(get_uton_xlate_handle_node(&node, pool)); + err = convert_cstring(dest, src, node, pool); + put_xlate_handle_node(node, SVN_UTF_UTON_XLATE_HANDLE, pool); + + return err; +} + + +svn_error_t * +svn_utf_cstring_from_utf8_ex2(const char **dest, + const char *src, + const char *topage, + apr_pool_t *pool) +{ + xlate_handle_node_t *node; + svn_error_t *err; + const char *convset_key = get_xlate_key(topage, SVN_APR_UTF8_CHARSET, + pool); + + SVN_ERR(check_utf8(src, strlen(src), pool)); + + SVN_ERR(get_xlate_handle_node(&node, topage, SVN_APR_UTF8_CHARSET, + convset_key, pool)); + err = convert_cstring(dest, src, node, pool); + put_xlate_handle_node(node, convset_key, pool); + + return err; +} + + +svn_error_t * +svn_utf_cstring_from_utf8_ex(const char **dest, + const char *src, + const char *topage, + const char *convset_key, + apr_pool_t *pool) +{ + return svn_utf_cstring_from_utf8_ex2(dest, src, topage, pool); +} + + +const char * +svn_utf__cstring_from_utf8_fuzzy(const char *src, + apr_pool_t *pool, + svn_error_t *(*convert_from_utf8) + (const char **, const char *, apr_pool_t *)) +{ + const char *escaped, *converted; + svn_error_t *err; + + escaped = fuzzy_escape(src, strlen(src), pool); + + /* Okay, now we have a *new* UTF-8 string, one that's guaranteed to + contain only 7-bit bytes :-). Recode to native... */ + err = convert_from_utf8(((const char **) &converted), escaped, pool); + + if (err) + { + svn_error_clear(err); + return escaped; + } + else + return converted; + + /* ### Check the client locale, maybe we can avoid that second + * conversion! See Ulrich Drepper's patch at + * http://subversion.tigris.org/issues/show_bug.cgi?id=807. + */ +} + + +const char * +svn_utf_cstring_from_utf8_fuzzy(const char *src, + apr_pool_t *pool) +{ + return svn_utf__cstring_from_utf8_fuzzy(src, pool, + svn_utf_cstring_from_utf8); +} + + +svn_error_t * +svn_utf_cstring_from_utf8_stringbuf(const char **dest, + const svn_stringbuf_t *src, + apr_pool_t *pool) +{ + svn_stringbuf_t *destbuf; + + SVN_ERR(svn_utf_stringbuf_from_utf8(&destbuf, src, pool)); + *dest = destbuf->data; + + return SVN_NO_ERROR; +} + + +svn_error_t * +svn_utf_cstring_from_utf8_string(const char **dest, + const svn_string_t *src, + apr_pool_t *pool) +{ + svn_stringbuf_t *dbuf; + xlate_handle_node_t *node; + svn_error_t *err; + + SVN_ERR(get_uton_xlate_handle_node(&node, pool)); + + if (node->handle) + { + err = check_utf8(src->data, src->len, pool); + if (! err) + err = convert_to_stringbuf(node, src->data, src->len, + &dbuf, pool); + if (! err) + *dest = dbuf->data; + } + else + { + err = check_non_ascii(src->data, src->len, pool); + if (! err) + *dest = apr_pstrmemdup(pool, src->data, src->len); + } + + put_xlate_handle_node(node, SVN_UTF_UTON_XLATE_HANDLE, pool); + + return err; +} diff --git a/src/TortoiseMerge/libsvn_diff/utf_validate.c b/src/TortoiseMerge/libsvn_diff/utf_validate.c new file mode 100644 index 0000000..ab92fad --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/utf_validate.c @@ -0,0 +1,375 @@ +/* + * utf_validate.c: Validate a UTF-8 string + * + * ==================================================================== + * Copyright (c) 2004, 2009 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + +/* Validate a UTF-8 string according to the rules in + * + * Table 3-6. Well-Formed UTF-8 Bytes Sequences + * + * in + * + * The Unicode Standard, Version 4.0 + * + * which is available at + * + * http://www.unicode.org/ + * + * UTF-8 was originally defined in RFC-2279, Unicode's "well-formed UTF-8" + * is a subset of that enconding. The Unicode enconding prohibits things + * like non-shortest encodings (some characters can be represented by more + * than one multi-byte encoding) and the encodings for the surrogate code + * points. RFC-3629 superceeds RFC-2279 and adopts the same well-formed + * rules as Unicode. This is the ABNF in RFC-3629 that describes + * well-formed UTF-8 rules: + * + * UTF8-octets = *( UTF8-char ) + * UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4 + * UTF8-1 = %x00-7F + * UTF8-2 = %xC2-DF UTF8-tail + * UTF8-3 = %xE0 %xA0-BF UTF8-tail / + * %xE1-EC 2( UTF8-tail ) / + * %xED %x80-9F UTF8-tail / + * %xEE-EF 2( UTF8-tail ) + * UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / + * %xF1-F3 3( UTF8-tail ) / + * %xF4 %x80-8F 2( UTF8-tail ) + * UTF8-tail = %x80-BF + * + */ + +#include "svn_utf_private.h" + +/* Lookup table to categorise each octet in the string. */ +static const char octet_category[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x7f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80-0x8f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x90-0x9f */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xa0-0xbf */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, /* 0xc0-0xc1 */ + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* 0xc2-0xdf */ + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, /* 0xe0 */ + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* 0xe1-0xec */ + 8, /* 0xed */ + 9, 9, /* 0xee-0xef */ + 10, /* 0xf0 */ + 11, 11, 11, /* 0xf1-0xf3 */ + 12, /* 0xf4 */ + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 /* 0xf5-0xff */ +}; + +/* Machine states */ +#define FSM_START 0 +#define FSM_80BF 1 +#define FSM_A0BF 2 +#define FSM_80BF80BF 3 +#define FSM_809F 4 +#define FSM_90BF 5 +#define FSM_80BF80BF80BF 6 +#define FSM_808F 7 +#define FSM_ERROR 8 + +/* In the FSM it appears that categories 0xc0-0xc1 and 0xf5-0xff make the + same transitions, as do categories 0xe1-0xec and 0xee-0xef. I wonder if + there is any great benefit in combining categories? It would reduce the + memory footprint of the transition table by 16 bytes, but might it be + harder to understand? */ + +/* Machine transition table */ +static const char machine [9][14] = { + /* FSM_START */ + {FSM_START, /* 0x00-0x7f */ + FSM_ERROR, /* 0x80-0x8f */ + FSM_ERROR, /* 0x90-0x9f */ + FSM_ERROR, /* 0xa0-0xbf */ + FSM_ERROR, /* 0xc0-0xc1 */ + FSM_80BF, /* 0xc2-0xdf */ + FSM_A0BF, /* 0xe0 */ + FSM_80BF80BF, /* 0xe1-0xec */ + FSM_809F, /* 0xed */ + FSM_80BF80BF, /* 0xee-0xef */ + FSM_90BF, /* 0xf0 */ + FSM_80BF80BF80BF, /* 0xf1-0xf3 */ + FSM_808F, /* 0xf4 */ + FSM_ERROR}, /* 0xf5-0xff */ + + /* FSM_80BF */ + {FSM_ERROR, /* 0x00-0x7f */ + FSM_START, /* 0x80-0x8f */ + FSM_START, /* 0x90-0x9f */ + FSM_START, /* 0xa0-0xbf */ + FSM_ERROR, /* 0xc0-0xc1 */ + FSM_ERROR, /* 0xc2-0xdf */ + FSM_ERROR, /* 0xe0 */ + FSM_ERROR, /* 0xe1-0xec */ + FSM_ERROR, /* 0xed */ + FSM_ERROR, /* 0xee-0xef */ + FSM_ERROR, /* 0xf0 */ + FSM_ERROR, /* 0xf1-0xf3 */ + FSM_ERROR, /* 0xf4 */ + FSM_ERROR}, /* 0xf5-0xff */ + + /* FSM_A0BF */ + {FSM_ERROR, /* 0x00-0x7f */ + FSM_ERROR, /* 0x80-0x8f */ + FSM_ERROR, /* 0x90-0x9f */ + FSM_80BF, /* 0xa0-0xbf */ + FSM_ERROR, /* 0xc0-0xc1 */ + FSM_ERROR, /* 0xc2-0xdf */ + FSM_ERROR, /* 0xe0 */ + FSM_ERROR, /* 0xe1-0xec */ + FSM_ERROR, /* 0xed */ + FSM_ERROR, /* 0xee-0xef */ + FSM_ERROR, /* 0xf0 */ + FSM_ERROR, /* 0xf1-0xf3 */ + FSM_ERROR, /* 0xf4 */ + FSM_ERROR}, /* 0xf5-0xff */ + + /* FSM_80BF80BF */ + {FSM_ERROR, /* 0x00-0x7f */ + FSM_80BF, /* 0x80-0x8f */ + FSM_80BF, /* 0x90-0x9f */ + FSM_80BF, /* 0xa0-0xbf */ + FSM_ERROR, /* 0xc0-0xc1 */ + FSM_ERROR, /* 0xc2-0xdf */ + FSM_ERROR, /* 0xe0 */ + FSM_ERROR, /* 0xe1-0xec */ + FSM_ERROR, /* 0xed */ + FSM_ERROR, /* 0xee-0xef */ + FSM_ERROR, /* 0xf0 */ + FSM_ERROR, /* 0xf1-0xf3 */ + FSM_ERROR, /* 0xf4 */ + FSM_ERROR}, /* 0xf5-0xff */ + + /* FSM_809F */ + {FSM_ERROR, /* 0x00-0x7f */ + FSM_80BF, /* 0x80-0x8f */ + FSM_80BF, /* 0x90-0x9f */ + FSM_ERROR, /* 0xa0-0xbf */ + FSM_ERROR, /* 0xc0-0xc1 */ + FSM_ERROR, /* 0xc2-0xdf */ + FSM_ERROR, /* 0xe0 */ + FSM_ERROR, /* 0xe1-0xec */ + FSM_ERROR, /* 0xed */ + FSM_ERROR, /* 0xee-0xef */ + FSM_ERROR, /* 0xf0 */ + FSM_ERROR, /* 0xf1-0xf3 */ + FSM_ERROR, /* 0xf4 */ + FSM_ERROR}, /* 0xf5-0xff */ + + /* FSM_90BF */ + {FSM_ERROR, /* 0x00-0x7f */ + FSM_ERROR, /* 0x80-0x8f */ + FSM_80BF80BF, /* 0x90-0x9f */ + FSM_80BF80BF, /* 0xa0-0xbf */ + FSM_ERROR, /* 0xc0-0xc1 */ + FSM_ERROR, /* 0xc2-0xdf */ + FSM_ERROR, /* 0xe0 */ + FSM_ERROR, /* 0xe1-0xec */ + FSM_ERROR, /* 0xed */ + FSM_ERROR, /* 0xee-0xef */ + FSM_ERROR, /* 0xf0 */ + FSM_ERROR, /* 0xf1-0xf3 */ + FSM_ERROR, /* 0xf4 */ + FSM_ERROR}, /* 0xf5-0xff */ + + /* FSM_80BF80BF80BF */ + {FSM_ERROR, /* 0x00-0x7f */ + FSM_80BF80BF, /* 0x80-0x8f */ + FSM_80BF80BF, /* 0x90-0x9f */ + FSM_80BF80BF, /* 0xa0-0xbf */ + FSM_ERROR, /* 0xc0-0xc1 */ + FSM_ERROR, /* 0xc2-0xdf */ + FSM_ERROR, /* 0xe0 */ + FSM_ERROR, /* 0xe1-0xec */ + FSM_ERROR, /* 0xed */ + FSM_ERROR, /* 0xee-0xef */ + FSM_ERROR, /* 0xf0 */ + FSM_ERROR, /* 0xf1-0xf3 */ + FSM_ERROR, /* 0xf4 */ + FSM_ERROR}, /* 0xf5-0xff */ + + /* FSM_808F */ + {FSM_ERROR, /* 0x00-0x7f */ + FSM_80BF80BF, /* 0x80-0x8f */ + FSM_ERROR, /* 0x90-0x9f */ + FSM_ERROR, /* 0xa0-0xbf */ + FSM_ERROR, /* 0xc0-0xc1 */ + FSM_ERROR, /* 0xc2-0xdf */ + FSM_ERROR, /* 0xe0 */ + FSM_ERROR, /* 0xe1-0xec */ + FSM_ERROR, /* 0xed */ + FSM_ERROR, /* 0xee-0xef */ + FSM_ERROR, /* 0xf0 */ + FSM_ERROR, /* 0xf1-0xf3 */ + FSM_ERROR, /* 0xf4 */ + FSM_ERROR}, /* 0xf5-0xff */ + + /* FSM_ERROR */ + {FSM_ERROR, /* 0x00-0x7f */ + FSM_ERROR, /* 0x80-0x8f */ + FSM_ERROR, /* 0x90-0x9f */ + FSM_ERROR, /* 0xa0-0xbf */ + FSM_ERROR, /* 0xc0-0xc1 */ + FSM_ERROR, /* 0xc2-0xdf */ + FSM_ERROR, /* 0xe0 */ + FSM_ERROR, /* 0xe1-0xec */ + FSM_ERROR, /* 0xed */ + FSM_ERROR, /* 0xee-0xef */ + FSM_ERROR, /* 0xf0 */ + FSM_ERROR, /* 0xf1-0xf3 */ + FSM_ERROR, /* 0xf4 */ + FSM_ERROR}, /* 0xf5-0xff */ +}; + + +const char * +svn_utf__last_valid(const char *data, apr_size_t len) +{ + const char *start = data, *end = data + len; + int state = FSM_START; + while (data < end) + { + unsigned char octet = *data++; + int category = octet_category[octet]; + state = machine[state][category]; + if (state == FSM_START) + start = data; + } + return start; +} + +svn_boolean_t +svn_utf__cstring_is_valid(const char *data) +{ + int state = FSM_START; + while (*data) + { + unsigned char octet = *data++; + int category = octet_category[octet]; + state = machine[state][category]; + } + return state == FSM_START; +} + +svn_boolean_t +svn_utf__is_valid(const char *data, apr_size_t len) +{ + const char *end = data + len; + int state = FSM_START; + while (data < end) + { + unsigned char octet = *data++; + int category = octet_category[octet]; + state = machine[state][category]; + } + return state == FSM_START; +} + +const char * +svn_utf__last_valid2(const char *data, apr_size_t len) +{ + const char *start = data, *end = data + len; + int state = FSM_START; + while (data < end) + { + unsigned char octet = *data++; + switch (state) + { + case FSM_START: + if (octet <= 0x7F) + break; + else if (octet <= 0xC1) + state = FSM_ERROR; + else if (octet <= 0xDF) + state = FSM_80BF; + else if (octet == 0xE0) + state = FSM_A0BF; + else if (octet <= 0xEC) + state = FSM_80BF80BF; + else if (octet == 0xED) + state = FSM_809F; + else if (octet <= 0xEF) + state = FSM_80BF80BF; + else if (octet == 0xF0) + state = FSM_90BF; + else if (octet <= 0xF3) + state = FSM_80BF80BF80BF; + else if (octet <= 0xF4) + state = FSM_808F; + else + state = FSM_ERROR; + break; + case FSM_80BF: + if (octet >= 0x80 && octet <= 0xBF) + state = FSM_START; + else + state = FSM_ERROR; + break; + case FSM_A0BF: + if (octet >= 0xA0 && octet <= 0xBF) + state = FSM_80BF; + else + state = FSM_ERROR; + break; + case FSM_80BF80BF: + if (octet >= 0x80 && octet <= 0xBF) + state = FSM_80BF; + else + state = FSM_ERROR; + break; + case FSM_809F: + if (octet >= 0x80 && octet <= 0x9F) + state = FSM_80BF; + else + state = FSM_ERROR; + break; + case FSM_90BF: + if (octet >= 0x90 && octet <= 0xBF) + state = FSM_80BF80BF; + else + state = FSM_ERROR; + break; + case FSM_80BF80BF80BF: + if (octet >= 0x80 && octet <= 0xBF) + state = FSM_80BF80BF; + else + state = FSM_ERROR; + break; + case FSM_808F: + if (octet >= 0x80 && octet <= 0x8F) + state = FSM_80BF80BF; + else + state = FSM_ERROR; + break; + default: + case FSM_ERROR: + return start; + } + if (state == FSM_START) + start = data; + } + return start; +} diff --git a/src/TortoiseMerge/libsvn_diff/util.c b/src/TortoiseMerge/libsvn_diff/util.c index 12b4790..8d9ccc4 100644 --- a/src/TortoiseMerge/libsvn_diff/util.c +++ b/src/TortoiseMerge/libsvn_diff/util.c @@ -21,12 +21,13 @@ #include #include "svn_error.h" -#include "svn_diff.h" +#include "svn_version.h" +#include "svn_io.h" #include "svn_types.h" #include "svn_ctype.h" #include "diff.h" - +#include "svn_diff.h" /** * An Adler-32 implementation per RFC1950. * diff --git a/src/TortoiseMerge/libsvn_diff/win32_xlate.c b/src/TortoiseMerge/libsvn_diff/win32_xlate.c new file mode 100644 index 0000000..c982e6b --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/win32_xlate.c @@ -0,0 +1,222 @@ +/* + * win32_xlate.c : Windows xlate stuff. + * + * ==================================================================== + * Copyright (c) 2007 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + +#ifdef WIN32 + +/* Define _WIN32_DCOM for CoInitializeEx(). */ +#define _WIN32_DCOM + +/* We must include windows.h ourselves or apr.h includes it for us with + many ignore options set. Including Winsock is required to resolve IPv6 + compilation errors. APR_HAVE_IPV6 is only defined after including + apr.h, so we can't detect this case here. */ + +/* winsock2.h includes windows.h */ +#include +#include +#include + +#include +#include +#include + +#include "svn_pools.h" +#include "svn_string.h" +#include "svn_utf.h" + +#include "win32_xlate.h" + +typedef struct win32_xlate_t +{ + UINT from_page_id; + UINT to_page_id; +} win32_xlate_t; + +static apr_status_t +get_page_id_from_name(UINT *page_id_p, const char *page_name, apr_pool_t *pool) +{ + IMultiLanguage * mlang = NULL; + HRESULT hr; + MIMECSETINFO page_info; + WCHAR ucs2_page_name[128]; + + if (page_name == SVN_APR_DEFAULT_CHARSET) + { + *page_id_p = CP_ACP; + return APR_SUCCESS; + } + else if (page_name == SVN_APR_LOCALE_CHARSET) + { + OSVERSIONINFO ver_info; + ver_info.dwOSVersionInfoSize = sizeof(ver_info); + + /* CP_THREAD_ACP supported only on Windows 2000 and later.*/ + if (GetVersionEx(&ver_info) && ver_info.dwMajorVersion >= 5 + && ver_info.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + *page_id_p = CP_THREAD_ACP; + return APR_SUCCESS; + } + + /* CP_THREAD_ACP isn't supported on current system, so get locale + encoding name from APR. */ + page_name = apr_os_locale_encoding(pool); + } + else if (!strcmp(page_name, "UTF-8")) + { + *page_id_p = CP_UTF8; + return APR_SUCCESS; + } + + /* Use codepage identifier nnn if the codepage name is in the form + of "CPnnn". + We need this code since apr_os_locale_encoding() and svn_cmdline_init() + generates such codepage names even if they are not valid IANA charset + name. */ + if ((page_name[0] == 'c' || page_name[0] == 'C') + && (page_name[1] == 'p' || page_name[1] == 'P')) + { + *page_id_p = atoi(page_name + 2); + return APR_SUCCESS; + } + + hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, + &IID_IMultiLanguage, (void **) &mlang); + + if (FAILED(hr)) + return APR_EGENERAL; + + /* Convert page name to wide string. */ + MultiByteToWideChar(CP_UTF8, 0, page_name, -1, ucs2_page_name, + sizeof(ucs2_page_name) / sizeof(ucs2_page_name[0])); + memset(&page_info, 0, sizeof(page_info)); + hr = mlang->lpVtbl->GetCharsetInfo(mlang, ucs2_page_name, &page_info); + if (FAILED(hr)) + { + mlang->lpVtbl->Release(mlang); + return APR_EINVAL; + } + + if (page_info.uiInternetEncoding) + *page_id_p = page_info.uiInternetEncoding; + else + *page_id_p = page_info.uiCodePage; + + mlang->lpVtbl->Release(mlang); + + return APR_SUCCESS; +} + +apr_status_t +svn_subr__win32_xlate_open(win32_xlate_t **xlate_p, const char *topage, + const char *frompage, apr_pool_t *pool) +{ + UINT from_page_id, to_page_id; + apr_status_t apr_err = APR_SUCCESS; + win32_xlate_t *xlate; + HRESULT hr; + + /* First try to initialize for apartment-threaded object concurrency. */ + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (hr == RPC_E_CHANGED_MODE) + { + /* COM already initalized for multi-threaded object concurrency. We are + neutral to object concurrency so try to initalize it in the same way + for us. */ + hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + } + + if (FAILED(hr)) + return APR_EGENERAL; + + apr_err = get_page_id_from_name(&to_page_id, topage, pool); + if (apr_err == APR_SUCCESS) + apr_err = get_page_id_from_name(&from_page_id, frompage, pool); + + if (apr_err == APR_SUCCESS) + { + xlate = apr_palloc(pool, sizeof(*xlate)); + xlate->from_page_id = from_page_id; + xlate->to_page_id = to_page_id; + + *xlate_p = xlate; + } + + CoUninitialize(); + return apr_err; +} + +apr_status_t +svn_subr__win32_xlate_to_stringbuf(win32_xlate_t *handle, + const char *src_data, + apr_size_t src_length, + svn_stringbuf_t **dest, + apr_pool_t *pool) +{ + WCHAR * wide_str; + int retval, wide_size; + + *dest = svn_stringbuf_create("", pool); + + if (src_length == 0) + return APR_SUCCESS; + + retval = MultiByteToWideChar(handle->from_page_id, 0, src_data, src_length, + NULL, 0); + if (retval == 0) + return apr_get_os_error(); + + wide_size = retval; + + /* Allocate temporary buffer for small strings on stack instead of heap. */ + if (wide_size <= MAX_PATH) + { + wide_str = _alloca(wide_size * sizeof(WCHAR)); + } + else + { + wide_str = apr_palloc(pool, wide_size * sizeof(WCHAR)); + } + + retval = MultiByteToWideChar(handle->from_page_id, 0, src_data, src_length, + wide_str, wide_size); + + if (retval == 0) + return apr_get_os_error(); + + retval = WideCharToMultiByte(handle->to_page_id, 0, wide_str, wide_size, + NULL, 0, NULL, NULL); + + if (retval == 0) + return apr_get_os_error(); + + /* Ensure that buffer is enough to hold result string and termination + character. */ + svn_stringbuf_ensure(*dest, retval + 1); + (*dest)->len = retval; + + retval = WideCharToMultiByte(handle->to_page_id, 0, wide_str, wide_size, + (*dest)->data, (*dest)->len, NULL, NULL); + if (retval == 0) + return apr_get_os_error(); + + (*dest)->len = retval; + return APR_SUCCESS; +} + +#endif /* WIN32 */ diff --git a/src/TortoiseMerge/libsvn_diff/win32_xlate.h b/src/TortoiseMerge/libsvn_diff/win32_xlate.h new file mode 100644 index 0000000..a33e5f6 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/win32_xlate.h @@ -0,0 +1,47 @@ +/* + * win32_xlate.h : Windows xlate stuff. + * + * ==================================================================== + * Copyright (c) 2007 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + */ + +#ifndef SVN_LIBSVN_SUBR_WIN32_XLATE_H +#define SVN_LIBSVN_SUBR_WIN32_XLATE_H + +#ifdef WIN32 + +/* Opaque translation buffer. */ +typedef struct win32_xlate_t win32_xlate_t; + +/* Set *XLATE_P to a handle node for converting from FROMPAGE to TOPAGE. + Returns APR_EINVAL or APR_ENOTIMPL, if a conversion isn't supported. + If fail for any other reason, return the error. + + Allocate *RET in POOL. */ +apr_status_t svn_subr__win32_xlate_open(win32_xlate_t **xlate_p, + const char *topage, + const char *frompage, + apr_pool_t *pool); + +/* Convert SRC_LENGTH bytes of SRC_DATA in NODE->handle, store the result + in *DEST, which is allocated in POOL. */ +apr_status_t svn_subr__win32_xlate_to_stringbuf(win32_xlate_t *handle, + const char *src_data, + apr_size_t src_length, + svn_stringbuf_t **dest, + apr_pool_t *pool); + +#endif /* WIN32 */ + +#endif /* SVN_LIBSVN_SUBR_WIN32_XLATE_H */ diff --git a/src/TortoiseMerge/libsvn_diff/zconf.h b/src/TortoiseMerge/libsvn_diff/zconf.h new file mode 100644 index 0000000..9e5e430 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/zconf.h @@ -0,0 +1,279 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2003/05/23 21:05:30 steveking Exp $ */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) +# ifndef __32BIT__ +# define __32BIT__ +# endif +#endif +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#if defined(MSDOS) && !defined(__32BIT__) +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) +# define STDC +#endif +#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__) +# ifndef STDC +# define STDC +# endif +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Old Borland C incorrectly complains about missing returns: */ +#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500) +# define NEED_DUMMY_RETURN +#endif + + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +#endif +#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) +# ifndef __32BIT__ +# define SMALL_MEDIUM +# define FAR _far +# endif +#endif + +/* Compile with -DZLIB_DLL for Windows DLL support */ +#if defined(ZLIB_DLL) +# if defined(_WINDOWS) || defined(WINDOWS) +# ifdef FAR +# undef FAR +# endif +# include +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR _cdecl _export +# endif +# endif +# if defined (__BORLANDC__) +# if (__BORLANDC__ >= 0x0500) && defined (WIN32) +# include +# define ZEXPORT __declspec(dllexport) WINAPI +# define ZEXPORTRVA __declspec(dllexport) WINAPIV +# else +# if defined (_Windows) && defined (__DLL__) +# define ZEXPORT _export +# define ZEXPORTVA _export +# endif +# endif +# endif +#endif + +#if defined (__BEOS__) +# if defined (ZLIB_DLL) +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +#endif + +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif +#ifndef ZEXTERN +# define ZEXTERN extern +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(MACOS) && !defined(TARGET_OS_MAC) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(inflate_blocks,"INBL") +# pragma map(inflate_blocks_new,"INBLNE") +# pragma map(inflate_blocks_free,"INBLFR") +# pragma map(inflate_blocks_reset,"INBLRE") +# pragma map(inflate_codes_free,"INCOFR") +# pragma map(inflate_codes,"INCO") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_flush,"INFLU") +# pragma map(inflate_mask,"INMA") +# pragma map(inflate_set_dictionary,"INSEDI2") +# pragma map(inflate_copyright,"INCOPY") +# pragma map(inflate_trees_bits,"INTRBI") +# pragma map(inflate_trees_dynamic,"INTRDY") +# pragma map(inflate_trees_fixed,"INTRFI") +# pragma map(inflate_trees_free,"INTRFR") +#endif + +#endif /* _ZCONF_H */ diff --git a/src/TortoiseMerge/libsvn_diff/zip.c b/src/TortoiseMerge/libsvn_diff/zip.c new file mode 100644 index 0000000..135d097 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/zip.c @@ -0,0 +1,719 @@ +/* zip.c -- IO on .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Read zip.h for more info +*/ + + +#include +#include +#include +#include "zlib.h" +#include "zip.h" +#include "zutil.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +const char zip_copyright[] = + " zip 0.15 Copyright 1998 Gilles Vollant "; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + uLong pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralheader; /* size of the central header for cur file */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; +} curfile_info; + +typedef struct +{ + FILE * filezip; + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile_info ci; /* info on the file curretly writing */ + + uLong begin_pos; /* position of the beginning of the zipfile */ + uLong number_entry; +} zip_internal; + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(ldi) + linkedlist_datablock_internal* ldi; +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(ll) + linkedlist_data* ll; +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(ll) + linkedlist_data* ll; +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(ll,buf,len) + linkedlist_data* ll; + const void* buf; + uLong len; +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + +local int write_datablock(fout,ll) + FILE * fout; + linkedlist_data* ll; +{ + linkedlist_datablock_internal* ldi; + ldi = ll->first_block; + while (ldi!=NULL) + { + if (ldi->filled_in_this_block > 0) + if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block,1,fout)!=1) + return ZIP_ERRNO; + ldi = ldi->next_datablock; + } + return ZIP_OK; +} + +/****************************************************************************/ + +/* =========================================================================== + Outputs a long in LSB order to the given file + nbByte == 1, 2 or 4 (byte, short or long) +*/ + +local int ziplocal_putValue OF((FILE *file, uLong x, int nbByte)); +local int ziplocal_putValue (file, x, nbByte) + FILE *file; + uLong x; + int nbByte; +{ + unsigned char buf[4]; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (fwrite(buf,nbByte,1,file)!=1) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); +local void ziplocal_putValue_inmemory (dest, x, nbByte) + void* dest; + uLong x; + int nbByte; +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } +} +/****************************************************************************/ + + +local uLong ziplocal_TmzDateToDosDate(ptm,dosDate) + tm_zip* ptm; + uLong dosDate; +{ + uLong year = (uLong)ptm->tm_year; + if (year>1980) + year-=1980; + else if (year>80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +extern zipFile ZEXPORT zipOpen (pathname, append) + const char *pathname; + int append; +{ + zip_internal ziinit; + zip_internal* zi; + + ziinit.filezip = fopen(pathname,(append == 0) ? "wb" : "ab"); + if (ziinit.filezip == NULL) + return NULL; + ziinit.begin_pos = ftell(ziinit.filezip); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + init_linkedlist(&(ziinit.central_dir)); + + + zi = (zip_internal*)ALLOC(sizeof(zip_internal)); + if (zi==NULL) + { + fclose(ziinit.filezip); + return NULL; + } + + *zi = ziinit; + return (zipFile)zi; +} + +extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; +{ + zip_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; + + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = strlen(comment); + + size_filename = strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); + } + + zi->ci.flag = 0; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if ((level==2)) + zi->ci.flag |= 4; + if ((level==1)) + zi->ci.flag |= 6; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.pos_local_header = ftell(zi->filezip); + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + + size_extrafield_global + size_comment; + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); + + ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2); + ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(filename+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + /* write the local header */ + err = ziplocal_putValue(zi->filezip,(uLong)LOCALHEADERMAGIC,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(zi->filezip,(uLong)20,2);/* version needed to extract */ + if (err==ZIP_OK) + err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.dosDate,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* compressed size, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* uncompressed size, unknown */ + + if (err==ZIP_OK) + err = ziplocal_putValue(zi->filezip,(uLong)size_filename,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(zi->filezip,(uLong)size_extrafield_local,2); + + if ((err==ZIP_OK) && (size_filename>0)) + if (fwrite(filename,(uInt)size_filename,1,zi->filezip)!=1) + err = ZIP_ERRNO; + + if ((err==ZIP_OK) && (size_extrafield_local>0)) + if (fwrite(extrafield_local,(uInt)size_extrafield_local,1,zi->filezip) + !=1) + err = ZIP_ERRNO; + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED)) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + err = deflateInit2(&zi->ci.stream, level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0); + + if (err==Z_OK) + zi->ci.stream_initialised = 1; + } + + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (file, buf, len) + zipFile file; + const voidp buf; + unsigned len; +{ + zip_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.stream.next_in = buf; + zi->ci.stream.avail_in = len; + zi->ci.crc32 = crc32(zi->ci.crc32,buf,len); + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip) + !=1) + err = ZIP_ERRNO; + zi->ci.pos_in_buffered_data = 0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + if (zi->ci.method == Z_DEFLATED) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + for (i=0;ici.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + } + + return 0; +} + +extern int ZEXPORT zipCloseFileInZip (file) + zipFile file; +{ + zip_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if (zi->ci.method == Z_DEFLATED) + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip) + !=1) + err = ZIP_ERRNO; + zi->ci.pos_in_buffered_data = 0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip) + !=1) + err = ZIP_ERRNO; + + if ((zi->ci.method == Z_DEFLATED) && (err==ZIP_OK)) + { + err=deflateEnd(&zi->ci.stream); + zi->ci.stream_initialised = 0; + } + + ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)zi->ci.crc32,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20, + (uLong)zi->ci.stream.total_out,4); /*compr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+24, + (uLong)zi->ci.stream.total_in,4); /*uncompr size*/ + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header, + (uLong)zi->ci.size_centralheader); + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + long cur_pos_inzip = ftell(zi->filezip); + if (fseek(zi->filezip, + zi->ci.pos_local_header + 14,SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.crc32,4); /* crc 32, unknown */ + + if (err==ZIP_OK) /* compressed size, unknown */ + err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_out,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_in,4); + + if (fseek(zi->filezip, + cur_pos_inzip,SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipClose (file, global_comment) + zipFile file; + const char* global_comment; +{ + zip_internal* zi; + int err = 0; + uLong size_centraldir = 0; + uLong centraldir_pos_inzip ; + uInt size_global_comment; + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + + if (global_comment==NULL) + size_global_comment = 0; + else + size_global_comment = strlen(global_comment); + + + centraldir_pos_inzip = ftell(zi->filezip); + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block ; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block, + 1,zi->filezip) !=1 ) + err = ZIP_ERRNO; + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_datablock(zi->central_dir.first_block); + + if (err==ZIP_OK) /* Magic End */ + err = ziplocal_putValue(zi->filezip,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = ziplocal_putValue(zi->filezip,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = ziplocal_putValue(zi->filezip,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* size of the central directory */ + err = ziplocal_putValue(zi->filezip,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the + starting disk number */ + err = ziplocal_putValue(zi->filezip,(uLong)centraldir_pos_inzip ,4); + + if (err==ZIP_OK) /* zipfile comment length */ + err = ziplocal_putValue(zi->filezip,(uLong)size_global_comment,2); + + if ((err==ZIP_OK) && (size_global_comment>0)) + if (fwrite(global_comment,(uInt)size_global_comment,1,zi->filezip) !=1 ) + err = ZIP_ERRNO; + fclose(zi->filezip); + TRYFREE(zi); + + return err; +} diff --git a/src/TortoiseMerge/libsvn_diff/zip.h b/src/TortoiseMerge/libsvn_diff/zip.h new file mode 100644 index 0000000..1eed469 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/zip.h @@ -0,0 +1,150 @@ +/* zip.h -- IO for compress .zip files using zlib + Version 0.15 alpha, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow creates .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + For uncompress .zip file, look at unzip.h + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/zip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ + +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip +*/ + +#ifndef _zip_H +#define _zip_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_INTERNALERROR (-104) + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows NT a filename like "c:\\zlib\\zlib111.zip" or on + an Unix computer "zlib/zlib111.zip". + if the file pathname exist and append=1, the zip will be created at the end + of the file. (useful if the file contain a self extractor code) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. + + +*/ + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) +*/ + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const voidp buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip_H */ diff --git a/src/TortoiseMerge/libsvn_diff/zlib.h b/src/TortoiseMerge/libsvn_diff/zlib.h new file mode 100644 index 0000000..5979f04 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/zlib.h @@ -0,0 +1,893 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.4, March 11th, 2002 + + Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef _ZLIB_H +#define _ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.1.4" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* _ZLIB_H */ diff --git a/src/TortoiseMerge/libsvn_diff/zlibcpp.cpp b/src/TortoiseMerge/libsvn_diff/zlibcpp.cpp new file mode 100644 index 0000000..a1b533d --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/zlibcpp.cpp @@ -0,0 +1,131 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Module: zlibcpp.cpp +// +// Desc: See zlibcpp.h +// +// Copyright (c) 2003 Michael Carruth +// +/////////////////////////////////////////////////////////////////////////////// + + +#include "stdafx.h" +#include "zlibcpp.h" +#include "utility.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + + +//----------------------------------------------------------------------------- +// CZLib::CZLib +// +// +// +CZLib::CZLib() +{ + m_zf = 0; +} + + +//----------------------------------------------------------------------------- +// CZLib::~CZLib +// +// Close open zip file +// +CZLib::~CZLib() +{ + if (m_zf) + Close(); +} + + +//----------------------------------------------------------------------------- +// CZLib::Open +// +// Create or open zip file +// +BOOL CZLib::Open(string f_file, int f_nAppend) +{ + m_zf = zipOpen(f_file.c_str(), f_nAppend); + return (m_zf != NULL); +} + + +//----------------------------------------------------------------------------- +// CZLib::Close +// +// Close open zip file +// +void CZLib::Close() +{ + if (m_zf) + zipClose(m_zf, NULL); + + m_zf = 0; +} + + +//----------------------------------------------------------------------------- +// CZLib::AddFile +// +// Adds a file to the zip archive +// +BOOL CZLib::AddFile(string f_file) +{ + BOOL bReturn = FALSE; + + // Open file being added + HANDLE hFile = NULL; + hFile = CreateFile(f_file.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile) + { + // Get file creation date + FILETIME ft = CUtility::getLastWriteFileTime(f_file); + zip_fileinfo zi = {0}; + + FileTimeToDosDateTime( + &ft, // last write FILETIME + ((LPWORD)&zi.dosDate)+1, // dos date + ((LPWORD)&zi.dosDate)+0); // dos time + + // Trim path off file name + string sFileName = f_file.substr(f_file.find_last_of(_T('\\')) + 1); + + // Start a new file in Zip + if (ZIP_OK == zipOpenNewFileInZip(m_zf, + sFileName.c_str(), + &zi, + NULL, + 0, + NULL, + 0, + NULL, + Z_DEFLATED, + Z_BEST_COMPRESSION)) + { + // Write file to Zip in 4 KB chunks + const DWORD BUFFSIZE = 4096; + TCHAR buffer[BUFFSIZE] = _T(""); + DWORD dwBytesRead = 0; + + while (ReadFile(hFile, &buffer, BUFFSIZE, &dwBytesRead, NULL) + && dwBytesRead) + { + if (ZIP_OK == zipWriteInFileInZip(m_zf, buffer, dwBytesRead) + && dwBytesRead < BUFFSIZE) + { + // Success + bReturn = TRUE; + } + } + + bReturn &= (ZIP_OK == zipCloseFileInZip(m_zf)); + } + + bReturn &= CloseHandle(hFile); + } + + return bReturn; +} \ No newline at end of file diff --git a/src/TortoiseMerge/libsvn_diff/zlibcpp.h b/src/TortoiseMerge/libsvn_diff/zlibcpp.h new file mode 100644 index 0000000..9d753c4 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/zlibcpp.h @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Module: zlibcpp.h +// +// Desc: Basic class wrapper for the zlib dll +// +// Copyright (c) 2003 Automatic Data Processing, Inc. All Rights Reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _ZLIBCPP_H_ +#define _ZLIBCPP_H_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef _WINDOWS +#define _WINDOWS +#endif // !_WINDOWS + +#ifndef _zip_H +#include "zip.h" +#endif // _zip_H + +class CZLib +{ +public: + CZLib(); + virtual ~CZLib(); + + BOOL Open(string f_file, int f_nAppend = 0); + BOOL AddFile(string f_file); + void Close(); +protected: + zipFile m_zf; +}; + +#endif // !_ZLIBCPP_H diff --git a/src/TortoiseMerge/libsvn_diff/zutil.c b/src/TortoiseMerge/libsvn_diff/zutil.c new file mode 100644 index 0000000..05b9f1b --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/zutil.c @@ -0,0 +1,225 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c,v 1.1 2003/05/23 21:05:30 steveking Exp $ */ + +#include "zutil.h" + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char *z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifdef __TURBOC__ +#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) +/* Small and medium model in Turbo C are for now limited to near allocation + * with reduced MAX_WBITS and MAX_MEM_LEVEL + */ +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} +#endif +#endif /* __TURBOC__ */ + + +#if defined(M_I86) && !defined(__32BIT__) +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* MSC */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/src/TortoiseMerge/libsvn_diff/zutil.h b/src/TortoiseMerge/libsvn_diff/zutil.h new file mode 100644 index 0000000..2326408 --- /dev/null +++ b/src/TortoiseMerge/libsvn_diff/zutil.h @@ -0,0 +1,220 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.1 2003/05/23 21:05:30 steveking Exp $ */ + +#ifndef _Z_UTIL_H +#define _Z_UTIL_H + +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#ifdef MSDOS +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#ifdef WIN32 /* Window 95 & Windows NT */ +# define OS_CODE 0x0b +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0F +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# define fdopen(fd,type) _fdopen(fd,type) +#endif + + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, + uInt len)); +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* _Z_UTIL_H */ diff --git a/src/TortoiseMerge/svninclude/SVNLineDiff.h b/src/TortoiseMerge/svninclude/SVNLineDiff.h new file mode 100644 index 0000000..56a7036 --- /dev/null +++ b/src/TortoiseMerge/svninclude/SVNLineDiff.h @@ -0,0 +1,74 @@ +// TortoiseMerge - a Diff/Patch program + +// Copyright (C) 2006-2007 - TortoiseSVN + +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +#pragma once +#include "svn_diff.h" +#include "diff.h" +#include "svn_pools.h" + +/** + * \ingroup TortoiseMerge + * Handles diffs of single lines. Used for inline diffs. + */ +class SVNLineDiff +{ +public: + SVNLineDiff(); + ~SVNLineDiff(); + + bool Diff(svn_diff_t** diff, LPCTSTR line1, int len1, LPCTSTR line2, int len2, bool bWordDiff); + /** Checks if we really should show inline diffs. + * Inline diffs are only useful if the two lines are not + * completely different but at least a little bit similar. + */ + static bool ShowInlineDiff(svn_diff_t* diff); + + std::vector m_line1tokens; + std::vector m_line2tokens; +private: + + apr_pool_t * m_pool; + apr_pool_t * m_subpool; + LPCTSTR m_line1; + unsigned long m_line1length; + LPCTSTR m_line2; + unsigned long m_line2length; + unsigned long m_line1pos; + unsigned long m_line2pos; + + bool m_bWordDiff; + + static svn_error_t * datasource_open(void *baton, svn_diff_datasource_e datasource); + static svn_error_t * datasource_close(void *baton, svn_diff_datasource_e datasource); + static svn_error_t * next_token(apr_uint32_t * hash, void ** token, void * baton, svn_diff_datasource_e datasource); + static svn_error_t * compare_token(void * baton, void * token1, void * token2, int * compare); + static void discard_token(void * baton, void * token); + static void discard_all_token(void *baton); + static bool IsCharWhiteSpace(TCHAR c); + + static apr_uint32_t Adler32(apr_uint32_t checksum, const WCHAR *data, apr_size_t len); + static void ParseLineWords( + LPCTSTR line, unsigned long lineLength, std::vector& tokens); + static void ParseLineChars( + LPCTSTR line, unsigned long lineLength, std::vector& tokens); + static void NextTokenWords( + apr_uint32_t* hash, void** token, unsigned long& linePos, const std::vector& tokens); + static void NextTokenChars( + apr_uint32_t* hash, void** token, unsigned long& linePos, LPCTSTR line, unsigned long lineLength); + static const svn_diff_fns_t SVNLineDiff_vtable; +}; \ No newline at end of file diff --git a/src/TortoiseMerge/svninclude/apr.h b/src/TortoiseMerge/svninclude/apr.h deleted file mode 100644 index d8cacf5..0000000 --- a/src/TortoiseMerge/svninclude/apr.h +++ /dev/null @@ -1,638 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef APR_H -#define APR_H - -/* GENERATED FILE WARNING! DO NOT EDIT apr.h - * - * You must modify apr.hw instead. - * - * And please, make an effort to stub apr.hnw and apr.h.in in the process. - * - * This is the Win32 specific version of apr.h. It is copied from - * apr.hw by the apr.dsp and libapr.dsp projects. - */ - -/** - * @file apr.h - * @brief APR Platform Definitions - * @remark This is a generated header generated from include/apr.h.in by - * ./configure, or copied from include/apr.hw or include/apr.hnw - * for Win32 or Netware by those build environments, respectively. - */ - -#if defined(WIN32) || defined(DOXYGEN) - -/* Ignore most warnings (back down to /W3) for poorly constructed headers - */ -#if defined(_MSC_VER) && _MSC_VER >= 1200 -#pragma warning(push, 3) -#endif - -/* disable or reduce the frequency of... - * C4057: indirection to slightly different base types - * C4075: slight indirection changes (unsigned short* vs short[]) - * C4100: unreferenced formal parameter - * C4127: conditional expression is constant - * C4163: '_rotl64' : not available as an intrinsic function - * C4201: nonstandard extension nameless struct/unions - * C4244: int to char/short - precision loss - * C4514: unreferenced inline function removed - */ -#pragma warning(disable: 4100 4127 4163 4201 4514; once: 4057 4075 4244) - -/* Ignore Microsoft's interpretation of secure development - * and the POSIX string handling API - */ -#if defined(_MSC_VER) && _MSC_VER >= 1400 -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE -#endif -#pragma warning(disable: 4996) -#endif - -/* Has windows.h already been included? If so, our preferences don't matter, - * but we will still need the winsock things no matter what was included. - * If not, include a restricted set of windows headers to our tastes. - */ -#ifndef _WINDOWS_ -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef _WIN32_WINNT - -/* Restrict the server to a subset of Windows XP header files by default - */ -#define _WIN32_WINNT 0x0501 -#endif -#ifndef NOUSER -#define NOUSER -#endif -#ifndef NOMCX -#define NOMCX -#endif -#ifndef NOIME -#define NOIME -#endif -#include -/* - * Add a _very_few_ declarations missing from the restricted set of headers - * (If this list becomes extensive, re-enable the required headers above!) - * winsock headers were excluded by WIN32_LEAN_AND_MEAN, so include them now - */ -#define SW_HIDE 0 -#ifndef _WIN32_WCE -#include -#include -#include -#include -#else -#include -#endif -#endif /* !_WINDOWS_ */ - -/** - * @defgroup APR Apache Portability Runtime library - * @{ - */ -/** - * @defgroup apr_platform Platform Definitions - * @{ - * @warning - * The actual values of macros and typedefs on this page
- * are platform specific and should NOT be relied upon!
- */ - -#define APR_INLINE __inline -#define APR_HAS_INLINE 1 -#if !defined(__GNUC__) && !defined(__attribute__) -#define __attribute__(__x) -#endif - -#ifndef _WIN32_WCE -#define APR_HAVE_ARPA_INET_H 0 -#define APR_HAVE_CONIO_H 1 -#define APR_HAVE_CRYPT_H 0 -#define APR_HAVE_CTYPE_H 1 -#define APR_HAVE_DIRENT_H 0 -#define APR_HAVE_ERRNO_H 1 -#define APR_HAVE_FCNTL_H 1 -#define APR_HAVE_IO_H 1 -#define APR_HAVE_LIMITS_H 1 -#define APR_HAVE_NETDB_H 0 -#define APR_HAVE_NETINET_IN_H 0 -#define APR_HAVE_NETINET_SCTP_H 0 -#define APR_HAVE_NETINET_SCTP_UIO_H 0 -#define APR_HAVE_NETINET_TCP_H 0 -#define APR_HAVE_PTHREAD_H 0 -#define APR_HAVE_SEMAPHORE_H 0 -#define APR_HAVE_SIGNAL_H 1 -#define APR_HAVE_STDARG_H 1 -#define APR_HAVE_STDINT_H 0 -#define APR_HAVE_STDIO_H 1 -#define APR_HAVE_STDLIB_H 1 -#define APR_HAVE_STRING_H 1 -#define APR_HAVE_STRINGS_H 0 -#define APR_HAVE_SYS_IOCTL_H 0 -#define APR_HAVE_SYS_SENDFILE_H 0 -#define APR_HAVE_SYS_SIGNAL_H 0 -#define APR_HAVE_SYS_SOCKET_H 0 -#define APR_HAVE_SYS_SOCKIO_H 0 -#define APR_HAVE_SYS_SYSLIMITS_H 0 -#define APR_HAVE_SYS_TIME_H 0 -#define APR_HAVE_SYS_TYPES_H 1 -#define APR_HAVE_SYS_UIO_H 0 -#define APR_HAVE_SYS_UN_H 0 -#define APR_HAVE_SYS_WAIT_H 0 -#define APR_HAVE_TIME_H 1 -#define APR_HAVE_UNISTD_H 0 -#define APR_HAVE_STDDEF_H 1 -#define APR_HAVE_PROCESS_H 1 -#else -#define APR_HAVE_ARPA_INET_H 0 -#define APR_HAVE_CONIO_H 0 -#define APR_HAVE_CRYPT_H 0 -#define APR_HAVE_CTYPE_H 0 -#define APR_HAVE_DIRENT_H 0 -#define APR_HAVE_ERRNO_H 0 -#define APR_HAVE_FCNTL_H 0 -#define APR_HAVE_IO_H 0 -#define APR_HAVE_LIMITS_H 0 -#define APR_HAVE_NETDB_H 0 -#define APR_HAVE_NETINET_IN_H 0 -#define APR_HAVE_NETINET_SCTP_H 0 -#define APR_HAVE_NETINET_SCTP_UIO_H 0 -#define APR_HAVE_NETINET_TCP_H 0 -#define APR_HAVE_PTHREAD_H 0 -#define APR_HAVE_SEMAPHORE_H 0 -#define APR_HAVE_SIGNAL_H 0 -#define APR_HAVE_STDARG_H 0 -#define APR_HAVE_STDINT_H 0 -#define APR_HAVE_STDIO_H 1 -#define APR_HAVE_STDLIB_H 1 -#define APR_HAVE_STRING_H 1 -#define APR_HAVE_STRINGS_H 0 -#define APR_HAVE_SYS_IOCTL_H 0 -#define APR_HAVE_SYS_SENDFILE_H 0 -#define APR_HAVE_SYS_SIGNAL_H 0 -#define APR_HAVE_SYS_SOCKET_H 0 -#define APR_HAVE_SYS_SOCKIO_H 0 -#define APR_HAVE_SYS_SYSLIMITS_H 0 -#define APR_HAVE_SYS_TIME_H 0 -#define APR_HAVE_SYS_TYPES_H 0 -#define APR_HAVE_SYS_UIO_H 0 -#define APR_HAVE_SYS_UN_H 0 -#define APR_HAVE_SYS_WAIT_H 0 -#define APR_HAVE_TIME_H 0 -#define APR_HAVE_UNISTD_H 0 -#define APR_HAVE_STDDEF_H 0 -#define APR_HAVE_PROCESS_H 0 -#endif - -/** @} */ -/** @} */ - -/* We don't include our conditional headers within the doxyblocks - * or the extern "C" namespace - */ - -#if APR_HAVE_STDLIB_H -#include -#endif -#if APR_HAVE_STDIO_H -#include -#endif -#if APR_HAVE_SYS_TYPES_H -#include -#endif -#if APR_HAVE_STDDEF_H -#include -#endif -#if APR_HAVE_TIME_H -#include -#endif -#if APR_HAVE_PROCESS_H -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @addtogroup apr_platform - * @ingroup APR - * @{ - */ - -#define APR_HAVE_SHMEM_MMAP_TMP 0 -#define APR_HAVE_SHMEM_MMAP_SHM 0 -#define APR_HAVE_SHMEM_MMAP_ZERO 0 -#define APR_HAVE_SHMEM_SHMGET_ANON 0 -#define APR_HAVE_SHMEM_SHMGET 0 -#define APR_HAVE_SHMEM_MMAP_ANON 0 -#define APR_HAVE_SHMEM_BEOS 0 - -#define APR_USE_SHMEM_MMAP_TMP 0 -#define APR_USE_SHMEM_MMAP_SHM 0 -#define APR_USE_SHMEM_MMAP_ZERO 0 -#define APR_USE_SHMEM_SHMGET_ANON 0 -#define APR_USE_SHMEM_SHMGET 0 -#define APR_USE_SHMEM_MMAP_ANON 0 -#define APR_USE_SHMEM_BEOS 0 - -#define APR_USE_FLOCK_SERIALIZE 0 -#define APR_USE_POSIXSEM_SERIALIZE 0 -#define APR_USE_SYSVSEM_SERIALIZE 0 -#define APR_USE_FCNTL_SERIALIZE 0 -#define APR_USE_PROC_PTHREAD_SERIALIZE 0 -#define APR_USE_PTHREAD_SERIALIZE 0 - -#define APR_HAS_FLOCK_SERIALIZE 0 -#define APR_HAS_SYSVSEM_SERIALIZE 0 -#define APR_HAS_POSIXSEM_SERIALIZE 0 -#define APR_HAS_FCNTL_SERIALIZE 0 -#define APR_HAS_PROC_PTHREAD_SERIALIZE 0 - -#define APR_PROCESS_LOCK_IS_GLOBAL 0 - -#define APR_HAVE_CORKABLE_TCP 0 -#define APR_HAVE_GETRLIMIT 0 -#define APR_HAVE_ICONV 0 -#define APR_HAVE_IN_ADDR 1 -#define APR_HAVE_INET_ADDR 1 -#define APR_HAVE_INET_NETWORK 0 -#define APR_HAVE_IPV6 0 -#define APR_HAVE_MEMMOVE 1 -#define APR_HAVE_SETRLIMIT 0 -#define APR_HAVE_SIGACTION 0 -#define APR_HAVE_SIGSUSPEND 0 -#define APR_HAVE_SIGWAIT 0 -#define APR_HAVE_STRCASECMP 0 -#define APR_HAVE_STRDUP 1 -#define APR_HAVE_STRNCASECMP 0 -#define APR_HAVE_STRSTR 1 -#define APR_HAVE_MEMCHR 1 -#define APR_HAVE_STRUCT_RLIMIT 0 -#define APR_HAVE_UNION_SEMUN 0 -#define APR_HAVE_SCTP 0 -#define APR_HAVE_IOVEC 0 - -#ifndef _WIN32_WCE -#define APR_HAVE_STRICMP 1 -#define APR_HAVE_STRNICMP 1 -#else -#define APR_HAVE_STRICMP 0 -#define APR_HAVE_STRNICMP 0 -#endif - -/* APR Feature Macros */ -#define APR_HAS_SHARED_MEMORY 1 -#define APR_HAS_THREADS 1 -#define APR_HAS_MMAP 0 -#define APR_HAS_FORK 0 -#define APR_HAS_RANDOM 1 -#define APR_HAS_OTHER_CHILD 1 -#define APR_HAS_DSO 1 -#define APR_HAS_SO_ACCEPTFILTER 0 -#define APR_HAS_UNICODE_FS 1 -#define APR_HAS_PROC_INVOKED 1 -#define APR_HAS_OS_UUID 1 - -#ifndef _WIN32_WCE -#define APR_HAS_SENDFILE 1 -#define APR_HAS_USER 1 -#define APR_HAS_LARGE_FILES 1 -#define APR_HAS_XTHREAD_FILES 1 -#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD 1 -#else -#define APR_HAS_SENDFILE 0 -#define APR_HAS_USER 0 -#define APR_HAS_LARGE_FILES 0 -#define APR_HAS_XTHREAD_FILES 0 -#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD 0 -#endif - -/* APR sets APR_FILES_AS_SOCKETS to 1 on systems where it is possible - * to poll on files/pipes. - */ -#define APR_FILES_AS_SOCKETS 0 - -/* This macro indicates whether or not EBCDIC is the native character set. - */ -#define APR_CHARSET_EBCDIC 0 - -/* If we have a TCP implementation that can be "corked", what flag - * do we use? - */ -#define APR_TCP_NOPUSH_FLAG @apr_tcp_nopush_flag@ - -/* Is the TCP_NODELAY socket option inherited from listening sockets? - */ -#define APR_TCP_NODELAY_INHERITED 1 - -/* Is the O_NONBLOCK flag inherited from listening sockets? - */ -#define APR_O_NONBLOCK_INHERITED 1 - -/* Typedefs that APR needs. */ - -typedef unsigned char apr_byte_t; - -typedef short apr_int16_t; -typedef unsigned short apr_uint16_t; - -typedef int apr_int32_t; -typedef unsigned int apr_uint32_t; - -typedef __int64 apr_int64_t; -typedef unsigned __int64 apr_uint64_t; - -typedef size_t apr_size_t; -#if APR_HAVE_STDDEF_H -typedef ptrdiff_t apr_ssize_t; -#else -typedef int apr_ssize_t; -#endif -#if APR_HAS_LARGE_FILES -typedef __int64 apr_off_t; -#else -typedef int apr_off_t; -#endif -typedef int apr_socklen_t; -typedef apr_uint64_t apr_ino_t; - -#ifdef WIN64 -#define APR_SIZEOF_VOIDP 8 -#else -#define APR_SIZEOF_VOIDP 4 -#endif - -#if APR_SIZEOF_VOIDP == 8 -typedef apr_uint64_t apr_uintptr_t; -#else -typedef apr_uint32_t apr_uintptr_t; -#endif - -/* Are we big endian? */ -/* XXX: Fatal assumption on Alpha platforms */ -#define APR_IS_BIGENDIAN 0 - -/* Mechanisms to properly type numeric literals */ - -#ifndef __GNUC__ -#define APR_INT64_C(val) (val##i64) -#define APR_UINT64_C(val) (val##Ui64) -#else -#define APR_INT64_C(val) (val##LL) -#define APR_UINT64_C(val) (val##ULL) -#endif - -#ifdef INT16_MIN -#define APR_INT16_MIN INT16_MIN -#else -#define APR_INT16_MIN (-0x7fff - 1) -#endif - -#ifdef INT16_MAX -#define APR_INT16_MAX INT16_MAX -#else -#define APR_INT16_MAX (0x7fff) -#endif - -#ifdef UINT16_MAX -#define APR_UINT16_MAX UINT16_MAX -#else -#define APR_UINT16_MAX (0xffff) -#endif - -#ifdef INT32_MIN -#define APR_INT32_MIN INT32_MIN -#else -#define APR_INT32_MIN (-0x7fffffff - 1) -#endif - -#ifdef INT32_MAX -#define APR_INT32_MAX INT32_MAX -#else -#define APR_INT32_MAX 0x7fffffff -#endif - -#ifdef UINT32_MAX -#define APR_UINT32_MAX UINT32_MAX -#else -#define APR_UINT32_MAX (0xffffffffU) -#endif - -#ifdef INT64_MIN -#define APR_INT64_MIN INT64_MIN -#else -#define APR_INT64_MIN (APR_INT64_C(-0x7fffffffffffffff) - 1) -#endif - -#ifdef INT64_MAX -#define APR_INT64_MAX INT64_MAX -#else -#define APR_INT64_MAX APR_INT64_C(0x7fffffffffffffff) -#endif - -#ifdef UINT64_MAX -#define APR_UINT64_MAX UINT64_MAX -#else -#define APR_UINT64_MAX APR_UINT64_C(0xffffffffffffffff) -#endif - -#define APR_SIZE_MAX (~((apr_size_t)0)) - -/* Definitions that APR programs need to work properly. */ - -/** - * APR public API wrap for C++ compilers. - */ -#ifdef __cplusplus -#define APR_BEGIN_DECLS extern "C" { -#define APR_END_DECLS } -#else -#define APR_BEGIN_DECLS -#define APR_END_DECLS -#endif - -/** - * Thread callbacks from APR functions must be declared with APR_THREAD_FUNC, - * so that they follow the platform's calling convention. - *
- *
- * void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data);
- *
- * 
- */ -#define APR_THREAD_FUNC __stdcall - - -#if defined(DOXYGEN) || !defined(WIN32) - -/** - * The public APR functions are declared with APR_DECLARE(), so they may - * use the most appropriate calling convention. Public APR functions with - * variable arguments must use APR_DECLARE_NONSTD(). - * - * @remark Both the declaration and implementations must use the same macro. - * - *
- * APR_DECLARE(rettype) apr_func(args)
- * 
- * @see APR_DECLARE_NONSTD @see APR_DECLARE_DATA - * @remark Note that when APR compiles the library itself, it passes the - * symbol -DAPR_DECLARE_EXPORT to the compiler on some platforms (e.g. Win32) - * to export public symbols from the dynamic library build.\n - * The user must define the APR_DECLARE_STATIC when compiling to target - * the static APR library on some platforms (e.g. Win32.) The public symbols - * are neither exported nor imported when APR_DECLARE_STATIC is defined.\n - * By default, compiling an application and including the APR public - * headers, without defining APR_DECLARE_STATIC, will prepare the code to be - * linked to the dynamic library. - */ -#define APR_DECLARE(type) type - -/** - * The public APR functions using variable arguments are declared with - * APR_DECLARE_NONSTD(), as they must follow the C language calling convention. - * @see APR_DECLARE @see APR_DECLARE_DATA - * @remark Both the declaration and implementations must use the same macro. - *
- *
- * APR_DECLARE_NONSTD(rettype) apr_func(args, ...);
- *
- * 
- */ -#define APR_DECLARE_NONSTD(type) type - -/** - * The public APR variables are declared with AP_MODULE_DECLARE_DATA. - * This assures the appropriate indirection is invoked at compile time. - * @see APR_DECLARE @see APR_DECLARE_NONSTD - * @remark Note that the declaration and implementations use different forms, - * but both must include the macro. - * - *
- *
- * extern APR_DECLARE_DATA type apr_variable;\n
- * APR_DECLARE_DATA type apr_variable = value;
- *
- * 
- */ -#define APR_DECLARE_DATA - -#elif defined(APR_DECLARE_STATIC) -#define APR_DECLARE(type) type __stdcall -#define APR_DECLARE_NONSTD(type) type __cdecl -#define APR_DECLARE_DATA -#elif defined(APR_DECLARE_EXPORT) -#define APR_DECLARE(type) __declspec(dllexport) type __stdcall -#define APR_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl -#define APR_DECLARE_DATA __declspec(dllexport) -#else -#define APR_DECLARE(type) __declspec(dllimport) type __stdcall -#define APR_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl -#define APR_DECLARE_DATA __declspec(dllimport) -#endif - -#ifdef WIN64 -#define APR_SSIZE_T_FMT "I64d" -#define APR_SIZE_T_FMT "I64u" -#else -#define APR_SSIZE_T_FMT "d" -#define APR_SIZE_T_FMT "u" -#endif - -#if APR_HAS_LARGE_FILES -#define APR_OFF_T_FMT "I64d" -#else -#define APR_OFF_T_FMT "d" -#endif - -#define APR_PID_T_FMT "d" - -#define APR_INT64_T_FMT "I64d" -#define APR_UINT64_T_FMT "I64u" -#define APR_UINT64_T_HEX_FMT "I64x" - -/* No difference between PROC and GLOBAL mutex */ -#define APR_PROC_MUTEX_IS_GLOBAL 1 - -/* Local machine definition for console and log output. */ -#define APR_EOL_STR "\r\n" - -typedef int apr_wait_t; - -#if APR_HAS_UNICODE_FS -/* An arbitrary size that is digestable. True max is a bit less than 32000 */ -#define APR_PATH_MAX 8192 -#else /* !APR_HAS_UNICODE_FS */ -#define APR_PATH_MAX MAX_PATH -#endif - -#define APR_DSOPATH "PATH" - -/** @} */ - -/* Definitions that only Win32 programs need to compile properly. */ - -/* XXX These simply don't belong here, perhaps in apr_portable.h - * based on some APR_HAVE_PID/GID/UID? - */ -#ifndef __GNUC__ -typedef int pid_t; -#endif -typedef int uid_t; -typedef int gid_t; - -/* Win32 .h ommissions we really need */ -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 - -#if APR_HAVE_IPV6 - -/* Appears in later flavors, not the originals. */ -#ifndef in_addr6 -#define in6_addr in_addr6 -#endif - -#ifndef WS2TCPIP_INLINE -#define IN6_IS_ADDR_V4MAPPED(a) \ - ( (*(const apr_uint64_t *)(const void *)(&(a)->s6_addr[0]) == 0) \ - && (*(const apr_uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) -#endif - -#endif /* APR_HAS_IPV6 */ - -#ifdef __cplusplus -} -#endif - -/* Done with badly written headers - */ -#if defined(_MSC_VER) && _MSC_VER >= 1200 -#pragma warning(pop) -#pragma warning(disable: 4996) -#endif - -#endif /* WIN32 */ - -#endif /* APR_H */ diff --git a/src/TortoiseMerge/svninclude/apr_errno.h b/src/TortoiseMerge/svninclude/apr_errno.h deleted file mode 100644 index 30f42f6..0000000 --- a/src/TortoiseMerge/svninclude/apr_errno.h +++ /dev/null @@ -1,1312 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APR_ERRNO_H -#define APR_ERRNO_H - -/** - * @file apr_errno.h - * @brief APR Error Codes - */ - -#include "apr.h" - -#if APR_HAVE_ERRNO_H -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** - * @defgroup apr_errno Error Codes - * @ingroup APR - * @{ - */ - -/** - * Type for specifying an error or status code. - */ -typedef int apr_status_t; - -/** - * Return a human readable string describing the specified error. - * @param statcode The error code the get a string for. - * @param buf A buffer to hold the error string. - * @param bufsize Size of the buffer to hold the string. - */ -APR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf, - apr_size_t bufsize); - -#if defined(DOXYGEN) -/** - * @def APR_FROM_OS_ERROR(os_err_type syserr) - * Fold a platform specific error into an apr_status_t code. - * @return apr_status_t - * @param e The platform os error code. - * @warning macro implementation; the syserr argument may be evaluated - * multiple times. - */ -#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) - -/** - * @def APR_TO_OS_ERROR(apr_status_t statcode) - * @return os_err_type - * Fold an apr_status_t code back to the native platform defined error. - * @param e The apr_status_t folded platform os error code. - * @warning macro implementation; the statcode argument may be evaluated - * multiple times. If the statcode was not created by apr_get_os_error - * or APR_FROM_OS_ERROR, the results are undefined. - */ -#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) - -/** @def apr_get_os_error() - * @return apr_status_t the last platform error, folded into apr_status_t, on most platforms - * @remark This retrieves errno, or calls a GetLastError() style function, and - * folds it with APR_FROM_OS_ERROR. Some platforms (such as OS2) have no - * such mechanism, so this call may be unsupported. Do NOT use this - * call for socket errors from socket, send, recv etc! - */ - -/** @def apr_set_os_error(e) - * Reset the last platform error, unfolded from an apr_status_t, on some platforms - * @param e The OS error folded in a prior call to APR_FROM_OS_ERROR() - * @warning This is a macro implementation; the statcode argument may be evaluated - * multiple times. If the statcode was not created by apr_get_os_error - * or APR_FROM_OS_ERROR, the results are undefined. This macro sets - * errno, or calls a SetLastError() style function, unfolding statcode - * with APR_TO_OS_ERROR. Some platforms (such as OS2) have no such - * mechanism, so this call may be unsupported. - */ - -/** @def apr_get_netos_error() - * Return the last socket error, folded into apr_status_t, on all platforms - * @remark This retrieves errno or calls a GetLastSocketError() style function, - * and folds it with APR_FROM_OS_ERROR. - */ - -/** @def apr_set_netos_error(e) - * Reset the last socket error, unfolded from an apr_status_t - * @param e The socket error folded in a prior call to APR_FROM_OS_ERROR() - * @warning This is a macro implementation; the statcode argument may be evaluated - * multiple times. If the statcode was not created by apr_get_os_error - * or APR_FROM_OS_ERROR, the results are undefined. This macro sets - * errno, or calls a WSASetLastError() style function, unfolding - * socketcode with APR_TO_OS_ERROR. - */ - -#endif /* defined(DOXYGEN) */ - -/** - * APR_OS_START_ERROR is where the APR specific error values start. - */ -#define APR_OS_START_ERROR 20000 -/** - * APR_OS_ERRSPACE_SIZE is the maximum number of errors you can fit - * into one of the error/status ranges below -- except for - * APR_OS_START_USERERR, which see. - */ -#define APR_OS_ERRSPACE_SIZE 50000 -/** - * APR_UTIL_ERRSPACE_SIZE is the size of the space that is reserved for - * use within apr-util. This space is reserved above that used by APR - * internally. - * @note This number MUST be smaller than APR_OS_ERRSPACE_SIZE by a - * large enough amount that APR has sufficient room for it's - * codes. - */ -#define APR_UTIL_ERRSPACE_SIZE 20000 -/** - * APR_OS_START_STATUS is where the APR specific status codes start. - */ -#define APR_OS_START_STATUS (APR_OS_START_ERROR + APR_OS_ERRSPACE_SIZE) -/** - * APR_UTIL_START_STATUS is where APR-Util starts defining it's - * status codes. - */ -#define APR_UTIL_START_STATUS (APR_OS_START_STATUS + \ - (APR_OS_ERRSPACE_SIZE - APR_UTIL_ERRSPACE_SIZE)) -/** - * APR_OS_START_USERERR are reserved for applications that use APR that - * layer their own error codes along with APR's. Note that the - * error immediately following this one is set ten times farther - * away than usual, so that users of apr have a lot of room in - * which to declare custom error codes. - * - * In general applications should try and create unique error codes. To try - * and assist in finding suitable ranges of numbers to use, the following - * ranges are known to be used by the listed applications. If your - * application defines error codes please advise the range of numbers it - * uses to dev@apr.apache.org for inclusion in this list. - * - * Ranges shown are in relation to APR_OS_START_USERERR - * - * Subversion - Defined ranges, of less than 100, at intervals of 5000 - * starting at an offset of 5000, e.g. - * +5000 to 5100, +10000 to 10100 - */ -#define APR_OS_START_USERERR (APR_OS_START_STATUS + APR_OS_ERRSPACE_SIZE) -/** - * APR_OS_START_USEERR is obsolete, defined for compatibility only. - * Use APR_OS_START_USERERR instead. - */ -#define APR_OS_START_USEERR APR_OS_START_USERERR -/** - * APR_OS_START_CANONERR is where APR versions of errno values are defined - * on systems which don't have the corresponding errno. - */ -#define APR_OS_START_CANONERR (APR_OS_START_USERERR \ - + (APR_OS_ERRSPACE_SIZE * 10)) -/** - * APR_OS_START_EAIERR folds EAI_ error codes from getaddrinfo() into - * apr_status_t values. - */ -#define APR_OS_START_EAIERR (APR_OS_START_CANONERR + APR_OS_ERRSPACE_SIZE) -/** - * APR_OS_START_SYSERR folds platform-specific system error values into - * apr_status_t values. - */ -#define APR_OS_START_SYSERR (APR_OS_START_EAIERR + APR_OS_ERRSPACE_SIZE) - -/** - * @defgroup APR_ERROR_map APR Error Space - *
- * The following attempts to show the relation of the various constants
- * used for mapping APR Status codes.
- *
- *       0          
- *
- *  20,000     APR_OS_START_ERROR
- *
- *         + APR_OS_ERRSPACE_SIZE (50,000)
- *
- *  70,000      APR_OS_START_STATUS
- *
- *         + APR_OS_ERRSPACE_SIZE - APR_UTIL_ERRSPACE_SIZE (30,000)
- *
- * 100,000      APR_UTIL_START_STATUS
- *
- *         + APR_UTIL_ERRSPACE_SIZE (20,000)
- *
- * 120,000      APR_OS_START_USERERR
- *
- *         + 10 x APR_OS_ERRSPACE_SIZE (50,000 * 10)
- *
- * 620,000      APR_OS_START_CANONERR
- *
- *         + APR_OS_ERRSPACE_SIZE (50,000)
- *
- * 670,000      APR_OS_START_EAIERR
- *
- *         + APR_OS_ERRSPACE_SIZE (50,000)
- *
- * 720,000      APR_OS_START_SYSERR
- *
- * 
- */ - -/** no error. */ -#define APR_SUCCESS 0 - -/** - * @defgroup APR_Error APR Error Values - *
- * APR ERROR VALUES
- * APR_ENOSTAT      APR was unable to perform a stat on the file 
- * APR_ENOPOOL      APR was not provided a pool with which to allocate memory
- * APR_EBADDATE     APR was given an invalid date 
- * APR_EINVALSOCK   APR was given an invalid socket
- * APR_ENOPROC      APR was not given a process structure
- * APR_ENOTIME      APR was not given a time structure
- * APR_ENODIR       APR was not given a directory structure
- * APR_ENOLOCK      APR was not given a lock structure
- * APR_ENOPOLL      APR was not given a poll structure
- * APR_ENOSOCKET    APR was not given a socket
- * APR_ENOTHREAD    APR was not given a thread structure
- * APR_ENOTHDKEY    APR was not given a thread key structure
- * APR_ENOSHMAVAIL  There is no more shared memory available
- * APR_EDSOOPEN     APR was unable to open the dso object.  For more 
- *                  information call apr_dso_error().
- * APR_EGENERAL     General failure (specific information not available)
- * APR_EBADIP       The specified IP address is invalid
- * APR_EBADMASK     The specified netmask is invalid
- * APR_ESYMNOTFOUND Could not find the requested symbol
- * APR_ENOTENOUGHENTROPY Not enough entropy to continue
- * 
- * - *
- * APR STATUS VALUES
- * APR_INCHILD        Program is currently executing in the child
- * APR_INPARENT       Program is currently executing in the parent
- * APR_DETACH         The thread is detached
- * APR_NOTDETACH      The thread is not detached
- * APR_CHILD_DONE     The child has finished executing
- * APR_CHILD_NOTDONE  The child has not finished executing
- * APR_TIMEUP         The operation did not finish before the timeout
- * APR_INCOMPLETE     The operation was incomplete although some processing
- *                    was performed and the results are partially valid
- * APR_BADCH          Getopt found an option not in the option string
- * APR_BADARG         Getopt found an option that is missing an argument 
- *                    and an argument was specified in the option string
- * APR_EOF            APR has encountered the end of the file
- * APR_NOTFOUND       APR was unable to find the socket in the poll structure
- * APR_ANONYMOUS      APR is using anonymous shared memory
- * APR_FILEBASED      APR is using a file name as the key to the shared memory
- * APR_KEYBASED       APR is using a shared key as the key to the shared memory
- * APR_EINIT          Ininitalizer value.  If no option has been found, but 
- *                    the status variable requires a value, this should be used
- * APR_ENOTIMPL       The APR function has not been implemented on this 
- *                    platform, either because nobody has gotten to it yet, 
- *                    or the function is impossible on this platform.
- * APR_EMISMATCH      Two passwords do not match.
- * APR_EABSOLUTE      The given path was absolute.
- * APR_ERELATIVE      The given path was relative.
- * APR_EINCOMPLETE    The given path was neither relative nor absolute.
- * APR_EABOVEROOT     The given path was above the root path.
- * APR_EBUSY          The given lock was busy.
- * APR_EPROC_UNKNOWN  The given process wasn't recognized by APR
- * 
- * @{ - */ -/** @see APR_STATUS_IS_ENOSTAT */ -#define APR_ENOSTAT (APR_OS_START_ERROR + 1) -/** @see APR_STATUS_IS_ENOPOOL */ -#define APR_ENOPOOL (APR_OS_START_ERROR + 2) -/* empty slot: +3 */ -/** @see APR_STATUS_IS_EBADDATE */ -#define APR_EBADDATE (APR_OS_START_ERROR + 4) -/** @see APR_STATUS_IS_EINVALSOCK */ -#define APR_EINVALSOCK (APR_OS_START_ERROR + 5) -/** @see APR_STATUS_IS_ENOPROC */ -#define APR_ENOPROC (APR_OS_START_ERROR + 6) -/** @see APR_STATUS_IS_ENOTIME */ -#define APR_ENOTIME (APR_OS_START_ERROR + 7) -/** @see APR_STATUS_IS_ENODIR */ -#define APR_ENODIR (APR_OS_START_ERROR + 8) -/** @see APR_STATUS_IS_ENOLOCK */ -#define APR_ENOLOCK (APR_OS_START_ERROR + 9) -/** @see APR_STATUS_IS_ENOPOLL */ -#define APR_ENOPOLL (APR_OS_START_ERROR + 10) -/** @see APR_STATUS_IS_ENOSOCKET */ -#define APR_ENOSOCKET (APR_OS_START_ERROR + 11) -/** @see APR_STATUS_IS_ENOTHREAD */ -#define APR_ENOTHREAD (APR_OS_START_ERROR + 12) -/** @see APR_STATUS_IS_ENOTHDKEY */ -#define APR_ENOTHDKEY (APR_OS_START_ERROR + 13) -/** @see APR_STATUS_IS_EGENERAL */ -#define APR_EGENERAL (APR_OS_START_ERROR + 14) -/** @see APR_STATUS_IS_ENOSHMAVAIL */ -#define APR_ENOSHMAVAIL (APR_OS_START_ERROR + 15) -/** @see APR_STATUS_IS_EBADIP */ -#define APR_EBADIP (APR_OS_START_ERROR + 16) -/** @see APR_STATUS_IS_EBADMASK */ -#define APR_EBADMASK (APR_OS_START_ERROR + 17) -/* empty slot: +18 */ -/** @see APR_STATUS_IS_EDSOPEN */ -#define APR_EDSOOPEN (APR_OS_START_ERROR + 19) -/** @see APR_STATUS_IS_EABSOLUTE */ -#define APR_EABSOLUTE (APR_OS_START_ERROR + 20) -/** @see APR_STATUS_IS_ERELATIVE */ -#define APR_ERELATIVE (APR_OS_START_ERROR + 21) -/** @see APR_STATUS_IS_EINCOMPLETE */ -#define APR_EINCOMPLETE (APR_OS_START_ERROR + 22) -/** @see APR_STATUS_IS_EABOVEROOT */ -#define APR_EABOVEROOT (APR_OS_START_ERROR + 23) -/** @see APR_STATUS_IS_EBADPATH */ -#define APR_EBADPATH (APR_OS_START_ERROR + 24) -/** @see APR_STATUS_IS_EPATHWILD */ -#define APR_EPATHWILD (APR_OS_START_ERROR + 25) -/** @see APR_STATUS_IS_ESYMNOTFOUND */ -#define APR_ESYMNOTFOUND (APR_OS_START_ERROR + 26) -/** @see APR_STATUS_IS_EPROC_UNKNOWN */ -#define APR_EPROC_UNKNOWN (APR_OS_START_ERROR + 27) -/** @see APR_STATUS_IS_ENOTENOUGHENTROPY */ -#define APR_ENOTENOUGHENTROPY (APR_OS_START_ERROR + 28) -/** @} */ - -/** - * @defgroup APR_STATUS_IS Status Value Tests - * @warning For any particular error condition, more than one of these tests - * may match. This is because platform-specific error codes may not - * always match the semantics of the POSIX codes these tests (and the - * corresponding APR error codes) are named after. A notable example - * are the APR_STATUS_IS_ENOENT and APR_STATUS_IS_ENOTDIR tests on - * Win32 platforms. The programmer should always be aware of this and - * adjust the order of the tests accordingly. - * @{ - */ -/** - * APR was unable to perform a stat on the file - * @warning always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_ENOSTAT(s) ((s) == APR_ENOSTAT) -/** - * APR was not provided a pool with which to allocate memory - * @warning always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_ENOPOOL(s) ((s) == APR_ENOPOOL) -/** APR was given an invalid date */ -#define APR_STATUS_IS_EBADDATE(s) ((s) == APR_EBADDATE) -/** APR was given an invalid socket */ -#define APR_STATUS_IS_EINVALSOCK(s) ((s) == APR_EINVALSOCK) -/** APR was not given a process structure */ -#define APR_STATUS_IS_ENOPROC(s) ((s) == APR_ENOPROC) -/** APR was not given a time structure */ -#define APR_STATUS_IS_ENOTIME(s) ((s) == APR_ENOTIME) -/** APR was not given a directory structure */ -#define APR_STATUS_IS_ENODIR(s) ((s) == APR_ENODIR) -/** APR was not given a lock structure */ -#define APR_STATUS_IS_ENOLOCK(s) ((s) == APR_ENOLOCK) -/** APR was not given a poll structure */ -#define APR_STATUS_IS_ENOPOLL(s) ((s) == APR_ENOPOLL) -/** APR was not given a socket */ -#define APR_STATUS_IS_ENOSOCKET(s) ((s) == APR_ENOSOCKET) -/** APR was not given a thread structure */ -#define APR_STATUS_IS_ENOTHREAD(s) ((s) == APR_ENOTHREAD) -/** APR was not given a thread key structure */ -#define APR_STATUS_IS_ENOTHDKEY(s) ((s) == APR_ENOTHDKEY) -/** Generic Error which can not be put into another spot */ -#define APR_STATUS_IS_EGENERAL(s) ((s) == APR_EGENERAL) -/** There is no more shared memory available */ -#define APR_STATUS_IS_ENOSHMAVAIL(s) ((s) == APR_ENOSHMAVAIL) -/** The specified IP address is invalid */ -#define APR_STATUS_IS_EBADIP(s) ((s) == APR_EBADIP) -/** The specified netmask is invalid */ -#define APR_STATUS_IS_EBADMASK(s) ((s) == APR_EBADMASK) -/* empty slot: +18 */ -/** - * APR was unable to open the dso object. - * For more information call apr_dso_error(). - */ -#if defined(WIN32) -#define APR_STATUS_IS_EDSOOPEN(s) ((s) == APR_EDSOOPEN \ - || APR_TO_OS_ERROR(s) == ERROR_MOD_NOT_FOUND) -#else -#define APR_STATUS_IS_EDSOOPEN(s) ((s) == APR_EDSOOPEN) -#endif -/** The given path was absolute. */ -#define APR_STATUS_IS_EABSOLUTE(s) ((s) == APR_EABSOLUTE) -/** The given path was relative. */ -#define APR_STATUS_IS_ERELATIVE(s) ((s) == APR_ERELATIVE) -/** The given path was neither relative nor absolute. */ -#define APR_STATUS_IS_EINCOMPLETE(s) ((s) == APR_EINCOMPLETE) -/** The given path was above the root path. */ -#define APR_STATUS_IS_EABOVEROOT(s) ((s) == APR_EABOVEROOT) -/** The given path was bad. */ -#define APR_STATUS_IS_EBADPATH(s) ((s) == APR_EBADPATH) -/** The given path contained wildcards. */ -#define APR_STATUS_IS_EPATHWILD(s) ((s) == APR_EPATHWILD) -/** Could not find the requested symbol. - * For more information call apr_dso_error(). - */ -#if defined(WIN32) -#define APR_STATUS_IS_ESYMNOTFOUND(s) ((s) == APR_ESYMNOTFOUND \ - || APR_TO_OS_ERROR(s) == ERROR_PROC_NOT_FOUND) -#else -#define APR_STATUS_IS_ESYMNOTFOUND(s) ((s) == APR_ESYMNOTFOUND) -#endif -/** The given process was not recognized by APR. */ -#define APR_STATUS_IS_EPROC_UNKNOWN(s) ((s) == APR_EPROC_UNKNOWN) -/** APR could not gather enough entropy to continue. */ -#define APR_STATUS_IS_ENOTENOUGHENTROPY(s) ((s) == APR_ENOTENOUGHENTROPY) - -/** @} */ - -/** - * @addtogroup APR_Error - * @{ - */ -/** @see APR_STATUS_IS_INCHILD */ -#define APR_INCHILD (APR_OS_START_STATUS + 1) -/** @see APR_STATUS_IS_INPARENT */ -#define APR_INPARENT (APR_OS_START_STATUS + 2) -/** @see APR_STATUS_IS_DETACH */ -#define APR_DETACH (APR_OS_START_STATUS + 3) -/** @see APR_STATUS_IS_NOTDETACH */ -#define APR_NOTDETACH (APR_OS_START_STATUS + 4) -/** @see APR_STATUS_IS_CHILD_DONE */ -#define APR_CHILD_DONE (APR_OS_START_STATUS + 5) -/** @see APR_STATUS_IS_CHILD_NOTDONE */ -#define APR_CHILD_NOTDONE (APR_OS_START_STATUS + 6) -/** @see APR_STATUS_IS_TIMEUP */ -#define APR_TIMEUP (APR_OS_START_STATUS + 7) -/** @see APR_STATUS_IS_INCOMPLETE */ -#define APR_INCOMPLETE (APR_OS_START_STATUS + 8) -/* empty slot: +9 */ -/* empty slot: +10 */ -/* empty slot: +11 */ -/** @see APR_STATUS_IS_BADCH */ -#define APR_BADCH (APR_OS_START_STATUS + 12) -/** @see APR_STATUS_IS_BADARG */ -#define APR_BADARG (APR_OS_START_STATUS + 13) -/** @see APR_STATUS_IS_EOF */ -#define APR_EOF (APR_OS_START_STATUS + 14) -/** @see APR_STATUS_IS_NOTFOUND */ -#define APR_NOTFOUND (APR_OS_START_STATUS + 15) -/* empty slot: +16 */ -/* empty slot: +17 */ -/* empty slot: +18 */ -/** @see APR_STATUS_IS_ANONYMOUS */ -#define APR_ANONYMOUS (APR_OS_START_STATUS + 19) -/** @see APR_STATUS_IS_FILEBASED */ -#define APR_FILEBASED (APR_OS_START_STATUS + 20) -/** @see APR_STATUS_IS_KEYBASED */ -#define APR_KEYBASED (APR_OS_START_STATUS + 21) -/** @see APR_STATUS_IS_EINIT */ -#define APR_EINIT (APR_OS_START_STATUS + 22) -/** @see APR_STATUS_IS_ENOTIMPL */ -#define APR_ENOTIMPL (APR_OS_START_STATUS + 23) -/** @see APR_STATUS_IS_EMISMATCH */ -#define APR_EMISMATCH (APR_OS_START_STATUS + 24) -/** @see APR_STATUS_IS_EBUSY */ -#define APR_EBUSY (APR_OS_START_STATUS + 25) -/** @} */ - -/** - * @addtogroup APR_STATUS_IS - * @{ - */ -/** - * Program is currently executing in the child - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code */ -#define APR_STATUS_IS_INCHILD(s) ((s) == APR_INCHILD) -/** - * Program is currently executing in the parent - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_INPARENT(s) ((s) == APR_INPARENT) -/** - * The thread is detached - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_DETACH(s) ((s) == APR_DETACH) -/** - * The thread is not detached - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_NOTDETACH(s) ((s) == APR_NOTDETACH) -/** - * The child has finished executing - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_CHILD_DONE(s) ((s) == APR_CHILD_DONE) -/** - * The child has not finished executing - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_CHILD_NOTDONE(s) ((s) == APR_CHILD_NOTDONE) -/** - * The operation did not finish before the timeout - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP) -/** - * The operation was incomplete although some processing was performed - * and the results are partially valid. - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_INCOMPLETE(s) ((s) == APR_INCOMPLETE) -/* empty slot: +9 */ -/* empty slot: +10 */ -/* empty slot: +11 */ -/** - * Getopt found an option not in the option string - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_BADCH(s) ((s) == APR_BADCH) -/** - * Getopt found an option not in the option string and an argument was - * specified in the option string - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_BADARG(s) ((s) == APR_BADARG) -/** - * APR has encountered the end of the file - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_EOF(s) ((s) == APR_EOF) -/** - * APR was unable to find the socket in the poll structure - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_NOTFOUND(s) ((s) == APR_NOTFOUND) -/* empty slot: +16 */ -/* empty slot: +17 */ -/* empty slot: +18 */ -/** - * APR is using anonymous shared memory - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_ANONYMOUS(s) ((s) == APR_ANONYMOUS) -/** - * APR is using a file name as the key to the shared memory - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_FILEBASED(s) ((s) == APR_FILEBASED) -/** - * APR is using a shared key as the key to the shared memory - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_KEYBASED(s) ((s) == APR_KEYBASED) -/** - * Ininitalizer value. If no option has been found, but - * the status variable requires a value, this should be used - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_EINIT(s) ((s) == APR_EINIT) -/** - * The APR function has not been implemented on this - * platform, either because nobody has gotten to it yet, - * or the function is impossible on this platform. - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_ENOTIMPL(s) ((s) == APR_ENOTIMPL) -/** - * Two passwords do not match. - * @warning - * always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_EMISMATCH(s) ((s) == APR_EMISMATCH) -/** - * The given lock was busy - * @warning always use this test, as platform-specific variances may meet this - * more than one error code - */ -#define APR_STATUS_IS_EBUSY(s) ((s) == APR_EBUSY) - -/** @} */ - -/** - * @addtogroup APR_Error APR Error Values - * @{ - */ -/* APR CANONICAL ERROR VALUES */ -/** @see APR_STATUS_IS_EACCES */ -#ifdef EACCES -#define APR_EACCES EACCES -#else -#define APR_EACCES (APR_OS_START_CANONERR + 1) -#endif - -/** @see APR_STATUS_IS_EEXIST */ -#ifdef EEXIST -#define APR_EEXIST EEXIST -#else -#define APR_EEXIST (APR_OS_START_CANONERR + 2) -#endif - -/** @see APR_STATUS_IS_ENAMETOOLONG */ -#ifdef ENAMETOOLONG -#define APR_ENAMETOOLONG ENAMETOOLONG -#else -#define APR_ENAMETOOLONG (APR_OS_START_CANONERR + 3) -#endif - -/** @see APR_STATUS_IS_ENOENT */ -#ifdef ENOENT -#define APR_ENOENT ENOENT -#else -#define APR_ENOENT (APR_OS_START_CANONERR + 4) -#endif - -/** @see APR_STATUS_IS_ENOTDIR */ -#ifdef ENOTDIR -#define APR_ENOTDIR ENOTDIR -#else -#define APR_ENOTDIR (APR_OS_START_CANONERR + 5) -#endif - -/** @see APR_STATUS_IS_ENOSPC */ -#ifdef ENOSPC -#define APR_ENOSPC ENOSPC -#else -#define APR_ENOSPC (APR_OS_START_CANONERR + 6) -#endif - -/** @see APR_STATUS_IS_ENOMEM */ -#ifdef ENOMEM -#define APR_ENOMEM ENOMEM -#else -#define APR_ENOMEM (APR_OS_START_CANONERR + 7) -#endif - -/** @see APR_STATUS_IS_EMFILE */ -#ifdef EMFILE -#define APR_EMFILE EMFILE -#else -#define APR_EMFILE (APR_OS_START_CANONERR + 8) -#endif - -/** @see APR_STATUS_IS_ENFILE */ -#ifdef ENFILE -#define APR_ENFILE ENFILE -#else -#define APR_ENFILE (APR_OS_START_CANONERR + 9) -#endif - -/** @see APR_STATUS_IS_EBADF */ -#ifdef EBADF -#define APR_EBADF EBADF -#else -#define APR_EBADF (APR_OS_START_CANONERR + 10) -#endif - -/** @see APR_STATUS_IS_EINVAL */ -#ifdef EINVAL -#define APR_EINVAL EINVAL -#else -#define APR_EINVAL (APR_OS_START_CANONERR + 11) -#endif - -/** @see APR_STATUS_IS_ESPIPE */ -#ifdef ESPIPE -#define APR_ESPIPE ESPIPE -#else -#define APR_ESPIPE (APR_OS_START_CANONERR + 12) -#endif - -/** - * @see APR_STATUS_IS_EAGAIN - * @warning use APR_STATUS_IS_EAGAIN instead of just testing this value - */ -#ifdef EAGAIN -#define APR_EAGAIN EAGAIN -#elif defined(EWOULDBLOCK) -#define APR_EAGAIN EWOULDBLOCK -#else -#define APR_EAGAIN (APR_OS_START_CANONERR + 13) -#endif - -/** @see APR_STATUS_IS_EINTR */ -#ifdef EINTR -#define APR_EINTR EINTR -#else -#define APR_EINTR (APR_OS_START_CANONERR + 14) -#endif - -/** @see APR_STATUS_IS_ENOTSOCK */ -#ifdef ENOTSOCK -#define APR_ENOTSOCK ENOTSOCK -#else -#define APR_ENOTSOCK (APR_OS_START_CANONERR + 15) -#endif - -/** @see APR_STATUS_IS_ECONNREFUSED */ -#ifdef ECONNREFUSED -#define APR_ECONNREFUSED ECONNREFUSED -#else -#define APR_ECONNREFUSED (APR_OS_START_CANONERR + 16) -#endif - -/** @see APR_STATUS_IS_EINPROGRESS */ -#ifdef EINPROGRESS -#define APR_EINPROGRESS EINPROGRESS -#else -#define APR_EINPROGRESS (APR_OS_START_CANONERR + 17) -#endif - -/** - * @see APR_STATUS_IS_ECONNABORTED - * @warning use APR_STATUS_IS_ECONNABORTED instead of just testing this value - */ - -#ifdef ECONNABORTED -#define APR_ECONNABORTED ECONNABORTED -#else -#define APR_ECONNABORTED (APR_OS_START_CANONERR + 18) -#endif - -/** @see APR_STATUS_IS_ECONNRESET */ -#ifdef ECONNRESET -#define APR_ECONNRESET ECONNRESET -#else -#define APR_ECONNRESET (APR_OS_START_CANONERR + 19) -#endif - -/** @see APR_STATUS_IS_ETIMEDOUT - * @deprecated */ -#ifdef ETIMEDOUT -#define APR_ETIMEDOUT ETIMEDOUT -#else -#define APR_ETIMEDOUT (APR_OS_START_CANONERR + 20) -#endif - -/** @see APR_STATUS_IS_EHOSTUNREACH */ -#ifdef EHOSTUNREACH -#define APR_EHOSTUNREACH EHOSTUNREACH -#else -#define APR_EHOSTUNREACH (APR_OS_START_CANONERR + 21) -#endif - -/** @see APR_STATUS_IS_ENETUNREACH */ -#ifdef ENETUNREACH -#define APR_ENETUNREACH ENETUNREACH -#else -#define APR_ENETUNREACH (APR_OS_START_CANONERR + 22) -#endif - -/** @see APR_STATUS_IS_EFTYPE */ -#ifdef EFTYPE -#define APR_EFTYPE EFTYPE -#else -#define APR_EFTYPE (APR_OS_START_CANONERR + 23) -#endif - -/** @see APR_STATUS_IS_EPIPE */ -#ifdef EPIPE -#define APR_EPIPE EPIPE -#else -#define APR_EPIPE (APR_OS_START_CANONERR + 24) -#endif - -/** @see APR_STATUS_IS_EXDEV */ -#ifdef EXDEV -#define APR_EXDEV EXDEV -#else -#define APR_EXDEV (APR_OS_START_CANONERR + 25) -#endif - -/** @see APR_STATUS_IS_ENOTEMPTY */ -#ifdef ENOTEMPTY -#define APR_ENOTEMPTY ENOTEMPTY -#else -#define APR_ENOTEMPTY (APR_OS_START_CANONERR + 26) -#endif - -/** @see APR_STATUS_IS_EAFNOSUPPORT */ -#ifdef EAFNOSUPPORT -#define APR_EAFNOSUPPORT EAFNOSUPPORT -#else -#define APR_EAFNOSUPPORT (APR_OS_START_CANONERR + 27) -#endif - -/** @} */ - -#if defined(OS2) && !defined(DOXYGEN) - -#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) -#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) - -#define INCL_DOSERRORS -#define INCL_DOS - -/* Leave these undefined. - * OS2 doesn't rely on the errno concept. - * The API calls always return a result codes which - * should be filtered through APR_FROM_OS_ERROR(). - * - * #define apr_get_os_error() (APR_FROM_OS_ERROR(GetLastError())) - * #define apr_set_os_error(e) (SetLastError(APR_TO_OS_ERROR(e))) - */ - -/* A special case, only socket calls require this; - */ -#define apr_get_netos_error() (APR_FROM_OS_ERROR(errno)) -#define apr_set_netos_error(e) (errno = APR_TO_OS_ERROR(e)) - -/* And this needs to be greped away for good: - */ -#define APR_OS2_STATUS(e) (APR_FROM_OS_ERROR(e)) - -/* These can't sit in a private header, so in spite of the extra size, - * they need to be made available here. - */ -#define SOCBASEERR 10000 -#define SOCEPERM (SOCBASEERR+1) /* Not owner */ -#define SOCESRCH (SOCBASEERR+3) /* No such process */ -#define SOCEINTR (SOCBASEERR+4) /* Interrupted system call */ -#define SOCENXIO (SOCBASEERR+6) /* No such device or address */ -#define SOCEBADF (SOCBASEERR+9) /* Bad file number */ -#define SOCEACCES (SOCBASEERR+13) /* Permission denied */ -#define SOCEFAULT (SOCBASEERR+14) /* Bad address */ -#define SOCEINVAL (SOCBASEERR+22) /* Invalid argument */ -#define SOCEMFILE (SOCBASEERR+24) /* Too many open files */ -#define SOCEPIPE (SOCBASEERR+32) /* Broken pipe */ -#define SOCEOS2ERR (SOCBASEERR+100) /* OS/2 Error */ -#define SOCEWOULDBLOCK (SOCBASEERR+35) /* Operation would block */ -#define SOCEINPROGRESS (SOCBASEERR+36) /* Operation now in progress */ -#define SOCEALREADY (SOCBASEERR+37) /* Operation already in progress */ -#define SOCENOTSOCK (SOCBASEERR+38) /* Socket operation on non-socket */ -#define SOCEDESTADDRREQ (SOCBASEERR+39) /* Destination address required */ -#define SOCEMSGSIZE (SOCBASEERR+40) /* Message too long */ -#define SOCEPROTOTYPE (SOCBASEERR+41) /* Protocol wrong type for socket */ -#define SOCENOPROTOOPT (SOCBASEERR+42) /* Protocol not available */ -#define SOCEPROTONOSUPPORT (SOCBASEERR+43) /* Protocol not supported */ -#define SOCESOCKTNOSUPPORT (SOCBASEERR+44) /* Socket type not supported */ -#define SOCEOPNOTSUPP (SOCBASEERR+45) /* Operation not supported on socket */ -#define SOCEPFNOSUPPORT (SOCBASEERR+46) /* Protocol family not supported */ -#define SOCEAFNOSUPPORT (SOCBASEERR+47) /* Address family not supported by protocol family */ -#define SOCEADDRINUSE (SOCBASEERR+48) /* Address already in use */ -#define SOCEADDRNOTAVAIL (SOCBASEERR+49) /* Can't assign requested address */ -#define SOCENETDOWN (SOCBASEERR+50) /* Network is down */ -#define SOCENETUNREACH (SOCBASEERR+51) /* Network is unreachable */ -#define SOCENETRESET (SOCBASEERR+52) /* Network dropped connection on reset */ -#define SOCECONNABORTED (SOCBASEERR+53) /* Software caused connection abort */ -#define SOCECONNRESET (SOCBASEERR+54) /* Connection reset by peer */ -#define SOCENOBUFS (SOCBASEERR+55) /* No buffer space available */ -#define SOCEISCONN (SOCBASEERR+56) /* Socket is already connected */ -#define SOCENOTCONN (SOCBASEERR+57) /* Socket is not connected */ -#define SOCESHUTDOWN (SOCBASEERR+58) /* Can't send after socket shutdown */ -#define SOCETOOMANYREFS (SOCBASEERR+59) /* Too many references: can't splice */ -#define SOCETIMEDOUT (SOCBASEERR+60) /* Connection timed out */ -#define SOCECONNREFUSED (SOCBASEERR+61) /* Connection refused */ -#define SOCELOOP (SOCBASEERR+62) /* Too many levels of symbolic links */ -#define SOCENAMETOOLONG (SOCBASEERR+63) /* File name too long */ -#define SOCEHOSTDOWN (SOCBASEERR+64) /* Host is down */ -#define SOCEHOSTUNREACH (SOCBASEERR+65) /* No route to host */ -#define SOCENOTEMPTY (SOCBASEERR+66) /* Directory not empty */ - -/* APR CANONICAL ERROR TESTS */ -#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES \ - || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED \ - || (s) == APR_OS_START_SYSERR + ERROR_SHARING_VIOLATION) -#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST \ - || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED \ - || (s) == APR_OS_START_SYSERR + ERROR_FILE_EXISTS \ - || (s) == APR_OS_START_SYSERR + ERROR_ALREADY_EXISTS \ - || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED) -#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG \ - || (s) == APR_OS_START_SYSERR + ERROR_FILENAME_EXCED_RANGE \ - || (s) == APR_OS_START_SYSERR + SOCENAMETOOLONG) -#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ - || (s) == APR_OS_START_SYSERR + ERROR_FILE_NOT_FOUND \ - || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ - || (s) == APR_OS_START_SYSERR + ERROR_NO_MORE_FILES \ - || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED) -#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) -#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ - || (s) == APR_OS_START_SYSERR + ERROR_DISK_FULL) -#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) -#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE \ - || (s) == APR_OS_START_SYSERR + ERROR_TOO_MANY_OPEN_FILES) -#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) -#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE) -#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_PARAMETER \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_FUNCTION) -#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE \ - || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) -#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ - || (s) == APR_OS_START_SYSERR + ERROR_NO_DATA \ - || (s) == APR_OS_START_SYSERR + SOCEWOULDBLOCK \ - || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION) -#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ - || (s) == APR_OS_START_SYSERR + SOCEINTR) -#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ - || (s) == APR_OS_START_SYSERR + SOCENOTSOCK) -#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ - || (s) == APR_OS_START_SYSERR + SOCECONNREFUSED) -#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ - || (s) == APR_OS_START_SYSERR + SOCEINPROGRESS) -#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ - || (s) == APR_OS_START_SYSERR + SOCECONNABORTED) -#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ - || (s) == APR_OS_START_SYSERR + SOCECONNRESET) -/* XXX deprecated */ -#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ - || (s) == APR_OS_START_SYSERR + SOCETIMEDOUT) -#undef APR_STATUS_IS_TIMEUP -#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ - || (s) == APR_OS_START_SYSERR + SOCETIMEDOUT) -#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ - || (s) == APR_OS_START_SYSERR + SOCEHOSTUNREACH) -#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ - || (s) == APR_OS_START_SYSERR + SOCENETUNREACH) -#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) -#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE \ - || (s) == APR_OS_START_SYSERR + ERROR_BROKEN_PIPE \ - || (s) == APR_OS_START_SYSERR + SOCEPIPE) -#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV \ - || (s) == APR_OS_START_SYSERR + ERROR_NOT_SAME_DEVICE) -#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY \ - || (s) == APR_OS_START_SYSERR + ERROR_DIR_NOT_EMPTY \ - || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED) -#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_AFNOSUPPORT \ - || (s) == APR_OS_START_SYSERR + SOCEAFNOSUPPORT) - -/* - Sorry, too tired to wrap this up for OS2... feel free to - fit the following into their best matches. - - { ERROR_NO_SIGNAL_SENT, ESRCH }, - { SOCEALREADY, EALREADY }, - { SOCEDESTADDRREQ, EDESTADDRREQ }, - { SOCEMSGSIZE, EMSGSIZE }, - { SOCEPROTOTYPE, EPROTOTYPE }, - { SOCENOPROTOOPT, ENOPROTOOPT }, - { SOCEPROTONOSUPPORT, EPROTONOSUPPORT }, - { SOCESOCKTNOSUPPORT, ESOCKTNOSUPPORT }, - { SOCEOPNOTSUPP, EOPNOTSUPP }, - { SOCEPFNOSUPPORT, EPFNOSUPPORT }, - { SOCEADDRINUSE, EADDRINUSE }, - { SOCEADDRNOTAVAIL, EADDRNOTAVAIL }, - { SOCENETDOWN, ENETDOWN }, - { SOCENETRESET, ENETRESET }, - { SOCENOBUFS, ENOBUFS }, - { SOCEISCONN, EISCONN }, - { SOCENOTCONN, ENOTCONN }, - { SOCESHUTDOWN, ESHUTDOWN }, - { SOCETOOMANYREFS, ETOOMANYREFS }, - { SOCELOOP, ELOOP }, - { SOCEHOSTDOWN, EHOSTDOWN }, - { SOCENOTEMPTY, ENOTEMPTY }, - { SOCEPIPE, EPIPE } -*/ - -#elif defined(WIN32) && !defined(DOXYGEN) /* !defined(OS2) */ - -#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) -#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) - -#define apr_get_os_error() (APR_FROM_OS_ERROR(GetLastError())) -#define apr_set_os_error(e) (SetLastError(APR_TO_OS_ERROR(e))) - -/* A special case, only socket calls require this: - */ -#define apr_get_netos_error() (APR_FROM_OS_ERROR(WSAGetLastError())) -#define apr_set_netos_error(e) (WSASetLastError(APR_TO_OS_ERROR(e))) - -/* APR CANONICAL ERROR TESTS */ -#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES \ - || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED \ - || (s) == APR_OS_START_SYSERR + ERROR_CANNOT_MAKE \ - || (s) == APR_OS_START_SYSERR + ERROR_CURRENT_DIRECTORY \ - || (s) == APR_OS_START_SYSERR + ERROR_DRIVE_LOCKED \ - || (s) == APR_OS_START_SYSERR + ERROR_FAIL_I24 \ - || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION \ - || (s) == APR_OS_START_SYSERR + ERROR_LOCK_FAILED \ - || (s) == APR_OS_START_SYSERR + ERROR_NOT_LOCKED \ - || (s) == APR_OS_START_SYSERR + ERROR_NETWORK_ACCESS_DENIED \ - || (s) == APR_OS_START_SYSERR + ERROR_SHARING_VIOLATION) -#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST \ - || (s) == APR_OS_START_SYSERR + ERROR_FILE_EXISTS \ - || (s) == APR_OS_START_SYSERR + ERROR_ALREADY_EXISTS) -#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG \ - || (s) == APR_OS_START_SYSERR + ERROR_FILENAME_EXCED_RANGE \ - || (s) == APR_OS_START_SYSERR + WSAENAMETOOLONG) -#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ - || (s) == APR_OS_START_SYSERR + ERROR_FILE_NOT_FOUND \ - || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ - || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED \ - || (s) == APR_OS_START_SYSERR + ERROR_NO_MORE_FILES) -#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR \ - || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ - || (s) == APR_OS_START_SYSERR + ERROR_BAD_NETPATH \ - || (s) == APR_OS_START_SYSERR + ERROR_BAD_NET_NAME \ - || (s) == APR_OS_START_SYSERR + ERROR_BAD_PATHNAME \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DRIVE) -#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ - || (s) == APR_OS_START_SYSERR + ERROR_DISK_FULL) -#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM \ - || (s) == APR_OS_START_SYSERR + ERROR_ARENA_TRASHED \ - || (s) == APR_OS_START_SYSERR + ERROR_NOT_ENOUGH_MEMORY \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_BLOCK \ - || (s) == APR_OS_START_SYSERR + ERROR_NOT_ENOUGH_QUOTA \ - || (s) == APR_OS_START_SYSERR + ERROR_OUTOFMEMORY) -#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE \ - || (s) == APR_OS_START_SYSERR + ERROR_TOO_MANY_OPEN_FILES) -#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) -#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_TARGET_HANDLE) -#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_ACCESS \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DATA \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_FUNCTION \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_PARAMETER \ - || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) -#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE \ - || (s) == APR_OS_START_SYSERR + ERROR_SEEK_ON_DEVICE \ - || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) -#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ - || (s) == APR_OS_START_SYSERR + ERROR_NO_DATA \ - || (s) == APR_OS_START_SYSERR + ERROR_NO_PROC_SLOTS \ - || (s) == APR_OS_START_SYSERR + ERROR_NESTING_NOT_ALLOWED \ - || (s) == APR_OS_START_SYSERR + ERROR_MAX_THRDS_REACHED \ - || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION \ - || (s) == APR_OS_START_SYSERR + WSAEWOULDBLOCK) -#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ - || (s) == APR_OS_START_SYSERR + WSAEINTR) -#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ - || (s) == APR_OS_START_SYSERR + WSAENOTSOCK) -#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ - || (s) == APR_OS_START_SYSERR + WSAECONNREFUSED) -#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ - || (s) == APR_OS_START_SYSERR + WSAEINPROGRESS) -#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ - || (s) == APR_OS_START_SYSERR + WSAECONNABORTED) -#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ - || (s) == APR_OS_START_SYSERR + ERROR_NETNAME_DELETED \ - || (s) == APR_OS_START_SYSERR + WSAECONNRESET) -/* XXX deprecated */ -#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ - || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ - || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) -#undef APR_STATUS_IS_TIMEUP -#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ - || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ - || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) -#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ - || (s) == APR_OS_START_SYSERR + WSAEHOSTUNREACH) -#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ - || (s) == APR_OS_START_SYSERR + WSAENETUNREACH) -#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE \ - || (s) == APR_OS_START_SYSERR + ERROR_EXE_MACHINE_TYPE_MISMATCH \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DLL \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_MODULETYPE \ - || (s) == APR_OS_START_SYSERR + ERROR_BAD_EXE_FORMAT \ - || (s) == APR_OS_START_SYSERR + ERROR_INVALID_EXE_SIGNATURE \ - || (s) == APR_OS_START_SYSERR + ERROR_FILE_CORRUPT \ - || (s) == APR_OS_START_SYSERR + ERROR_BAD_FORMAT) -#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE \ - || (s) == APR_OS_START_SYSERR + ERROR_BROKEN_PIPE) -#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV \ - || (s) == APR_OS_START_SYSERR + ERROR_NOT_SAME_DEVICE) -#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY \ - || (s) == APR_OS_START_SYSERR + ERROR_DIR_NOT_EMPTY) -#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_EAFNOSUPPORT \ - || (s) == APR_OS_START_SYSERR + WSAEAFNOSUPPORT) - -#elif defined(NETWARE) && defined(USE_WINSOCK) && !defined(DOXYGEN) /* !defined(OS2) && !defined(WIN32) */ - -#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) -#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) - -#define apr_get_os_error() (errno) -#define apr_set_os_error(e) (errno = (e)) - -/* A special case, only socket calls require this: */ -#define apr_get_netos_error() (APR_FROM_OS_ERROR(WSAGetLastError())) -#define apr_set_netos_error(e) (WSASetLastError(APR_TO_OS_ERROR(e))) - -/* APR CANONICAL ERROR TESTS */ -#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES) -#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST) -#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG) -#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT) -#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) -#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC) -#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) -#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE) -#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) -#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF) -#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL) -#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE) - -#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ - || (s) == EWOULDBLOCK \ - || (s) == APR_OS_START_SYSERR + WSAEWOULDBLOCK) -#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ - || (s) == APR_OS_START_SYSERR + WSAEINTR) -#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ - || (s) == APR_OS_START_SYSERR + WSAENOTSOCK) -#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ - || (s) == APR_OS_START_SYSERR + WSAECONNREFUSED) -#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ - || (s) == APR_OS_START_SYSERR + WSAEINPROGRESS) -#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ - || (s) == APR_OS_START_SYSERR + WSAECONNABORTED) -#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ - || (s) == APR_OS_START_SYSERR + WSAECONNRESET) -/* XXX deprecated */ -#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ - || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ - || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) -#undef APR_STATUS_IS_TIMEUP -#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ - || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ - || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) -#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ - || (s) == APR_OS_START_SYSERR + WSAEHOSTUNREACH) -#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ - || (s) == APR_OS_START_SYSERR + WSAENETUNREACH) -#define APR_STATUS_IS_ENETDOWN(s) ((s) == APR_OS_START_SYSERR + WSAENETDOWN) -#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) -#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE) -#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV) -#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY) -#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_EAFNOSUPPORT \ - || (s) == APR_OS_START_SYSERR + WSAEAFNOSUPPORT) - -#else /* !defined(NETWARE) && !defined(OS2) && !defined(WIN32) */ - -/* - * os error codes are clib error codes - */ -#define APR_FROM_OS_ERROR(e) (e) -#define APR_TO_OS_ERROR(e) (e) - -#define apr_get_os_error() (errno) -#define apr_set_os_error(e) (errno = (e)) - -/* A special case, only socket calls require this: - */ -#define apr_get_netos_error() (errno) -#define apr_set_netos_error(e) (errno = (e)) - -/** - * @addtogroup APR_STATUS_IS - * @{ - */ - -/** permission denied */ -#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES) -/** file exists */ -#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST) -/** path name is too long */ -#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG) -/** - * no such file or directory - * @remark - * EMVSCATLG can be returned by the automounter on z/OS for - * paths which do not exist. - */ -#ifdef EMVSCATLG -#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ - || (s) == EMVSCATLG) -#else -#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT) -#endif -/** not a directory */ -#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) -/** no space left on device */ -#ifdef EDQUOT -#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ - || (s) == EDQUOT) -#else -#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC) -#endif -/** not enough memory */ -#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) -/** too many open files */ -#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE) -/** file table overflow */ -#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) -/** bad file # */ -#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF) -/** invalid argument */ -#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL) -/** illegal seek */ -#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE) - -/** operation would block */ -#if !defined(EWOULDBLOCK) || !defined(EAGAIN) -#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN) -#elif (EWOULDBLOCK == EAGAIN) -#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN) -#else -#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ - || (s) == EWOULDBLOCK) -#endif - -/** interrupted system call */ -#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR) -/** socket operation on a non-socket */ -#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK) -/** Connection Refused */ -#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED) -/** operation now in progress */ -#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS) - -/** - * Software caused connection abort - * @remark - * EPROTO on certain older kernels really means ECONNABORTED, so we need to - * ignore it for them. See discussion in new-httpd archives nh.9701 & nh.9603 - * - * There is potentially a bug in Solaris 2.x x<6, and other boxes that - * implement tcp sockets in userland (i.e. on top of STREAMS). On these - * systems, EPROTO can actually result in a fatal loop. See PR#981 for - * example. It's hard to handle both uses of EPROTO. - */ -#ifdef EPROTO -#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ - || (s) == EPROTO) -#else -#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED) -#endif - -/** Connection Reset by peer */ -#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET) -/** Operation timed out - * @deprecated */ -#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT) -/** no route to host */ -#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH) -/** network is unreachable */ -#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH) -/** inappropiate file type or format */ -#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) -/** broken pipe */ -#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE) -/** cross device link */ -#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV) -/** Directory Not Empty */ -#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY || \ - (s) == APR_EEXIST) -/** Address Family not supported */ -#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_EAFNOSUPPORT) -/** @} */ - -#endif /* !defined(NETWARE) && !defined(OS2) && !defined(WIN32) */ - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* ! APR_ERRNO_H */ diff --git a/src/TortoiseMerge/svninclude/apr_file_info.h b/src/TortoiseMerge/svninclude/apr_file_info.h deleted file mode 100644 index d620439..0000000 --- a/src/TortoiseMerge/svninclude/apr_file_info.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef ARP_FILE_INFO_XX -#define ARP_FILE_INFO_XX -#include "apr_time.h" - - -#endif \ No newline at end of file diff --git a/src/TortoiseMerge/svninclude/apr_file_io.h b/src/TortoiseMerge/svninclude/apr_file_io.h deleted file mode 100644 index 10e3b89..0000000 --- a/src/TortoiseMerge/svninclude/apr_file_io.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ARP_FILE_IO_XX -#define ARP_FILE_IO_XX -typedef FILE apr_file_t; -#define APR_SET SEEK_SET -#define APR_READ 0 -#define APR_OS_DEFAULT 0 -#define APR_FINFO_SIZE 0 - -struct apr_getopt_option_t { - /** long option name, or NULL if option has no long name */ - const char *name; - /** option letter, or a value greater than 255 if option has no letter */ - int optch; - /** nonzero if option takes an argument */ - int has_arg; - /** a description of the option */ - const char *description; -}; - -typedef struct apr_getopt_option_t apr_getopt_option_t; -#endif \ No newline at end of file diff --git a/src/TortoiseMerge/svninclude/apr_general.h b/src/TortoiseMerge/svninclude/apr_general.h deleted file mode 100644 index a584c65..0000000 --- a/src/TortoiseMerge/svninclude/apr_general.h +++ /dev/null @@ -1,241 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef APR_GENERAL_H -#define APR_GENERAL_H - -/** - * @file apr_general.h - * This is collection of oddballs that didn't fit anywhere else, - * and might move to more appropriate headers with the release - * of APR 1.0. - * @brief APR Miscellaneous library routines - */ - -#include "apr.h" -//#include "apr_pools.h" -#include "apr_errno.h" - -#if APR_HAVE_SIGNAL_H -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** - * @defgroup apr_general Miscellaneous library routines - * @ingroup APR - * This is collection of oddballs that didn't fit anywhere else, - * and might move to more appropriate headers with the release - * of APR 1.0. - * @{ - */ - -/** FALSE */ -#ifndef FALSE -#define FALSE 0 -#endif -/** TRUE */ -#ifndef TRUE -#define TRUE (!FALSE) -#endif - -/** a space */ -#define APR_ASCII_BLANK '\040' -/** a carrige return */ -#define APR_ASCII_CR '\015' -/** a line feed */ -#define APR_ASCII_LF '\012' -/** a tab */ -#define APR_ASCII_TAB '\011' - -/** signal numbers typedef */ -typedef int apr_signum_t; - -/** - * Finding offsets of elements within structures. - * Taken from the X code... they've sweated portability of this stuff - * so we don't have to. Sigh... - * @param p_type pointer type name - * @param field data field within the structure pointed to - * @return offset - */ - -#if defined(CRAY) || (defined(__arm) && !defined(LINUX)) -#ifdef __STDC__ -#define APR_OFFSET(p_type,field) _Offsetof(p_type,field) -#else -#ifdef CRAY2 -#define APR_OFFSET(p_type,field) \ - (sizeof(int)*((unsigned int)&(((p_type)NULL)->field))) - -#else /* !CRAY2 */ - -#define APR_OFFSET(p_type,field) ((unsigned int)&(((p_type)NULL)->field)) - -#endif /* !CRAY2 */ -#endif /* __STDC__ */ -#else /* ! (CRAY || __arm) */ - -#define APR_OFFSET(p_type,field) \ - ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL))) - -#endif /* !CRAY */ - -/** - * Finding offsets of elements within structures. - * @param s_type structure type name - * @param field data field within the structure - * @return offset - */ -#if defined(offsetof) && !defined(__cplusplus) -#define APR_OFFSETOF(s_type,field) offsetof(s_type,field) -#else -#define APR_OFFSETOF(s_type,field) APR_OFFSET(s_type*,field) -#endif - -#ifndef DOXYGEN - -/* A couple of prototypes for functions in case some platform doesn't - * have it - */ -#if (!APR_HAVE_STRCASECMP) && (APR_HAVE_STRICMP) -#define strcasecmp(s1, s2) stricmp(s1, s2) -#elif (!APR_HAVE_STRCASECMP) -int strcasecmp(const char *a, const char *b); -#endif - -#if (!APR_HAVE_STRNCASECMP) && (APR_HAVE_STRNICMP) -#define strncasecmp(s1, s2, n) strnicmp(s1, s2, n) -#elif (!APR_HAVE_STRNCASECMP) -int strncasecmp(const char *a, const char *b, size_t n); -#endif - -#endif - -/** - * Alignment macros - */ - -/* APR_ALIGN() is only to be used to align on a power of 2 boundary */ -#define APR_ALIGN(size, boundary) \ - (((size) + ((boundary) - 1)) & ~((boundary) - 1)) - -/** Default alignment */ -#define APR_ALIGN_DEFAULT(size) APR_ALIGN(size, 8) - - -/** - * String and memory functions - */ - -/* APR_STRINGIFY is defined here, and also in apr_release.h, so wrap it */ -#ifndef APR_STRINGIFY -/** Properly quote a value as a string in the C preprocessor */ -#define APR_STRINGIFY(n) APR_STRINGIFY_HELPER(n) -/** Helper macro for APR_STRINGIFY */ -#define APR_STRINGIFY_HELPER(n) #n -#endif - -#if (!APR_HAVE_MEMMOVE) -#define memmove(a,b,c) bcopy(b,a,c) -#endif - -#if (!APR_HAVE_MEMCHR) -void *memchr(const void *s, int c, size_t n); -#endif - -/** @} */ - -/** - * @defgroup apr_library Library initialization and termination - * @{ - */ - -/** - * Setup any APR internal data structures. This MUST be the first function - * called for any APR library. - * @remark See apr_app_initialize if this is an application, rather than - * a library consumer of apr. - */ -APR_DECLARE(apr_status_t) apr_initialize(void); - -/** - * Set up an application with normalized argc, argv (and optionally env) in - * order to deal with platform-specific oddities, such as Win32 services, - * code pages and signals. This must be the first function called for any - * APR program. - * @param argc Pointer to the argc that may be corrected - * @param argv Pointer to the argv that may be corrected - * @param env Pointer to the env that may be corrected, may be NULL - * @remark See apr_initialize if this is a library consumer of apr. - * Otherwise, this call is identical to apr_initialize, and must be closed - * with a call to apr_terminate at the end of program execution. - */ -APR_DECLARE(apr_status_t) apr_app_initialize(int *argc, - char const * const * *argv, - char const * const * *env); - -/** - * Tear down any APR internal data structures which aren't torn down - * automatically. - * @remark An APR program must call this function at termination once it - * has stopped using APR services. The APR developers suggest using - * atexit to ensure this is called. When using APR from a language - * other than C that has problems with the calling convention, use - * apr_terminate2() instead. - */ -APR_DECLARE_NONSTD(void) apr_terminate(void); - -/** - * Tear down any APR internal data structures which aren't torn down - * automatically, same as apr_terminate - * @remark An APR program must call either the apr_terminate or apr_terminate2 - * function once it it has finished using APR services. The APR - * developers suggest using atexit(apr_terminate) to ensure this is done. - * apr_terminate2 exists to allow non-c language apps to tear down apr, - * while apr_terminate is recommended from c language applications. - */ -APR_DECLARE(void) apr_terminate2(void); - -/** @} */ - -/** - * @defgroup apr_random Random Functions - * @{ - */ - -#if APR_HAS_RANDOM || defined(DOXYGEN) - -/* TODO: I'm not sure this is the best place to put this prototype...*/ -/** - * Generate random bytes. - * @param buf Buffer to fill with random bytes - * @param length Length of buffer in bytes - */ -APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char * buf, - apr_size_t length); - -#endif -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* ! APR_GENERAL_H */ diff --git a/src/TortoiseMerge/svninclude/apr_getopt.h b/src/TortoiseMerge/svninclude/apr_getopt.h deleted file mode 100644 index a2624fd..0000000 --- a/src/TortoiseMerge/svninclude/apr_getopt.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef APR_GETOPT_XX -#define APR_GETOPT_XX -/** @see apr_getopt_t */ -typedef struct apr_getopt_t apr_getopt_t; - -/** - * Structure to store command line argument information. - */ -struct apr_getopt_t { - /** context for processing */ - apr_pool_t *cont; - /** function to print error message (NULL == no messages) */ -// apr_getopt_err_fn_t *errfn; - /** user defined first arg to pass to error message */ - void *errarg; - /** index into parent argv vector */ - int ind; - /** character checked for validity */ - int opt; - /** reset getopt */ - int reset; - /** count of arguments */ - int argc; - /** array of pointers to arguments */ - const char **argv; - /** argument associated with option */ - char const* place; - /** set to nonzero to support interleaving options with regular args */ - int interleave; - /** start of non-option arguments skipped for interleaving */ - int skip_start; - /** end of non-option arguments skipped for interleaving */ - int skip_end; -}; - -struct apr_finfo_t { - /** Allocates memory and closes lingering handles in the specified pool */ - apr_pool_t *pool; - /** The bitmask describing valid fields of this apr_finfo_t structure - * including all available 'wanted' fields and potentially more */ - apr_int32_t valid; - /** The access permissions of the file. Mimics Unix access rights. */ - - apr_off_t size; - /** The storage size consumed by the file */ - apr_off_t csize; - /** The time the file was last accessed */ - apr_time_t atime; - /** The time the file was last modified */ - apr_time_t mtime; - /** The time the file was created, or the inode was last changed */ - apr_time_t ctime; - /** The pathname of the file (possibly unrooted) */ - const char *fname; - /** The file's name (no path) in filesystem case */ - const char *name; - -}; - -typedef struct apr_finfo_t apr_finfo_t; -#endif \ No newline at end of file diff --git a/src/TortoiseMerge/svninclude/apr_hash.h b/src/TortoiseMerge/svninclude/apr_hash.h deleted file mode 100644 index 7d8bf4d..0000000 --- a/src/TortoiseMerge/svninclude/apr_hash.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef APR_HASH_XX -#define APR_HASH_XX - -typedef int apr_hash_t; - -#endif \ No newline at end of file diff --git a/src/TortoiseMerge/svninclude/apr_mmap.h b/src/TortoiseMerge/svninclude/apr_mmap.h deleted file mode 100644 index e69de29..0000000 diff --git a/src/TortoiseMerge/svninclude/apr_pools.h b/src/TortoiseMerge/svninclude/apr_pools.h deleted file mode 100644 index e388aa1..0000000 --- a/src/TortoiseMerge/svninclude/apr_pools.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef APR_POOLS_XX -#define APR_POOLS_XX - -typedef struct -{ - unsigned char *data; - int size; - int start; - -}apr_pool_t; - -typedef int (*apr_abortfunc_t)(int retcode); - -#ifdef __CPLUSPLUS_ -extern "C" -{ -#endif -void * apr_palloc(apr_pool_t *p, apr_size_t size); - -int apr_pool_create_ex(apr_pool_t **newpool, - apr_pool_t *parent, - apr_abortfunc_t abort_fn, - void *allocator); -void apr_pool_destroy(apr_pool_t *p); - -#ifdef __CPLUSPLUS_ -extern "C" -} -#endif - -#endif diff --git a/src/TortoiseMerge/svninclude/apr_sha1.h b/src/TortoiseMerge/svninclude/apr_sha1.h deleted file mode 100644 index e69de29..0000000 diff --git a/src/TortoiseMerge/svninclude/apr_strings.h b/src/TortoiseMerge/svninclude/apr_strings.h deleted file mode 100644 index 23d0472..0000000 --- a/src/TortoiseMerge/svninclude/apr_strings.h +++ /dev/null @@ -1,361 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Portions of this file are covered by */ -/* -*- mode: c; c-file-style: "k&r" -*- - - strnatcmp.c -- Perform 'natural order' comparisons of strings in C. - Copyright (C) 2000 by Martin Pool - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -#ifndef APR_STRINGS_H -#define APR_STRINGS_H - -/** - * @file apr_strings.h - * @brief APR Strings library - */ - -#include "apr.h" -#include "apr_errno.h" -#include "apr_pools.h" -#define APR_WANT_IOVEC -#include "apr_want.h" - -#if APR_HAVE_STDARG_H -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** - * @defgroup apr_strings String routines - * @ingroup APR - * @{ - */ - -/** - * Do a natural order comparison of two strings. - * @param a The first string to compare - * @param b The second string to compare - * @return Either <0, 0, or >0. If the first string is less than the second - * this returns <0, if they are equivalent it returns 0, and if the - * first string is greater than second string it retuns >0. - */ -APR_DECLARE(int) apr_strnatcmp(char const *a, char const *b); - -/** - * Do a natural order comparison of two strings ignoring the case of the - * strings. - * @param a The first string to compare - * @param b The second string to compare - * @return Either <0, 0, or >0. If the first string is less than the second - * this returns <0, if they are equivalent it returns 0, and if the - * first string is greater than second string it retuns >0. - */ -APR_DECLARE(int) apr_strnatcasecmp(char const *a, char const *b); - -/** - * duplicate a string into memory allocated out of a pool - * @param p The pool to allocate out of - * @param s The string to duplicate - * @return The new string - */ -APR_DECLARE(char *) apr_pstrdup(apr_pool_t *p, const char *s); - -/** - * Create a null-terminated string by making a copy of a sequence - * of characters and appending a null byte - * @param p The pool to allocate out of - * @param s The block of characters to duplicate - * @param n The number of characters to duplicate - * @return The new string - * @remark This is a faster alternative to apr_pstrndup, for use - * when you know that the string being duplicated really - * has 'n' or more characters. If the string might contain - * fewer characters, use apr_pstrndup. - */ -APR_DECLARE(char *) apr_pstrmemdup(apr_pool_t *p, const char *s, apr_size_t n); - -/** - * Duplicate at most n characters of a string into memory allocated - * out of a pool; the new string will be NUL-terminated - * @param p The pool to allocate out of - * @param s The string to duplicate - * @param n The maximum number of characters to duplicate - * @return The new string - * @remark The amount of memory allocated from the pool is the length - * of the returned string including the NUL terminator - */ -APR_DECLARE(char *) apr_pstrndup(apr_pool_t *p, const char *s, apr_size_t n); - -/** - * Duplicate a block of memory. - * - * @param p The pool to allocate from - * @param m The memory to duplicate - * @param n The number of bytes to duplicate - * @return The new block of memory - */ -APR_DECLARE(void *) apr_pmemdup(apr_pool_t *p, const void *m, apr_size_t n); - -/** - * Concatenate multiple strings, allocating memory out a pool - * @param p The pool to allocate out of - * @param ... The strings to concatenate. The final string must be NULL - * @return The new string - */ -APR_DECLARE_NONSTD(char *) apr_pstrcat(apr_pool_t *p, ...); - -/** - * Concatenate multiple strings specified in a writev-style vector - * @param p The pool from which to allocate - * @param vec The strings to concatenate - * @param nvec The number of strings to concatenate - * @param nbytes (output) strlen of new string (pass in NULL to omit) - * @return The new string - */ -APR_DECLARE(char *) apr_pstrcatv(apr_pool_t *p, const struct iovec *vec, - apr_size_t nvec, apr_size_t *nbytes); - -/** - * printf-style style printing routine. The data is output to a string - * allocated from a pool - * @param p The pool to allocate out of - * @param fmt The format of the string - * @param ap The arguments to use while printing the data - * @return The new string - */ -APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *p, const char *fmt, va_list ap); - -/** - * printf-style style printing routine. The data is output to a string - * allocated from a pool - * @param p The pool to allocate out of - * @param fmt The format of the string - * @param ... The arguments to use while printing the data - * @return The new string - */ -APR_DECLARE_NONSTD(char *) apr_psprintf(apr_pool_t *p, const char *fmt, ...) - __attribute__((format(printf,2,3))); - -/** - * Copy up to dst_size characters from src to dst; does not copy - * past a NUL terminator in src, but always terminates dst with a NUL - * regardless. - * @param dst The destination string - * @param src The source string - * @param dst_size The space available in dst; dst always receives - * NUL termination, so if src is longer than - * dst_size, the actual number of characters copied is - * dst_size - 1. - * @return Pointer to the NUL terminator of the destination string, dst - * @remark - *
- * Note the differences between this function and strncpy():
- *  1) strncpy() doesn't always NUL terminate; apr_cpystrn() does.
- *  2) strncpy() pads the destination string with NULs, which is often 
- *     unnecessary; apr_cpystrn() does not.
- *  3) strncpy() returns a pointer to the beginning of the dst string;
- *     apr_cpystrn() returns a pointer to the NUL terminator of dst, 
- *     to allow a check for truncation.
- * 
- */ -APR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, - apr_size_t dst_size); - -/** - * Strip spaces from a string - * @param dest The destination string. It is okay to modify the string - * in place. Namely dest == src - * @param src The string to rid the spaces from. - * @return The destination string, dest. - */ -APR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src); - -/** - * Convert the arguments to a program from one string to an array of - * strings terminated by a NULL pointer - * @param arg_str The arguments to convert - * @param argv_out Output location. This is a pointer to an array of strings. - * @param token_context Pool to use. - */ -APR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str, - char ***argv_out, - apr_pool_t *token_context); - -/** - * Split a string into separate null-terminated tokens. The tokens are - * delimited in the string by one or more characters from the sep - * argument. - * @param str The string to separate; this should be specified on the - * first call to apr_strtok() for a given string, and NULL - * on subsequent calls. - * @param sep The set of delimiters - * @param last Internal state saved by apr_strtok() between calls. - * @return The next token from the string - */ -APR_DECLARE(char *) apr_strtok(char *str, const char *sep, char **last); - -/** - * @defgroup APR_Strings_Snprintf snprintf implementations - * @warning - * These are snprintf implementations based on apr_vformatter(). - * - * Note that various standards and implementations disagree on the return - * value of snprintf, and side-effects due to %n in the formatting string. - * apr_snprintf (and apr_vsnprintf) behaves as follows: - * - * Process the format string until the entire string is exhausted, or - * the buffer fills. If the buffer fills then stop processing immediately - * (so no further %n arguments are processed), and return the buffer - * length. In all cases the buffer is NUL terminated. It will return the - * number of characters inserted into the buffer, not including the - * terminating NUL. As a special case, if len is 0, apr_snprintf will - * return the number of characters that would have been inserted if - * the buffer had been infinite (in this case, *buffer can be NULL) - * - * In no event does apr_snprintf return a negative number. - * @{ - */ - -/** - * snprintf routine based on apr_vformatter. This means it understands the - * same extensions. - * @param buf The buffer to write to - * @param len The size of the buffer - * @param format The format string - * @param ... The arguments to use to fill out the format string. - */ -APR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, - const char *format, ...) - __attribute__((format(printf,3,4))); - -/** - * vsnprintf routine based on apr_vformatter. This means it understands the - * same extensions. - * @param buf The buffer to write to - * @param len The size of the buffer - * @param format The format string - * @param ap The arguments to use to fill out the format string. - */ -APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format, - va_list ap); -/** @} */ - -/** - * create a string representation of an int, allocated from a pool - * @param p The pool from which to allocate - * @param n The number to format - * @return The string representation of the number - */ -APR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n); - -/** - * create a string representation of a long, allocated from a pool - * @param p The pool from which to allocate - * @param n The number to format - * @return The string representation of the number - */ -APR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n); - -/** - * create a string representation of an apr_off_t, allocated from a pool - * @param p The pool from which to allocate - * @param n The number to format - * @return The string representation of the number - */ -APR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, apr_off_t n); - -/** - * Convert a numeric string into an apr_off_t numeric value. - * @param offset The value of the parsed string. - * @param buf The string to parse. It may contain optional whitespace, - * followed by an optional '+' (positive, default) or '-' (negative) - * character, followed by an optional '0x' prefix if base is 0 or 16, - * followed by numeric digits appropriate for base. - * @param end A pointer to the end of the valid character in buf. If - * not NULL, it is set to the first invalid character in buf. - * @param base A numeric base in the range between 2 and 36 inclusive, - * or 0. If base is zero, buf will be treated as base ten unless its - * digits are prefixed with '0x', in which case it will be treated as - * base 16. - * @bug *end breaks type safety; where *buf is const, *end needs to be - * declared as const in APR 2.0 - */ -APR_DECLARE(apr_status_t) apr_strtoff(apr_off_t *offset, const char *buf, - char **end, int base); - -/** - * parse a numeric string into a 64-bit numeric value - * @param buf The string to parse. It may contain optional whitespace, - * followed by an optional '+' (positive, default) or '-' (negative) - * character, followed by an optional '0x' prefix if base is 0 or 16, - * followed by numeric digits appropriate for base. - * @param end A pointer to the end of the valid character in buf. If - * not NULL, it is set to the first invalid character in buf. - * @param base A numeric base in the range between 2 and 36 inclusive, - * or 0. If base is zero, buf will be treated as base ten unless its - * digits are prefixed with '0x', in which case it will be treated as - * base 16. - * @return The numeric value of the string. On overflow, errno is set - * to ERANGE. - */ -APR_DECLARE(apr_int64_t) apr_strtoi64(const char *buf, char **end, int base); - -/** - * parse a base-10 numeric string into a 64-bit numeric value. - * Equivalent to apr_strtoi64(buf, (char**)NULL, 10). - * @param buf The string to parse - * @return The numeric value of the string - */ -APR_DECLARE(apr_int64_t) apr_atoi64(const char *buf); - -/** - * Format a binary size (magnitiudes are 2^10 rather than 10^3) from an apr_off_t, - * as bytes, K, M, T, etc, to a four character compacted human readable string. - * @param size The size to format - * @param buf The 5 byte text buffer (counting the trailing null) - * @return The buf passed to apr_strfsize() - * @remark All negative sizes report ' - ', apr_strfsize only formats positive values. - */ -APR_DECLARE(char *) apr_strfsize(apr_off_t size, char *buf); - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* !APR_STRINGS_H */ diff --git a/src/TortoiseMerge/svninclude/apr_tables.h b/src/TortoiseMerge/svninclude/apr_tables.h deleted file mode 100644 index bd25a22..0000000 --- a/src/TortoiseMerge/svninclude/apr_tables.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef APR_TABEL_XX -#define ARP_TABEL_XX - -typedef int apr_array_header_t ; - -#endif \ No newline at end of file diff --git a/src/TortoiseMerge/svninclude/apr_time.h b/src/TortoiseMerge/svninclude/apr_time.h deleted file mode 100644 index 2036913..0000000 --- a/src/TortoiseMerge/svninclude/apr_time.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef APR_TIME_XX -#define APR_TIME_XX - -typedef int apr_time_t; - - -#endif \ No newline at end of file diff --git a/src/TortoiseMerge/svninclude/apr_want.h b/src/TortoiseMerge/svninclude/apr_want.h deleted file mode 100644 index e69de29..0000000 diff --git a/src/TortoiseMerge/svninclude/svn_auth.h b/src/TortoiseMerge/svninclude/svn_auth.h new file mode 100644 index 0000000..cd2eabe --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_auth.h @@ -0,0 +1,1220 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2002-2009 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_auth.h + * @brief Subversion's authentication system + */ + +#ifndef SVN_AUTH_H +#define SVN_AUTH_H + +#include +#include +#include +#include + +#include "svn_types.h" +#include "svn_config.h" +#include "svn_version.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Overview of the svn authentication system. + * + * We define an authentication "provider" as a module that is able to + * return a specific set of credentials. (e.g. username/password, + * certificate, etc.) Each provider implements a vtable that + * + * - can fetch initial credentials + * - can retry the fetch (or try to fetch something different) + * - can store the credentials for future use + * + * For any given type of credentials, there can exist any number of + * separate providers -- each provider has a different method of + * fetching. (i.e. from a disk store, by prompting the user, etc.) + * + * The application begins by creating an auth baton object, and + * "registers" some number of providers with the auth baton, in a + * specific order. (For example, it may first register a + * username/password provider that looks in disk store, then register + * a username/password provider that prompts the user.) + * + * Later on, when any svn library is challenged, it asks the auth + * baton for the specific credentials. If the initial credentials + * fail to authenticate, the caller keeps requesting new credentials. + * Under the hood, libsvn_auth effectively "walks" over each provider + * (in order of registry), one at a time, until all the providers have + * exhausted all their retry options. + * + * This system allows an application to flexibly define authentication + * behaviors (by changing registration order), and very easily write + * new authentication providers. + * + * An auth_baton also contains an internal hashtable of run-time + * parameters; any provider or library layer can set these run-time + * parameters at any time, so that the provider has access to the + * data. (For example, certain run-time data may not be available + * until an authentication challenge is made.) Each credential type + * must document the run-time parameters that are made available to + * its providers. + * + * @defgroup auth_fns Authentication functions + * @{ + */ + + +/** The type of a Subversion authentication object */ +typedef struct svn_auth_baton_t svn_auth_baton_t; + +/** The type of a Subversion authentication-iteration object */ +typedef struct svn_auth_iterstate_t svn_auth_iterstate_t; + + +/** The main authentication "provider" vtable. */ +typedef struct svn_auth_provider_t +{ + /** The kind of credentials this provider knows how to retrieve. */ + const char *cred_kind; + + /** Get an initial set of credentials. + * + * Set @a *credentials to a set of valid credentials within @a + * realmstring, or NULL if no credentials are available. Set @a + * *iter_baton to context that allows a subsequent call to @c + * next_credentials, in case the first credentials fail to + * authenticate. @a provider_baton is general context for the + * vtable, @a parameters contains any run-time data that the + * provider may need, and @a realmstring comes from the + * svn_auth_first_credentials() call. + */ + svn_error_t * (*first_credentials)(void **credentials, + void **iter_baton, + void *provider_baton, + apr_hash_t *parameters, + const char *realmstring, + apr_pool_t *pool); + + /** Get a different set of credentials. + * + * Set @a *credentials to another set of valid credentials (using @a + * iter_baton as the context from previous call to first_credentials + * or next_credentials). If no more credentials are available, set + * @a *credentials to NULL. If the provider only has one set of + * credentials, this function pointer should simply be NULL. @a + * provider_baton is general context for the vtable, @a parameters + * contains any run-time data that the provider may need, and @a + * realmstring comes from the svn_auth_first_credentials() call. + */ + svn_error_t * (*next_credentials)(void **credentials, + void *iter_baton, + void *provider_baton, + apr_hash_t *parameters, + const char *realmstring, + apr_pool_t *pool); + + /** Save credentials. + * + * Store @a credentials for future use. @a provider_baton is + * general context for the vtable, and @a parameters contains any + * run-time data the provider may need. Set @a *saved to TRUE if + * the save happened, or FALSE if not. The provider is not required + * to save; if it refuses or is unable to save for non-fatal + * reasons, return FALSE. If the provider never saves data, then + * this function pointer should simply be NULL. @a realmstring comes + * from the svn_auth_first_credentials() call. + */ + svn_error_t * (*save_credentials)(svn_boolean_t *saved, + void *credentials, + void *provider_baton, + apr_hash_t *parameters, + const char *realmstring, + apr_pool_t *pool); + +} svn_auth_provider_t; + + +/** A provider object, ready to be put into an array and given to + svn_auth_open(). */ +typedef struct svn_auth_provider_object_t +{ + const svn_auth_provider_t *vtable; + void *provider_baton; + +} svn_auth_provider_object_t; + +/** The type of function returning authentication provider. */ +typedef void (*svn_auth_simple_provider_func_t) + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); + + +/** Specific types of credentials **/ + +/** Simple username/password pair credential kind. + * + * The following auth parameters are available to the providers: + * + * - @c SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG (@c svn_config_t*) + * - @c SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS (@c svn_config_t*) + * + * The following auth parameters may be available to the providers: + * + * - @c SVN_AUTH_PARAM_NO_AUTH_CACHE (@c void*) + * - @c SVN_AUTH_PARAM_DEFAULT_USERNAME (@c char*) + * - @c SVN_AUTH_PARAM_DEFAULT_PASSWORD (@c char*) + */ +#define SVN_AUTH_CRED_SIMPLE "svn.simple" + +/** @c SVN_AUTH_CRED_SIMPLE credentials. */ +typedef struct svn_auth_cred_simple_t +{ + /** Username */ + const char *username; + /** Password */ + const char *password; + /** Indicates if the credentials may be saved (to disk). For example, a + * GUI prompt implementation with a remember password checkbox shall set + * @a may_save to TRUE if the checkbox is checked. + */ + svn_boolean_t may_save; +} svn_auth_cred_simple_t; + + +/** Username credential kind. + * + * The following optional auth parameters are relevant to the providers: + * + * - @c SVN_AUTH_PARAM_NO_AUTH_CACHE (@c void*) + * - @c SVN_AUTH_PARAM_DEFAULT_USERNAME (@c char*) + */ +#define SVN_AUTH_CRED_USERNAME "svn.username" + +/** @c SVN_AUTH_CRED_USERNAME credentials. */ +typedef struct svn_auth_cred_username_t +{ + /** Username */ + const char *username; + /** Indicates if the credentials may be saved (to disk). For example, a + * GUI prompt implementation with a remember username checkbox shall set + * @a may_save to TRUE if the checkbox is checked. + */ + svn_boolean_t may_save; +} svn_auth_cred_username_t; + + +/** SSL client certificate credential type. + * + * The following auth parameters are available to the providers: + * + * - @c SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS (@c svn_config_t*) + * - @c SVN_AUTH_PARAM_SERVER_GROUP (@c char*) + * + * The following optional auth parameters are relevant to the providers: + * + * - @c SVN_AUTH_PARAM_NO_AUTH_CACHE (@c void*) + */ +#define SVN_AUTH_CRED_SSL_CLIENT_CERT "svn.ssl.client-cert" + +/** @c SVN_AUTH_CRED_SSL_CLIENT_CERT credentials. */ +typedef struct svn_auth_cred_ssl_client_cert_t +{ + /** Absolute path to the certificate file */ + const char *cert_file; + /** Indicates if the credentials may be saved (to disk). For example, a + * GUI prompt implementation with a remember certificate checkbox shall + * set @a may_save to TRUE if the checkbox is checked. + */ + svn_boolean_t may_save; +} svn_auth_cred_ssl_client_cert_t; + + +/** A function returning an SSL client certificate passphrase provider. */ +typedef void (*svn_auth_ssl_client_cert_pw_provider_func_t) + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); + +/** SSL client certificate passphrase credential type. + * + * @note The realmstring used with this credential type must be a name that + * makes it possible for the user to identify the certificate. + * + * The following auth parameters are available to the providers: + * + * - @c SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG (@c svn_config_t*) + * - @c SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS (@c svn_config_t*) + * - @c SVN_AUTH_PARAM_SERVER_GROUP (@c char*) + * + * The following optional auth parameters are relevant to the providers: + * + * - @c SVN_AUTH_PARAM_NO_AUTH_CACHE (@c void*) + */ +#define SVN_AUTH_CRED_SSL_CLIENT_CERT_PW "svn.ssl.client-passphrase" + +/** @c SVN_AUTH_CRED_SSL_CLIENT_CERT_PW credentials. */ +typedef struct svn_auth_cred_ssl_client_cert_pw_t +{ + /** Certificate password */ + const char *password; + /** Indicates if the credentials may be saved (to disk). For example, a + * GUI prompt implementation with a remember password checkbox shall set + * @a may_save to TRUE if the checkbox is checked. + */ + svn_boolean_t may_save; +} svn_auth_cred_ssl_client_cert_pw_t; + + +/** SSL server verification credential type. + * + * The following auth parameters are available to the providers: + * + * - @c SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS (@c svn_config_t*) + * - @c SVN_AUTH_PARAM_SERVER_GROUP (@c char*) + * - @c SVN_AUTH_PARAM_SSL_SERVER_FAILURES (@c apr_uint32_t*) + * - @c SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO + * (@c svn_auth_ssl_server_cert_info_t*) + * + * The following optional auth parameters are relevant to the providers: + * + * - @c SVN_AUTH_PARAM_NO_AUTH_CACHE (@c void*) + */ +#define SVN_AUTH_CRED_SSL_SERVER_TRUST "svn.ssl.server" + +/** SSL server certificate information used by @c + * SVN_AUTH_CRED_SSL_SERVER_TRUST providers. + */ +typedef struct svn_auth_ssl_server_cert_info_t +{ + /** Primary CN */ + const char *hostname; + /** ASCII fingerprint */ + const char *fingerprint; + /** ASCII date from which the certificate is valid */ + const char *valid_from; + /** ASCII date until which the certificate is valid */ + const char *valid_until; + /** DN of the certificate issuer */ + const char *issuer_dname; + /** Base-64 encoded DER certificate representation */ + const char *ascii_cert; +} svn_auth_ssl_server_cert_info_t; + +/** + * Return a deep copy of @a info, allocated in @a pool. + * + * @since New in 1.3. + */ +svn_auth_ssl_server_cert_info_t * +svn_auth_ssl_server_cert_info_dup(const svn_auth_ssl_server_cert_info_t *info, + apr_pool_t *pool); + +/** @c SVN_AUTH_CRED_SSL_SERVER_TRUST credentials. */ +typedef struct svn_auth_cred_ssl_server_trust_t +{ + /** Indicates if the credentials may be saved (to disk). For example, a + * GUI prompt implementation with a checkbox to accept the certificate + * permanently shall set @a may_save to TRUE if the checkbox is checked. + */ + svn_boolean_t may_save; + /** Bit mask of the accepted failures */ + apr_uint32_t accepted_failures; +} svn_auth_cred_ssl_server_trust_t; + + + +/** Credential-constructing prompt functions. **/ + +/** These exist so that different client applications can use + * different prompt mechanisms to supply the same credentials. For + * example, if authentication requires a username and password, a + * command-line client's prompting function might prompt first for the + * username and then for the password, whereas a GUI client's would + * present a single dialog box asking for both, and a telepathic + * client's would read all the information directly from the user's + * mind. All these prompting functions return the same type of + * credential, but the information used to construct the credential is + * gathered in an interface-specific way in each case. + */ + +/** Set @a *cred by prompting the user, allocating @a *cred in @a pool. + * @a baton is an implementation-specific closure. + * + * If @a realm is non-NULL, maybe use it in the prompt string. + * + * If @a username is non-NULL, then the user might be prompted only + * for a password, but @a *cred would still be filled with both + * username and password. For example, a typical usage would be to + * pass @a username on the first call, but then leave it NULL for + * subsequent calls, on the theory that if credentials failed, it's + * as likely to be due to incorrect username as incorrect password. + * + * If @a may_save is FALSE, the auth system does not allow the credentials + * to be saved (to disk). A prompt function shall not ask the user if the + * credentials shall be saved if @a may_save is FALSE. For example, a GUI + * client with a remember password checkbox would grey out the checkbox if + * @a may_save is FALSE. + */ +typedef svn_error_t *(*svn_auth_simple_prompt_func_t) + (svn_auth_cred_simple_t **cred, + void *baton, + const char *realm, + const char *username, + svn_boolean_t may_save, + apr_pool_t *pool); + + +/** Set @a *cred by prompting the user, allocating @a *cred in @a pool. + * @a baton is an implementation-specific closure. + * + * If @a realm is non-NULL, maybe use it in the prompt string. + * + * If @a may_save is FALSE, the auth system does not allow the credentials + * to be saved (to disk). A prompt function shall not ask the user if the + * credentials shall be saved if @a may_save is FALSE. For example, a GUI + * client with a remember username checkbox would grey out the checkbox if + * @a may_save is FALSE. + */ +typedef svn_error_t *(*svn_auth_username_prompt_func_t) + (svn_auth_cred_username_t **cred, + void *baton, + const char *realm, + svn_boolean_t may_save, + apr_pool_t *pool); + + +/** @name SSL server certificate failure bits + * + * @note These values are stored in the on disk auth cache by the SSL + * server certificate auth provider, so the meaning of these bits must + * not be changed. + * @{ + */ +/** Certificate is not yet valid. */ +#define SVN_AUTH_SSL_NOTYETVALID 0x00000001 +/** Certificate has expired. */ +#define SVN_AUTH_SSL_EXPIRED 0x00000002 +/** Certificate's CN (hostname) does not match the remote hostname. */ +#define SVN_AUTH_SSL_CNMISMATCH 0x00000004 +/** @brief Certificate authority is unknown (i.e. not trusted) */ +#define SVN_AUTH_SSL_UNKNOWNCA 0x00000008 +/** @brief Other failure. This can happen if neon has introduced a new + * failure bit that we do not handle yet. */ +#define SVN_AUTH_SSL_OTHER 0x40000000 +/** @} */ + +/** Set @a *cred by prompting the user, allocating @a *cred in @a pool. + * @a baton is an implementation-specific closure. + * + * @a cert_info is a structure describing the server cert that was + * presented to the client, and @a failures is a bitmask that + * describes exactly why the cert could not be automatically validated, + * composed from the constants SVN_AUTH_SSL_* (@c SVN_AUTH_SSL_NOTYETVALID + * etc.). @a realm is a string that can be used in the prompt string. + * + * If @a may_save is FALSE, the auth system does not allow the credentials + * to be saved (to disk). A prompt function shall not ask the user if the + * credentials shall be saved if @a may_save is FALSE. For example, a GUI + * client with a trust permanently checkbox would grey out the checkbox if + * @a may_save is FALSE. + */ +typedef svn_error_t *(*svn_auth_ssl_server_trust_prompt_func_t) + (svn_auth_cred_ssl_server_trust_t **cred, + void *baton, + const char *realm, + apr_uint32_t failures, + const svn_auth_ssl_server_cert_info_t *cert_info, + svn_boolean_t may_save, + apr_pool_t *pool); + + +/** Set @a *cred by prompting the user, allocating @a *cred in @a pool. + * @a baton is an implementation-specific closure. @a realm is a string + * that can be used in the prompt string. + * + * If @a may_save is FALSE, the auth system does not allow the credentials + * to be saved (to disk). A prompt function shall not ask the user if the + * credentials shall be saved if @a may_save is FALSE. For example, a GUI + * client with a remember certificate checkbox would grey out the checkbox + * if @a may_save is FALSE. + */ +typedef svn_error_t *(*svn_auth_ssl_client_cert_prompt_func_t) + (svn_auth_cred_ssl_client_cert_t **cred, + void *baton, + const char *realm, + svn_boolean_t may_save, + apr_pool_t *pool); + + +/** Set @a *cred by prompting the user, allocating @a *cred in @a pool. + * @a baton is an implementation-specific closure. @a realm is a string + * identifying the certificate, and can be used in the prompt string. + * + * If @a may_save is FALSE, the auth system does not allow the credentials + * to be saved (to disk). A prompt function shall not ask the user if the + * credentials shall be saved if @a may_save is FALSE. For example, a GUI + * client with a remember password checkbox would grey out the checkbox if + * @a may_save is FALSE. + */ +typedef svn_error_t *(*svn_auth_ssl_client_cert_pw_prompt_func_t) + (svn_auth_cred_ssl_client_cert_pw_t **cred, + void *baton, + const char *realm, + svn_boolean_t may_save, + apr_pool_t *pool); + +/** A type of callback function for asking whether storing a password to + * disk in plaintext is allowed. + * + * In this callback, the client should ask the user whether storing + * a password for the realm identified by @a realmstring to disk + * in plaintext is allowed. + * + * The answer is returned in @a *may_save_plaintext. + * @a baton is an implementation-specific closure. + * All allocations should be done in @a pool. + * + * @since New in 1.6 + */ +typedef svn_error_t *(*svn_auth_plaintext_prompt_func_t) + (svn_boolean_t *may_save_plaintext, + const char *realmstring, + void *baton, + apr_pool_t *pool); + +/** A type of callback function for asking whether storing a passphrase to + * disk in plaintext is allowed. + * + * In this callback, the client should ask the user whether storing + * a passphrase for the realm identified by @a realmstring to disk + * in plaintext is allowed. + * + * The answer is returned in @a *may_save_plaintext. + * @a baton is an implementation-specific closure. + * All allocations should be done in @a pool. + * + * @since New in 1.6 + */ +typedef svn_error_t *(*svn_auth_plaintext_passphrase_prompt_func_t) + (svn_boolean_t *may_save_plaintext, + const char *realmstring, + void *baton, + apr_pool_t *pool); + + +/** Initialize an authentication system. + * + * Return an authentication object in @a *auth_baton (allocated in @a + * pool) that represents a particular instance of the svn + * authentication system. @a providers is an array of @c + * svn_auth_provider_object_t pointers, already allocated in @a pool + * and intentionally ordered. These pointers will be stored within @a + * *auth_baton, grouped by credential type, and searched in this exact + * order. + */ +void +svn_auth_open(svn_auth_baton_t **auth_baton, + apr_array_header_t *providers, + apr_pool_t *pool); + +/** Set an authentication run-time parameter. + * + * Store @a name / @a value pair as a run-time parameter in @a + * auth_baton, making the data accessible to all providers. @a name + * and @a value will NOT be duplicated into the auth_baton's pool. + * To delete a run-time parameter, pass NULL for @a value. + */ +void +svn_auth_set_parameter(svn_auth_baton_t *auth_baton, + const char *name, + const void *value); + +/** Get an authentication run-time parameter. + * + * Return a value for run-time parameter @a name from @a auth_baton. + * Return NULL if the parameter doesn't exist. + */ +const void * +svn_auth_get_parameter(svn_auth_baton_t *auth_baton, + const char *name); + +/** Universal run-time parameters, made available to all providers. + + If you are writing a new provider, then to be a "good citizen", + you should notice these global parameters! Note that these + run-time params should be treated as read-only by providers; the + application is responsible for placing them into the auth_baton + hash. */ + +/** The auth-hash prefix indicating that the parameter is global. */ +#define SVN_AUTH_PARAM_PREFIX "svn:auth:" + +/** + * @name Default credentials defines + * Any 'default' credentials that came in through the application itself, + * (e.g. --username and --password options). Property values are + * const char *. + * @{ */ +#define SVN_AUTH_PARAM_DEFAULT_USERNAME SVN_AUTH_PARAM_PREFIX "username" +#define SVN_AUTH_PARAM_DEFAULT_PASSWORD SVN_AUTH_PARAM_PREFIX "password" +/** @} */ + +/** @brief The application doesn't want any providers to prompt + * users. Property value is irrelevant; only property's existence + * matters. */ +#define SVN_AUTH_PARAM_NON_INTERACTIVE SVN_AUTH_PARAM_PREFIX "non-interactive" + +/** @brief The application doesn't want any providers to save passwords + * to disk. Property value is irrelevant; only property's existence + * matters. */ +#define SVN_AUTH_PARAM_DONT_STORE_PASSWORDS SVN_AUTH_PARAM_PREFIX \ + "dont-store-passwords" + +/** @brief Indicates whether providers may save passwords to disk in + * plaintext. Property value can be either SVN_CONFIG_TRUE, + * SVN_CONFIG_FALSE, or SVN_CONFIG_ASK. */ +#define SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS SVN_AUTH_PARAM_PREFIX \ + "store-plaintext-passwords" + +/** @brief The application doesn't want any providers to save passphrase + * to disk. Property value is irrelevant; only property's existence + * matters. */ +#define SVN_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP \ + SVN_AUTH_PARAM_PREFIX "dont-store-ssl-client-cert-pp" + +/** @brief Indicates whether providers may save passphrase to disk in + * plaintext. Property value can be either SVN_CONFIG_TRUE, + * SVN_CONFIG_FALSE, or SVN_CONFIG_ASK. */ +#define SVN_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \ + SVN_AUTH_PARAM_PREFIX "store-ssl-client-cert-pp-plaintext" + +/** @brief The application doesn't want any providers to save credentials + * to disk. Property value is irrelevant; only property's existence + * matters. */ +#define SVN_AUTH_PARAM_NO_AUTH_CACHE SVN_AUTH_PARAM_PREFIX "no-auth-cache" + +/** @brief The following property is for SSL server cert providers. This + * provides a pointer to an @c apr_uint32_t containing the failures + * detected by the certificate validator. */ +#define SVN_AUTH_PARAM_SSL_SERVER_FAILURES SVN_AUTH_PARAM_PREFIX \ + "ssl:failures" + +/** @brief The following property is for SSL server cert providers. This + * provides the cert info (svn_auth_ssl_server_cert_info_t). */ +#define SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO SVN_AUTH_PARAM_PREFIX \ + "ssl:cert-info" + +/** Some providers need access to the @c svn_config_t configuration. */ +#define SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG SVN_AUTH_PARAM_PREFIX "config-category-config" +#define SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS SVN_AUTH_PARAM_PREFIX "config-category-servers" + +/** @deprecated Provided for backward compatibility with the 1.5 API. */ +#define SVN_AUTH_PARAM_CONFIG SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS + +/** The current server group. */ +#define SVN_AUTH_PARAM_SERVER_GROUP SVN_AUTH_PARAM_PREFIX "server-group" + +/** @brief A configuration directory that overrides the default + * ~/.subversion. */ +#define SVN_AUTH_PARAM_CONFIG_DIR SVN_AUTH_PARAM_PREFIX "config-dir" + +/** Get an initial set of credentials. + * + * Ask @a auth_baton to set @a *credentials to a set of credentials + * defined by @a cred_kind and valid within @a realmstring, or NULL if + * no credentials are available. Otherwise, return an iteration state + * in @a *state, so that the caller can call + * svn_auth_next_credentials(), in case the first set of credentials + * fails to authenticate. + * + * Use @a pool to allocate @a *state, and for temporary allocation. + * Note that @a *credentials will be allocated in @a auth_baton's pool. + */ +svn_error_t * +svn_auth_first_credentials(void **credentials, + svn_auth_iterstate_t **state, + const char *cred_kind, + const char *realmstring, + svn_auth_baton_t *auth_baton, + apr_pool_t *pool); + +/** Get another set of credentials, assuming previous ones failed to + * authenticate. + * + * Use @a state to fetch a different set of @a *credentials, as a + * follow-up to svn_auth_first_credentials() or + * svn_auth_next_credentials(). If no more credentials are available, + * set @a *credentials to NULL. + * + * Note that @a *credentials will be allocated in @c auth_baton's pool. + */ +svn_error_t * +svn_auth_next_credentials(void **credentials, + svn_auth_iterstate_t *state, + apr_pool_t *pool); + +/** Save a set of credentials. + * + * Ask @a state to store the most recently returned credentials, + * presumably because they successfully authenticated. + * All allocations should be done in @a pool. + * + * If no credentials were ever returned, do nothing. + */ +svn_error_t * +svn_auth_save_credentials(svn_auth_iterstate_t *state, + apr_pool_t *pool); + +/** @} */ + +/** Set @a *provider to an authentication provider of type + * svn_auth_cred_simple_t that gets information by prompting the user + * with @a prompt_func and @a prompt_baton. Allocate @a *provider in + * @a pool. + * + * If both @c SVN_AUTH_PARAM_DEFAULT_USERNAME and + * @c SVN_AUTH_PARAM_DEFAULT_PASSWORD are defined as runtime + * parameters in the @c auth_baton, then @a *provider will return the + * default arguments when svn_auth_first_credentials() is called. If + * svn_auth_first_credentials() fails, then @a *provider will + * re-prompt @a retry_limit times (via svn_auth_next_credentials()). + * For infinite retries, set @a retry_limit to value less than 0. + * + * @since New in 1.4. + */ +void +svn_auth_get_simple_prompt_provider(svn_auth_provider_object_t **provider, + svn_auth_simple_prompt_func_t prompt_func, + void *prompt_baton, + int retry_limit, + apr_pool_t *pool); + + +/** Set @a *provider to an authentication provider of type @c + * svn_auth_cred_username_t that gets information by prompting the + * user with @a prompt_func and @a prompt_baton. Allocate @a *provider + * in @a pool. + * + * If @c SVN_AUTH_PARAM_DEFAULT_USERNAME is defined as a runtime + * parameter in the @c auth_baton, then @a *provider will return the + * default argument when svn_auth_first_credentials() is called. If + * svn_auth_first_credentials() fails, then @a *provider will + * re-prompt @a retry_limit times (via svn_auth_next_credentials()). + * For infinite retries, set @a retry_limit to value less than 0. + * + * @since New in 1.4. + */ +void +svn_auth_get_username_prompt_provider + (svn_auth_provider_object_t **provider, + svn_auth_username_prompt_func_t prompt_func, + void *prompt_baton, + int retry_limit, + apr_pool_t *pool); + + +/** Set @a *provider to an authentication provider of type @c + * svn_auth_cred_simple_t that gets/sets information from the user's + * ~/.subversion configuration directory. + * + * If the provider is going to save the password unencrypted, it calls @a + * plaintext_prompt_func, passing @a prompt_baton, before saving the + * password. + * + * If @a plaintext_prompt_func is NULL it is not called and the answer is + * assumed to be TRUE. This matches the deprecated behaviour of storing + * unencrypted passwords by default, and is only done this way for backward + * compatibility reasons. + * Client developers are highly encouraged to provide this callback + * to ensure their users are made aware of the fact that their password + * is going to be stored unencrypted. In the future, providers may + * default to not storing the password unencrypted if this callback is NULL. + * + * Clients can however set the callback to NULL and set + * SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS to SVN_CONFIG_FALSE or + * SVN_CONFIG_TRUE to enforce a certain behaviour. + * + * Allocate @a *provider in @a pool. + * + * If a default username or password is available, @a *provider will + * honor them as well, and return them when + * svn_auth_first_credentials() is called. (see @c + * SVN_AUTH_PARAM_DEFAULT_USERNAME and @c + * SVN_AUTH_PARAM_DEFAULT_PASSWORD). + * + * @since New in 1.6. + */ +void +svn_auth_get_simple_provider2 + (svn_auth_provider_object_t **provider, + svn_auth_plaintext_prompt_func_t plaintext_prompt_func, + void *prompt_baton, + apr_pool_t *pool); + +/** Like svn_auth_get_simple_provider2, but without the ability to + * call the svn_auth_plaintext_prompt_func_t callback, and the provider + * always assumes that it is allowed to store the password in plaintext. + * + * @deprecated Provided for backwards compatibility with the 1.5 API. + * @since New in 1.4. + */ +SVN_DEPRECATED +void +svn_auth_get_simple_provider(svn_auth_provider_object_t **provider, + apr_pool_t *pool); + +/** Set @a *provider to an authentication provider of type @c + * svn_auth_provider_object_t, or return @a NULL if the provider is not + * available for the requested platform or the requested provider is unknown. + * + * Valid @a provider_name values are: "gnome_keyring", "keychain", "kwallet" + * and "windows". + * + * Valid @a provider_type values are: "simple", "ssl_client_cert_pw" and + * "ssl_server_trust". + * + * Allocate @a *provider in @a pool. + * + * What actually happens is we invoke the appropriate provider function to + * supply the @a provider, like so: + * + * svn_auth_get___provider(@a provider, @a pool); + * + * @since New in 1.6. + */ +svn_error_t * +svn_auth_get_platform_specific_provider + (svn_auth_provider_object_t **provider, + const char *provider_name, + const char *provider_type, + apr_pool_t *pool); + +/** Set @a *providers to an array of svn_auth_provider_object_t * + * objects. + * Only client authentication providers available for the current platform are + * returned. Order of the platform-specific authentication providers is + * determined by the 'password-stores' configuration option which is retrieved + * from @a config. @a config can be NULL. + * + * Create and allocate @a *providers in @a pool. + * + * Default order of the platform-specific authentication providers: + * 1. gnome-keyring + * 2. kwallet + * 3. keychain + * 4. windows-cryptoapi + * + * @since New in 1.6. + */ +svn_error_t * +svn_auth_get_platform_specific_client_providers + (apr_array_header_t **providers, + svn_config_t *config, + apr_pool_t *pool); + +#if (defined(WIN32) && !defined(__MINGW32__)) || defined(DOXYGEN) +/** + * Set @a *provider to an authentication provider of type @c + * svn_auth_cred_simple_t that gets/sets information from the user's + * ~/.subversion configuration directory. Allocate @a *provider in + * @a pool. + * + * This is like svn_auth_get_simple_provider(), except that, when + * running on Window 2000 or newer (or any other Windows version that + * includes the CryptoAPI), the provider encrypts the password before + * storing it to disk. On earlier versions of Windows, the provider + * does nothing. + * + * @since New in 1.4. + * @note This function is only available on Windows. + * + * @note An administrative password reset may invalidate the account's + * secret key. This function will detect that situation and behave as + * if the password were not cached at all. + */ +void +svn_auth_get_windows_simple_provider(svn_auth_provider_object_t **provider, + apr_pool_t *pool); + +/** + * Set @a *provider to an authentication provider of type @c + * svn_auth_cred_ssl_client_cert_pw_t that gets/sets information from the + * user's ~/.subversion configuration directory. Allocate @a *provider in + * @a pool. + * + * This is like svn_auth_get_ssl_client_cert_pw_file_provider(), except that + * when running on Window 2000 or newer, the provider encrypts the password + * before storing it to disk. On earlier versions of Windows, the provider + * does nothing. + * + * @since New in 1.6 + * @note This function is only available on Windows. + * + * @note An administrative password reset may invalidate the account's + * secret key. This function will detect that situation and behave as + * if the password were not cached at all. + */ +void +svn_auth_get_windows_ssl_client_cert_pw_provider + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); + +/** + * Set @a *provider to an authentication provider of type @c + * svn_auth_cred_ssl_server_trust_t, allocated in @a pool. + * + * This provider automatically validates ssl server certificates with + * the CryptoApi, like Internet Explorer and the Windows network API do. + * This allows the rollout of root certificates via Windows Domain + * policies, instead of Subversion specific configuration. + * + * @since New in 1.5. + * @note This function is only available on Windows. + */ +void +svn_auth_get_windows_ssl_server_trust_provider + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); + +#endif /* WIN32 && !__MINGW32__ || DOXYGEN */ + +#if defined(DARWIN) || defined(DOXYGEN) +/** + * Set @a *provider to an authentication provider of type @c + * svn_auth_cred_simple_t that gets/sets information from the user's + * ~/.subversion configuration directory. Allocate @a *provider in + * @a pool. + * + * This is like svn_auth_get_simple_provider(), except that the + * password is stored in the Mac OS KeyChain. + * + * @since New in 1.4 + * @note This function is only available on Mac OS 10.2 and higher. + */ +void +svn_auth_get_keychain_simple_provider(svn_auth_provider_object_t **provider, + apr_pool_t *pool); + +/** + * Set @a *provider to an authentication provider of type @c + * svn_auth_cred_ssl_client_cert_pw_t that gets/sets information from the + * user's ~/.subversion configuration directory. Allocate @a *provider in + * @a pool. + * + * This is like svn_auth_get_ssl_client_cert_pw_file_provider(), except + * that the password is stored in the Mac OS KeyChain. + * + * @since New in 1.6 + * @note This function is only available on Mac OS 10.2 and higher. + */ +void +svn_auth_get_keychain_ssl_client_cert_pw_provider + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); +#endif /* DARWIN || DOXYGEN */ + +#if (!defined(DARWIN) && !defined(WIN32)) || defined(DOXYGEN) +/** A type of callback function for obtaining the GNOME Keyring password. + * + * In this callback, the client should ask the user for default keyring + * @a keyring_name password. + * + * The answer is returned in @a *keyring_password. + * @a baton is an implementation-specific closure. + * All allocations should be done in @a pool. + * + * @since New in 1.6 + */ +typedef svn_error_t *(*svn_auth_gnome_keyring_unlock_prompt_func_t) + (char **keyring_password, + const char *keyring_name, + void *baton, + apr_pool_t *pool); + + +/** libsvn_auth_gnome_keyring-specific run-time parameters. */ + +/** @brief The pointer to function which prompts user for GNOME Keyring + * password. + * The type of this pointer should be svn_auth_gnome_keyring_unlock_prompt_func_t. */ +#define SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC "gnome-keyring-unlock-prompt-func" + +/** @brief The baton which is passed to + * @c *SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC. */ +#define SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_BATON "gnome-keyring-unlock-prompt-baton" + + +/** + * Get libsvn_auth_gnome_keyring version information. + * + * @since New in 1.6 + */ +const svn_version_t * +svn_auth_gnome_keyring_version(void); + + +/** + * Set @a *provider to an authentication provider of type @c + * svn_auth_cred_simple_t that gets/sets information from the user's + * ~/.subversion configuration directory. + * + * This is like svn_client_get_simple_provider(), except that the + * password is stored in GNOME Keyring. + * + * If the GNOME Keyring is locked the provider calls + * @c *SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC in order to unlock + * the keyring. + * + * @c SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_BATON is passed to + * @c *SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC. + * + * Allocate @a *provider in @a pool. + * + * @since New in 1.6 + * @note This function actually works only on systems with + * libsvn_auth_gnome_keyring and GNOME Keyring installed. + */ +void +svn_auth_get_gnome_keyring_simple_provider + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); + + +/** + * Set @a *provider to an authentication provider of type @c + * svn_auth_cred_ssl_client_cert_pw_t that gets/sets information from the + * user's ~/.subversion configuration directory. + * + * This is like svn_client_get_ssl_client_cert_pw_file_provider(), except + * that the password is stored in GNOME Keyring. + * + * If the GNOME Keyring is locked the provider calls + * @c *SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC in order to unlock + * the keyring. + * + * @c SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_BATON is passed to + * @c *SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC. + * + * Allocate @a *provider in @a pool. + * + * @since New in 1.6 + * @note This function actually works only on systems with + * libsvn_auth_gnome_keyring and GNOME Keyring installed. + */ +void +svn_auth_get_gnome_keyring_ssl_client_cert_pw_provider + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); + + +/** + * Get libsvn_auth_kwallet version information. + * + * @since New in 1.6 + */ +const svn_version_t * +svn_auth_kwallet_version(void); + + +/** + * Set @a *provider to an authentication provider of type @c + * svn_auth_cred_simple_t that gets/sets information from the user's + * ~/.subversion configuration directory. Allocate @a *provider in + * @a pool. + * + * This is like svn_client_get_simple_provider(), except that the + * password is stored in KWallet. + * + * @since New in 1.6 + * @note This function actually works only on systems with libsvn_auth_kwallet + * and KWallet installed. + */ +void +svn_auth_get_kwallet_simple_provider(svn_auth_provider_object_t **provider, + apr_pool_t *pool); + + +/** + * Set @a *provider to an authentication provider of type @c + * svn_auth_cred_ssl_client_cert_pw_t that gets/sets information from the + * user's ~/.subversion configuration directory. Allocate @a *provider in + * @a pool. + * + * This is like svn_client_get_ssl_client_cert_pw_file_provider(), except + * that the password is stored in KWallet. + * + * @since New in 1.6 + * @note This function actually works only on systems with libsvn_auth_kwallet + * and KWallet installed. + */ +void +svn_auth_get_kwallet_ssl_client_cert_pw_provider + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); +#endif /* (!DARWIN && !WIN32) || DOXYGEN */ + + +/** Set @a *provider to an authentication provider of type @c + * svn_auth_cred_username_t that gets/sets information from a user's + * ~/.subversion configuration directory. Allocate @a *provider in + * @a pool. + * + * If a default username is available, @a *provider will honor it, + * and return it when svn_auth_first_credentials() is called. (See + * @c SVN_AUTH_PARAM_DEFAULT_USERNAME.) + * + * @since New in 1.4. + */ +void +svn_auth_get_username_provider(svn_auth_provider_object_t **provider, + apr_pool_t *pool); + + +/** Set @a *provider to an authentication provider of type @c + * svn_auth_cred_ssl_server_trust_t, allocated in @a pool. + * + * @a *provider retrieves its credentials from the configuration + * mechanism. The returned credential is used to override SSL + * security on an error. + * + * @since New in 1.4. + */ +void +svn_auth_get_ssl_server_trust_file_provider + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); + +/** Set @a *provider to an authentication provider of type @c + * svn_auth_cred_ssl_client_cert_t, allocated in @a pool. + * + * @a *provider retrieves its credentials from the configuration + * mechanism. The returned credential is used to load the appropriate + * client certificate for authentication when requested by a server. + * + * @since New in 1.4. + */ +void +svn_auth_get_ssl_client_cert_file_provider + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); + + +/** Set @a *provider to an authentication provider of type @c + * svn_auth_cred_ssl_client_cert_pw_t that gets/sets information from the user's + * ~/.subversion configuration directory. + * + * If the provider is going to save the passphrase unencrypted, + * it calls @a plaintext_passphrase_prompt_func, passing @a + * prompt_baton, before saving the passphrase. + * + * If @a plaintext_passphrase_prompt_func is NULL it is not called + * and the passphrase is not stored in plaintext. + * Client developers are highly encouraged to provide this callback + * to ensure their users are made aware of the fact that their passphrase + * is going to be stored unencrypted. + * + * Clients can however set the callback to NULL and set + * SVN_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT to SVN_CONFIG_FALSE or + * SVN_CONFIG_TRUE to enforce a certain behaviour. + * + * Allocate @a *provider in @a pool. + * + * @since New in 1.6. + */ +void +svn_auth_get_ssl_client_cert_pw_file_provider2 + (svn_auth_provider_object_t **provider, + svn_auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func, + void *prompt_baton, + apr_pool_t *pool); + +/** Like svn_auth_get_ssl_client_cert_pw_file_provider2, but without + * the ability to call the svn_auth_plaintext_passphrase_prompt_func_t + * callback, and the provider always assumes that it is not allowed + * to store the passphrase in plaintext. + * + * @deprecated Provided for backwards compatibility with the 1.5 API. + * @since New in 1.4. + */ +SVN_DEPRECATED +void +svn_auth_get_ssl_client_cert_pw_file_provider + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); + + +/** Set @a *provider to an authentication provider of type @c + * svn_auth_cred_ssl_server_trust_t, allocated in @a pool. + * + * @a *provider retrieves its credentials by using the @a prompt_func + * and @a prompt_baton. The returned credential is used to override + * SSL security on an error. + * + * @since New in 1.4. + */ +void +svn_auth_get_ssl_server_trust_prompt_provider + (svn_auth_provider_object_t **provider, + svn_auth_ssl_server_trust_prompt_func_t prompt_func, + void *prompt_baton, + apr_pool_t *pool); + + +/** Set @a *provider to an authentication provider of type @c + * svn_auth_cred_ssl_client_cert_t, allocated in @a pool. + * + * @a *provider retrieves its credentials by using the @a prompt_func + * and @a prompt_baton. The returned credential is used to load the + * appropriate client certificate for authentication when requested by + * a server. The prompt will be retried @a retry_limit times. For + * infinite retries, set @a retry_limit to value less than 0. + * + * @since New in 1.4. + */ +void +svn_auth_get_ssl_client_cert_prompt_provider + (svn_auth_provider_object_t **provider, + svn_auth_ssl_client_cert_prompt_func_t prompt_func, + void *prompt_baton, + int retry_limit, + apr_pool_t *pool); + + +/** Set @a *provider to an authentication provider of type @c + * svn_auth_cred_ssl_client_cert_pw_t, allocated in @a pool. + * + * @a *provider retrieves its credentials by using the @a prompt_func + * and @a prompt_baton. The returned credential is used when a loaded + * client certificate is protected by a passphrase. The prompt will + * be retried @a retry_limit times. For infinite retries, set + * @a retry_limit to value less than 0. + * + * @since New in 1.4. + */ +void +svn_auth_get_ssl_client_cert_pw_prompt_provider + (svn_auth_provider_object_t **provider, + svn_auth_ssl_client_cert_pw_prompt_func_t prompt_func, + void *prompt_baton, + int retry_limit, + apr_pool_t *pool); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_AUTH_H */ diff --git a/src/TortoiseMerge/svninclude/svn_checksum.h b/src/TortoiseMerge/svninclude/svn_checksum.h new file mode 100644 index 0000000..7a0ba35 --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_checksum.h @@ -0,0 +1,225 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_checksum.h + * @brief Subversion checksum routines + */ + +#ifndef SVN_CHECKSUM_H +#define SVN_CHECKSUM_H + +#include /* for apr_size_t */ +#include /* for apr_pool_t */ + +#include "svn_types.h" /* for svn_boolean_t, svn_error_t */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/** + * Various types of checksums. + * + * @since New in 1.6. + */ +typedef enum +{ + /** The checksum is (or should be set to) an MD5 checksum. */ + svn_checksum_md5, + + /** The checksum is (or should be set to) a SHA1 checksum. */ + svn_checksum_sha1 +} svn_checksum_kind_t; + +/** + * A generic checksum representation. + * + * @since New in 1.6. + */ +typedef struct svn_checksum_t +{ + /** The bytes of the checksum. */ + const unsigned char *digest; + + /** The type of the checksum. This should never be changed by consumers + of the APIs. */ + svn_checksum_kind_t kind; +} svn_checksum_t; + +/** + * Opaque type for creating checksums of data. + */ +typedef struct svn_checksum_ctx_t svn_checksum_ctx_t; + +/** Return a new checksum structure of type @a kind, initialized to the all- + * zeros value, allocated in @a pool. + * + * @since New in 1.6. + */ +svn_checksum_t * +svn_checksum_create(svn_checksum_kind_t kind, + apr_pool_t *pool); + +/** Set @c checksum->digest to all zeros, which, by convention, matches + * all other checksums. + * + * @since New in 1.6. + */ +svn_error_t * +svn_checksum_clear(svn_checksum_t *checksum); + +/** Compare checksums @a checksum1 and @a checksum2. If their kinds do not + * match or if neither is all zeros, and their content does not match, then + * return FALSE; else return TRUE. + * + * @since New in 1.6. + */ +svn_boolean_t +svn_checksum_match(const svn_checksum_t *checksum1, + const svn_checksum_t *checksum2); + + +/** + * Return a deep copy of @a checksum, allocated in @a pool. + * + * @since New in 1.6. + */ +svn_checksum_t * +svn_checksum_dup(const svn_checksum_t *checksum, + apr_pool_t *pool); + + +/** Return the hex representation of @a checksum, allocating the string + * in @a pool. + * + * @since New in 1.6. + */ +const char * +svn_checksum_to_cstring_display(const svn_checksum_t *checksum, + apr_pool_t *pool); + + +/** Return the hex representation of @a checksum, allocating the + * string in @a pool. If @a checksum->digest is all zeros (that is, + * 0, not '0'), then return NULL. + * + * @since New in 1.6. + */ +const char * +svn_checksum_to_cstring(const svn_checksum_t *checksum, + apr_pool_t *pool); + + +/** Parse the hex representation @a hex of a checksum of kind @a kind and + * set @a *checksum to the result, allocating in @a pool. + * + * If @a hex is @c NULL or is the all-zeros checksum, then set @a *checksum + * to @c NULL. + * + * @since New in 1.6. + */ +svn_error_t * +svn_checksum_parse_hex(svn_checksum_t **checksum, + svn_checksum_kind_t kind, + const char *hex, + apr_pool_t *pool); + +/** + * Return in @a *checksum the checksum of type @a kind for the bytes beginning + * at @a data, and going for @a len. @a *checksum is allocated in @a pool. + * + * @since New in 1.6. + */ +svn_error_t * +svn_checksum(svn_checksum_t **checksum, + svn_checksum_kind_t kind, + const void *data, + apr_size_t len, + apr_pool_t *pool); + + +/** + * Return in @a pool a newly allocated checksum populated with the checksum + * of type @a kind for the empty string. + * + * @since New in 1.6. + */ +svn_checksum_t * +svn_checksum_empty_checksum(svn_checksum_kind_t kind, + apr_pool_t *pool); + + +/** + * Create a new @c svn_checksum_ctx_t structure, allocated from @a pool for + * calculating checksums of type @a kind. @see svn_checksum_final() + * + * @since New in 1.6. + */ +svn_checksum_ctx_t * +svn_checksum_ctx_create(svn_checksum_kind_t kind, + apr_pool_t *pool); + +/** + * Update the checksum represented by @a ctx, with @a len bytes starting at + * @a data. + * + * @since New in 1.6. + */ +svn_error_t * +svn_checksum_update(svn_checksum_ctx_t *ctx, + const void *data, + apr_size_t len); + + +/** + * Finalize the checksum used when creating @a ctx, and put the resultant + * checksum in @a *checksum, allocated in @a pool. + * + * @since New in 1.6. + */ +svn_error_t * +svn_checksum_final(svn_checksum_t **checksum, + const svn_checksum_ctx_t *ctx, + apr_pool_t *pool); + + +/** + * Return the digest size of @a checksum. + * + * @since New in 1.6. + */ +apr_size_t +svn_checksum_size(const svn_checksum_t *checksum); + + +/** + * Internal function for creating a checksum from a binary digest. + * + * @since New in 1.6 + */ +svn_checksum_t * +svn_checksum__from_digest(const unsigned char *digest, + svn_checksum_kind_t kind, + apr_pool_t *result_pool); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_CHECKSUM_H */ diff --git a/src/TortoiseMerge/svninclude/svn_config.h b/src/TortoiseMerge/svninclude/svn_config.h new file mode 100644 index 0000000..a20e5ba --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_config.h @@ -0,0 +1,565 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_config.h + * @brief Accessing SVN configuration files. + */ + + + +#ifndef SVN_CONFIG_H +#define SVN_CONFIG_H + +#include /* for apr_int64_t */ +#include /* for apr_pool_t */ +#include /* for apr_hash_t */ + +#include "svn_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/************************************************************************** + *** *** + *** For a description of the SVN configuration file syntax, see *** + *** your ~/.subversion/README, which is written out automatically by *** + *** svn_config_ensure(). *** + *** *** + **************************************************************************/ + + +/** Opaque structure describing a set of configuration options. */ +typedef struct svn_config_t svn_config_t; + + +/*** Configuration Defines ***/ + +/** + * @name Client configuration files strings + * Strings for the names of files, sections, and options in the + * client configuration files. + * @{ + */ +#define SVN_CONFIG_CATEGORY_SERVERS "servers" +#define SVN_CONFIG_SECTION_GROUPS "groups" +#define SVN_CONFIG_SECTION_GLOBAL "global" +#define SVN_CONFIG_OPTION_HTTP_PROXY_HOST "http-proxy-host" +#define SVN_CONFIG_OPTION_HTTP_PROXY_PORT "http-proxy-port" +#define SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME "http-proxy-username" +#define SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD "http-proxy-password" +#define SVN_CONFIG_OPTION_HTTP_PROXY_EXCEPTIONS "http-proxy-exceptions" +#define SVN_CONFIG_OPTION_HTTP_TIMEOUT "http-timeout" +#define SVN_CONFIG_OPTION_HTTP_COMPRESSION "http-compression" +#define SVN_CONFIG_OPTION_NEON_DEBUG_MASK "neon-debug-mask" +#define SVN_CONFIG_OPTION_HTTP_AUTH_TYPES "http-auth-types" +#define SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES "ssl-authority-files" +#define SVN_CONFIG_OPTION_SSL_TRUST_DEFAULT_CA "ssl-trust-default-ca" +#define SVN_CONFIG_OPTION_SSL_CLIENT_CERT_FILE "ssl-client-cert-file" +#define SVN_CONFIG_OPTION_SSL_CLIENT_CERT_PASSWORD "ssl-client-cert-password" +#define SVN_CONFIG_OPTION_SSL_PKCS11_PROVIDER "ssl-pkcs11-provider" +#define SVN_CONFIG_OPTION_HTTP_LIBRARY "http-library" +#define SVN_CONFIG_OPTION_STORE_PASSWORDS "store-passwords" +#define SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS "store-plaintext-passwords" +#define SVN_CONFIG_OPTION_STORE_AUTH_CREDS "store-auth-creds" +#define SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP "store-ssl-client-cert-pp" +#define SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \ + "store-ssl-client-cert-pp-plaintext" +#define SVN_CONFIG_OPTION_USERNAME "username" + +#define SVN_CONFIG_CATEGORY_CONFIG "config" +#define SVN_CONFIG_SECTION_AUTH "auth" +#define SVN_CONFIG_OPTION_PASSWORD_STORES "password-stores" +#define SVN_CONFIG_OPTION_KWALLET_WALLET "kwallet-wallet" +#define SVN_CONFIG_OPTION_KWALLET_SVN_APPLICATION_NAME_WITH_PID "kwallet-svn-application-name-with-pid" +/* The majority of options of the "auth" section + * has been moved to SVN_CONFIG_CATEGORY_SERVERS. */ +#define SVN_CONFIG_SECTION_HELPERS "helpers" +#define SVN_CONFIG_OPTION_EDITOR_CMD "editor-cmd" +#define SVN_CONFIG_OPTION_DIFF_CMD "diff-cmd" +#define SVN_CONFIG_OPTION_DIFF3_CMD "diff3-cmd" +#define SVN_CONFIG_OPTION_DIFF3_HAS_PROGRAM_ARG "diff3-has-program-arg" +#define SVN_CONFIG_OPTION_MERGE_TOOL_CMD "merge-tool-cmd" +#define SVN_CONFIG_SECTION_MISCELLANY "miscellany" +#define SVN_CONFIG_OPTION_GLOBAL_IGNORES "global-ignores" +#define SVN_CONFIG_OPTION_LOG_ENCODING "log-encoding" +#define SVN_CONFIG_OPTION_USE_COMMIT_TIMES "use-commit-times" +#define SVN_CONFIG_OPTION_TEMPLATE_ROOT "template-root" +#define SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS "enable-auto-props" +#define SVN_CONFIG_OPTION_NO_UNLOCK "no-unlock" +#define SVN_CONFIG_OPTION_MIMETYPES_FILE "mime-types-file" +#define SVN_CONFIG_OPTION_PRESERVED_CF_EXTS "preserved-conflict-file-exts" +#define SVN_CONFIG_OPTION_INTERACTIVE_CONFLICTS "interactive-conflicts" +#define SVN_CONFIG_SECTION_TUNNELS "tunnels" +#define SVN_CONFIG_SECTION_AUTO_PROPS "auto-props" +/** @} */ + +/** @name Repository conf directory configuration files strings + * Strings for the names of sections and options in the + * repository conf directory configuration files. + * @{ + */ +/* For repository svnserve.conf files */ +#define SVN_CONFIG_SECTION_GENERAL "general" +#define SVN_CONFIG_OPTION_ANON_ACCESS "anon-access" +#define SVN_CONFIG_OPTION_AUTH_ACCESS "auth-access" +#define SVN_CONFIG_OPTION_PASSWORD_DB "password-db" +#define SVN_CONFIG_OPTION_REALM "realm" +#define SVN_CONFIG_OPTION_AUTHZ_DB "authz-db" +#define SVN_CONFIG_SECTION_SASL "sasl" +#define SVN_CONFIG_OPTION_USE_SASL "use-sasl" +#define SVN_CONFIG_OPTION_MIN_SSF "min-encryption" +#define SVN_CONFIG_OPTION_MAX_SSF "max-encryption" + +/* For repository password database */ +#define SVN_CONFIG_SECTION_USERS "users" +/** @} */ + +/*** Configuration Default Values ***/ + +/* '*' matches leading dots, e.g. '*.rej' matches '.foo.rej'. */ +/* We want this to be printed on two lines in the generated config file, + * but we don't want the # character to end up in the variable. + */ +#define SVN_CONFIG__DEFAULT_GLOBAL_IGNORES_LINE_1 \ + "*.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo" +#define SVN_CONFIG__DEFAULT_GLOBAL_IGNORES_LINE_2 \ + "*.rej *~ #*# .#* .*.swp .DS_Store" + +#define SVN_CONFIG_DEFAULT_GLOBAL_IGNORES \ + SVN_CONFIG__DEFAULT_GLOBAL_IGNORES_LINE_1 " " \ + SVN_CONFIG__DEFAULT_GLOBAL_IGNORES_LINE_2 + +#define SVN_CONFIG_TRUE "TRUE" +#define SVN_CONFIG_FALSE "FALSE" +#define SVN_CONFIG_ASK "ASK" + +/* Default values for some options. Should be passed as default values + * to svn_config_get and friends, instead of hard-coding the defaults in + * multiple places. */ +#define SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS TRUE +#define SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS SVN_CONFIG_ASK +#define SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS TRUE +#define SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP TRUE +#define SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \ + SVN_CONFIG_ASK + +/** Read configuration information from the standard sources and merge it + * into the hash @a *cfg_hash. If @a config_dir is not NULL it specifies a + * directory from which to read the configuration files, overriding all + * other sources. Otherwise, first read any system-wide configurations + * (from a file or from the registry), then merge in personal + * configurations (again from file or registry). The hash and all its data + * are allocated in @a pool. + * + * @a *cfg_hash is a hash whose keys are @c const char * configuration + * categories (@c SVN_CONFIG_CATEGORY_SERVERS, + * @c SVN_CONFIG_CATEGORY_CONFIG, etc.) and whose values are the @c + * svn_config_t * items representing the configuration values for that + * category. + */ +svn_error_t * +svn_config_get_config(apr_hash_t **cfg_hash, + const char *config_dir, + apr_pool_t *pool); + + +/** Read configuration data from @a file (a file or registry path) into + * @a *cfgp, allocated in @a pool. + * + * If @a file does not exist, then if @a must_exist, return an error, + * otherwise return an empty @c svn_config_t. + */ +svn_error_t * +svn_config_read(svn_config_t **cfgp, + const char *file, + svn_boolean_t must_exist, + apr_pool_t *pool); + +/** Like svn_config_read(), but merges the configuration data from @a file + * (a file or registry path) into @a *cfg, which was previously returned + * from svn_config_read(). This function invalidates all value + * expansions in @a cfg, so that the next svn_config_get() takes the + * modifications into account. + */ +svn_error_t * +svn_config_merge(svn_config_t *cfg, + const char *file, + svn_boolean_t must_exist); + + +/** Find the value of a (@a section, @a option) pair in @a cfg, set @a + * *valuep to the value. + * + * If @a cfg is @c NULL, just sets @a *valuep to @a default_value. If + * the value does not exist, expand and return @a default_value. @a + * default_value can be NULL. + * + * The returned value will be valid at least until the next call to + * svn_config_get(), or for the lifetime of @a default_value. It is + * safest to consume the returned value immediately. + * + * This function may change @a cfg by expanding option values. + */ +void +svn_config_get(svn_config_t *cfg, + const char **valuep, + const char *section, + const char *option, + const char *default_value); + +/** Add or replace the value of a (@a section, @a option) pair in @a cfg with + * @a value. + * + * This function invalidates all value expansions in @a cfg. + * + * To remove an option, pass NULL for the @c value. + */ +void +svn_config_set(svn_config_t *cfg, + const char *section, + const char *option, + const char *value); + +/** Like svn_config_get(), but for boolean values. + * + * Parses the option as a boolean value. The recognized representations + * are 'TRUE'/'FALSE', 'yes'/'no', 'on'/'off', '1'/'0'; case does not + * matter. Returns an error if the option doesn't contain a known string. + */ +svn_error_t * +svn_config_get_bool(svn_config_t *cfg, + svn_boolean_t *valuep, + const char *section, + const char *option, + svn_boolean_t default_value); + +/** Like svn_config_set(), but for boolean values. + * + * Sets the option to 'TRUE'/'FALSE', depending on @a value. + */ +void +svn_config_set_bool(svn_config_t *cfg, + const char *section, + const char *option, + svn_boolean_t value); + +/** Like svn_config_get(), but only for yes/no/ask values. + * + * Parse @a option in @a section and set @a *valuep to one of + * SVN_CONFIG_TRUE, SVN_CONFIG_FALSE, or SVN_CONFIG_ASK. If there is + * no setting for @a option, then parse @a default_value and set + * @a *valuep accordingly. If @a default_value is NULL, the result is + * undefined, and may be an error; we recommend that you pass one of + * SVN_CONFIG_TRUE, SVN_CONFIG_FALSE, or SVN_CONFIG_ASK for @a default value. + * + * Valid representations are (at least) "true"/"false", "yes"/"no", + * "on"/"off", "1"/"0", and "ask"; they are case-insensitive. Return + * an SVN_ERR_BAD_CONFIG_VALUE error if either @a default_value or + * @a option's value is not a valid representation. + * + * @since New in 1.6. + */ +svn_error_t * +svn_config_get_yes_no_ask(svn_config_t *cfg, + const char **valuep, + const char *section, + const char *option, + const char* default_value); + +/** Similar to @c svn_config_section_enumerator2_t, but is not + * provided with a memory pool argument. + * + * See svn_config_enumerate_sections() for the details of this type. + * + * @deprecated Provided for backwards compatibility with the 1.2 API. + */ +typedef svn_boolean_t (*svn_config_section_enumerator_t)(const char *name, + void *baton); + +/** Similar to svn_config_enumerate_sections2(), but uses a memory pool of + * @a cfg instead of one that is explicitely provided. + * + * @deprecated Provided for backwards compatibility with the 1.2 API. + */ +SVN_DEPRECATED +int +svn_config_enumerate_sections(svn_config_t *cfg, + svn_config_section_enumerator_t callback, + void *baton); + +/** A callback function used in enumerating config sections. + * + * See svn_config_enumerate_sections2() for the details of this type. + * + * @since New in 1.3. + */ +typedef svn_boolean_t (*svn_config_section_enumerator2_t)(const char *name, + void *baton, + apr_pool_t *pool); + +/** Enumerate the sections, passing @a baton and the current section's name + * to @a callback. Continue the enumeration if @a callback returns @c TRUE. + * Return the number of times @a callback was called. + * + * ### See kff's comment to svn_config_enumerate2(). It applies to this + * function, too. ### + * + * @a callback's @a name parameter is only valid for the duration of the call. + * + * @since New in 1.3. + */ +int +svn_config_enumerate_sections2(svn_config_t *cfg, + svn_config_section_enumerator2_t callback, + void *baton, apr_pool_t *pool); + +/** Similar to @c svn_config_enumerator2_t, but is not + * provided with a memory pool argument. + * See svn_config_enumerate() for the details of this type. + * + * @deprecated Provided for backwards compatibility with the 1.2 API. + */ +typedef svn_boolean_t (*svn_config_enumerator_t)(const char *name, + const char *value, + void *baton); + +/** Similar to svn_config_enumerate2(), but uses a memory pool of + * @a cfg instead of one that is explicitely provided. + * + * @deprecated Provided for backwards compatibility with the 1.2 API. + */ +SVN_DEPRECATED +int +svn_config_enumerate(svn_config_t *cfg, + const char *section, + svn_config_enumerator_t callback, + void *baton); + + +/** A callback function used in enumerating config options. + * + * See svn_config_enumerate2() for the details of this type. + * + * @since New in 1.3. + */ +typedef svn_boolean_t (*svn_config_enumerator2_t)(const char *name, + const char *value, + void *baton, + apr_pool_t *pool); + +/** Enumerate the options in @a section, passing @a baton and the current + * option's name and value to @a callback. Continue the enumeration if + * @a callback returns @c TRUE. Return the number of times @a callback + * was called. + * + * ### kff asks: A more usual interface is to continue enumerating + * while @a callback does not return error, and if @a callback does + * return error, to return the same error (or a wrapping of it) + * from svn_config_enumerate(). What's the use case for + * svn_config_enumerate()? Is it more likely to need to break out + * of an enumeration early, with no error, than an invocation of + * @a callback is likely to need to return an error? ### + * + * @a callback's @a name and @a value parameters are only valid for the + * duration of the call. + * + * @since New in 1.3. + */ +int +svn_config_enumerate2(svn_config_t *cfg, + const char *section, + svn_config_enumerator2_t callback, + void *baton, + apr_pool_t *pool); + +/** + * Return @c TRUE if @a section exists in @a cfg, @c FALSE otherwise. + * + * @since New in 1.4. + */ +svn_boolean_t +svn_config_has_section(svn_config_t *cfg, + const char *section); + +/** Enumerate the group @a master_section in @a cfg. Each variable + * value is interpreted as a list of glob patterns (separated by comma + * and optional whitespace). Return the name of the first variable + * whose value matches @a key, or @c NULL if no variable matches. + */ +const char * +svn_config_find_group(svn_config_t *cfg, + const char *key, + const char *master_section, + apr_pool_t *pool); + +/** Retrieve value corresponding to @a option_name in @a cfg, or + * return @a default_value if none is found. + * + * The config will first be checked for a default. + * If @a server_group is not @c NULL, the config will also be checked + * for an override in a server group, + * + */ +const char * +svn_config_get_server_setting(svn_config_t *cfg, + const char* server_group, + const char* option_name, + const char* default_value); + +/** Retrieve value into @a result_value corresponding to @a option_name for a + * given @a server_group in @a cfg, or return @a default_value if none is + * found. + * + * The config will first be checked for a default, then will be checked for + * an override in a server group. If the value found is not a valid integer, + * a @c svn_error_t* will be returned. + */ +svn_error_t * +svn_config_get_server_setting_int(svn_config_t *cfg, + const char *server_group, + const char *option_name, + apr_int64_t default_value, + apr_int64_t *result_value, + apr_pool_t *pool); + + +/** Set @a *valuep according to @a option_name for a given + * @a server_group in @a cfg, or set to @a default_value if no value is + * specified. + * + * Check first a default, then for an override in a server group. If + * a value is found but is not a valid boolean, return an + * SVN_ERR_BAD_CONFIG_VALUE error. + * + * @since New in 1.6. + */ +svn_error_t * +svn_config_get_server_setting_bool(svn_config_t *cfg, + svn_boolean_t *valuep, + const char *server_group, + const char *option_name, + svn_boolean_t default_value); + + + +/** Try to ensure that the user's ~/.subversion/ area exists, and create + * no-op template files for any absent config files. Use @a pool for any + * temporary allocation. If @a config_dir is not @c NULL it specifies a + * directory from which to read the config overriding all other sources. + * + * Don't error if something exists but is the wrong kind (for example, + * ~/.subversion exists but is a file, or ~/.subversion/servers exists + * but is a directory). + * + * Also don't error if trying to create something and failing -- it's + * okay for the config area or its contents not to be created. + * However, if creating a config template file succeeds, return an + * error if unable to initialize its contents. + */ +svn_error_t * +svn_config_ensure(const char *config_dir, + apr_pool_t *pool); + + + + +/** Accessing cached authentication data in the user config area. + * + * @defgroup cached_authentication_data Cached authentication data + * @{ + */ + + +/** A hash-key pointing to a realmstring. Every file containing + * authentication data should have this key. + */ +#define SVN_CONFIG_REALMSTRING_KEY "svn:realmstring" + +/** Use @a cred_kind and @a realmstring to locate a file within the + * ~/.subversion/auth/ area. If the file exists, initialize @a *hash + * and load the file contents into the hash, using @a pool. If the + * file doesn't exist, set @a *hash to NULL. + * + * If @a config_dir is not NULL it specifies a directory from which to + * read the config overriding all other sources. + * + * Besides containing the original credential fields, the hash will + * also contain @c SVN_CONFIG_REALMSTRING_KEY. The caller can examine + * this value as a sanity-check that the correct file was loaded. + * + * The hashtable will contain const char * keys and + * svn_string_t * values. + */ +svn_error_t * +svn_config_read_auth_data(apr_hash_t **hash, + const char *cred_kind, + const char *realmstring, + const char *config_dir, + apr_pool_t *pool); + +/** Use @a cred_kind and @a realmstring to create or overwrite a file + * within the ~/.subversion/auth/ area. Write the contents of @a hash into + * the file. If @a config_dir is not NULL it specifies a directory to read + * the config overriding all other sources. + * + * Also, add @a realmstring to the file, with key @c + * SVN_CONFIG_REALMSTRING_KEY. This allows programs (or users) to + * verify exactly which set credentials live within the file. + * + * The hashtable must contain const char * keys and + * svn_string_t * values. + */ +svn_error_t * +svn_config_write_auth_data(apr_hash_t *hash, + const char *cred_kind, + const char *realmstring, + const char *config_dir, + apr_pool_t *pool); + +/** Put the absolute path to the user's configuration directory, + * or to a file within that directory, into @a *path. + * + * If @a config_dir is not NULL, it must point to an alternative + * config directory location. If it is NULL, the default location + * is used. If @a fname is not NULL, it must specify the last + * component of the path to be returned. This can be used to create + * a path to any file in the configuration directory. + * + * Do all allocations in @a pool. + * + * Hint: + * To get the user configuration file, pass @c SVN_CONFIG_CATEGORY_CONFIG + * for @a fname. To get the servers configuration file, pass + * @c SVN_CONFIG_CATEGORY_SERVERS for @a fname. + * + * @since New in 1.6. + */ +svn_error_t * +svn_config_get_user_config_path(const char **path, + const char *config_dir, + const char *fname, + apr_pool_t *pool); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_CONFIG_H */ diff --git a/src/TortoiseMerge/svninclude/svn_ctype.h b/src/TortoiseMerge/svninclude/svn_ctype.h new file mode 100644 index 0000000..7d7164e --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_ctype.h @@ -0,0 +1,191 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2004, 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_ctype.h + * @brief Character classification routines + * @since New in 1.2. + */ + + +#ifndef SVN_CTYPE_H +#define SVN_CTYPE_H + +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/** Table of flags for character classification. */ +extern const apr_uint32_t *const svn_ctype_table; + + +/** Check if @a c is in the character class described by @a flags. + * The @a flags is a bitwise-or combination of @c SVN_CTYPE_* + * constants. Uses #svn_ctype_table. + */ +#define svn_ctype_test(c, flags) \ + (0 != (svn_ctype_table[(unsigned char)(c)] & (flags))) + + +/** + * @defgroup ctype_basic Basic character classification - 7-bit ASCII only + * @{ + */ + +/* Basic character classes */ +#define SVN_CTYPE_CNTRL 0x0001 /**< Control character */ +#define SVN_CTYPE_SPACE 0x0002 /**< Whitespace */ +#define SVN_CTYPE_DIGIT 0x0004 /**< Decimal digit */ +#define SVN_CTYPE_UPPER 0x0008 /**< Uppercase letter */ +#define SVN_CTYPE_LOWER 0x0010 /**< Lowercase letter */ +#define SVN_CTYPE_PUNCT 0x0020 /**< Punctuation mark */ +#define SVN_CTYPE_XALPHA 0x0040 /**< Hexadecimal digits A to F */ +#define SVN_CTYPE_ASCII 0x0080 /**< ASCII subset*/ + +/* Derived character classes */ +/** ASCII letter */ +#define SVN_CTYPE_ALPHA (SVN_CTYPE_LOWER | SVN_CTYPE_UPPER) +/** ASCII letter or decimal digit */ +#define SVN_CTYPE_ALNUM (SVN_CTYPE_ALPHA | SVN_CTYPE_DIGIT) +/** ASCII hexadecimal digit */ +#define SVN_CTYPE_XDIGIT (SVN_CTYPE_DIGIT | SVN_CTYPE_XALPHA) +/** Printable ASCII except space */ +#define SVN_CTYPE_GRAPH (SVN_CTYPE_PUNCT | SVN_CTYPE_ALNUM) +/** All printable ASCII */ +#define SVN_CTYPE_PRINT (SVN_CTYPE_GRAPH | SVN_CTYPE_SPACE) + + +/** Check if @a c is an ASCII control character. */ +#define svn_ctype_iscntrl(c) svn_ctype_test((c), SVN_CTYPE_CNTRL) + +/** Check if @a c is an ASCII whitespace character. */ +#define svn_ctype_isspace(c) svn_ctype_test((c), SVN_CTYPE_SPACE) + +/** Check if @a c is an ASCII digit. */ +#define svn_ctype_isdigit(c) svn_ctype_test((c), SVN_CTYPE_DIGIT) + +/** Check if @a c is an ASCII uppercase letter. */ +#define svn_ctype_isupper(c) svn_ctype_test((c), SVN_CTYPE_UPPER) + +/** Check if @a c is an ASCII lowercase letter. */ +#define svn_ctype_islower(c) svn_ctype_test((c), SVN_CTYPE_LOWER) + +/** Check if @a c is an ASCII punctuation mark. */ +#define svn_ctype_ispunct(c) svn_ctype_test((c), SVN_CTYPE_PUNCT) + +/** Check if @a c is an ASCII character. */ +#define svn_ctype_isascii(c) svn_ctype_test((c), SVN_CTYPE_ASCII) + +/** Check if @a c is an ASCII letter. */ +#define svn_ctype_isalpha(c) svn_ctype_test((c), SVN_CTYPE_ALPHA) + +/** Check if @a c is an ASCII letter or decimal digit. */ +#define svn_ctype_isalnum(c) svn_ctype_test((c), SVN_CTYPE_ALNUM) + +/** Check if @a c is an ASCII hexadecimal digit. */ +#define svn_ctype_isxdigit(c) svn_ctype_test((c), SVN_CTYPE_XDIGIT) + +/** Check if @a c is an ASCII graphical (visible printable) character. */ +#define svn_ctype_isgraph(c) svn_ctype_test((c), SVN_CTYPE_GRAPH) + +/** Check if @a c is an ASCII printable character. */ +#define svn_ctype_isprint(c) svn_ctype_test((c), SVN_CTYPE_PRINT) + +/** @} */ + +/** + * @defgroup ctype_extra Extended character classification + * @{ + */ + +/* Basic extended character classes */ +#define SVN_CTYPE_UTF8LEAD 0x0100 /**< UTF-8 multibyte lead byte */ +#define SVN_CTYPE_UTF8CONT 0x0200 /**< UTF-8 multibyte non-lead byte */ +/* ### TBD +#define SVN_CTYPE_XMLNAME 0x0400 +#define SVN_CTYPE_URISAFE 0x0800 +*/ + +/* Derived extended character classes */ +/** Part of a UTF-8 multibyte character. */ +#define SVN_CTYPE_UTF8MBC (SVN_CTYPE_UTF8LEAD | SVN_CTYPE_UTF8CONT) +/** All valid UTF-8 bytes. */ +#define SVN_CTYPE_UTF8 (SVN_CTYPE_ASCII | SVN_CTYPE_UTF8MBC) + +/** Check if @a c is a UTF-8 multibyte lead byte. */ +#define svn_ctype_isutf8lead(c) svn_ctype_test((c), SVN_CTYPE_UTF8LEAD) + +/** Check if @a c is a UTF-8 multibyte continuation (non-lead) byte. */ +#define svn_ctype_isutf8cont(c) svn_ctype_test((c), SVN_CTYLE_UTF8CONT) + +/** Check if @a c is part of a UTF-8 multibyte character. */ +#define svn_ctype_isutf8mbc(c) svn_ctype_test((c), SVN_CTYPE_UTF8MBC) + +/** Check if @a c is valid in UTF-8. */ +#define svn_ctype_isutf8(c) svn_ctype_test((c), SVN_CTYPE_UTF8) + +/** @} */ + +/** + * @defgroup ctype_ascii ASCII character value constants + * @{ + */ + +#define SVN_CTYPE_ASCII_MINUS 45 /**< ASCII value of '-' */ +#define SVN_CTYPE_ASCII_DOT 46 /**< ASCII value of '.' */ +#define SVN_CTYPE_ASCII_COLON 58 /**< ASCII value of ':' */ +#define SVN_CTYPE_ASCII_UNDERSCORE 95 /**< ASCII value of '_' */ +#define SVN_CTYPE_ASCII_TAB 9 /**< ASCII value of a tab */ +#define SVN_CTYPE_ASCII_LINEFEED 10 /**< ASCII value of a line feed */ +#define SVN_CTYPE_ASCII_CARRIAGERETURN 13 + /**< ASCII value of a carriage return */ +#define SVN_CTYPE_ASCII_DELETE 127 + /**< ASCII value of a delete character */ + + +/** @} */ + +/** + * @defgroup ctype_case ASCII-subset case folding + * @{ + */ + +/** + * Compare two characters @a a and @a b, treating case-equivalent + * unaccented Latin (ASCII subset) letters as equal. + * + * Returns in integer greater than, equal to, or less than 0, + * according to whether @a a is considered greater than, equal to, + * or less than @a b. + * + * @since New in 1.5. + */ +int +svn_ctype_casecmp(int a, + int b); + + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_CTYPE_H */ diff --git a/src/TortoiseMerge/svninclude/svn_delta.h b/src/TortoiseMerge/svninclude/svn_delta.h new file mode 100644 index 0000000..121e585 --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_delta.h @@ -0,0 +1,1230 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_delta.h + * @brief Delta-parsing + */ + +/* ==================================================================== */ + + + +#ifndef SVN_DELTA_H +#define SVN_DELTA_H + +#include +#include +#include +#include +#include /* for apr_file_t */ + +#include "svn_types.h" +#include "svn_string.h" +#include "svn_io.h" +#include "svn_version.h" +#include "svn_checksum.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +/** + * Get libsvn_delta version information. + * + * @since New in 1.1. + */ +const svn_version_t * +svn_delta_version(void); + +/** + * @defgroup delta_support Delta generation and handling + * + * @{ + */ + +/** Text deltas. + * + * A text delta represents the difference between two strings of + * bytes, the `source' string and the `target' string. Given a source + * string and a target string, we can compute a text delta; given a + * source string and a delta, we can reconstruct the target string. + * However, note that deltas are not reversible: you cannot always + * reconstruct the source string given the target string and delta. + * + * Since text deltas can be very large, the interface here allows us + * to produce and consume them in pieces. Each piece, represented by + * an @c svn_txdelta_window_t structure, describes how to produce the + * next section of the target string. + * + * To compute a new text delta: + * + * - We call svn_txdelta() on the streams we want to compare. That + * returns us an @c svn_txdelta_stream_t object. + * + * - We then call svn_txdelta_next_window() on the stream object + * repeatedly. Each call returns a new @c svn_txdelta_window_t + * object, which describes the next portion of the target string. + * When svn_txdelta_next_window() returns zero, we are done building + * the target string. + * + * @defgroup svn_delta_txt_delta Text deltas + * @{ + */ + +/** Action codes for text delta instructions. */ +enum svn_delta_action { + /** Append the @a length bytes at @a offset in the source view to the + * target. + * + * It must be the case that 0 <= @a offset < @a offset + + * @a length <= size of source view. + */ + svn_txdelta_source, + + /** Append the @a length bytes at @a offset in the target view, to the + * target. + * + * It must be the case that 0 <= @a offset < current position in the + * target view. + * + * However! @a offset + @a length may be *beyond* the end of the existing + * target data. "Where the heck does the text come from, then?" + * If you start at @a offset, and append @a length bytes one at a time, + * it'll work out --- you're adding new bytes to the end at the + * same rate you're reading them from the middle. Thus, if your + * current target text is "abcdefgh", and you get an @c svn_txdelta_target + * instruction whose @a offset is 6 and whose @a length is 7, + * the resulting string is "abcdefghghghghg". This trick is actually + * useful in encoding long runs of consecutive characters, long runs + * of CR/LF pairs, etc. + */ + svn_txdelta_target, + + /** Append the @a length bytes at @a offset in the window's @a new string + * to the target. + * + * It must be the case that 0 <= @a offset < @a offset + + * @a length <= length of @a new. Windows MUST use new data in ascending + * order with no overlap at the moment; svn_txdelta_to_svndiff() + * depends on this. + */ + svn_txdelta_new +}; + +/** A single text delta instruction. */ +typedef struct svn_txdelta_op_t +{ + /** Action code of delta instruction */ + enum svn_delta_action action_code; + /** Offset of delta, see #svn_delta_action for more details. */ + apr_size_t offset; + /** Number of bytes of delta, see #svn_delta_action for more details. */ + apr_size_t length; +} svn_txdelta_op_t; + + +/** An @c svn_txdelta_window_t object describes how to reconstruct a + * contiguous section of the target string (the "target view") using a + * specified contiguous region of the source string (the "source + * view"). It contains a series of instructions which assemble the + * new target string text by pulling together substrings from: + * + * - the source view, + * + * - the previously constructed portion of the target view, + * + * - a string of new data contained within the window structure + * + * The source view must always slide forward from one window to the + * next; that is, neither the beginning nor the end of the source view + * may move to the left as we read from a window stream. This + * property allows us to apply deltas to non-seekable source streams + * without making a full copy of the source stream. + */ +typedef struct svn_txdelta_window_t +{ + + /** The offset of the source view for this window. */ + svn_filesize_t sview_offset; + + /** The length of the source view for this window. */ + apr_size_t sview_len; + + /** The length of the target view for this window, i.e. the number of + * bytes which will be reconstructed by the instruction stream. */ + apr_size_t tview_len; + + /** The number of instructions in this window. */ + int num_ops; + + /** The number of svn_txdelta_source instructions in this window. If + * this number is 0, we don't need to read the source in order to + * reconstruct the target view. + */ + int src_ops; + + /** The instructions for this window. */ + const svn_txdelta_op_t *ops; + + /** New data, for use by any `svn_txdelta_new' instructions. */ + const svn_string_t *new_data; + +} svn_txdelta_window_t; + +/** + * Return a deep copy of @a window, allocated in @a pool. + * + * @since New in 1.3. + */ +svn_txdelta_window_t * +svn_txdelta_window_dup(const svn_txdelta_window_t *window, + apr_pool_t *pool); + +/** + * Compose two delta windows, yielding a third, allocated in @a pool. + * + * @since New in 1.4 + * + */ +svn_txdelta_window_t * +svn_txdelta_compose_windows(const svn_txdelta_window_t *window_A, + const svn_txdelta_window_t *window_B, + apr_pool_t *pool); + +/** + * Apply the instructions from @a window to a source view @a sbuf to + * produce a target view @a tbuf. + * + * @a sbuf is assumed to have @a window->sview_len bytes of data and + * @a tbuf is assumed to have room for @a tlen bytes of output. @a + * tlen may be more than @a window->tview_len, so return the actual + * number of bytes written. @a sbuf is not touched and may be NULL if + * @a window contains no source-copy operations. This is purely a + * memory operation; nothing can go wrong as long as we have a valid + * window. + * + * @since New in 1.4 + * + */ +void +svn_txdelta_apply_instructions(svn_txdelta_window_t *window, + const char *sbuf, char *tbuf, + apr_size_t *tlen); + +/** A typedef for functions that consume a series of delta windows, for + * use in caller-pushes interfaces. Such functions will typically + * apply the delta windows to produce some file, or save the windows + * somewhere. At the end of the delta window stream, you must call + * this function passing zero for the @a window argument. + */ +typedef svn_error_t *(*svn_txdelta_window_handler_t) + (svn_txdelta_window_t *window, void *baton); + + +/** This function will generate delta windows that turn @a source into + * @a target, and pushing these windows into the @a handler window handler + * callback (passing @a handler_baton to each invocation). + * + * If @a checksum is not NULL, then a checksum (of kind @a checksum_kind) + * will be computed for the target stream, and placed into *checksum. + * + * If @a cancel_func is not NULL, then it should refer to a cancellation + * function (along with @a cancel_baton). + * + * Results (the checksum) will be allocated from @a result_pool, and all + * temporary allocations will be performed in @a scratch_pool. + * + * Note: this function replaces the combination of svn_txdelta() and + * svn_txdelta_send_txstream(). + * + * @since New in 1.6. + */ +svn_error_t * +svn_txdelta_run(svn_stream_t *source, + svn_stream_t *target, + svn_txdelta_window_handler_t handler, + void *handler_baton, + svn_checksum_kind_t checksum_kind, + svn_checksum_t **checksum, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + +/** A delta stream --- this is the hat from which we pull a series of + * svn_txdelta_window_t objects, which, taken in order, describe the + * entire target string. This type is defined within libsvn_delta, and + * opaque outside that library. + */ +typedef struct svn_txdelta_stream_t svn_txdelta_stream_t; + + +/** A typedef for a function that will set @a *window to the next + * window from a @c svn_txdelta_stream_t object. If there are no more + * delta windows, NULL will be used. The returned window, if any, + * will be allocated in @a pool. @a baton is the baton specified + * when the stream was created. + * + * @since New in 1.4. + */ +typedef svn_error_t * +(*svn_txdelta_next_window_fn_t)(svn_txdelta_window_t **window, + void *baton, + apr_pool_t *pool); + +/** A typedef for a function that will return the md5 checksum of the + * fulltext deltified by a @c svn_txdelta_stream_t object. Will + * return NULL if the final null window hasn't yet been returned by + * the stream. The returned value will be allocated in the same pool + * as the stream. @a baton is the baton specified when the stream was + * created. + * + * @since New in 1.4. + */ +typedef const unsigned char * +(*svn_txdelta_md5_digest_fn_t)(void *baton); + +/** Create and return a generic text delta stream with @a baton, @a + * next_window and @a md5_digest. Allocate the new stream in @a + * pool. + * + * @since New in 1.4. + */ +svn_txdelta_stream_t * +svn_txdelta_stream_create(void *baton, + svn_txdelta_next_window_fn_t next_window, + svn_txdelta_md5_digest_fn_t md5_digest, + apr_pool_t *pool); + +/** Set @a *window to a pointer to the next window from the delta stream + * @a stream. When we have completely reconstructed the target string, + * set @a *window to zero. + * + * The window will be allocated in @a pool. + */ +svn_error_t * +svn_txdelta_next_window(svn_txdelta_window_t **window, + svn_txdelta_stream_t *stream, + apr_pool_t *pool); + + +/** Return the md5 digest for the complete fulltext deltified by + * @a stream, or @c NULL if @a stream has not yet returned its final + * @c NULL window. The digest is allocated in the same memory as @a + * STREAM. + */ +const unsigned char * +svn_txdelta_md5_digest(svn_txdelta_stream_t *stream); + +/** Set @a *stream to a pointer to a delta stream that will turn the byte + * string from @a source into the byte stream from @a target. + * + * @a source and @a target are both readable generic streams. When we call + * svn_txdelta_next_window() on @a *stream, it will read from @a source and + * @a target to gather as much data as it needs. + * + * Do any necessary allocation in a sub-pool of @a pool. + */ +void +svn_txdelta(svn_txdelta_stream_t **stream, + svn_stream_t *source, + svn_stream_t *target, + apr_pool_t *pool); + + +/** + * Return a writable stream which, when fed target data, will send + * delta windows to @a handler/@a handler_baton which transform the + * data in @a source to the target data. As usual, the window handler + * will receive a NULL window to signify the end of the window stream. + * The stream handler functions will read data from @a source as + * necessary. + * + * @since New in 1.1. + */ +svn_stream_t * +svn_txdelta_target_push(svn_txdelta_window_handler_t handler, + void *handler_baton, + svn_stream_t *source, + apr_pool_t *pool); + + +/** Send the contents of @a string to window-handler @a handler/@a baton. + * This is effectively a 'copy' operation, resulting in delta windows that + * make the target equivalent to the value of @a string. + * + * All temporary allocation is performed in @a pool. + */ +svn_error_t * +svn_txdelta_send_string(const svn_string_t *string, + svn_txdelta_window_handler_t handler, + void *handler_baton, + apr_pool_t *pool); + +/** Send the contents of @a stream to window-handler @a handler/@a baton. + * This is effectively a 'copy' operation, resulting in delta windows that + * make the target equivalent to the stream. + * + * If @a digest is non-NULL, populate it with the md5 checksum for the + * fulltext that was deltified (@a digest must be at least + * @c APR_MD5_DIGESTSIZE bytes long). + * + * All temporary allocation is performed in @a pool. + */ +svn_error_t * +svn_txdelta_send_stream(svn_stream_t *stream, + svn_txdelta_window_handler_t handler, + void *handler_baton, + unsigned char *digest, + apr_pool_t *pool); + +/** Send the contents of @a txstream to window-handler @a handler/@a baton. + * Windows will be extracted from the stream and delivered to the handler. + * + * All temporary allocation is performed in @a pool. + */ +svn_error_t * +svn_txdelta_send_txstream(svn_txdelta_stream_t *txstream, + svn_txdelta_window_handler_t handler, + void *handler_baton, + apr_pool_t *pool); + + +/** Prepare to apply a text delta. @a source is a readable generic stream + * yielding the source data, @a target is a writable generic stream to + * write target data to, and allocation takes place in a sub-pool of + * @a pool. On return, @a *handler is set to a window handler function and + * @a *handler_baton is set to the value to pass as the @a baton argument to + * @a *handler. + * + * If @a result_digest is non-NULL, it points to APR_MD5_DIGESTSIZE bytes + * of storage, and the final call to @a handler populates it with the + * MD5 digest of the resulting fulltext. + * + * If @a error_info is non-NULL, it is inserted parenthetically into + * the error string for any error returned by svn_txdelta_apply() or + * @a *handler. (It is normally used to provide path information, + * since there's nothing else in the delta application's context to + * supply a path for error messages.) + * + * @note To avoid lifetime issues, @a error_info is copied into + * @a pool or a subpool thereof. + */ +void +svn_txdelta_apply(svn_stream_t *source, + svn_stream_t *target, + unsigned char *result_digest, + const char *error_info, + apr_pool_t *pool, + svn_txdelta_window_handler_t *handler, + void **handler_baton); + + + +/*** Producing and consuming svndiff-format text deltas. ***/ + +/** Prepare to produce an svndiff-format diff from text delta windows. + * @a output is a writable generic stream to write the svndiff data to. + * Allocation takes place in a sub-pool of @a pool. On return, @a *handler + * is set to a window handler function and @a *handler_baton is set to + * the value to pass as the @a baton argument to @a *handler. The svndiff + * version is @a svndiff_version. + * + * @since New in 1.4. + */ +void +svn_txdelta_to_svndiff2(svn_txdelta_window_handler_t *handler, + void **handler_baton, + svn_stream_t *output, + int svndiff_version, + apr_pool_t *pool); + +/** Similar to svn_txdelta_to_svndiff2, but always using svndiff + * version 0. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +void +svn_txdelta_to_svndiff(svn_stream_t *output, + apr_pool_t *pool, + svn_txdelta_window_handler_t *handler, + void **handler_baton); + +/** Return a writable generic stream which will parse svndiff-format + * data into a text delta, invoking @a handler with @a handler_baton + * whenever a new window is ready. If @a error_on_early_close is @c + * TRUE, attempting to close this stream before it has handled the entire + * svndiff data set will result in @c SVN_ERR_SVNDIFF_UNEXPECTED_END, + * else this error condition will be ignored. + */ +svn_stream_t * +svn_txdelta_parse_svndiff(svn_txdelta_window_handler_t handler, + void *handler_baton, + svn_boolean_t error_on_early_close, + apr_pool_t *pool); + +/** + * Read and parse one delta window in svndiff format from the + * readable stream @a stream and place it in @a *window, allocating + * the result in @a pool. The caller must take responsibility for + * stripping off the four-byte 'SVN@' header at the beginning of + * the svndiff document before reading the first window, and must + * provide the version number (the value of the fourth byte) to each + * invocation of this routine with the @a svndiff_version argument. + * + * @since New in 1.1. + */ +svn_error_t * +svn_txdelta_read_svndiff_window(svn_txdelta_window_t **window, + svn_stream_t *stream, + int svndiff_version, + apr_pool_t *pool); + +/** + * Read and skip one delta window in svndiff format from the + * file @a file. @a pool is used for temporary allocations. The + * caller must take responsibility for stripping off the four-byte + * 'SVN@' header at the beginning of the svndiff document before + * reading or skipping the first window, and must provide the version + * number (the value of the fourth byte) to each invocation of this + * routine with the @a svndiff_version argument. + * + * @since New in 1.1. + */ +svn_error_t * +svn_txdelta_skip_svndiff_window(apr_file_t *file, + int svndiff_version, + apr_pool_t *pool); + +/** @} */ + + +/** Traversing tree deltas. + * + * In Subversion, we've got various producers and consumers of tree + * deltas. + * + * In processing a `commit' command: + * - The client examines its working copy data, and produces a tree + * delta describing the changes to be committed. + * - The client networking library consumes that delta, and sends them + * across the wire as an equivalent series of network requests (for + * example, to svnserve as an ra_svn protocol stream, or to an + * Apache httpd server as WebDAV commands) + * - The server receives those requests and produces a tree delta --- + * hopefully equivalent to the one the client produced above. + * - The Subversion server module consumes that delta and commits an + * appropriate transaction to the filesystem. + * + * In processing an `update' command, the process is reversed: + * - The Subversion server module talks to the filesystem and produces + * a tree delta describing the changes necessary to bring the + * client's working copy up to date. + * - The server consumes this delta, and assembles a reply + * representing the appropriate changes. + * - The client networking library receives that reply, and produces a + * tree delta --- hopefully equivalent to the one the Subversion + * server produced above. + * - The working copy library consumes that delta, and makes the + * appropriate changes to the working copy. + * + * The simplest approach would be to represent tree deltas using the + * obvious data structure. To do an update, the server would + * construct a delta structure, and the working copy library would + * apply that structure to the working copy; the network layer's job + * would simply be to get the structure across the net intact. + * + * However, we expect that these deltas will occasionally be too large + * to fit in a typical workstation's swap area. For example, in + * checking out a 200Mb source tree, the entire source tree is + * represented by a single tree delta. So it's important to handle + * deltas that are too large to fit in swap all at once. + * + * So instead of representing the tree delta explicitly, we define a + * standard way for a consumer to process each piece of a tree delta + * as soon as the producer creates it. The @c svn_delta_editor_t + * structure is a set of callback functions to be defined by a delta + * consumer, and invoked by a delta producer. Each invocation of a + * callback function describes a piece of the delta --- a file's + * contents changing, something being renamed, etc. + * + * @defgroup svn_delta_tree_deltas Tree deltas + * @{ + */ + +/** A structure full of callback functions the delta source will invoke + * as it produces the delta. + * + * Note: Don't try to allocate one of these yourself. Instead, always + * use svn_delta_default_editor() or some other constructor, to ensure + * that unused slots are filled in with no-op functions. + * + *

Function Usage

+ * + * Here's how to use these functions to express a tree delta. + * + * The delta consumer implements the callback functions described in + * this structure, and the delta producer invokes them. So the + * caller (producer) is pushing tree delta data at the callee + * (consumer). + * + * At the start of traversal, the consumer provides @a edit_baton, a + * baton global to the entire delta edit. If there is a target + * revision that needs to be set for this operation, the producer + * should call the @c set_target_revision function at this point. + * + * Next, if there are any tree deltas to express, the producer should + * pass the @a edit_baton to the @c open_root function, to get a baton + * representing root of the tree being edited. + * + * Most of the callbacks work in the obvious way: + * + * @c delete_entry + * @c add_file + * @c add_directory + * @c open_file + * @c open_directory + * + * Each of these takes a directory baton, indicating the directory + * in which the change takes place, and a @a path argument, giving the + * path (relative to the root of the edit) of the file, + * subdirectory, or directory entry to change. Editors will usually + * want to join this relative path with some base stored in the edit + * baton (e.g. a URL, a location in the OS filesystem). + * + * Since every call requires a parent directory baton, including + * @c add_directory and @c open_directory, where do we ever get our + * initial directory baton, to get things started? The @c open_root + * function returns a baton for the top directory of the change. In + * general, the producer needs to invoke the editor's @c open_root + * function before it can get anything of interest done. + * + * While @c open_root provides a directory baton for the root of + * the tree being changed, the @c add_directory and @c open_directory + * callbacks provide batons for other directories. Like the + * callbacks above, they take a @a parent_baton and a relative path + * @a path, and then return a new baton for the subdirectory being + * created / modified --- @a child_baton. The producer can then use + * @a child_baton to make further changes in that subdirectory. + * + * So, if we already have subdirectories named `foo' and `foo/bar', + * then the producer can create a new file named `foo/bar/baz.c' by + * calling: + * + * - @c open_root () --- yielding a baton @a root for the top directory + * + * - @c open_directory (@a root, "foo") --- yielding a baton @a f for `foo' + * + * - @c open_directory (@a f, "foo/bar") --- yielding a baton @a b for + * `foo/bar' + * + * - @c add_file (@a b, "foo/bar/baz.c") + * + * When the producer is finished making changes to a directory, it + * should call @c close_directory. This lets the consumer do any + * necessary cleanup, and free the baton's storage. + * + * The @c add_file and @c open_file callbacks each return a baton + * for the file being created or changed. This baton can then be + * passed to @c apply_textdelta to change the file's contents, or + * @c change_file_prop to change the file's properties. When the + * producer is finished making changes to a file, it should call + * @c close_file, to let the consumer clean up and free the baton. + * + * The @c add_file and @c add_directory functions each take arguments + * @a copyfrom_path and @a copyfrom_revision. If @a copyfrom_path is + * non-@c NULL, then @a copyfrom_path and @a copyfrom_revision indicate where + * the file or directory should be copied from (to create the file + * or directory being added). In that case, @a copyfrom_path must be + * either a path relative to the root of the edit, or a URI from the + * repository being edited. If @a copyfrom_path is @c NULL, then @a + * copyfrom_revision must be @c SVN_INVALID_REVNUM; it is invalid to + * pass a mix of valid and invalid copyfrom arguments. + * + * + *

Function Call Ordering

+ * + * There are six restrictions on the order in which the producer + * may use the batons: + * + * 1. The producer may call @c open_directory, @c add_directory, + * @c open_file, @c add_file at most once on any given directory + * entry. @c delete_entry may be called at most once on any given + * directory entry and may later be followed by @c add_directory or + * @c add_file on the same directory entry. @c delete_entry may + * not be called on any directory entry after @c open_directory, + * @c add_directory, @c open_file or @c add_file has been called on + * that directory entry. + * + * 2. The producer may not close a directory baton until it has + * closed all batons for its subdirectories. + * + * 3. When a producer calls @c open_directory or @c add_directory, + * it must specify the most recently opened of the currently open + * directory batons. Put another way, the producer cannot have + * two sibling directory batons open at the same time. + * + * 4. A producer must call @c change_dir_prop on a directory either + * before opening any of the directory's subdirs or after closing + * them, but not in the middle. + * + * 5. When the producer calls @c open_file or @c add_file, either: + * + * (a) The producer must follow with any changes to the file + * (@c change_file_prop and/or @c apply_textdelta, as applicable), + * followed by a @c close_file call, before issuing any other file + * or directory calls, or + * + * (b) The producer must follow with a @c change_file_prop call if + * it is applicable, before issuing any other file or directory + * calls; later, after all directory batons including the root + * have been closed, the producer must issue @c apply_textdelta + * and @c close_file calls. + * + * 6. When the producer calls @c apply_textdelta, it must make all of + * the window handler calls (including the @c NULL window at the + * end) before issuing any other @c svn_delta_editor_t calls. + * + * So, the producer needs to use directory and file batons as if it + * is doing a single depth-first traversal of the tree, with the + * exception that the producer may keep file batons open in order to + * make @c apply_textdelta calls at the end. + * + * + *

Pool Usage

+ * + * Many editor functions are invoked multiple times, in a sequence + * determined by the editor "driver". The driver is responsible for + * creating a pool for use on each iteration of the editor function, + * and clearing that pool between each iteration. The driver passes + * the appropriate pool on each function invocation. + * + * Based on the requirement of calling the editor functions in a + * depth-first style, it is usually customary for the driver to similarly + * nest the pools. However, this is only a safety feature to ensure + * that pools associated with deeper items are always cleared when the + * top-level items are also cleared. The interface does not assume, nor + * require, any particular organization of the pools passed to these + * functions. In fact, if "postfix deltas" are used for files, the file + * pools definitely need to live outside the scope of their parent + * directories' pools. + * + * Note that close_directory can be called *before* a file in that + * directory has been closed. That is, the directory's baton is + * closed before the file's baton. The implication is that + * @c apply_textdelta and @c close_file should not refer to a parent + * directory baton UNLESS the editor has taken precautions to + * allocate it in a pool of the appropriate lifetime (the @a dir_pool + * passed to @c open_directory and @c add_directory definitely does not + * have the proper lifetime). In general, it is recommended to simply + * avoid keeping a parent directory baton in a file baton. + * + * + *

Errors

+ * + * At least one implementation of the editor interface is + * asynchronous; an error from one operation may be detected some + * number of operations later. As a result, an editor driver must not + * assume that an error from an editing function resulted from the + * particular operation being detected. Moreover, once an editing + * function returns an error, the edit is dead; the only further + * operation which may be called on the editor is abort_edit. + */ +typedef struct svn_delta_editor_t +{ + /** Set the target revision for this edit to @a target_revision. This + * call, if used, should precede all other editor calls. + * + * @note This is typically used only for server->client update-type + * operations. It doesn't really make much sense for commit-type + * operations, because the revision of a commit isn't known until + * the commit is finalized. + */ + svn_error_t *(*set_target_revision)(void *edit_baton, + svn_revnum_t target_revision, + apr_pool_t *pool); + + /** Set @a *root_baton to a baton for the top directory of the change. + * (This is the top of the subtree being changed, not necessarily + * the root of the filesystem.) As with any other directory baton, the + * producer should call @c close_directory on @a root_baton when done. + * And as with other @c open_* calls, the @a base_revision here is the + * current revision of the directory (before getting bumped up to the + * new target revision set with @c set_target_revision). + * + * Allocations for the returned @a root_baton should be performed in + * @a dir_pool. It is also typical to (possibly) save this pool for later + * usage by @c close_directory. + */ + svn_error_t *(*open_root)(void *edit_baton, + svn_revnum_t base_revision, + apr_pool_t *dir_pool, + void **root_baton); + + + /** Remove the directory entry named @a path, a child of the directory + * represented by @a parent_baton. If @a revision is a valid + * revision number, it is used as a sanity check to ensure that you + * are really removing the revision of @a path that you think you are. + * + * All allocations should be performed in @a pool. + * + * @note The @a revision parameter is typically used only for + * client->server commit-type operations, allowing the server to + * verify that it is deleting what the client thinks it should be + * deleting. It only really makes sense in the opposite direction + * (during server->client update-type operations) when the trees + * whose delta is being described are ancestrally related (that is, + * one tree is an ancestor of the other). + */ + svn_error_t *(*delete_entry)(const char *path, + svn_revnum_t revision, + void *parent_baton, + apr_pool_t *pool); + + + /** We are going to add a new subdirectory named @a path. We will use + * the value this callback stores in @a *child_baton as the + * @a parent_baton for further changes in the new subdirectory. + * + * If @a copyfrom_path is non-@c NULL, this add has history (i.e., is a + * copy), and the origin of the copy may be recorded as + * @a copyfrom_path under @a copyfrom_revision. + * + * Allocations for the returned @a child_baton should be performed in + * @a dir_pool. It is also typical to (possibly) save this pool for later + * usage by @c close_directory. + */ + svn_error_t *(*add_directory)(const char *path, + void *parent_baton, + const char *copyfrom_path, + svn_revnum_t copyfrom_revision, + apr_pool_t *dir_pool, + void **child_baton); + + /** We are going to make changes in a subdirectory (of the directory + * identified by @a parent_baton). The subdirectory is specified by + * @a path. The callback must store a value in @a *child_baton that + * should be used as the @a parent_baton for subsequent changes in this + * subdirectory. If a valid revnum, @a base_revision is the current + * revision of the subdirectory. + * + * Allocations for the returned @a child_baton should be performed in + * @a dir_pool. It is also typical to (possibly) save this pool for later + * usage by @c close_directory. + */ + svn_error_t *(*open_directory)(const char *path, + void *parent_baton, + svn_revnum_t base_revision, + apr_pool_t *dir_pool, + void **child_baton); + + /** Change the value of a directory's property. + * - @a dir_baton specifies the directory whose property should change. + * - @a name is the name of the property to change. + * - @a value is the new (final) value of the property, or @c NULL if the + * property should be removed altogether. + * + * The callback is guaranteed to be called exactly once for each property + * whose value differs between the start and the end of the edit. + * + * All allocations should be performed in @a pool. + */ + svn_error_t *(*change_dir_prop)(void *dir_baton, + const char *name, + const svn_string_t *value, + apr_pool_t *pool); + + /** We are done processing a subdirectory, whose baton is @a dir_baton + * (set by @c add_directory or @c open_directory). We won't be using + * the baton any more, so whatever resources it refers to may now be + * freed. + */ + svn_error_t *(*close_directory)(void *dir_baton, + apr_pool_t *pool); + + + /** In the directory represented by @a parent_baton, indicate that + * @a path is present as a subdirectory in the edit source, but + * cannot be conveyed to the edit consumer (perhaps because of + * authorization restrictions). + */ + svn_error_t *(*absent_directory)(const char *path, + void *parent_baton, + apr_pool_t *pool); + + /** We are going to add a new file named @a path. The callback can + * store a baton for this new file in @a **file_baton; whatever value + * it stores there should be passed through to @c apply_textdelta. + * + * If @a copyfrom_path is non-@c NULL, this add has history (i.e., is a + * copy), and the origin of the copy may be recorded as + * @a copyfrom_path under @a copyfrom_revision. + * + * Allocations for the returned @a file_baton should be performed in + * @a file_pool. It is also typical to save this pool for later usage + * by @c apply_textdelta and possibly @c close_file. + */ + svn_error_t *(*add_file)(const char *path, + void *parent_baton, + const char *copyfrom_path, + svn_revnum_t copyfrom_revision, + apr_pool_t *file_pool, + void **file_baton); + + /** We are going to make change to a file named @a path, which resides + * in the directory identified by @a parent_baton. + * + * The callback can store a baton for this new file in @a **file_baton; + * whatever value it stores there should be passed through to + * @c apply_textdelta. If a valid revnum, @a base_revision is the + * current revision of the file. + * + * Allocations for the returned @a file_baton should be performed in + * @a file_pool. It is also typical to save this pool for later usage + * by @c apply_textdelta and possibly @c close_file. + */ + svn_error_t *(*open_file)(const char *path, + void *parent_baton, + svn_revnum_t base_revision, + apr_pool_t *file_pool, + void **file_baton); + + /** Apply a text delta, yielding the new revision of a file. + * + * @a file_baton indicates the file we're creating or updating, and the + * ancestor file on which it is based; it is the baton set by some + * prior @c add_file or @c open_file callback. + * + * The callback should set @a *handler to a text delta window + * handler; we will then call @a *handler on successive text + * delta windows as we receive them. The callback should set + * @a *handler_baton to the value we should pass as the @a baton + * argument to @a *handler. + * + * @a base_checksum is the hex MD5 digest for the base text against + * which the delta is being applied; it is ignored if NULL, and may + * be ignored even if not NULL. If it is not ignored, it must match + * the checksum of the base text against which svndiff data is being + * applied; if it does not, @c apply_textdelta or the @a *handler call + * which detects the mismatch will return the error + * SVN_ERR_CHECKSUM_MISMATCH (if there is no base text, there may + * still be an error if @a base_checksum is neither NULL nor the hex + * MD5 checksum of the empty string). + */ + svn_error_t *(*apply_textdelta)(void *file_baton, + const char *base_checksum, + apr_pool_t *pool, + svn_txdelta_window_handler_t *handler, + void **handler_baton); + + /** Change the value of a file's property. + * - @a file_baton specifies the file whose property should change. + * - @a name is the name of the property to change. + * - @a value is the new (final) value of the property, or @c NULL if the + * property should be removed altogether. + * + * The callback is guaranteed to be called exactly once for each property + * whose value differs between the start and the end of the edit. + * + * All allocations should be performed in @a pool. + */ + svn_error_t *(*change_file_prop)(void *file_baton, + const char *name, + const svn_string_t *value, + apr_pool_t *pool); + + /** We are done processing a file, whose baton is @a file_baton (set by + * @c add_file or @c open_file). We won't be using the baton any + * more, so whatever resources it refers to may now be freed. + * + * @a text_checksum is the hex MD5 digest for the fulltext that + * resulted from a delta application, see @c apply_textdelta. The + * checksum is ignored if NULL. If not null, it is compared to the + * checksum of the new fulltext, and the error + * SVN_ERR_CHECKSUM_MISMATCH is returned if they do not match. If + * there is no new fulltext, @a text_checksum is ignored. + */ + svn_error_t *(*close_file)(void *file_baton, + const char *text_checksum, + apr_pool_t *pool); + + /** In the directory represented by @a parent_baton, indicate that + * @a path is present as a file in the edit source, but cannot be + * conveyed to the edit consumer (perhaps because of authorization + * restrictions). + */ + svn_error_t *(*absent_file)(const char *path, + void *parent_baton, + apr_pool_t *pool); + + /** All delta processing is done. Call this, with the @a edit_baton for + * the entire edit. + */ + svn_error_t *(*close_edit)(void *edit_baton, + apr_pool_t *pool); + + /** The editor-driver has decided to bail out. Allow the editor to + * gracefully clean up things if it needs to. + */ + svn_error_t *(*abort_edit)(void *edit_baton, + apr_pool_t *pool); + + /* Be sure to update svn_delta_get_cancellation_editor() and + * svn_delta_default_editor() if you add a new callback here. */ +} svn_delta_editor_t; + + +/** Return a default delta editor template, allocated in @a pool. + * + * The editor functions in the template do only the most basic + * baton-swapping: each editor function that produces a baton does so + * by copying its incoming baton into the outgoing baton reference. + * + * This editor is not intended to be useful by itself, but is meant to + * be the basis for a useful editor. After getting a default editor, + * you substitute in your own implementations for the editor functions + * you care about. The ones you don't care about, you don't have to + * implement -- you can rely on the template's implementation to + * safely do nothing of consequence. + */ +svn_delta_editor_t * +svn_delta_default_editor(apr_pool_t *pool); + +/** A text-delta window handler which does nothing. + * + * Editors can return this handler from @c apply_textdelta if they don't + * care about text delta windows. + */ +svn_error_t * +svn_delta_noop_window_handler(svn_txdelta_window_t *window, + void *baton); + +/** Set @a *editor and @a *edit_baton to a cancellation editor that + * wraps @a wrapped_editor and @a wrapped_baton. + * + * The @a editor will call @a cancel_func with @a cancel_baton when each of + * its functions is called, continuing on to call the corresponding wrapped + * function if @a cancel_func returns @c SVN_NO_ERROR. + * + * If @a cancel_func is @c NULL, set @a *editor to @a wrapped_editor and + * @a *edit_baton to @a wrapped_baton. + */ +svn_error_t * +svn_delta_get_cancellation_editor(svn_cancel_func_t cancel_func, + void *cancel_baton, + const svn_delta_editor_t *wrapped_editor, + void *wrapped_baton, + const svn_delta_editor_t **editor, + void **edit_baton, + apr_pool_t *pool); + +/** Set @a *editor and @a *edit_baton to an depth-based filtering + * editor that wraps @a wrapped_editor and @a wrapped_baton. + * + * The @a editor will track the depth of this drive against the @a + * requested_depth, taking into account whether not the edit drive is + * making use of a target (via @a has_target), and forward editor + * calls which operate "within" the request depth range through to @a + * wrapped_editor. + * + * @a requested_depth must be one of the following depth values: + * @c svn_depth_infinity, @c svn_depth_empty, @c svn_depth_files, + * @c svn_depth_immediates, or @c svn_depth_unknown. + * + * If filtering is deemed unncessary (or if @a requested_depth is @c + * svn_depth_unknown), @a *editor and @a *edit_baton will be set to @a + * wrapped_editor and @a wrapped_baton, respectively; otherwise, + * they'll be set to new objects allocated from @a pool. + * + * @note Because the svn_delta_editor_t interface's @c delete_entry() + * function doesn't carry node kind information, a depth-based + * filtering editor being asked to filter for @c svn_depth_files but + * receiving a @c delete_entry() call on an immediate child of the + * editor's target is unable to know if that deletion should be + * allowed or filtered out -- a delete of a top-level file is okay in + * this case, a delete of a top-level subdirectory is not. As such, + * this filtering editor takes a conservative approach, and ignores + * top-level deletion requests when filtering for @c svn_depth_files. + * Fortunately, most non-depth-aware (pre-1.5) Subversion editor + * drivers can be told to drive non-recursively (where non-recursive + * means essentially @c svn_depth_files), which means they won't + * transmit out-of-scope editor commands anyway. + * + * @since New in 1.5. + */ +svn_error_t * +svn_delta_depth_filter_editor(const svn_delta_editor_t **editor, + void **edit_baton, + const svn_delta_editor_t *wrapped_editor, + void *wrapped_edit_baton, + svn_depth_t requested_depth, + svn_boolean_t has_target, + apr_pool_t *pool); + +/** @} */ + + +/** Path-based editor drives. + * + * @defgroup svn_delta_path_delta_drivers Path-based delta drivers + * @{ + */ + +/** Callback function type for svn_delta_path_driver(). + * + * The handler of this callback is given the callback baton @a + * callback_baton, @a path, and the @a parent_baton which represents + * path's parent directory as created by the editor passed to + * svn_delta_path_driver(). + * + * If @a path represents a directory, the handler must return a @a + * *dir_baton for @a path, generated from the same editor (so that the + * driver can later close that directory). + * + * If, however, @a path represents a file, the handler should NOT + * return any file batons. It can close any opened or added files + * immediately, or delay that close until the end of the edit when + * svn_delta_path_driver() returns. + * + * Finally, if @a parent_baton is @c NULL, then the root of the edit + * is also one of the paths passed to svn_delta_path_driver(). The + * handler of this callback must call the editor's open_root() + * function and return the top-level root dir baton in @a *dir_baton. + */ +typedef svn_error_t *(*svn_delta_path_driver_cb_func_t) + (void **dir_baton, + void *parent_baton, + void *callback_baton, + const char *path, + apr_pool_t *pool); + + +/** Drive @a editor (with its @a edit_baton) in such a way that + * each path in @a paths is traversed in a depth-first fashion. As + * each path is hit as part of the editor drive, use @a + * callback_func and @a callback_baton to allow the caller to handle + * the portion of the editor drive related to that path. + * + * Use @a revision as the revision number passed to intermediate + * directory openings. + * + * Use @a pool for all necessary allocations. + */ +svn_error_t * +svn_delta_path_driver(const svn_delta_editor_t *editor, + void *edit_baton, + svn_revnum_t revision, + apr_array_header_t *paths, + svn_delta_path_driver_cb_func_t callback_func, + void *callback_baton, + apr_pool_t *pool); + +/** @} */ + + +/*** File revision iterator types ***/ + +/** + * The callback invoked by file rev loopers, such as + * svn_ra_plugin_t.get_file_revs2() and svn_repos_get_file_revs2(). + * + * @a baton is provided by the caller, @a path is the pathname of the file + * in revision @a rev and @a rev_props are the revision properties. + * + * If @a delta_handler and @a delta_baton are non-NULL, they may be set to a + * handler/baton which will be called with the delta between the previous + * revision and this one after the return of this callback. They may be + * left as NULL/NULL. + * + * @a result_of_merge will be @c TRUE if the revision being returned was + * included as the result of a merge. + * + * @a prop_diffs is an array of svn_prop_t elements indicating the property + * delta for this and the previous revision. + * + * @a pool may be used for temporary allocations, but you can't rely + * on objects allocated to live outside of this particular call and + * the immediately following calls to @a *delta_handler if any. (Pass + * in a pool via @a baton if need be.) + * + * @since New in 1.5. + */ +typedef svn_error_t *(*svn_file_rev_handler_t) + (void *baton, + const char *path, + svn_revnum_t rev, + apr_hash_t *rev_props, + svn_boolean_t result_of_merge, + svn_txdelta_window_handler_t *delta_handler, + void **delta_baton, + apr_array_header_t *prop_diffs, + apr_pool_t *pool); + +/** + * The old file rev handler interface. + * + * @note @c svn_file_rev_handler_old_t is a placeholder type for both + * @c svn_repos_file_rev_handler_t and @c svn_ra_file_rev_handler_t. It is + * reproduced here for dependency reasons. + * + * @deprecated This type is provided for the svn_compat_wrap_file_rev_handler() + * compatibilty wrapper, and should not be used for new development. + * @since New in 1.5. + */ +typedef svn_error_t *(*svn_file_rev_handler_old_t) + (void *baton, + const char *path, + svn_revnum_t rev, + apr_hash_t *rev_props, + svn_txdelta_window_handler_t *delta_handler, + void **delta_baton, + apr_array_header_t *prop_diffs, + apr_pool_t *pool); + +/** Return, in @a *handler2 and @a *handler2_baton a function/baton that + * will call @a handler/@a handler_baton, allocating the @a *handler2_baton + * in @a pool. + * + * @note This is used by compatibility wrappers, which exist in more than + * Subversion core library. + * + * @note @c svn_file_rev_handler_old_t is a placeholder type for both + * @c svn_repos_file_rev_handler_t and @c svn_ra_file_rev_handler_t. It is + * reproduced here for dependency reasons. + * + * @since New in 1.5. + */ +void +svn_compat_wrap_file_rev_handler(svn_file_rev_handler_t *handler2, + void **handler2_baton, + svn_file_rev_handler_old_t handler, + void *handler_baton, + apr_pool_t *pool); + +/** @} end group: delta_support */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_DELTA_H */ diff --git a/src/TortoiseMerge/svninclude/svn_diff.h b/src/TortoiseMerge/svninclude/svn_diff.h new file mode 100644 index 0000000..c0844b0 --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_diff.h @@ -0,0 +1,745 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_diff.h + * @brief Contextual diffing. + * + * This is an internalized library for performing contextual diffs + * between sources of data. + * + * @note This is different than Subversion's binary-diffing engine. + * That API lives in @c svn_delta.h -- see the "text deltas" section. A + * "text delta" is way of representing precise binary diffs between + * strings of data. The Subversion client and server send text deltas + * to one another during updates and commits. + * + * This API, however, is (or will be) used for performing *contextual* + * merges between files in the working copy. During an update or + * merge, 3-way file merging is needed. And 'svn diff' needs to show + * the differences between 2 files. + * + * The nice thing about this API is that it's very general. It + * operates on any source of data (a "datasource") and calculates + * contextual differences on "tokens" within the data. In our + * particular usage, the datasources are files and the tokens are + * lines. But the possibilities are endless. + */ + + +#ifndef SVN_DIFF_H +#define SVN_DIFF_H + +#include +#include +#include /* for apr_array_header_t */ + +#include "svn_types.h" +#include "svn_io.h" /* for svn_stream_t */ +#include "svn_version.h" +#include "svn_string.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +/** + * Get libsvn_diff version information. + * + * @since New in 1.1. + */ +const svn_version_t * +svn_diff_version(void); + + +/* Diffs. */ + +/** An opaque type that represents a difference between either two or + * three datasources. This object is returned by svn_diff_diff(), + * svn_diff_diff3() and svn_diff_diff4(), and consumed by a number of + * other routines. + */ +typedef struct svn_diff_t svn_diff_t; + +/** + * There are four types of datasources. In GNU diff3 terminology, + * the first three types correspond to the phrases "older", "mine", + * and "yours". + */ +typedef enum svn_diff_datasource_e +{ + /** The oldest form of the data. */ + svn_diff_datasource_original, + + /** The same data, but potentially changed by the user. */ + svn_diff_datasource_modified, + + /** The latest version of the data, possibly different than the + * user's modified version. + */ + svn_diff_datasource_latest, + + /** The common ancestor of original and modified. */ + svn_diff_datasource_ancestor + +} svn_diff_datasource_e; + + +/** A vtable for reading data from the three datasources. */ +typedef struct svn_diff_fns_t +{ + /** Open the datasource of type @a datasource. */ + svn_error_t *(*datasource_open)(void *diff_baton, + svn_diff_datasource_e datasource); + + /** Close the datasource of type @a datasource. */ + svn_error_t *(*datasource_close)(void *diff_baton, + svn_diff_datasource_e datasource); + + /** Get the next "token" from the datasource of type @a datasource. + * Return a "token" in @a *token. Return a hash of "token" in @a *hash. + * Leave @a token and @a hash untouched when the datasource is exhausted. + */ + svn_error_t *(*datasource_get_next_token)(apr_uint32_t *hash, void **token, + void *diff_baton, + svn_diff_datasource_e datasource); + + /** A function for ordering the tokens, resembling 'strcmp' in functionality. + * @a compare should contain the return value of the comparison: + * If @a ltoken and @a rtoken are "equal", return 0. If @a ltoken is + * "less than" @a rtoken, return a number < 0. If @a ltoken is + * "greater than" @a rtoken, return a number > 0. + */ + svn_error_t *(*token_compare)(void *diff_baton, + void *ltoken, + void *rtoken, + int *compare); + + /** Free @a token from memory, the diff algorithm is done with it. */ + void (*token_discard)(void *diff_baton, + void *token); + + /** Free *all* tokens from memory, they're no longer needed. */ + void (*token_discard_all)(void *diff_baton); +} svn_diff_fns_t; + + +/* The Main Events */ + +/** Given a vtable of @a diff_fns/@a diff_baton for reading datasources, + * return a diff object in @a *diff that represents a difference between + * an "original" and "modified" datasource. Do all allocation in @a pool. + */ +svn_error_t * +svn_diff_diff(svn_diff_t **diff, + void *diff_baton, + const svn_diff_fns_t *diff_fns, + apr_pool_t *pool); + +/** Given a vtable of @a diff_fns/@a diff_baton for reading datasources, + * return a diff object in @a *diff that represents a difference between + * three datasources: "original", "modified", and "latest". Do all + * allocation in @a pool. + */ +svn_error_t * +svn_diff_diff3(svn_diff_t **diff, + void *diff_baton, + const svn_diff_fns_t *diff_fns, + apr_pool_t *pool); + +/** Given a vtable of @a diff_fns/@a diff_baton for reading datasources, + * return a diff object in @a *diff that represents a difference between + * two datasources: "original" and "latest", adjusted to become a full + * difference between "original", "modified" and "latest" using "ancestor". + * Do all allocation in @a pool. + */ +svn_error_t * +svn_diff_diff4(svn_diff_t **diff, + void *diff_baton, + const svn_diff_fns_t *diff_fns, + apr_pool_t *pool); + + +/* Utility functions */ + +/** Determine if a diff object contains conflicts. If it does, return + * @c TRUE, else return @c FALSE. + */ +svn_boolean_t +svn_diff_contains_conflicts(svn_diff_t *diff); + + +/** Determine if a diff object contains actual differences between the + * datasources. If so, return @c TRUE, else return @c FALSE. + */ +svn_boolean_t +svn_diff_contains_diffs(svn_diff_t *diff); + + + + +/* Displaying Diffs */ + +/** A vtable for displaying (or consuming) differences between datasources. + * + * Differences, similarities, and conflicts are described by lining up + * "ranges" of data. + * + * @note These callbacks describe data ranges in units of "tokens". + * A "token" is whatever you've defined it to be in your datasource + * @c svn_diff_fns_t vtable. + */ +typedef struct svn_diff_output_fns_t +{ + /* Two-way and three-way diffs both call the first two output functions: */ + + /** + * If doing a two-way diff, then an *identical* data range was found + * between the "original" and "modified" datasources. Specifically, + * the match starts at @a original_start and goes for @a original_length + * tokens in the original data, and at @a modified_start for + * @a modified_length tokens in the modified data. + * + * If doing a three-way diff, then all three datasources have + * matching data ranges. The range @a latest_start, @a latest_length in + * the "latest" datasource is identical to the range @a original_start, + * @a original_length in the original data, and is also identical to + * the range @a modified_start, @a modified_length in the modified data. + */ + svn_error_t *(*output_common)(void *output_baton, + apr_off_t original_start, + apr_off_t original_length, + apr_off_t modified_start, + apr_off_t modified_length, + apr_off_t latest_start, + apr_off_t latest_length); + + /** + * If doing a two-way diff, then an *conflicting* data range was found + * between the "original" and "modified" datasources. Specifically, + * the conflict starts at @a original_start and goes for @a original_length + * tokens in the original data, and at @a modified_start for + * @a modified_length tokens in the modified data. + * + * If doing a three-way diff, then an identical data range was discovered + * between the "original" and "latest" datasources, but this conflicts with + * a range in the "modified" datasource. + */ + svn_error_t *(*output_diff_modified)(void *output_baton, + apr_off_t original_start, + apr_off_t original_length, + apr_off_t modified_start, + apr_off_t modified_length, + apr_off_t latest_start, + apr_off_t latest_length); + + /* ------ The following callbacks are used by three-way diffs only --- */ + + /** An identical data range was discovered between the "original" and + * "modified" datasources, but this conflicts with a range in the + * "latest" datasource. + */ + svn_error_t *(*output_diff_latest)(void *output_baton, + apr_off_t original_start, + apr_off_t original_length, + apr_off_t modified_start, + apr_off_t modified_length, + apr_off_t latest_start, + apr_off_t latest_length); + + /** An identical data range was discovered between the "modified" and + * "latest" datasources, but this conflicts with a range in the + * "original" datasource. + */ + svn_error_t *(*output_diff_common)(void *output_baton, + apr_off_t original_start, + apr_off_t original_length, + apr_off_t modified_start, + apr_off_t modified_length, + apr_off_t latest_start, + apr_off_t latest_length); + + /** All three datasources have conflicting data ranges. The range + * @a latest_start, @a latest_length in the "latest" datasource conflicts + * with the range @a original_start, @a original_length in the "original" + * datasource, and also conflicts with the range @a modified_start, + * @a modified_length in the "modified" datasource. + * If there are common ranges in the "modified" and "latest" datasources + * in this conflicting range, @a resolved_diff will contain a diff + * which can be used to retrieve the common and conflicting ranges. + */ + svn_error_t *(*output_conflict)(void *output_baton, + apr_off_t original_start, + apr_off_t original_length, + apr_off_t modified_start, + apr_off_t modified_length, + apr_off_t latest_start, + apr_off_t latest_length, + svn_diff_t *resolved_diff); +} svn_diff_output_fns_t; + +/** Style for displaying conflicts during diff3 output. + * + * @since New in 1.6. + */ +typedef enum svn_diff_conflict_display_style_t +{ + /** Display modified and latest, with conflict markers. */ + svn_diff_conflict_display_modified_latest, + + /** Like svn_diff_conflict_display_modified_latest, but with an + extra effort to identify common sequences between modified and + latest. */ + svn_diff_conflict_display_resolved_modified_latest, + + /** Display modified, original, and latest, with conflict + markers. */ + svn_diff_conflict_display_modified_original_latest, + + /** Just display modified, with no markers. */ + svn_diff_conflict_display_modified, + + /** Just display latest, with no markers. */ + svn_diff_conflict_display_latest, + + /** Like svn_diff_conflict_display_modified_original_latest, but + *only* showing conflicts. */ + svn_diff_conflict_display_only_conflicts +} svn_diff_conflict_display_style_t; + + +/** Given a vtable of @a output_fns/@a output_baton for consuming + * differences, output the differences in @a diff. + */ +svn_error_t * +svn_diff_output(svn_diff_t *diff, + void *output_baton, + const svn_diff_output_fns_t *output_fns); + + + +/* Diffs on files */ + +/** To what extent whitespace should be ignored when comparing lines. + * + * @since New in 1.4. + */ +typedef enum svn_diff_file_ignore_space_t +{ + /** Ignore no whitespace. */ + svn_diff_file_ignore_space_none, + + /** Ignore changes in sequences of whitespace characters, treating each + * sequence of whitespace characters as a single space. */ + svn_diff_file_ignore_space_change, + + /** Ignore all whitespace characters. */ + svn_diff_file_ignore_space_all +} svn_diff_file_ignore_space_t; + +/** Options to control the behaviour of the file diff routines. + * + * @since New in 1.4. + * + * @note This structure may be extended in the future, so to preserve binary + * compatibility, users must not allocate structs of this type themselves. + * @see svn_diff_file_options_create(). + * + * @note Although its name suggests otherwise, this structure is used to + * pass options to file as well as in-memory diff functions. + */ +typedef struct svn_diff_file_options_t +{ + /** To what extent whitespace should be ignored when comparing lines. + * The default is @c svn_diff_file_ignore_space_none. */ + svn_diff_file_ignore_space_t ignore_space; + /** Whether to treat all end-of-line markers the same when comparing lines. + * The default is @c FALSE. */ + svn_boolean_t ignore_eol_style; + /** Whether the '@@' lines of the unified diff output should include a prefix + * of the nearest preceding line that starts with a character that might be + * the initial character of a C language identifier. The default is + * @c FALSE. + */ + svn_boolean_t show_c_function; +} svn_diff_file_options_t; + +/** Allocate a @c svn_diff_file_options_t structure in @a pool, initializing + * it with default values. + * + * @since New in 1.4. + */ +svn_diff_file_options_t * +svn_diff_file_options_create(apr_pool_t *pool); + +/** + * Parse @a args, an array of const char * command line switches + * and adjust @a options accordingly. @a options is assumed to be initialized + * with default values. @a pool is used for temporary allocation. + * + * @since New in 1.4. + * + * The following options are supported: + * - --ignore-space-change, -b + * - --ignore-all-space, -w + * - --ignore-eol-style + * - --unified, -u (for compatibility, does nothing). + */ +svn_error_t * +svn_diff_file_options_parse(svn_diff_file_options_t *options, + const apr_array_header_t *args, + apr_pool_t *pool); + + +/** A convenience function to produce a diff between two files. + * + * @since New in 1.4. + * + * Return a diff object in @a *diff (allocated from @a pool) that represents + * the difference between an @a original file and @a modified file. + * (The file arguments must be full paths to the files.) + * + * Compare lines according to the relevant fields of @a options. + */ +svn_error_t * +svn_diff_file_diff_2(svn_diff_t **diff, + const char *original, + const char *modified, + const svn_diff_file_options_t *options, + apr_pool_t *pool); + +/** Similar to svn_file_diff_2(), but with @a options set to a struct with + * default options. + * + * @deprecated Provided for backwards compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_diff_file_diff(svn_diff_t **diff, + const char *original, + const char *modified, + apr_pool_t *pool); + +/** A convenience function to produce a diff between three files. + * + * @since New in 1.4. + * + * Return a diff object in @a *diff (allocated from @a pool) that represents + * the difference between an @a original file, @a modified file, and @a latest + * file. + * + * Compare lines according to the relevant fields of @a options. + */ +svn_error_t * +svn_diff_file_diff3_2(svn_diff_t **diff, + const char *original, + const char *modified, + const char *latest, + const svn_diff_file_options_t *options, + apr_pool_t *pool); + +/** Similar to svn_diff_file_diff3_2(), but with @a options set to a struct + * with default options. + * + * @deprecated Provided for backwards compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_diff_file_diff3(svn_diff_t **diff, + const char *original, + const char *modified, + const char *latest, + apr_pool_t *pool); + +/** A convenience function to produce a diff between four files. + * + * @since New in 1.4. + * + * Return a diff object in @a *diff (allocated from @a pool) that represents + * the difference between an @a original file, @a modified file, @a latest + * and @a ancestor file. (The file arguments must be full paths to the files.) + * + * Compare lines according to the relevant fields of @a options. + */ +svn_error_t * +svn_diff_file_diff4_2(svn_diff_t **diff, + const char *original, + const char *modified, + const char *latest, + const char *ancestor, + const svn_diff_file_options_t *options, + apr_pool_t *pool); + +/** Simliar to svn_file_diff4_2(), but with @a options set to a struct with + * default options. + * + * @deprecated Provided for backwards compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_diff_file_diff4(svn_diff_t **diff, + const char *original, + const char *modified, + const char *latest, + const char *ancestor, + apr_pool_t *pool); + +/** A convenience function to produce unified diff output from the + * diff generated by svn_diff_file_diff(). + * + * @since New in 1.5. + * + * Output a @a diff between @a original_path and @a modified_path in unified + * context diff format to @a output_stream. Optionally supply + * @a original_header and/or @a modified_header to be displayed in the header + * of the output. If @a original_header or @a modified_header is @c NULL, a + * default header will be displayed, consisting of path and last modified time. + * Output all headers and markers in @a header_encoding. If @a relative_to_dir + * is not @c NULL, the @a original_path and @a modified_path will have the + * @a relative_to_dir stripped from the front of the respective paths. If + * @a relative_to_dir is @c NULL, paths will be not be modified. If + * @a relative_to_dir is not @c NULL but @a relative_to_dir is not a parent + * path of the target, an error is returned. Finally, if @a relative_to_dir + * is a URL, an error will be returned. + */ +svn_error_t * +svn_diff_file_output_unified3(svn_stream_t *output_stream, + svn_diff_t *diff, + const char *original_path, + const char *modified_path, + const char *original_header, + const char *modified_header, + const char *header_encoding, + const char *relative_to_dir, + svn_boolean_t show_c_function, + apr_pool_t *pool); + +/** Similar to svn_diff_file_output_unified3(), but with @a relative_to_dir + * set to NULL and @a show_c_function to false. + * + * @deprecated Provided for backwards compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_diff_file_output_unified2(svn_stream_t *output_stream, + svn_diff_t *diff, + const char *original_path, + const char *modified_path, + const char *original_header, + const char *modified_header, + const char *header_encoding, + apr_pool_t *pool); + +/** Similar to svn_diff_file_output_unified2(), but with @a header_encoding + * set to @c APR_LOCALE_CHARSET. + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_diff_file_output_unified(svn_stream_t *output_stream, + svn_diff_t *diff, + const char *original_path, + const char *modified_path, + const char *original_header, + const char *modified_header, + apr_pool_t *pool); + + +/** A convenience function to produce diff3 output from the + * diff generated by svn_diff_file_diff3(). + * + * Output a @a diff between @a original_path, @a modified_path and + * @a latest_path in merged format to @a output_stream. Optionally supply + * @a conflict_modified, @a conflict_original, @a conflict_separator and/or + * @a conflict_latest to be displayed as conflict markers in the output. + * If @a conflict_original, @a conflict_modified, @a conflict_latest and/or + * @a conflict_separator is @c NULL, a default marker will be displayed. + * @a conflict_style dictates how conflicts are displayed. + * + * @since New in 1.6. + */ +svn_error_t * +svn_diff_file_output_merge2(svn_stream_t *output_stream, + svn_diff_t *diff, + const char *original_path, + const char *modified_path, + const char *latest_path, + const char *conflict_original, + const char *conflict_modified, + const char *conflict_latest, + const char *conflict_separator, + svn_diff_conflict_display_style_t conflict_style, + apr_pool_t *pool); + + +/** Similar to svn_diff_file_output_merge2, but with @a + * display_original_in_conflict and @a display_resolved_conflicts + * booleans instead of the @a conflict_style enum. + * + * If both booleans are false, acts like + * svn_diff_conflict_display_modified_latest; if @a + * display_original_in_conflict is true, acts like + * svn_diff_conflict_display_modified_original_latest; if @a + * display_resolved_conflicts is true, acts like + * svn_diff_conflict_display_resolved_modified_latest. The booleans + * may not both be true. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_diff_file_output_merge(svn_stream_t *output_stream, + svn_diff_t *diff, + const char *original_path, + const char *modified_path, + const char *latest_path, + const char *conflict_original, + const char *conflict_modified, + const char *conflict_latest, + const char *conflict_separator, + svn_boolean_t display_original_in_conflict, + svn_boolean_t display_resolved_conflicts, + apr_pool_t *pool); + + + +/* Diffs on in-memory structures */ + +/** Generate @a diff output from the @a original and @a modified + * in-memory strings. @a diff will be allocated from @a pool. + * + * @since New in 1.5. + */ +svn_error_t * +svn_diff_mem_string_diff(svn_diff_t **diff, + const svn_string_t *original, + const svn_string_t *modified, + const svn_diff_file_options_t *options, + apr_pool_t *pool); + + +/** Generate @a diff output from the @a orginal, @a modified and @a latest + * in-memory strings. @a diff will be allocated in @a pool. + * + * @since New in 1.5. + */ +svn_error_t * +svn_diff_mem_string_diff3(svn_diff_t **diff, + const svn_string_t *original, + const svn_string_t *modified, + const svn_string_t *latest, + const svn_diff_file_options_t *options, + apr_pool_t *pool); + + +/** Generate @a diff output from the @a original, @a modified and @a latest + * in-memory strings, using @a ancestor. @a diff will be allocated in @a pool. + * + * @since New in 1.5. + */ +svn_error_t * +svn_diff_mem_string_diff4(svn_diff_t **diff, + const svn_string_t *original, + const svn_string_t *modified, + const svn_string_t *latest, + const svn_string_t *ancestor, + const svn_diff_file_options_t *options, + apr_pool_t *pool); + + +/** Outputs the @a diff object generated by svn_diff_mem_string_diff() + * in unified diff format on @a output_stream, using @a original + * and @a modified for the text in the output. + * Outputs the header and markers in @a header_encoding. + * + * @a original_header and @a modified header are + * used to fill the field after the "---" and "+++" header markers. + * + * @since New in 1.5. + */ +svn_error_t * +svn_diff_mem_string_output_unified(svn_stream_t *output_stream, + svn_diff_t *diff, + const char *original_header, + const char *modified_header, + const char *header_encoding, + const svn_string_t *original, + const svn_string_t *modified, + apr_pool_t *pool); + +/** Output the @a diff generated by svn_diff_mem_string_diff3() in diff3 + * format on @a output_stream, using @a original, @a modified and @a latest + * for content changes. + * + * Use the conflict markers @a conflict_original, @a conflict_modified, + * @a conflict_latest and @a conflict_separator or the default one for + * each of these if @c NULL is passed. + * + * @a conflict_style dictates how conflicts are displayed. + * + * @since New in 1.6. + */ +svn_error_t * +svn_diff_mem_string_output_merge2(svn_stream_t *output_stream, + svn_diff_t *diff, + const svn_string_t *original, + const svn_string_t *modified, + const svn_string_t *latest, + const char *conflict_original, + const char *conflict_modified, + const char *conflict_latest, + const char *conflict_separator, + svn_diff_conflict_display_style_t style, + apr_pool_t *pool); + +/** Similar to svn_diff_mem_string_output_merge2, but with @a + * display_original_in_conflict and @a display_resolved_conflicts + * booleans instead of the @a conflict_style enum. + * + * If both booleans are false, acts like + * svn_diff_conflict_display_modified_latest; if @a + * display_original_in_conflict is true, acts like + * svn_diff_conflict_display_modified_original_latest; if @a + * display_resolved_conflicts is true, acts like + * svn_diff_conflict_display_resolved_modified_latest. The booleans + * may not both be true. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_diff_mem_string_output_merge(svn_stream_t *output_stream, + svn_diff_t *diff, + const svn_string_t *original, + const svn_string_t *modified, + const svn_string_t *latest, + const char *conflict_original, + const char *conflict_modified, + const char *conflict_latest, + const char *conflict_separator, + svn_boolean_t display_original_in_conflict, + svn_boolean_t display_resolved_conflicts, + apr_pool_t *pool); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_DIFF_H */ diff --git a/src/TortoiseMerge/svninclude/svn_dso.h b/src/TortoiseMerge/svninclude/svn_dso.h new file mode 100644 index 0000000..38c1f99 --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_dso.h @@ -0,0 +1,106 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2006, 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_dso.h + * @brief DSO loading routines + */ + + + +#ifndef SVN_DSO_H +#define SVN_DSO_H + +#include + +#include "svn_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * Initialize the DSO loading routines. + * + * @note This should be called prior to the creation of any pool that + * is passed to a function that comes from a DSO, otherwise you + * risk having the DSO unloaded before all pool cleanup callbacks + * that live in the DSO have been executed. If it is not called + * prior to @c svn_dso_load being used for the first time there + * will be a best effort attempt made to initialize the subsystem, + * but it will not be entirely thread safe and it risks running + * into the previously mentioned problems with DSO unloading and + * pool cleanup callbacks. + * + * Returns svn_error_t object with corresponding apr_err returned by + * underlying calls. In case of no error returns @c SVN_NO_ERROR. + * + * @since New in 1.6. + */ +svn_error_t * +svn_dso_initialize2(void); + +/** + * Initialize the DSO loading routines. + * + * @note This should be called prior to the creation of any pool that + * is passed to a function that comes from a DSO, otherwise you + * risk having the DSO unloaded before all pool cleanup callbacks + * that live in the DSO have been executed. If it is not called + * prior to @c svn_dso_load being used for the first time there + * will be a best effort attempt made to initialize the subsystem, + * but it will not be entirely thread safe and it risks running + * into the previously mentioned problems with DSO unloading and + * pool cleanup callbacks. + * + * Calls svn_dso_initialize2(void) upon error aborts. + * + * @deprecated Provided for backwards compatibility with the 1.5 API. + * + * @since New in 1.4. + */ +SVN_DEPRECATED +void +svn_dso_initialize(void); + + +#if APR_HAS_DSO + +/** + * Attempt to load @a libname, returning it in @a dso. + * + * If @a libname cannot be loaded set @a dso to NULL and return + * @c SVN_NO_ERROR. + * + * @note Due to pool lifetime issues DSOs are all loaded into a global + * pool, so you must be certain that there is a bounded number of + * them that will ever be loaded by the system, otherwise you will + * leak memory. + * + * @since New in 1.4. + */ +svn_error_t * +svn_dso_load(apr_dso_handle_t **dso, + const char *libname); + +#endif /* APR_HAS_DSO */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_DSO_H */ diff --git a/src/TortoiseMerge/svninclude/svn_error.h b/src/TortoiseMerge/svninclude/svn_error.h index c348acb..a3c3a21 100644 --- a/src/TortoiseMerge/svninclude/svn_error.h +++ b/src/TortoiseMerge/svninclude/svn_error.h @@ -25,14 +25,14 @@ #ifndef SVN_ERROR_H #define SVN_ERROR_H -#include -#include /* APR's error system */ -#include +#include /* for apr_size_t */ +#include /* APR's error system */ +#include /* for apr_pool_t */ #ifndef DOXYGEN_SHOULD_SKIP_THIS #define APR_WANT_STDIO #endif -#include +#include /* for FILE* */ #include "svn_types.h" @@ -155,6 +155,17 @@ svn_error_quick_wrap(svn_error_t *child, #define svn_error_quick_wrap \ (svn_error__locate(__FILE__,__LINE__), (svn_error_quick_wrap)) +/** Compose two errors, returning the composition as a brand new error + * and consuming the original errors. Either or both of @a err1 and + * @a err2 may be @c SVN_NO_ERROR. If both are not @c SVN_NO_ERROR, + * @a err2 will follow @a err1 in the chain of the returned error. + * + * @since New in 1.6. + */ +svn_error_t * +svn_error_compose_create(svn_error_t *err1, + svn_error_t *err2); + /** Add @a new_err to the end of @a chain's chain of errors. The @a new_err * chain will be copied into @a chain's pool and destroyed, so @a new_err * itself becomes invalid after this function. @@ -338,11 +349,24 @@ svn_handle_warning(FILE *stream, * * @since New in 1.6. */ -#define SVN_ERR_MALFUNCTION() \ - do { \ - return svn_error__malfunction(__FILE__, __LINE__, NULL); \ +#define SVN_ERR_MALFUNCTION() \ + do { \ + return svn_error__malfunction(TRUE, __FILE__, __LINE__, NULL); \ } while (0) +/** Similar to SVN_ERR_MALFUNCTION(), but without the option of returning + * an error to the calling function. + * + * If possible you should use SVN_ERR_MALFUNCTION() instead. + * + * @since New in 1.6. + */ +#define SVN_ERR_MALFUNCTION_NO_RETURN() \ + do { \ + svn_error__malfunction(FALSE, __FILE__, __LINE__, NULL); \ + abort(); \ + } while (1) + /** Check that a condition is true: if not, report an error and possibly * terminate the program. * @@ -362,12 +386,28 @@ svn_handle_warning(FILE *stream, * * @since New in 1.6. */ -#define SVN_ERR_ASSERT(expr) \ - do { \ - if (!(expr)) \ - SVN_ERR(svn_error__malfunction(__FILE__, __LINE__, #expr)); \ +#define SVN_ERR_ASSERT(expr) \ + do { \ + if (!(expr)) \ + SVN_ERR(svn_error__malfunction(TRUE, __FILE__, __LINE__, #expr)); \ } while (0) +/** Similar to SVN_ERR_ASSERT(), but without the option of returning + * an error to the calling function. + * + * If possible you should use SVN_ERR_ASSERT() instead. + * + * @since New in 1.6. + */ +#define SVN_ERR_ASSERT_NO_RETURN(expr) \ + do { \ + if (!(expr)) { \ + svn_error__malfunction(FALSE, __FILE__, __LINE__, #expr); \ + abort(); \ + } \ + } while (0) + + /** A helper function for the macros that report malfunctions. Handle a * malfunction by calling the current "malfunction handler" which may have * been specified by a call to svn_error_set_malfunction_handler() or else @@ -377,13 +417,15 @@ svn_handle_warning(FILE *stream, * source file @a file at line @a line, and was an assertion failure of the * expression @a expr, or, if @a expr is null, an unconditional error. * - * If the malfunction handler returns, then return the error object that it - * generated. + * If @a can_return is true, the handler can return an error object + * that is returned by the caller. If @a can_return is false the + * method should never return. (The caller will call abort()) * * @since New in 1.6. */ svn_error_t * -svn_error__malfunction(const char *file, +svn_error__malfunction(svn_boolean_t can_return, + const char *file, int line, const char *expr); @@ -394,7 +436,9 @@ svn_error__malfunction(const char *file, * assertion failure of the expression @a expr, or, if @a expr is null, an * unconditional error. * - * A function of this type must do one of: + * If @a can_return is false a function of this type must never return. + * + * If @a can_return is true a function of this type must do one of: * - Return an error object describing the error, using an error code in * the category SVN_ERR_MALFUNC_CATEGORY_START. * - Never return. @@ -405,7 +449,7 @@ svn_error__malfunction(const char *file, * @since New in 1.6. */ typedef svn_error_t *(*svn_error_malfunction_handler_t) - (const char *file, int line, const char *expr); + (svn_boolean_t can_return, const char *file, int line, const char *expr); /** Cause subsequent malfunctions to be handled by @a func. * Return the handler that was previously in effect. @@ -423,12 +467,15 @@ svn_error_set_malfunction_handler(svn_error_malfunction_handler_t func); /** Handle a malfunction by returning an error object that describes it. * + * When @a can_return is false, abort() + * * This function implements @c svn_error_malfunction_handler_t. * * @since New in 1.6. */ svn_error_t * -svn_error_raise_on_malfunction(const char *file, +svn_error_raise_on_malfunction(svn_boolean_t can_return, + const char *file, int line, const char *expr); @@ -439,7 +486,8 @@ svn_error_raise_on_malfunction(const char *file, * @since New in 1.6. */ svn_error_t * -svn_error_abort_on_malfunction(const char *file, +svn_error_abort_on_malfunction(svn_boolean_t can_return, + const char *file, int line, const char *expr); diff --git a/src/TortoiseMerge/svninclude/svn_error_codes.h b/src/TortoiseMerge/svninclude/svn_error_codes.h index 91d3ffb..2a6af70 100644 --- a/src/TortoiseMerge/svninclude/svn_error_codes.h +++ b/src/TortoiseMerge/svninclude/svn_error_codes.h @@ -1,7 +1,7 @@ /** * @copyright * ==================================================================== - * Copyright (c) 2000-2008 CollabNet. All rights reserved. + * Copyright (c) 2000-2009 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -42,11 +42,8 @@ #if defined(SVN_ERROR_BUILD_ARRAY) || !defined(SVN_ERROR_ENUM_DEFINED) -#include #include /* APR's error system */ -//#include "svn_props.h" /* For SVN_PROP_EXTERNALS. */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -315,6 +312,10 @@ SVN_ERROR_START SVN_ERR_ENTRY_CATEGORY_START + 5, "Entry has an invalid attribute") + SVN_ERRDEF(SVN_ERR_ENTRY_FORBIDDEN, + SVN_ERR_ENTRY_CATEGORY_START + 6, + "Can't create an entry for a forbidden name") + /* wc errors */ SVN_ERRDEF(SVN_ERR_WC_OBSTRUCTED_UPDATE, @@ -841,6 +842,13 @@ SVN_ERROR_START SVN_ERR_RA_DAV_CATEGORY_START + 11, "Repository has been moved") + /* SVN_ERR_RA_DAV_CATEGORY_START + 12 is reserved for use in 1.7. */ + + /** @since New in 1.6 */ + SVN_ERRDEF(SVN_ERR_RA_DAV_FORBIDDEN, + SVN_ERR_RA_DAV_CATEGORY_START + 13, + "URL access forbidden for unknown reason") + /* ra_local errors */ SVN_ERRDEF(SVN_ERR_RA_LOCAL_REPOS_NOT_FOUND, diff --git a/src/TortoiseMerge/svninclude/svn_io.h b/src/TortoiseMerge/svninclude/svn_io.h new file mode 100644 index 0000000..91e15ca --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_io.h @@ -0,0 +1,1666 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_io.h + * @brief General file I/O for Subversion + */ + +/* ==================================================================== */ + + +#ifndef SVN_IO_H +#define SVN_IO_H + +#include +#include +#include +#include +#include +#include +#include +#include /* for apr_proc_t, apr_exit_why_e */ + +#include "svn_types.h" +#include "svn_string.h" +#include "svn_checksum.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +/** Used as an argument when creating temporary files to indicate + * when a file should be removed. + * + * @since New in 1.4. + * + * Not specifying any of these means no removal at all. */ +typedef enum svn_io_file_del_t +{ + /** No deletion ever */ + svn_io_file_del_none = 0, + /** Remove when the file is closed */ + svn_io_file_del_on_close, + /** Remove when the associated pool is cleared */ + svn_io_file_del_on_pool_cleanup +} svn_io_file_del_t; + + + +/** Represents the kind and special status of a directory entry. + * + * @since New in 1.3. + */ +typedef struct svn_io_dirent_t { + /** The kind of this entry. */ + svn_node_kind_t kind; + /** If @c kind is @c svn_node_file, whether this entry is a special file; + * else FALSE. + * + * @see svn_io_check_special_path(). + */ + svn_boolean_t special; +} svn_io_dirent_t; + +/** Determine the @a kind of @a path. @a path should be UTF-8 encoded. + * + * If @a path is a file, set @a *kind to @c svn_node_file. + * + * If @a path is a directory, set @a *kind to @c svn_node_dir. + * + * If @a path does not exist, set @a *kind to @c svn_node_none. + * + * If @a path exists but is none of the above, set @a *kind to @c + * svn_node_unknown. + * + * If unable to determine @a path's kind, return an error, with @a *kind's + * value undefined. + * + * Use @a pool for temporary allocations. + * + * @see svn_node_kind_t + */ +svn_error_t * +svn_io_check_path(const char *path, + svn_node_kind_t *kind, + apr_pool_t *pool); + +/** + * Like svn_io_check_path(), but also set *is_special to @c TRUE if + * the path is not a normal file. + * + * @since New in 1.1. + */ +svn_error_t * +svn_io_check_special_path(const char *path, + svn_node_kind_t *kind, + svn_boolean_t *is_special, + apr_pool_t *pool); + +/** Like svn_io_check_path(), but resolve symlinks. This returns the + same varieties of @a kind as svn_io_check_path(). */ +svn_error_t * +svn_io_check_resolved_path(const char *path, + svn_node_kind_t *kind, + apr_pool_t *pool); + + +/** Open a new file (for reading and writing) with a unique name based on + * utf-8 encoded @a filename, in the directory @a dirpath. The file handle is + * returned in @a *file, and the name, which ends with @a suffix, is returned + * in @a *unique_name, also utf8-encoded. Either @a file or @a unique_name + * may be @c NULL. + * + * If @a delete_when is @c svn_io_file_del_on_close, then the @c APR_DELONCLOSE + * flag will be used when opening the file. The @c APR_BUFFERED flag will + * always be used. + * + * The first attempt will just append @a suffix. If the result is not + * a unique name, then subsequent attempts will append a dot, + * followed by an iteration number ("2", then "3", and so on), + * followed by the suffix. For example, successive calls to + * + * svn_io_open_uniquely_named(&f, &u, "tests/t1/A/D/G", "pi", ".tmp", ...) + * + * will open + * + * tests/t1/A/D/G/pi.tmp + * tests/t1/A/D/G/pi.2.tmp + * tests/t1/A/D/G/pi.3.tmp + * tests/t1/A/D/G/pi.4.tmp + * tests/t1/A/D/G/pi.5.tmp + * ... + * + * Assuming @a suffix is non-empty, @a *unique_name will never be exactly + * the same as @a filename, even if @a filename does not exist. + * + * If @a dirpath is NULL, then the directory returned by svn_io_temp_dir() + * will be used. + * + * If @a filename is NULL, then "tempfile" will be used. + * + * If @a suffix is NULL, then ".tmp" will be used. + * + * Allocates @a *file and @a *unique_name in @a result_pool. All + * intermediate allocations will be performed in @a scratch_pool. + * + * If no unique name can be found, @c SVN_ERR_IO_UNIQUE_NAMES_EXHAUSTED is + * the error returned. + * + * Claim of Historical Inevitability: this function was written + * because + * + * - tmpnam() is not thread-safe. + * - tempname() tries standard system tmp areas first. + * + * @since New in 1.6 + */ +svn_error_t * +svn_io_open_uniquely_named(apr_file_t **file, + const char **unique_name, + const char *dirpath, + const char *filename, + const char *suffix, + svn_io_file_del_t delete_when, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + +/** Create a writable file in the directory @a dirpath. The file will have + * an arbitrary and unique name, and the full path will be returned in + * @a temp_path. The file will be returned in @a file. Both will be + * allocated from @a result_pool. + * + * If @a dirpath is @c NULL, use the path returned from svn_io_temp_dir(). + * (Note that when using the system-provided temp directory, it may not + * be possibly to atomically rename the resulting file due to cross-device + * issues.) + * + * The file will be deleted according to @a delete_when. + * + * Temporary allocations will be performed in @a scratch_pool. + * + * @since New in 1.6 + * @see svn_stream_open_unique() + */ +svn_error_t * +svn_io_open_unique_file3(apr_file_t **file, + const char **temp_path, + const char *dirpath, + svn_io_file_del_t delete_when, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + +/** Like svn_io_open_uniquely_named(), but takes a joined dirpath and + * filename, and a single pool. + * + * @since New in 1.4 + * + * @deprecated Provided for backward compatibility with the 1.5 API + */ +SVN_DEPRECATED +svn_error_t * +svn_io_open_unique_file2(apr_file_t **f, + const char **unique_name_p, + const char *path, + const char *suffix, + svn_io_file_del_t delete_when, + apr_pool_t *pool); + +/** Like svn_io_open_unique_file2, but can't delete on pool cleanup. + * + * @deprecated Provided for backward compatibility with the 1.0 API + * + * @note In 1.4 the API was extended to require either @a f or + * @a unique_name_p (the other can be NULL). Before that, both were + * required. + */ +SVN_DEPRECATED +svn_error_t * +svn_io_open_unique_file(apr_file_t **f, + const char **unique_name_p, + const char *path, + const char *suffix, + svn_boolean_t delete_on_close, + apr_pool_t *pool); + + +/** + * Like svn_io_open_unique_file(), except that instead of creating a + * file, a symlink is generated that references the path @a dest. + * + * @since New in 1.1. + */ +svn_error_t * +svn_io_create_unique_link(const char **unique_name_p, + const char *path, + const char *dest, + const char *suffix, + apr_pool_t *pool); + + +/** + * Set @a *dest to the path that the symlink at @a path references. + * Allocate the string from @a pool. + * + * @since New in 1.1. + */ +svn_error_t * +svn_io_read_link(svn_string_t **dest, + const char *path, + apr_pool_t *pool); + + +/** Set @a *dir to a directory path (allocated in @a pool) deemed + * usable for the creation of temporary files and subdirectories. + */ +svn_error_t * +svn_io_temp_dir(const char **dir, + apr_pool_t *pool); + + +/** Copy @a src to @a dst atomically, in a "byte-for-byte" manner. + * Overwrite @a dst if it exists, else create it. Both @a src and @a dst + * are utf8-encoded filenames. If @a copy_perms is TRUE, set @a dst's + * permissions to match those of @a src. + */ +svn_error_t * +svn_io_copy_file(const char *src, + const char *dst, + svn_boolean_t copy_perms, + apr_pool_t *pool); + + +/** Copy permission flags from @a src onto the file at @a dst. Both + * filenames are utf8-encoded filenames. + */ +svn_error_t * +svn_io_copy_perms(const char *src, + const char *dst, + apr_pool_t *pool); + + +/** + * Copy symbolic link @a src to @a dst atomically. Overwrite @a dst + * if it exists, else create it. Both @a src and @a dst are + * utf8-encoded filenames. After copying, the @a dst link will point + * to the same thing @a src does. + * + * @since New in 1.1. + */ +svn_error_t * +svn_io_copy_link(const char *src, + const char *dst, + apr_pool_t *pool); + + +/** Recursively copy directory @a src into @a dst_parent, as a new entry named + * @a dst_basename. If @a dst_basename already exists in @a dst_parent, + * return error. @a copy_perms will be passed through to svn_io_copy_file() + * when any files are copied. @a src, @a dst_parent, and @a dst_basename are + * all utf8-encoded. + * + * If @a cancel_func is non-NULL, invoke it with @a cancel_baton at + * various points during the operation. If it returns any error + * (typically @c SVN_ERR_CANCELLED), return that error immediately. + */ +svn_error_t * +svn_io_copy_dir_recursively(const char *src, + const char *dst_parent, + const char *dst_basename, + svn_boolean_t copy_perms, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + + +/** Create directory @a path on the file system, creating intermediate + * directories as required, like mkdir -p. Report no error if @a + * path already exists. @a path is utf8-encoded. + * + * This is essentially a wrapper for apr_dir_make_recursive(), passing + * @c APR_OS_DEFAULT as the permissions. + */ +svn_error_t * +svn_io_make_dir_recursively(const char *path, + apr_pool_t *pool); + + +/** Set @a *is_empty_p to @c TRUE if directory @a path is empty, else to + * @c FALSE if it is not empty. @a path must be a directory, and is + * utf8-encoded. Use @a pool for temporary allocation. + */ +svn_error_t * +svn_io_dir_empty(svn_boolean_t *is_empty_p, + const char *path, + apr_pool_t *pool); + + +/** Append @a src to @a dst. @a dst will be appended to if it exists, else it + * will be created. Both @a src and @a dst are utf8-encoded. + */ +svn_error_t * +svn_io_append_file(const char *src, + const char *dst, + apr_pool_t *pool); + + +/** Make a file as read-only as the operating system allows. + * @a path is the utf8-encoded path to the file. If @a ignore_enoent is + * @c TRUE, don't fail if the target file doesn't exist. + * + * If @a path is a symlink, do nothing. + * + * @note If @a path is a directory, act on it as though it were a + * file, as described above, but note that you probably don't want to + * call this function on directories. We have left it effective on + * directories for compatibility reasons, but as its name implies, it + * should be used only for files. + */ +svn_error_t * +svn_io_set_file_read_only(const char *path, + svn_boolean_t ignore_enoent, + apr_pool_t *pool); + + +/** Make a file as writable as the operating system allows. + * @a path is the utf8-encoded path to the file. If @a ignore_enoent is + * @c TRUE, don't fail if the target file doesn't exist. + * @warning On Unix this function will do the equivalent of chmod a+w path. + * If this is not what you want you should not use this function, but rather + * use apr_file_perms_set(). + * + * If @a path is a symlink, do nothing. + * + * @note If @a path is a directory, act on it as though it were a + * file, as described above, but note that you probably don't want to + * call this function on directories. We have left it effective on + * directories for compatibility reasons, but as its name implies, it + * should be used only for files. + */ +svn_error_t * +svn_io_set_file_read_write(const char *path, + svn_boolean_t ignore_enoent, + apr_pool_t *pool); + + +/** Similar to svn_io_set_file_read_* functions. + * Change the read-write permissions of a file. + * @since New in 1.1. + * + * When making @a path read-write on operating systems with unix style + * permissions, set the permissions on @a path to the permissions that + * are set when a new file is created (effectively honoring the user's + * umask). + * + * When making the file read-only on operating systems with unix style + * permissions, remove all write permissions. + * + * On other operating systems, toggle the file's "writability" as much as + * the operating system allows. + * + * @a path is the utf8-encoded path to the file. If @a enable_write + * is @c TRUE, then make the file read-write. If @c FALSE, make it + * read-only. If @a ignore_enoent is @c TRUE, don't fail if the target + * file doesn't exist. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_io_set_file_read_write_carefully(const char *path, + svn_boolean_t enable_write, + svn_boolean_t ignore_enoent, + apr_pool_t *pool); + +/** Set @a path's "executability" (but do nothing if it is a symlink). + * + * @a path is the utf8-encoded path to the file. If @a executable + * is @c TRUE, then make the file executable. If @c FALSE, make it + * non-executable. If @a ignore_enoent is @c TRUE, don't fail if the target + * file doesn't exist. + * + * When making the file executable on operating systems with unix style + * permissions, never add an execute permission where there is not + * already a read permission: that is, only make the file executable + * for the user, group or world if the corresponding read permission + * is already set for user, group or world. + * + * When making the file non-executable on operating systems with unix style + * permissions, remove all execute permissions. + * + * On other operating systems, toggle the file's "executability" as much as + * the operating system allows. + * + * @note If @a path is a directory, act on it as though it were a + * file, as described above, but note that you probably don't want to + * call this function on directories. We have left it effective on + * directories for compatibility reasons, but as its name implies, it + * should be used only for files. + */ +svn_error_t * +svn_io_set_file_executable(const char *path, + svn_boolean_t executable, + svn_boolean_t ignore_enoent, + apr_pool_t *pool); + +/** Determine whether a file is executable by the current user. + * Set @a *executable to @c TRUE if the file @a path is executable by the + * current user, otherwise set it to @c FALSE. + * + * On Windows and on platforms without userids, always returns @c FALSE. + */ +svn_error_t * +svn_io_is_file_executable(svn_boolean_t *executable, + const char *path, + apr_pool_t *pool); + + +/** Read a line from @a file into @a buf, but not exceeding @a *limit bytes. + * Does not include newline, instead '\\0' is put there. + * Length (as in strlen) is returned in @a *limit. + * @a buf should be pre-allocated. + * @a file should be already opened. + * + * When the file is out of lines, @c APR_EOF will be returned. + */ +svn_error_t * +svn_io_read_length_line(apr_file_t *file, + char *buf, + apr_size_t *limit, + apr_pool_t *pool); + + +/** Set @a *apr_time to the time of last modification of the contents of the + * file @a path. @a path is utf8-encoded. + * + * @note This is the APR mtime which corresponds to the traditional mtime + * on Unix, and the last write time on Windows. + */ +svn_error_t * +svn_io_file_affected_time(apr_time_t *apr_time, + const char *path, + apr_pool_t *pool); + +/** Set the timestamp of file @a path to @a apr_time. @a path is + * utf8-encoded. + * + * @note This is the APR mtime which corresponds to the traditional mtime + * on Unix, and the last write time on Windows. + */ +svn_error_t * +svn_io_set_file_affected_time(apr_time_t apr_time, + const char *path, + apr_pool_t *pool); + +/** Sleep to ensure that any files modified after we exit have a different + * timestamp than the one we recorded. If @a path is not NULL, check if we + * can determine how long we should wait for a new timestamp on the filesystem + * containing @a path, an existing file or directory. If @a path is NULL or we + * can't determine the timestamp resolution, sleep until the next second. + * + * Use @a pool for any necessary allocations. @a pool can be null if @a path + * is NULL. + * + * Errors while retrieving the timestamp resolution will result in sleeping + * to the next second, to keep the working copy stable in error conditions. + * + * @since New in 1.6. + */ +void +svn_io_sleep_for_timestamps(const char *path, apr_pool_t *pool); + +/** Set @a *different_p to non-zero if @a file1 and @a file2 have different + * sizes, else set to zero. Both @a file1 and @a file2 are utf8-encoded. + * + * Setting @a *different_p to zero does not mean the files definitely + * have the same size, it merely means that the sizes are not + * definitely different. That is, if the size of one or both files + * cannot be determined, then the sizes are not known to be different, + * so @a *different_p is set to 0. + */ +svn_error_t * +svn_io_filesizes_different_p(svn_boolean_t *different_p, + const char *file1, + const char *file2, + apr_pool_t *pool); + + +/** Return in @a *checksum the checksum of type @a kind of @a file + * Use @a pool for temporary allocations and to allocate @a *checksum. + * + * @since New in 1.6. + */ +svn_error_t * +svn_io_file_checksum2(svn_checksum_t **checksum, + const char *file, + svn_checksum_kind_t kind, + apr_pool_t *pool); + + +/** Put the md5 checksum of @a file into @a digest. + * @a digest points to @c APR_MD5_DIGESTSIZE bytes of storage. + * Use @a pool only for temporary allocations. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_io_file_checksum(unsigned char digest[], + const char *file, + apr_pool_t *pool); + + +/** Set @a *same to TRUE if @a file1 and @a file2 have the same + * contents, else set it to FALSE. Use @a pool for temporary allocations. + */ +svn_error_t * +svn_io_files_contents_same_p(svn_boolean_t *same, + const char *file1, + const char *file2, + apr_pool_t *pool); + +/** Create file at utf8-encoded @a file with contents @a contents. + * @a file must not already exist. + * Use @a pool for memory allocations. + */ +svn_error_t * +svn_io_file_create(const char *file, + const char *contents, + apr_pool_t *pool); + +/** + * Lock file at @a lock_file. If @a exclusive is TRUE, + * obtain exclusive lock, otherwise obtain shared lock. + * Lock will be automatically released when @a pool is cleared or destroyed. + * Use @a pool for memory allocations. + * + * @deprecated Provided for backward compatibility with the 1.0 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_io_file_lock(const char *lock_file, + svn_boolean_t exclusive, + apr_pool_t *pool); + +/** + * Lock file at @a lock_file. If @a exclusive is TRUE, + * obtain exclusive lock, otherwise obtain shared lock. + * + * If @a nonblocking is TRUE, do not wait for the lock if it + * is not available: throw an error instead. + * + * Lock will be automatically released when @a pool is cleared or destroyed. + * Use @a pool for memory allocations. + * + * @since New in 1.1. + */ +svn_error_t * +svn_io_file_lock2(const char *lock_file, + svn_boolean_t exclusive, + svn_boolean_t nonblocking, + apr_pool_t *pool); +/** + * Flush any unwritten data from @a file to disk. Use @a pool for + * memory allocations. + * + * @since New in 1.1. + */ +svn_error_t * +svn_io_file_flush_to_disk(apr_file_t *file, + apr_pool_t *pool); + +/** Copy file @a file from location @a src_path to location @a dest_path. + * Use @a pool for memory allocations. + */ +svn_error_t * +svn_io_dir_file_copy(const char *src_path, + const char *dest_path, + const char *file, + apr_pool_t *pool); + + +/** Generic byte-streams + * + * @defgroup svn_io_byte_streams Generic byte streams + * @{ + */ + +/** An abstract stream of bytes--either incoming or outgoing or both. + * + * The creator of a stream sets functions to handle read and write. + * Both of these handlers accept a baton whose value is determined at + * stream creation time; this baton can point to a structure + * containing data associated with the stream. If a caller attempts + * to invoke a handler which has not been set, it will generate a + * runtime assertion failure. The creator can also set a handler for + * close requests so that it can flush buffered data or whatever; + * if a close handler is not specified, a close request on the stream + * will simply be ignored. Note that svn_stream_close() does not + * deallocate the memory used to allocate the stream structure; free + * the pool you created the stream in to free that memory. + * + * The read and write handlers accept length arguments via pointer. + * On entry to the handler, the pointed-to value should be the amount + * of data which can be read or the amount of data to write. When the + * handler returns, the value is reset to the amount of data actually + * read or written. Handlers are obliged to complete a read or write + * to the maximum extent possible; thus, a short read with no + * associated error implies the end of the input stream, and a short + * write should never occur without an associated error. + */ +typedef struct svn_stream_t svn_stream_t; + + + +/** Read handler function for a generic stream. @see svn_stream_t. */ +typedef svn_error_t *(*svn_read_fn_t)(void *baton, + char *buffer, + apr_size_t *len); + +/** Write handler function for a generic stream. @see svn_stream_t. */ +typedef svn_error_t *(*svn_write_fn_t)(void *baton, + const char *data, + apr_size_t *len); + +/** Close handler function for a generic stream. @see svn_stream_t. */ +typedef svn_error_t *(*svn_close_fn_t)(void *baton); + + +/** Create a generic stream. @see svn_stream_t. */ +svn_stream_t * +svn_stream_create(void *baton, + apr_pool_t *pool); + +/** Set @a stream's baton to @a baton */ +void +svn_stream_set_baton(svn_stream_t *stream, + void *baton); + +/** Set @a stream's read function to @a read_fn */ +void +svn_stream_set_read(svn_stream_t *stream, + svn_read_fn_t read_fn); + +/** Set @a stream's write function to @a write_fn */ +void +svn_stream_set_write(svn_stream_t *stream, + svn_write_fn_t write_fn); + +/** Set @a stream's close function to @a close_fn */ +void +svn_stream_set_close(svn_stream_t *stream, + svn_close_fn_t close_fn); + + +/** Create a stream that is empty for reading and infinite for writing. */ +svn_stream_t * +svn_stream_empty(apr_pool_t *pool); + +/** Return a stream allocated in @a pool which forwards all requests + * to @a stream. Destruction is explicitly excluded from forwarding. + * + * @see notes/destruction-of-stacked-resources + * + * @since New in 1.4. + */ +svn_stream_t * +svn_stream_disown(svn_stream_t *stream, + apr_pool_t *pool); + + +/** Create a stream to read the file at @a path. It will be opened using + * the APR_BUFFERED and APR_BINARY flag, and APR_OS_DEFAULT for the perms. + * If you'd like to use different values, then open the file yourself, and + * use the svn_stream_from_aprfile2() interface. + * + * The stream will be returned in @a stream, and allocated from @a result_pool. + * Temporary allocations will be performed in @a scratch_pool. + * + * @since New in 1.6 + */ +svn_error_t * +svn_stream_open_readonly(svn_stream_t **stream, + const char *path, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + +/** Create a stream to write a file at @a path. The file will be *created* + * using the APR_BUFFERED and APR_BINARY flag, and APR_OS_DEFAULT for the + * perms. The file will be created "exclusively", so if it already exists, + * then an error will be thrown. If you'd like to use different values, or + * open an existing file, then open the file yourself, and use the + * svn_stream_from_aprfile2() interface. + * + * The stream will be returned in @a stream, and allocated from @a result_pool. + * Temporary allocations will be performed in @a scratch_pool. + * + * @since New in 1.6 + */ +svn_error_t * +svn_stream_open_writable(svn_stream_t **stream, + const char *path, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + +/** Create a writable stream to a file in the directory @a dirpath. + * The file will have an arbitrary and unique name, and the full path + * will be returned in @a temp_path. The stream will be returned in + * @a stream. Both will be allocated from @a result_pool. + * + * If @a dirpath is @c NULL, use the path returned from svn_io_temp_dir(). + * (Note that when using the system-provided temp directory, it may not + * be possibly to atomically rename the resulting file due to cross-device + * issues.) + * + * The file will be deleted according to @a delete_when. + * + * Temporary allocations will be performed in @a scratch_pool. + * + * @since New in 1.6 + * @see svn_io_open_unique_file3() + */ +svn_error_t * +svn_stream_open_unique(svn_stream_t **stream, + const char **temp_path, + const char *dirpath, + svn_io_file_del_t delete_when, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + +/** Create a stream from an APR file. For convenience, if @a file is + * @c NULL, an empty stream created by svn_stream_empty() is returned. + * + * This function should normally be called with @a disown set to FALSE, + * in which case closing the stream will also close the underlying file. + * + * If @a disown is TRUE, the stream will disown the underlying file, + * meaning that svn_stream_close() will not close the file. + * + * @since New in 1.4. + */ +svn_stream_t * +svn_stream_from_aprfile2(apr_file_t *file, + svn_boolean_t disown, + apr_pool_t *pool); + +/** Similar to svn_stream_from_aprfile2(), except that the file will + * always be disowned. + * + * @note The stream returned is not considered to "own" the underlying + * file, meaning that svn_stream_close() on the stream will not + * close the file. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_stream_t * +svn_stream_from_aprfile(apr_file_t *file, + apr_pool_t *pool); + +/** Set @a *out to a generic stream connected to stdout, allocated in + * @a pool. The stream and its underlying APR handle will be closed + * when @a pool is cleared or destroyed. + */ +svn_error_t * +svn_stream_for_stdout(svn_stream_t **out, + apr_pool_t *pool); + +/** Return a generic stream connected to stringbuf @a str. Allocate the + * stream in @a pool. + */ +svn_stream_t * +svn_stream_from_stringbuf(svn_stringbuf_t *str, + apr_pool_t *pool); + +/** Return a generic read-only stream connected to string @a str. + * Allocate the stream in @a pool. + */ +svn_stream_t * +svn_stream_from_string(const svn_string_t *str, + apr_pool_t *pool); + +/** Return a stream that decompresses all data read and compresses all + * data written. The stream @a stream is used to read and write all + * compressed data. All compression data structures are allocated on + * @a pool. If compression support is not compiled in then + * svn_stream_compressed() returns @a stream unmodified. Make sure you + * call svn_stream_close() on the stream returned by this function, + * so that all data are flushed and cleaned up. + * + * @note From 1.4, compression support is always compiled in. + */ +svn_stream_t * +svn_stream_compressed(svn_stream_t *stream, + apr_pool_t *pool); + +/** Return a stream that calculates checksums for all data read + * and written. The stream @a stream is used to read and write all data. + * The stream and the resulting digests are allocated in @a pool. + * + * When the stream is closed, @a *read_checksum and @a *write_checksum + * are set to point to the resulting checksums, of type @a read_checksum_kind + * and @a write_checksum_kind, respectively. + * + * Both @a read_checksum and @a write_checksum can be @c NULL, in which case + * the respective checksum isn't calculated. + * + * If @a read_all is TRUE, make sure that all data available on @a + * stream is read (and checksummed) when the stream is closed. + * + * Read and write operations can be mixed without interfering. + * + * The @a stream passed into this function is closed when the created + * stream is closed. + * + * @since New in 1.6. + */ +svn_stream_t * +svn_stream_checksummed2(svn_stream_t *stream, + svn_checksum_t **read_checksum, + svn_checksum_t **write_checksum, + svn_checksum_kind_t checksum_kind, + svn_boolean_t read_all, + apr_pool_t *pool); + +/** + * Similar to svn_stream_checksummed2(), but always returning the MD5 + * checksum in @a read_digest and @a write_digest. + * + * @since New in 1.4. + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_stream_t * +svn_stream_checksummed(svn_stream_t *stream, + const unsigned char **read_digest, + const unsigned char **write_digest, + svn_boolean_t read_all, + apr_pool_t *pool); + +/** Read from a generic stream. @see svn_stream_t. */ +svn_error_t * +svn_stream_read(svn_stream_t *stream, + char *buffer, + apr_size_t *len); + +/** Write to a generic stream. @see svn_stream_t. */ +svn_error_t * +svn_stream_write(svn_stream_t *stream, + const char *data, + apr_size_t *len); + +/** Close a generic stream. @see svn_stream_t. */ +svn_error_t * +svn_stream_close(svn_stream_t *stream); + + +/** Write to @a stream using a printf-style @a fmt specifier, passed through + * apr_psprintf() using memory from @a pool. + */ +svn_error_t * +svn_stream_printf(svn_stream_t *stream, + apr_pool_t *pool, + const char *fmt, + ...) + __attribute__((format(printf, 3, 4))); + +/** Write to @a stream using a printf-style @a fmt specifier, passed through + * apr_psprintf() using memory from @a pool. The resulting string + * will be translated to @a encoding before it is sent to @a stream. + * + * @note Use @c APR_LOCALE_CHARSET to translate to the encoding of the + * current locale. + * + * @since New in 1.3. + */ +svn_error_t * +svn_stream_printf_from_utf8(svn_stream_t *stream, + const char *encoding, + apr_pool_t *pool, + const char *fmt, + ...) + __attribute__((format(printf, 4, 5))); + +/** Allocate @a *stringbuf in @a pool, and read into it one line (terminated + * by @a eol) from @a stream. The line-terminator is read from the stream, + * but is not added to the end of the stringbuf. Instead, the stringbuf + * ends with a usual '\\0'. + * + * If @a stream runs out of bytes before encountering a line-terminator, + * then set @a *eof to @c TRUE, otherwise set @a *eof to FALSE. + */ +svn_error_t * +svn_stream_readline(svn_stream_t *stream, + svn_stringbuf_t **stringbuf, + const char *eol, + svn_boolean_t *eof, + apr_pool_t *pool); + + +/** + * Read the contents of the readable stream @a from and write them to the + * writable stream @a to calling @a cancel_func before copying each chunk. + * + * @a cancel_func may be @c NULL. + * + * @note both @a from and @a to will be closed upon successful completion of + * the copy (but an error may still be returned, based on trying to close + * the two streams). If the closure is not desired, then you can use + * svn_stream_disown() to protect either or both of the streams from + * being closed. + * ### TODO: should close the streams ALWAYS, even on error exit + * + * @since New in 1.6. + */ +svn_error_t * +svn_stream_copy3(svn_stream_t *from, + svn_stream_t *to, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** + * Same as svn_stream_copy3() but the streams are not closed. + * + * @since New in 1.5. + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_stream_copy2(svn_stream_t *from, + svn_stream_t *to, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** + * Same as svn_stream_copy3(), but without the cancellation function + * or stream closing. + * + * @since New in 1.1. + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_stream_copy(svn_stream_t *from, + svn_stream_t *to, + apr_pool_t *pool); + + +/** Set @a *same to TRUE if @a stream1 and @a stream2 have the same + * contents, else set it to FALSE. Use @a pool for temporary allocations. + * + * @since New in 1.4. + */ +svn_error_t * +svn_stream_contents_same(svn_boolean_t *same, + svn_stream_t *stream1, + svn_stream_t *stream2, + apr_pool_t *pool); + + +/** Read the contents of @a stream into memory, returning the data in + * @a result. The stream will be closed when it has been successfully and + * completely read. + * + * The returned memory is allocated in @a result_pool, and any temporary + * allocations are performed in @a scratch_pool. + * + * @note due to memory pseudo-reallocation behavior (due to pools), this + * can be a memory-intensive operation for large files. + * + * @since New in 1.6 + */ +svn_error_t * +svn_string_from_stream(svn_string_t **result, + svn_stream_t *stream, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + +/** @} */ + +/** Set @a *result to a string containing the contents of @a + * filename, which is either "-" (indicating that stdin should be + * read) or the utf8-encoded path of a real file. + * + * @warning Callers should be aware of possible unexpected results + * when using this function to read from stdin where additional + * stdin-reading processes abound. For example, if a program tries + * both to invoke an external editor and to read from stdin, stdin + * could be trashed and the editor might act funky or die outright. + * + * @note due to memory pseudo-reallocation behavior (due to pools), this + * can be a memory-intensive operation for large files. + * + * @since New in 1.5. + */ +svn_error_t * +svn_stringbuf_from_file2(svn_stringbuf_t **result, + const char *filename, + apr_pool_t *pool); + +/** Similar to svn_stringbuf_from_file2(), except that if @a filename + * is "-", return the error @c SVN_ERR_UNSUPPORTED_FEATURE and don't + * touch @a *result. + * + * @deprecated Provided for backwards compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_stringbuf_from_file(svn_stringbuf_t **result, + const char *filename, + apr_pool_t *pool); + +/** Sets @a *result to a string containing the contents of the already opened + * @a file. Reads from the current position in file to the end. Does not + * close the file or reset the cursor position. + * + * @note due to memory pseudo-reallocation behavior (due to pools), this + * can be a memory-intensive operation for large files. + */ +svn_error_t * +svn_stringbuf_from_aprfile(svn_stringbuf_t **result, + apr_file_t *file, + apr_pool_t *pool); + +/** Remove file @a path, a utf8-encoded path. This wraps apr_file_remove(), + * converting any error to a Subversion error. + */ +svn_error_t * +svn_io_remove_file(const char *path, + apr_pool_t *pool); + +/** Recursively remove directory @a path. @a path is utf8-encoded. + * If @a ignore_enoent is @c TRUE, don't fail if the target directory + * doesn't exist. Use @a pool for temporary allocations. + * + * Because recursive delete of a directory tree can be a lengthy operation, + * provide @a cancel_func and @a cancel_baton for interruptability. + * + * @since New in 1.5. + */ +svn_error_t * +svn_io_remove_dir2(const char *path, + svn_boolean_t ignore_enoent, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** Similar to svn_io_remove_dir2(), but with @a ignore_enoent set to + * @c FALSE and @a cancel_func and @a cancel_baton set to @c NULL. + * + * @deprecated Provided for backward compatibility with the 1.4 API + */ +SVN_DEPRECATED +svn_error_t * +svn_io_remove_dir(const char *path, + apr_pool_t *pool); + +/** Read all of the disk entries in directory @a path, a utf8-encoded + * path. Set @a *dirents to a hash mapping dirent names (char *) to + * undefined non-NULL values, allocated in @a pool. + * + * @note The `.' and `..' directories normally returned by + * apr_dir_read() are NOT returned in the hash. + * + * @since New in 1.4. + */ +svn_error_t * +svn_io_get_dir_filenames(apr_hash_t **dirents, + const char *path, + apr_pool_t *pool); + +/** Read all of the disk entries in directory @a path, a utf8-encoded + * path. Set @a *dirents to a hash mapping dirent names (char *) to + * @c svn_io_dirent_t structures, allocated in @a pool. + * + * @note The `.' and `..' directories normally returned by + * apr_dir_read() are NOT returned in the hash. + * + * @note The kind field in the @a dirents is set according to the mapping + * as documented for svn_io_check_path() + * + * @since New in 1.3. + */ +svn_error_t * +svn_io_get_dirents2(apr_hash_t **dirents, + const char *path, + apr_pool_t *pool); + +/** Similar to svn_io_get_dirents2(), but @a *dirents is a hash table + * with @c svn_node_kind_t values. + * + * @deprecated Provided for backwards compatibility with the 1.2 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_io_get_dirents(apr_hash_t **dirents, + const char *path, + apr_pool_t *pool); + + +/** Callback function type for svn_io_dir_walk() */ +typedef svn_error_t * (*svn_io_walk_func_t)(void *baton, + const char *path, + const apr_finfo_t *finfo, + apr_pool_t *pool); + +/** This function will recursively walk over the files and directories + * rooted at @a dirname, a utf8-encoded path. For each file or directory, + * @a walk_func is invoked, passing in the @a walk_baton, the utf8-encoded + * full path to the entry, an @c apr_finfo_t structure, and a temporary + * pool for allocations. For any directory, @a walk_func will be invoked + * on the directory itself before being invoked on any subdirectories or + * files within the directory. + * + * The set of information passed to @a walk_func is specified by @a wanted, + * and the items specified by @c APR_FINFO_TYPE and @c APR_FINFO_NAME. + * + * All allocations will be performed in @a pool. + */ +svn_error_t * +svn_io_dir_walk(const char *dirname, + apr_int32_t wanted, + svn_io_walk_func_t walk_func, + void *walk_baton, + apr_pool_t *pool); + +/** + * Start @a cmd with @a args, using utf8-encoded @a path as working + * directory. Connect @a cmd's stdin, stdout, and stderr to @a infile, + * @a outfile, and @a errfile, except where they are NULL. Return the + * process handle for the invoked program in @a *cmd_proc. + * + * @a args is a list of utf8-encoded const char * arguments, + * terminated by @c NULL. @a args[0] is the name of the program, though it + * need not be the same as @a cmd. + * + * If @a inherit is TRUE, the invoked program inherits its environment from + * the caller and @a cmd, if not absolute, is searched for in PATH. + * Otherwise, the invoked program runs with an empty environment and @a cmd + * must be an absolute path. + * + * @note On some platforms, failure to execute @a cmd in the child process + * will result in error output being written to @a errfile, if non-NULL, and + * a non-zero exit status being returned to the parent process. + * + * @since New in 1.3. + */ +svn_error_t * +svn_io_start_cmd(apr_proc_t *cmd_proc, + const char *path, + const char *cmd, + const char *const *args, + svn_boolean_t inherit, + apr_file_t *infile, + apr_file_t *outfile, + apr_file_t *errfile, + apr_pool_t *pool); + +/** + * Wait for the process @a *cmd_proc to complete and optionally retrieve + * its exit code. @a cmd is used only in error messages. + * + * If @a exitcode is not NULL, @a *exitcode will contain the exit code + * of the process upon return, and if @a exitwhy is not NULL, @a + * *exitwhy will indicate why the process terminated. If @a exitwhy is + * NULL, and the exit reason is not @c APR_PROC_CHECK_EXIT(), or if + * @a exitcode is NULL and the exit code is non-zero, then an + * @c SVN_ERR_EXTERNAL_PROGRAM error will be returned. + * + * @since New in 1.3. + */ +svn_error_t * +svn_io_wait_for_cmd(apr_proc_t *cmd_proc, + const char *cmd, + int *exitcode, + apr_exit_why_e *exitwhy, + apr_pool_t *pool); + +/** Run a command to completion, by first calling svn_io_start_cmd() and + * then calling svn_io_wait_for_cmd(). The parameters correspond to + * the same-named parameters of those two functions. + */ +svn_error_t * +svn_io_run_cmd(const char *path, + const char *cmd, + const char *const *args, + int *exitcode, + apr_exit_why_e *exitwhy, + svn_boolean_t inherit, + apr_file_t *infile, + apr_file_t *outfile, + apr_file_t *errfile, + apr_pool_t *pool); + +/** Invoke the configured @c diff program, with @a user_args (an array + * of utf8-encoded @a num_user_args arguments) if they are specified + * (that is, if @a user_args is non-NULL), or "-u" if they are not. + * If @a user_args is NULL, the value of @a num_user_args is ignored. + * + * Diff runs in utf8-encoded @a dir, and its exit status is stored in + * @a exitcode, if it is not @c NULL. + * + * If @a label1 and/or @a label2 are not NULL they will be passed to the diff + * process as the arguments of "-L" options. @a label1 and @a label2 are also + * in utf8, and will be converted to native charset along with the other args. + * + * @a from is the first file passed to diff, and @a to is the second. The + * stdout of diff will be sent to @a outfile, and the stderr to @a errfile. + * + * @a diff_cmd must be non-NULL. + * + * Do all allocation in @a pool. + * @since New in 1.6.0. + */ +svn_error_t * +svn_io_run_diff2(const char *dir, + const char *const *user_args, + int num_user_args, + const char *label1, + const char *label2, + const char *from, + const char *to, + int *exitcode, + apr_file_t *outfile, + apr_file_t *errfile, + const char *diff_cmd, + apr_pool_t *pool); + +/** Similar to svn_io_run_diff2() but with @diff_cmd encoded in internal + * encoding used by APR. + * + * @deprecated Provided for backwards compatibility with the 1.5 API. */ +SVN_DEPRECATED +svn_error_t * +svn_io_run_diff(const char *dir, + const char *const *user_args, + int num_user_args, + const char *label1, + const char *label2, + const char *from, + const char *to, + int *exitcode, + apr_file_t *outfile, + apr_file_t *errfile, + const char *diff_cmd, + apr_pool_t *pool); + + + +/** Invoke the configured @c diff3 program, in utf8-encoded @a dir + * like this: + * + * diff3 -E -m @a mine @a older @a yours > @a merged + * + * (See the diff3 documentation for details.) + * + * If @a user_args is non-NULL, replace "-E" with the const char* + * elements that @a user_args contains. + * + * @a mine, @a older and @a yours are utf8-encoded paths (relative to + * @a dir or absolute) to three files that already exist. + * + * @a merged is an open file handle, and is left open after the merge + * result is written to it. (@a merged should *not* be the same file + * as @a mine, or nondeterministic things may happen!) + * + * @a mine_label, @a older_label, @a yours_label are utf8-encoded label + * parameters for diff3's -L option. Any of them may be @c NULL, in + * which case the corresponding @a mine, @a older, or @a yours parameter is + * used instead. + * + * Set @a *exitcode to diff3's exit status. If @a *exitcode is anything + * other than 0 or 1, then return @c SVN_ERR_EXTERNAL_PROGRAM. (Note the + * following from the diff3 info pages: "An exit status of 0 means + * `diff3' was successful, 1 means some conflicts were found, and 2 + * means trouble.") + * + * @a diff3_cmd must be non-NULL. + * + * Do all allocation in @a pool. + * + * @since New in 1.4. + */ +svn_error_t * +svn_io_run_diff3_3(int *exitcode, + const char *dir, + const char *mine, + const char *older, + const char *yours, + const char *mine_label, + const char *older_label, + const char *yours_label, + apr_file_t *merged, + const char *diff3_cmd, + const apr_array_header_t *user_args, + apr_pool_t *pool); + +/** Similar to svn_io_run_diff3_3(), but with @a diff3_cmd encoded in + * internal encoding used by APR. + * + * @deprecated Provided for backwards compatibility with the 1.5 API. + * @since New in 1.4. + */ +SVN_DEPRECATED +svn_error_t * +svn_io_run_diff3_2(int *exitcode, + const char *dir, + const char *mine, + const char *older, + const char *yours, + const char *mine_label, + const char *older_label, + const char *yours_label, + apr_file_t *merged, + const char *diff3_cmd, + const apr_array_header_t *user_args, + apr_pool_t *pool); + +/** Similar to svn_io_run_diff3_2(), but with @a user_args set to @c NULL. + * + * @deprecated Provided for backwards compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_io_run_diff3(const char *dir, + const char *mine, + const char *older, + const char *yours, + const char *mine_label, + const char *older_label, + const char *yours_label, + apr_file_t *merged, + int *exitcode, + const char *diff3_cmd, + apr_pool_t *pool); + + +/** Parse utf8-encoded @a mimetypes_file as a MIME types file (such as + * is provided with Apache HTTP Server), and set @a *type_map to a + * hash mapping const char * filename extensions to + * const char * MIME types. + * + * @since New in 1.5. + */ +svn_error_t * +svn_io_parse_mimetypes_file(apr_hash_t **type_map, + const char *mimetypes_file, + apr_pool_t *pool); + + +/** Examine utf8-encoded @a file to determine if it can be described by a + * known (as in, known by this function) Multipurpose Internet Mail + * Extension (MIME) type. If so, set @a *mimetype to a character string + * describing the MIME type, else set it to @c NULL. + * + * If not @c NULL, @a mimetype_map is a hash mapping const char * + * filename extensions to const char * MIME types, and is the + * first source consulted regarding @a file's MIME type. + * + * Use @a pool for any necessary allocations. + * + * @since New in 1.5. + */ +svn_error_t * +svn_io_detect_mimetype2(const char **mimetype, + const char *file, + apr_hash_t *mimetype_map, + apr_pool_t *pool); + + +/** Like svn_io_detect_mimetype2, but with @a mimetypes_map set to + * @c NULL. + * + * @deprecated Provided for backward compatibility with the 1.4 API + */ +SVN_DEPRECATED +svn_error_t * +svn_io_detect_mimetype(const char **mimetype, + const char *file, + apr_pool_t *pool); + + +/** Wrapper for apr_file_open(). @a fname is utf8-encoded. */ +svn_error_t * +svn_io_file_open(apr_file_t **new_file, + const char *fname, + apr_int32_t flag, + apr_fileperms_t perm, + apr_pool_t *pool); + + +/** Wrapper for apr_file_close(). */ +svn_error_t * +svn_io_file_close(apr_file_t *file, + apr_pool_t *pool); + + +/** Wrapper for apr_file_getc(). */ +svn_error_t * +svn_io_file_getc(char *ch, + apr_file_t *file, + apr_pool_t *pool); + + +/** Wrapper for apr_file_info_get(). */ +svn_error_t * +svn_io_file_info_get(apr_finfo_t *finfo, + apr_int32_t wanted, + apr_file_t *file, + apr_pool_t *pool); + + +/** Wrapper for apr_file_read(). */ +svn_error_t * +svn_io_file_read(apr_file_t *file, + void *buf, + apr_size_t *nbytes, + apr_pool_t *pool); + + +/** Wrapper for apr_file_read_full(). */ +svn_error_t * +svn_io_file_read_full(apr_file_t *file, + void *buf, + apr_size_t nbytes, + apr_size_t *bytes_read, + apr_pool_t *pool); + + +/** Wrapper for apr_file_seek(). */ +svn_error_t * +svn_io_file_seek(apr_file_t *file, + apr_seek_where_t where, + apr_off_t *offset, + apr_pool_t *pool); + + +/** Wrapper for apr_file_write(). */ +svn_error_t * +svn_io_file_write(apr_file_t *file, + const void *buf, + apr_size_t *nbytes, + apr_pool_t *pool); + + +/** Wrapper for apr_file_write_full(). */ +svn_error_t * +svn_io_file_write_full(apr_file_t *file, + const void *buf, + apr_size_t nbytes, + apr_size_t *bytes_written, + apr_pool_t *pool); + +/** + * Open a unique file in @a dirpath, and write @a nbytes from @a buf to + * the file before closing it. Return the name of the newly created file + * in @a *tmp_path, allocated in @a pool. + * + * If @a dirpath is @c NULL, use the path returned from svn_io_temp_dir(). + * (Note that when using the system-provided temp directory, it may not + * be possibly to atomically rename the resulting file due to cross-device + * issues.) + * + * The file will be deleted according to @a delete_when. + * + * @since New in 1.6. + */ +svn_error_t * +svn_io_write_unique(const char **tmp_path, + const char *dirpath, + const void *buf, + apr_size_t nbytes, + svn_io_file_del_t delete_when, + apr_pool_t *pool); + +/** Wrapper for apr_file_trunc(). + * @since New in 1.6. */ +svn_error_t * +svn_io_file_trunc(apr_file_t *file, + apr_off_t offset, + apr_pool_t *pool); + + +/** Wrapper for apr_stat(). @a fname is utf8-encoded. */ +svn_error_t * +svn_io_stat(apr_finfo_t *finfo, + const char *fname, + apr_int32_t wanted, + apr_pool_t *pool); + + +/** Wrapper for apr_file_rename(). @a from_path and @a to_path are + * utf8-encoded. + */ +svn_error_t * +svn_io_file_rename(const char *from_path, + const char *to_path, + apr_pool_t *pool); + + +/** Move the file from @a from_path to @a to_path, even across device + * boundaries. Overwrite @a to_path if it exists. + * + * @note This function is different from svn_io_file_rename in that the + * latter fails in the 'across device boundaries' case. + * + * @since New in 1.3. + */ +svn_error_t * +svn_io_file_move(const char *from_path, + const char *to_path, + apr_pool_t *pool); + + +/** Wrapper for apr_dir_make(). @a path is utf8-encoded. */ +svn_error_t * +svn_io_dir_make(const char *path, + apr_fileperms_t perm, + apr_pool_t *pool); + +/** Same as svn_io_dir_make(), but sets the hidden attribute on the + directory on systems that support it. */ +svn_error_t * +svn_io_dir_make_hidden(const char *path, + apr_fileperms_t perm, + apr_pool_t *pool); + +/** + * Same as svn_io_dir_make(), but attempts to set the sgid on the + * directory on systems that support it. Does not return an error if + * the attempt to set the sgid bit fails. On Unix filesystems, + * setting the sgid bit on a directory ensures that files and + * subdirectories created within inherit group ownership from the + * parent instead of from the primary gid. + * + * @since New in 1.1. + */ +svn_error_t * +svn_io_dir_make_sgid(const char *path, + apr_fileperms_t perm, + apr_pool_t *pool); + +/** Wrapper for apr_dir_open(). @a dirname is utf8-encoded. */ +svn_error_t * +svn_io_dir_open(apr_dir_t **new_dir, + const char *dirname, + apr_pool_t *pool); + + +/** Wrapper for apr_dir_remove(). @a dirname is utf8-encoded. + * @note This function has this name to avoid confusion with + * svn_io_remove_dir2(), which is recursive. + */ +svn_error_t * +svn_io_dir_remove_nonrecursive(const char *dirname, + apr_pool_t *pool); + + +/** Wrapper for apr_dir_read(). Ensures that @a finfo->name is + * utf8-encoded, which means allocating @a finfo->name in @a pool, + * which may or may not be the same as @a finfo's pool. Use @a pool + * for error allocation as well. + */ +svn_error_t * +svn_io_dir_read(apr_finfo_t *finfo, + apr_int32_t wanted, + apr_dir_t *thedir, + apr_pool_t *pool); + + + +/** Version/format files. + * + * @defgroup svn_io_format_files Version/format files + * @{ + */ + +/** Set @a *version to the integer that starts the file at @a path. If the + * file does not begin with a series of digits followed by a newline, + * return the error @c SVN_ERR_BAD_VERSION_FILE_FORMAT. Use @a pool for + * all allocations. + */ +svn_error_t * +svn_io_read_version_file(int *version, + const char *path, + apr_pool_t *pool); + +/** Create (or overwrite) the file at @a path with new contents, + * formatted as a non-negative integer @a version followed by a single + * newline. On successful completion the file will be read-only. Use + * @a pool for all allocations. + */ +svn_error_t * +svn_io_write_version_file(const char *path, + int version, + apr_pool_t *pool); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_IO_H */ diff --git a/src/TortoiseMerge/svninclude/svn_mergeinfo.h b/src/TortoiseMerge/svninclude/svn_mergeinfo.h new file mode 100644 index 0000000..e357dcd --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_mergeinfo.h @@ -0,0 +1,452 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2006-2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_mergeinfo.h + * @brief mergeinfo handling and processing + */ + + +#ifndef SVN_MERGEINFO_H +#define SVN_MERGEINFO_H + +#include +#include /* for apr_array_header_t */ +#include + +#include "svn_types.h" +#include "svn_string.h" /* for svn_string_t */ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Overview of the @c SVN_PROP_MERGEINFO property. + * + * Merge history is stored in the @c SVN_PROP_MERGEINFO property of files + * and directories. The @c SVN_PROP_MERGEINFO property on a path stores the + * complete list of changes merged to that path, either directly or via the + * path's parent, grand-parent, etc.. A path may have empty mergeinfo which + * means that nothing has been merged to that path or all previous merges + * to the path were reversed. Note that a path may have no mergeinfo, this + * is not the same as empty mergeinfo. + * + * Every path in a tree may have @c SVN_PROP_MERGEINFO set, but if the + * @c SVN_PROP_MERGEINFO for a path is equivalent to the + * @c SVN_PROP_MERGEINFO for its parent, then the @c SVN_PROP_MERGEINFO on + * the path will 'elide' (be removed) from the path as a post step to any + * merge. If a path's parent does not have any @c SVN_PROP_MERGEINFO set, + * the path's mergeinfo can elide to its nearest grand-parent, + * great-grand-parent, etc. that has equivalent @c SVN_PROP_MERGEINFO set + * on it. + * + * If a path has no @c SVN_PROP_MERGEINFO of its own, it inherits mergeinfo + * from its nearest parent that has @c SVN_PROP_MERGEINFO set. The + * exception to this is @c SVN_PROP_MERGEINFO with non-ineritable revision + * ranges. These non-inheritable ranges apply only to the path which they + * are set on. + * + * Due to Subversion's allowance for mixed revision working copies, both + * elision and inheritance within the working copy presume the path + * between a path and its nearest parent with mergeinfo is at the same + * working revision. If this is not the case then neither inheritance nor + * elision can occur. + * + * The value of the @c SVN_PROP_MERGEINFO property is either an empty string + * (representing empty mergeinfo) or a non-empty string consisting of + * a path, a colon, and comma separated revision list, containing one or more + * revision or revision ranges. Revision range start and end points are + * separated by "-". Revisions and revision ranges may have the optional + * @c SVN_MERGEINFO_NONINHERITABLE_STR suffix to signify a non-inheritable + * revision/revision range. + * + * @c SVN_PROP_MERGEINFO Value Grammar: + * + * Token Definition + * ----- ---------- + * revisionrange REVISION1 "-" REVISION2 + * revisioneelement (revisionrange | REVISION)"*"? + * rangelist revisioneelement (COMMA revisioneelement)* + * revisionline PATHNAME COLON rangelist + * top "" | (revisionline (NEWLINE revisionline))* + * + * The PATHNAME is the source of a merge and the rangelist the revision(s) + * merged to the path @c SVN_PROP_MERGEINFO is set on directly or indirectly + * via inheritance. PATHNAME must always exist at the specified rangelist + * and thus a single merge may result in multiple revisionlines if the source + * was renamed. + * + * Rangelists must be sorted from lowest to highest revision and cannot + * contain overlapping revisionlistelements. REVISION1 must be less than + * REVISION2. Consecutive single revisions that can be represented by a + * revisionrange are allowed however (e.g. '5,6,7,8,9-12' or '5-12' are + * both acceptable). + */ + +/* Suffix for SVN_PROP_MERGEINFO revision ranges indicating a given + range is non-inheritable. */ +#define SVN_MERGEINFO_NONINHERITABLE_STR "*" + +/** Terminology for data structures that contain mergeinfo. + * + * Subversion commonly uses several data structures to represent + * mergeinfo in RAM: + * + * (a) Strings (@c svn_string_t *) containing "unparsed mergeinfo". + * + * (b) A "rangelist". An array (@c apr_array_header_t *) of non-overlapping + * merge ranges (@c svn_merge_range_t *), sorted as said by + * @c svn_sort_compare_ranges(). An empty range list is represented by + * an empty array. Unless specifically noted otherwise, all APIs require + * rangelists that describe only forward ranges, i.e. the range's start + * revision is less than its end revision. + * + * (c) @c svn_mergeinfo_t, called "mergeinfo". A hash mapping merge + * source paths (@c const char *, starting with slashes) to + * non-empty rangelist arrays. A @c NULL hash is used to represent + * no mergeinfo and an empty hash is used to represent empty + * mergeinfo. + * + * (d) @c svn_mergeinfo_catalog_t, called a "mergeinfo catalog". A hash + * mapping paths (@c const char *, starting with slashes) to + * @c svn_mergeinfo_t. + * + * Both @c svn_mergeinfo_t and @c svn_mergeinfo_catalog_t are just + * typedefs for @c apr_hash_t *; there is no static type-checking, and + * you still use standard @c apr_hash_t functions to interact with + * them. + * + * Note that while the keys of mergeinfos are always relative to the + * repository root, the keys of a catalog may be relative to something + * else, such as an RA session root. + */ + +typedef apr_hash_t *svn_mergeinfo_t; +typedef apr_hash_t *svn_mergeinfo_catalog_t; + +/** Parse the mergeinfo from @a input into @a *mergeinfo. If no + * mergeinfo is available, return an empty mergeinfo (never @c NULL). + * Perform temporary allocations in @a pool. + * + * If @a input is not a grammatically correct @c SVN_PROP_MERGEINFO + * property, contains overlapping revision ranges of differing + * inheritability, or revision ranges with a start revision greater + * than or equal to its end revision, or contains paths mapped to empty + * revision ranges, then return @c SVN_ERR_MERGEINFO_PARSE_ERROR. + * Unordered revision ranges are allowed, but will be sorted when + * placed into @a *mergeinfo. Overlapping revision ranges of the same + * inheritability are also allowed, but will be combined into a single + * range when placed into @a *mergeinfo. + * + * @since New in 1.5. + */ +svn_error_t * +svn_mergeinfo_parse(svn_mergeinfo_t *mergeinfo, const char *input, + apr_pool_t *pool); + +/** Calculate the delta between two mergeinfos, @a mergefrom and @a mergeto + * (which may be @c NULL), and place the result in @a *deleted and @a + * *added (neither output argument may be @c NULL). + * + * @a consider_inheritance determines how the rangelists in the two + * hashes are compared for equality. If @a consider_inheritance is FALSE, + * then the start and end revisions of the @c svn_merge_range_t's being + * compared are the only factors considered when determining equality. + * + * e.g. '/trunk: 1,3-4*,5' == '/trunk: 1,3-5' + * + * If @a consider_inheritance is TRUE, then the inheritability of the + * @c svn_merge_range_t's is also considered and must be the same for two + * otherwise identical ranges to be judged equal. + * + * e.g. '/trunk: 1,3-4*,5' != '/trunk: 1,3-5' + * '/trunk: 1,3-4*,5' == '/trunk: 1,3-4*,5' + * '/trunk: 1,3-4,5' == '/trunk: 1,3-4,5' + * + * @since New in 1.5. + */ +svn_error_t * +svn_mergeinfo_diff(svn_mergeinfo_t *deleted, svn_mergeinfo_t *added, + svn_mergeinfo_t mergefrom, svn_mergeinfo_t mergeto, + svn_boolean_t consider_inheritance, + apr_pool_t *pool); + +/** Merge one mergeinfo, @a changes, into another mergeinfo @a + * mergeinfo. + * + * When intersecting rangelists for a path are merged, the inheritability of + * the resulting svn_merge_range_t depends on the inheritability of the + * operands. If two non-inheritable ranges are merged the result is always + * non-inheritable, in all other cases the resulting range is inheritable. + * + * e.g. '/A: 1,3-4' merged with '/A: 1,3,4*,5' --> '/A: 1,3-5' + * '/A: 1,3-4*' merged with '/A: 1,3,4*,5' --> '/A: 1,3,4*,5' + * + * @since New in 1.5. + */ +svn_error_t * +svn_mergeinfo_merge(svn_mergeinfo_t mergeinfo, svn_mergeinfo_t changes, + apr_pool_t *pool); + +/** Removes @a eraser (the subtrahend) from @a whiteboard (the + * minuend), and places the resulting difference in @a *mergeinfo. + * + * @since New in 1.5. + */ +svn_error_t * +svn_mergeinfo_remove(svn_mergeinfo_t *mergeinfo, svn_mergeinfo_t eraser, + svn_mergeinfo_t whiteboard, apr_pool_t *pool); + +/** Calculate the delta between two rangelists consisting of @c + * svn_merge_range_t * elements (sorted in ascending order), @a from + * and @a to, and place the result in @a *deleted and @a *added + * (neither output argument will ever be @c NULL). + * + * @a consider_inheritance determines how to account for the inheritability + * of the two rangelist's ranges when calculating the diff, + * as described for svn_mergeinfo_diff(). + * + * @since New in 1.5. + */ +svn_error_t * +svn_rangelist_diff(apr_array_header_t **deleted, apr_array_header_t **added, + apr_array_header_t *from, apr_array_header_t *to, + svn_boolean_t consider_inheritance, + apr_pool_t *pool); + +/** Merge two rangelists consisting of @c svn_merge_range_t * + * elements, @a *rangelist and @a changes, placing the results in + * @a *rangelist. Either rangelist may be empty. + * + * When intersecting rangelists are merged, the inheritability of + * the resulting svn_merge_range_t depends on the inheritability of the + * operands: see svn_mergeinfo_merge(). + * + * Note: @a *rangelist and @a changes must be sorted as said by @c + * svn_sort_compare_ranges(). @a *rangelist is guaranteed to remain + * in sorted order and be compacted to the minimal number of ranges + * needed to represent the merged result. + * + * @since New in 1.5. + */ +svn_error_t * +svn_rangelist_merge(apr_array_header_t **rangelist, + apr_array_header_t *changes, + apr_pool_t *pool); + +/** Removes @a eraser (the subtrahend) from @a whiteboard (the + * minuend), and places the resulting difference in @a output. + * + * Note: @a eraser and @a whiteboard must be sorted as said by @c + * svn_sort_compare_ranges(). @a output is guaranteed to be in sorted + * order. + * + * @a consider_inheritance determines how to account for the + * @c svn_merge_range_t inheritable field when comparing @a whiteboard's + * and @a *eraser's rangelists for equality. @see svn_mergeinfo_diff(). + * + * @since New in 1.5. + */ +svn_error_t * +svn_rangelist_remove(apr_array_header_t **output, apr_array_header_t *eraser, + apr_array_header_t *whiteboard, + svn_boolean_t consider_inheritance, + apr_pool_t *pool); + +/** Find the intersection of two mergeinfos, @a mergeinfo1 and @a + * mergeinfo2, and place the result in @a *mergeinfo, which is (deeply) + * allocated in @a pool. + * + * @since New in 1.5. + */ +svn_error_t * +svn_mergeinfo_intersect(svn_mergeinfo_t *mergeinfo, + svn_mergeinfo_t mergeinfo1, + svn_mergeinfo_t mergeinfo2, + apr_pool_t *pool); + +/** Find the intersection of two rangelists consisting of @c + * svn_merge_range_t * elements, @a rangelist1 and @a rangelist2, and + * place the result in @a *rangelist (which is never @c NULL). + * + * @a consider_inheritance determines how to account for the inheritability + * of the two rangelist's ranges when calculating the intersection, + * @see svn_mergeinfo_diff(). + * + * Note: @a rangelist1 and @a rangelist2 must be sorted as said by @c + * svn_sort_compare_ranges(). @a *rangelist is guaranteed to be in sorted + * order. + * @since New in 1.5. + */ +svn_error_t * +svn_rangelist_intersect(apr_array_header_t **rangelist, + apr_array_header_t *rangelist1, + apr_array_header_t *rangelist2, + svn_boolean_t consider_inheritance, + apr_pool_t *pool); + +/** Reverse @a rangelist, and the @c start and @c end fields of each + * range in @a rangelist, in place. + * + * TODO(miapi): Is this really a valid function? Rangelists that + * aren't sorted, or rangelists containing reverse ranges, are + * generally not valid in mergeinfo code. Can we rewrite the two + * places where this is used? + * + * @since New in 1.5. + */ +svn_error_t * +svn_rangelist_reverse(apr_array_header_t *rangelist, apr_pool_t *pool); + +/** Take an array of svn_merge_range_t *'s in @a rangelist, and convert it + * back to a text format rangelist in @a output. If @a rangelist contains + * no elements, sets @a output to the empty string. + * + * @since New in 1.5. + */ +svn_error_t * +svn_rangelist_to_string(svn_string_t **output, + const apr_array_header_t *rangelist, + apr_pool_t *pool); + +/** Return a deep copy of @c svn_merge_range_t *'s in @a rangelist excluding + * all non-inheritable @c svn_merge_range_t. If @a start and @a end are valid + * revisions and @a start is less than or equal to @a end, then exclude only the + * non-inheritable revision ranges that intersect inclusively with the range + * defined by @a start and @a end. If @a rangelist contains no elements, return + * an empty array. Allocate the copy in @a pool. + * + * @since New in 1.5. + */ +svn_error_t * +svn_rangelist_inheritable(apr_array_header_t **inheritable_rangelist, + apr_array_header_t *rangelist, + svn_revnum_t start, + svn_revnum_t end, + apr_pool_t *pool); + +/** Return a deep copy of @a mergeinfo, excluding all non-inheritable + * @c svn_merge_range_t. If @a start and @a end are valid revisions + * and @a start is less than or equal to @a end, then exclude only the + * non-inheritable revisions that intersect inclusively with the range + * defined by @a start and @a end. If @a path is not NULL remove + * non-inheritable ranges only for @a path. If all ranges are removed + * for a given path then remove that path as well. If all paths are + * removed or @a rangelist is empty then set @a *inheritable_rangelist + * to an empty array. Allocate the copy in @a pool. + * + * @since New in 1.5. + */ +svn_error_t * +svn_mergeinfo_inheritable(svn_mergeinfo_t *inheritable_mergeinfo, + svn_mergeinfo_t mergeinfo, + const char *path, + svn_revnum_t start, + svn_revnum_t end, + apr_pool_t *pool); + +/** Take a mergeinfo in MERGEINPUT, and convert it back to unparsed + * mergeinfo in *OUTPUT. If INPUT contains no elements, return the + * empty string. + * + * @since New in 1.5. +*/ +svn_error_t * +svn_mergeinfo_to_string(svn_string_t **output, + svn_mergeinfo_t mergeinput, + apr_pool_t *pool); + +/** Take a hash of mergeinfo in @a mergeinfo, and sort the rangelists + * associated with each key (in place). + * + * TODO(miapi): mergeinfos should *always* be sorted. This should be + * a private function. + * + * @since New in 1.5 + */ +svn_error_t * +svn_mergeinfo_sort(svn_mergeinfo_t mergeinfo, apr_pool_t *pool); + +/** Return a deep copy of @a mergeinfo_catalog, allocated in @a pool. + * + * @since New in 1.6. + */ +svn_mergeinfo_catalog_t +svn_mergeinfo_catalog_dup(svn_mergeinfo_catalog_t mergeinfo_catalog, + apr_pool_t *pool); + +/** Return a deep copy of @a mergeinfo, allocated in @a pool. + * + * @since New in 1.5. + */ +svn_mergeinfo_t +svn_mergeinfo_dup(svn_mergeinfo_t mergeinfo, apr_pool_t *pool); + +/** Return a deep copy of @a rangelist, allocated in @a pool. + * + * @since New in 1.5. + */ +apr_array_header_t * +svn_rangelist_dup(apr_array_header_t *rangelist, apr_pool_t *pool); + + +/** + * The three ways to request mergeinfo affecting a given path. + * + * @since New in 1.5. + */ +typedef enum +{ + /** Explicit mergeinfo only. */ + svn_mergeinfo_explicit, + + /** Explicit mergeinfo, or if that doesn't exist, the inherited + mergeinfo from a target's nearest (path-wise, not history-wise) + ancestor. */ + svn_mergeinfo_inherited, + + /** Mergeinfo on target's nearest (path-wise, not history-wise) + ancestor, regardless of whether target has explict mergeinfo. */ + svn_mergeinfo_nearest_ancestor +} svn_mergeinfo_inheritance_t; + +/** Return a constant string expressing @a inherit as an English word, + * i.e., "explicit" (default), "inherited", or "nearest_ancestor". + * The string is not localized, as it may be used for client<->server + * communications. + * + * @since New in 1.5. + */ +const char * +svn_inheritance_to_word(svn_mergeinfo_inheritance_t inherit); + + +/** Return the appropriate @c svn_mergeinfo_inheritance_t for @a word. + * @a word is as returned from svn_inheritance_to_word(). Defaults to + * @c svn_mergeinfo_explicit. + * + * @since New in 1.5. + */ +svn_mergeinfo_inheritance_t +svn_inheritance_from_word(const char *word); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_MERGEINFO_H */ diff --git a/src/TortoiseMerge/svninclude/svn_opt.h b/src/TortoiseMerge/svninclude/svn_opt.h new file mode 100644 index 0000000..6c06d38 --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_opt.h @@ -0,0 +1,741 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_opt.h + * @brief Option and argument parsing for Subversion command lines + */ + +#ifndef SVN_OPTS_H +#define SVN_OPTS_H + +#include +#include +#include +#include +#include + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +#define APR_WANT_STDIO +#endif +#include /* for FILE* */ + +#include "svn_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +/** + * All subcommand procedures in Subversion conform to this prototype. + * + * @a os is the apr option state after getopt processing has been run; in + * other words, it still contains the non-option arguments following + * the subcommand. See @a os->argv and @a os->ind. + * + * @a baton is anything you need it to be. + * + * @a pool is used for allocating errors, and for any other allocation + * unless the instance is explicitly documented to allocate from a + * pool in @a baton. + */ +typedef svn_error_t *(svn_opt_subcommand_t) + (apr_getopt_t *os, void *baton, apr_pool_t *pool); + + +/** The maximum number of aliases a subcommand can have. */ +#define SVN_OPT_MAX_ALIASES 3 + +/** The maximum number of options that can be accepted by a subcommand. */ +#define SVN_OPT_MAX_OPTIONS 50 + +/** Options that have no short option char should use an identifying + * integer equal to or greater than this. + */ +#define SVN_OPT_FIRST_LONGOPT_ID 256 + + +/** One element of a subcommand dispatch table. + * + * @since New in 1.4. + */ +typedef struct svn_opt_subcommand_desc2_t +{ + /** The full name of this command. */ + const char *name; + + /** The function this command invokes. */ + svn_opt_subcommand_t *cmd_func; + + /** A list of alias names for this command (e.g., 'up' for 'update'). */ + const char *aliases[SVN_OPT_MAX_ALIASES]; + + /** A brief string describing this command, for usage messages. */ + const char *help; + + /** A list of options accepted by this command. Each value in the + * array is a unique enum (the 2nd field in apr_getopt_option_t) + */ + int valid_options[SVN_OPT_MAX_OPTIONS]; + + /** A list of option help descriptions, keyed by the option unique enum + * (the 2nd field in apr_getopt_option_t), which override the generic + * descriptions given in an apr_getopt_option_t on a per-subcommand basis. + */ + struct { int optch; const char *desc; } desc_overrides[SVN_OPT_MAX_OPTIONS]; +} svn_opt_subcommand_desc2_t; + + +/** One element of a subcommand dispatch table. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + * + * Like #svn_opt_subcommand_desc2_t but lacking the @c desc_overrides + * member. + */ +typedef struct svn_opt_subcommand_desc_t +{ + /** The full name of this command. */ + const char *name; + + /** The function this command invokes. */ + svn_opt_subcommand_t *cmd_func; + + /** A list of alias names for this command (e.g., 'up' for 'update'). */ + const char *aliases[SVN_OPT_MAX_ALIASES]; + + /** A brief string describing this command, for usage messages. */ + const char *help; + + /** A list of options accepted by this command. Each value in the + * array is a unique enum (the 2nd field in apr_getopt_option_t) + */ + int valid_options[SVN_OPT_MAX_OPTIONS]; + +} svn_opt_subcommand_desc_t; + + +/** + * Return the entry in @a table whose name matches @a cmd_name, or @c NULL if + * none. @a cmd_name may be an alias. + * + * @since New in 1.4. + */ +const svn_opt_subcommand_desc2_t * +svn_opt_get_canonical_subcommand2(const svn_opt_subcommand_desc2_t *table, + const char *cmd_name); + + +/** + * Return the entry in @a table whose name matches @a cmd_name, or @c NULL if + * none. @a cmd_name may be an alias. + * + * Same as svn_opt_get_canonical_subcommand2(), but acts on + * #svn_opt_subcommand_desc_t. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +const svn_opt_subcommand_desc_t * +svn_opt_get_canonical_subcommand(const svn_opt_subcommand_desc_t *table, + const char *cmd_name); + + +/** + * Return pointer to an @c apr_getopt_option_t for the option whose + * option code is @a code, or @c NULL if no match. @a option_table must end + * with an element whose every field is zero. If @c command is non-NULL, + * then return the subcommand-specific option description instead of the + * generic one, if a specific description is defined. + * + * The returned value may be statically allocated, or allocated in @a pool. + * + * @since New in 1.4. + */ +const apr_getopt_option_t * +svn_opt_get_option_from_code2(int code, + const apr_getopt_option_t *option_table, + const svn_opt_subcommand_desc2_t *command, + apr_pool_t *pool); + + +/** + * Return the first entry from @a option_table whose option code is @a code, + * or @c NULL if no match. @a option_table must end with an element whose + * every field is zero. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +const apr_getopt_option_t * +svn_opt_get_option_from_code(int code, + const apr_getopt_option_t *option_table); + + +/** + * Return @c TRUE iff subcommand @a command supports option @a + * option_code, else return @c FALSE. If @a global_options is + * non-NULL, it is a zero-terminated array, and all subcommands take + * the options listed in it. + * + * @since New in 1.5. + */ +svn_boolean_t +svn_opt_subcommand_takes_option3(const svn_opt_subcommand_desc2_t *command, + int option_code, + const int *global_options); + +/** + * Same as svn_opt_subcommand_takes_option3(), but with @c NULL for @a + * global_options. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_boolean_t +svn_opt_subcommand_takes_option2(const svn_opt_subcommand_desc2_t *command, + int option_code); + + +/** + * Return @c TRUE iff subcommand @a command supports option @a option_code, + * else return @c FALSE. + * + * Same as svn_opt_subcommand_takes_option2(), but acts on + * #svn_opt_subcommand_desc_t. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_boolean_t +svn_opt_subcommand_takes_option(const svn_opt_subcommand_desc_t *command, + int option_code); + + +/** + * Print a generic (not command-specific) usage message to @a stream. + * + * ### @todo Why is @a stream a stdio file instead of an svn stream? + * + * If @a header is non-NULL, print @a header followed by a newline. Then + * loop over @a cmd_table printing the usage for each command (getting + * option usages from @a opt_table). Then if @a footer is non-NULL, print + * @a footer followed by a newline. + * + * Use @a pool for temporary allocation. + * + * @since New in 1.4. + */ +void +svn_opt_print_generic_help2(const char *header, + const svn_opt_subcommand_desc2_t *cmd_table, + const apr_getopt_option_t *opt_table, + const char *footer, + apr_pool_t *pool, + FILE *stream); + + +/** + * Same as svn_opt_print_generic_help2(), but acts on + * #svn_opt_subcommand_desc_t. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +void +svn_opt_print_generic_help(const char *header, + const svn_opt_subcommand_desc_t *cmd_table, + const apr_getopt_option_t *opt_table, + const char *footer, + apr_pool_t *pool, + FILE *stream); + + +/** + * Print an option @a opt nicely into a @a string allocated in @a pool. + * If @a doc is set, include the generic documentation string of @a opt, + * localized to the current locale if a translation is available. + */ +void +svn_opt_format_option(const char **string, + const apr_getopt_option_t *opt, + svn_boolean_t doc, + apr_pool_t *pool); + + + +/** + * Get @a subcommand's usage from @a table, and print it to @c stdout. + * Obtain option usage from @a options_table. If not @c NULL, @a + * global_options is a zero-terminated list of global options. Use @a + * pool for temporary allocation. @a subcommand may be a canonical + * command name or an alias. ### @todo Why does this only print to + * @c stdout, whereas svn_opt_print_generic_help() gives us a choice? + * + * @since New in 1.5. + */ +void +svn_opt_subcommand_help3(const char *subcommand, + const svn_opt_subcommand_desc2_t *table, + const apr_getopt_option_t *options_table, + const int *global_options, + apr_pool_t *pool); + +/** + * Same as svn_opt_subcommand_help3(), but with @a global_options + * always NULL. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +void +svn_opt_subcommand_help2(const char *subcommand, + const svn_opt_subcommand_desc2_t *table, + const apr_getopt_option_t *options_table, + apr_pool_t *pool); + + +/** + * Same as svn_opt_subcommand_help2(), but acts on + * #svn_opt_subcommand_desc_t. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +void +svn_opt_subcommand_help(const char *subcommand, + const svn_opt_subcommand_desc_t *table, + const apr_getopt_option_t *options_table, + apr_pool_t *pool); + + + +/* Parsing revision and date options. */ + +/** + * Various ways of specifying revisions. + * + * @note + * In contexts where local mods are relevant, the `working' kind + * refers to the uncommitted "working" revision, which may be modified + * with respect to its base revision. In other contexts, `working' + * should behave the same as `committed' or `current'. + */ +enum svn_opt_revision_kind { + /** No revision information given. */ + svn_opt_revision_unspecified, + + /** revision given as number */ + svn_opt_revision_number, + + /** revision given as date */ + svn_opt_revision_date, + + /** rev of most recent change */ + svn_opt_revision_committed, + + /** (rev of most recent change) - 1 */ + svn_opt_revision_previous, + + /** .svn/entries current revision */ + svn_opt_revision_base, + + /** current, plus local mods */ + svn_opt_revision_working, + + /** repository youngest */ + svn_opt_revision_head +}; + +/** + * A revision value, which can be specified as a number or a date. + * + * @note This union was formerly an anonymous inline type in + * @c svn_opt_revision_t, and was converted to a named type just to + * make things easier for SWIG. + * + * @since New in 1.3. + */ +typedef union svn_opt_revision_value_t +{ + /** The revision number */ + svn_revnum_t number; + + /** the date of the revision */ + apr_time_t date; +} svn_opt_revision_value_t; + +/** A revision, specified in one of @c svn_opt_revision_kind ways. */ +typedef struct svn_opt_revision_t +{ + enum svn_opt_revision_kind kind; /**< See svn_opt_revision_kind */ + svn_opt_revision_value_t value; /**< Extra data qualifying the @c kind */ +} svn_opt_revision_t; + +/** A revision range, specified in one of @c svn_opt_revision_kind ways. */ +typedef struct svn_opt_revision_range_t +{ + /** The first revision in the range */ + svn_opt_revision_t start; + + /** The last revision in the range */ + svn_opt_revision_t end; +} svn_opt_revision_range_t; + +/** + * Set @a *start_revision and/or @a *end_revision according to @a arg, + * where @a arg is "N" or "N:M", like so: + * + * - If @a arg is "N", set @a *start_revision to represent N, and + * leave @a *end_revision untouched. + * + * - If @a arg is "N:M", set @a *start_revision and @a *end_revision + * to represent N and M respectively. + * + * N and/or M may be one of the special revision descriptors + * recognized by revision_from_word(), or a date in curly braces. + * + * If @a arg is invalid, return -1; else return 0. + * It is invalid to omit a revision (as in, ":", "N:" or ":M"). + * + * @note It is typical, though not required, for @a *start_revision and + * @a *end_revision to be @c svn_opt_revision_unspecified kind on entry. + * + * Use @a pool for temporary allocations. + */ +int +svn_opt_parse_revision(svn_opt_revision_t *start_revision, + svn_opt_revision_t *end_revision, + const char *arg, + apr_pool_t *pool); + +/** + * Parse @a arg, where @a arg is "N" or "N:M", into a + * @c svn_opt_revision_range_t and push that onto @a opt_ranges. + * + * - If @a arg is "N", set the @c start field of the + * @c svn_opt_revision_range_t to represent N and the @c end field + * to @c svn_opt_revision_unspecified. + * + * - If @a arg is "N:M", set the @c start field of the + * @c svn_opt_revision_range_t to represent N and the @c end field + * to represent M. + * + * If @a arg is invalid, return -1; else return 0. It is invalid to omit + * a revision (as in, ":", "N:" or ":M"). + * + * Use @a pool to allocate @c svn_opt_revision_range_t pushed to the array. + * + * @since New in 1.5. + */ +int +svn_opt_parse_revision_to_range(apr_array_header_t *opt_ranges, + const char *arg, + apr_pool_t *pool); + +/** + * Resolve peg revisions and operational revisions in the following way: + * + * - If @a is_url is set and @a peg_rev->kind is + * @c svn_opt_revision_unspecified, @a peg_rev->kind defaults to + * @c svn_opt_revision_head. + * + * - If @a is_url is not set, and @a peg_rev->kind is + * @c svn_opt_revision_unspecified, @a peg_rev->kind defaults to + * @c svn_opt_revision_base. + * + * - If @a op_rev->kind is @c svn_opt_revision_unspecified, @a op_rev + * defaults to @a peg_rev. + * + * Both @a peg_rev and @a op_rev may be modified as a result of this + * function. @a is_url should be set if the path the revisions refer to is + * a url, and unset otherwise. + * + * If @a notice_local_mods is set, @c svn_opt_revision_working is used, + * instead of @c svn_opt_revision_base. + * + * Use @a pool for allocations. + * + * @since New in 1.5. + */ +svn_error_t * +svn_opt_resolve_revisions(svn_opt_revision_t *peg_rev, + svn_opt_revision_t *op_rev, + svn_boolean_t is_url, + svn_boolean_t notice_local_mods, + apr_pool_t *pool); + + +/* Parsing arguments. */ + +/** + * Pull remaining target arguments from @a os into @a *targets_p, + * converting them to UTF-8, followed by targets from @a known_targets + * (which might come from, for example, the "--targets" command line + * option), which are already in UTF-8. + * + * On each URL target, do some IRI-to-URI encoding and some + * auto-escaping. On each local path, canonicalize case and path + * separators. + * + * Allocate @a *targets_p and its elements in @a pool. + * + * If a path has the same name as a Subversion working copy + * administrative directory, return SVN_ERR_RESERVED_FILENAME_SPECIFIED; + * if multiple reserved paths are encountered, return a chain of + * errors, all of which are SVN_ERR_RESERVED_FILENAME_SPECIFIED. Do + * not return this type of error in a chain with any other type of + * error, and if this is the only type of error encountered, complete + * the operation before returning the error(s). + * + * @deprecated Provided for backward compatibility with the 1.5 API. + * @see svn_client_args_to_target_array() + */ +SVN_DEPRECATED +svn_error_t * +svn_opt_args_to_target_array3(apr_array_header_t **targets_p, + apr_getopt_t *os, + apr_array_header_t *known_targets, + apr_pool_t *pool); + +/** + * This is the same as svn_opt_args_to_target_array3() except that it + * silently ignores paths that have the same name as a working copy + * administrative directory. + * + * @since New in 1.2. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_opt_args_to_target_array2(apr_array_header_t **targets_p, + apr_getopt_t *os, + apr_array_header_t *known_targets, + apr_pool_t *pool); + + +/** + * The same as svn_opt_args_to_target_array2() except that, in + * addition, if @a extract_revisions is set, then look for trailing + * "@rev" syntax on the first two paths. If the first target in @a + * *targets_p ends in "@rev", replace it with a canonicalized version of + * the part before "@rev" and replace @a *start_revision with the value + * of "rev". If the second target in @a *targets_p ends in "@rev", + * replace it with a canonicalized version of the part before "@rev" + * and replace @a *end_revision with the value of "rev". Ignore + * revision specifiers on any further paths. "rev" can be any form of + * single revision specifier, as accepted by svn_opt_parse_revision(). + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_opt_args_to_target_array(apr_array_header_t **targets_p, + apr_getopt_t *os, + apr_array_header_t *known_targets, + svn_opt_revision_t *start_revision, + svn_opt_revision_t *end_revision, + svn_boolean_t extract_revisions, + apr_pool_t *pool); + + +/** + * Parse revprop key/value pair from @a revprop_spec (name[=value]) into + * @a revprops, making copies of both with @a pool. If @a revprops is + * @c NULL, allocate a new apr_hash_t in it. @a revprops maps + * const char * revprop names to svn_string_t * revprop values for use + * with svn_repos_get_commit_editor5 and other get_commit_editor APIs. + * + * @since New in 1.6. + */ +svn_error_t * +svn_opt_parse_revprop(apr_hash_t **revprops, const char *revprop_spec, + apr_pool_t *pool); + + +/** + * If no targets exist in @a *targets, add `.' as the lone target. + * + * (Some commands take an implicit "." string argument when invoked + * with no arguments. Those commands make use of this function to + * add "." to the target array if the user passes no args.) + */ +void +svn_opt_push_implicit_dot_target(apr_array_header_t *targets, + apr_pool_t *pool); + + +/** + * Parse @a num_args non-target arguments from the list of arguments in + * @a os->argv, return them as const char * in @a *args_p, without + * doing any UTF-8 conversion. Allocate @a *args_p and its values in @a pool. + */ +svn_error_t * +svn_opt_parse_num_args(apr_array_header_t **args_p, + apr_getopt_t *os, + int num_args, + apr_pool_t *pool); + + +/** + * Parse all remaining arguments from @a os->argv, return them as + * const char * in @a *args_p, without doing any UTF-8 conversion. + * Allocate @a *args_p and its values in @a pool. + */ +svn_error_t * +svn_opt_parse_all_args(apr_array_header_t **args_p, + apr_getopt_t *os, + apr_pool_t *pool); + +/** + * Parse a working-copy or URL in @a path, extracting any trailing + * revision specifier of the form "@rev" from the last component of + * the path. + * + * Some examples would be: + * + * "foo/bar" -> "foo/bar", (unspecified) + * "foo/bar@13" -> "foo/bar", (number, 13) + * "foo/bar@HEAD" -> "foo/bar", (head) + * "foo/bar@{1999-12-31}" -> "foo/bar", (date, 1999-12-31) + * "http://a/b@27" -> "http://a/b", (number, 27) + * "http://a/b@COMMITTED" -> "http://a/b", (committed) [*] + * "http://a/b@{1999-12-31} -> "http://a/b", (date, 1999-12-31) + * "http://a/b@%7B1999-12-31%7D -> "http://a/b", (date, 1999-12-31) + * "foo/bar@1:2" -> error + * "foo/bar@baz" -> error + * "foo/bar@" -> "foo/bar", (base) + * "foo/bar/@13" -> "foo/bar/", (number, 13) + * "foo/bar@@13" -> "foo/bar@", (number, 13) + * "foo/@bar@HEAD" -> "foo/@bar", (head) + * "foo@/bar" -> "foo@/bar", (unspecified) + * "foo@HEAD/bar" -> "foo@HEAD/bar", (unspecified) + * + * [*] Syntactically valid but probably not semantically useful. + * + * If a trailing revision specifier is found, parse it into @a *rev and + * put the rest of the path into @a *truepath, allocating from @a pool; + * or return an @c SVN_ERR_CL_ARG_PARSING_ERROR (with the effect on + * @a *truepath undefined) if the revision specifier is invalid. + * If no trailing revision specifier is found, set @a *truepath to + * @a path and @a rev->kind to @c svn_opt_revision_unspecified. + * + * This function does not require that @a path be in canonical form. + * No canonicalization is done and @a *truepath will only be in + * canonical form if @a path is in canonical form. + * + * @since New in 1.1. + */ +svn_error_t * +svn_opt_parse_path(svn_opt_revision_t *rev, + const char **truepath, + const char *path, + apr_pool_t *pool); + +/** + * Central dispatcher function for various kinds of help message. + * Prints one of: + * * subcommand-specific help (svn_opt_subcommand_help) + * * generic help (svn_opt_print_generic_help) + * * version info + * * simple usage complaint: "Type '@a pgm_name help' for usage." + * + * If @a os is not @c NULL and it contains arguments, then try + * printing help for them as though they are subcommands, using @a + * cmd_table and @a option_table for option information. If not @c + * NULL, @a global_options is a zero-terminated array of options taken + * by all subcommands. + * + * Else, if @a print_version is TRUE, then print version info, in + * brief form if @a quiet is also TRUE; if @a quiet is FALSE, then if + * @a version_footer is non-NULL, print it following the version + * information. + * + * Else, if @a os is not @c NULL and does not contain arguments, print + * generic help, via svn_opt_print_generic_help2() with the @a header, + * @a cmd_table, @a option_table, and @a footer arguments. + * + * Else, when @a os is @c NULL, print the simple usage complaint. + * + * Use @a pool for temporary allocations. + * + * Notes: The reason this function handles both version printing and + * general usage help is that a confused user might put both the + * --version flag *and* subcommand arguments on a help command line. + * The logic for handling such a situation should be in one place. + * + * @since New in 1.5. + */ +svn_error_t * +svn_opt_print_help3(apr_getopt_t *os, + const char *pgm_name, + svn_boolean_t print_version, + svn_boolean_t quiet, + const char *version_footer, + const char *header, + const svn_opt_subcommand_desc2_t *cmd_table, + const apr_getopt_option_t *option_table, + const int *global_options, + const char *footer, + apr_pool_t *pool); + +/** + * Same as svn_opt_print_help3(), but with @a global_options always @c + * NULL. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ + +SVN_DEPRECATED +svn_error_t * +svn_opt_print_help2(apr_getopt_t *os, + const char *pgm_name, + svn_boolean_t print_version, + svn_boolean_t quiet, + const char *version_footer, + const char *header, + const svn_opt_subcommand_desc2_t *cmd_table, + const apr_getopt_option_t *option_table, + const char *footer, + apr_pool_t *pool); + + +/** + * Same as svn_opt_print_help2(), but acts on #svn_opt_subcommand_desc_t. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_opt_print_help(apr_getopt_t *os, + const char *pgm_name, + svn_boolean_t print_version, + svn_boolean_t quiet, + const char *version_footer, + const char *header, + const svn_opt_subcommand_desc_t *cmd_table, + const apr_getopt_option_t *option_table, + const char *footer, + apr_pool_t *pool); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_OPTS_H */ diff --git a/src/TortoiseMerge/svninclude/svn_path.h b/src/TortoiseMerge/svninclude/svn_path.h new file mode 100644 index 0000000..8814073 --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_path.h @@ -0,0 +1,595 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2004 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_path.h + * @brief A path manipulation library + * + * All incoming and outgoing paths are non-NULL and in UTF-8, unless + * otherwise documented. + * + * No result path ever ends with a separator, no matter whether the + * path is a file or directory, because we always canonicalize() it. + * + * Nearly all the @c svn_path_xxx functions expect paths passed into + * them to be in canonical form as defined by the Subversion path + * library itself. The only functions which do *not* have such + * expectations are: + * + * - @c svn_path_canonicalize() + * - @c svn_path_is_canonical() + * - @c svn_path_internal_style() + * - @c svn_path_uri_encode() + * + * For the most part, we mean what most anyone would mean when talking + * about canonical paths, but to be on the safe side, you must run + * your paths through @c svn_path_canonicalize() before passing them to + * other functions in this API. + */ + +#ifndef SVN_PATH_H +#define SVN_PATH_H + +#include +#include +#include + +#include "svn_types.h" +#include "svn_string.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +/** Convert @a path from the local style to the canonical internal style. */ +const char * +svn_path_internal_style(const char *path, apr_pool_t *pool); + +/** Convert @a path from the canonical internal style to the local style. */ +const char * +svn_path_local_style(const char *path, apr_pool_t *pool); + + +/** Join a base path (@a base) with a component (@a component), allocating + * the result in @a pool. @a component need not be a single component: it + * can be any path, absolute or relative to @a base. + * + * If either @a base or @a component is the empty path, then the other + * argument will be copied and returned. If both are the empty path the + * empty path is returned. + * + * If the @a component is an absolute path, then it is copied and returned. + * Exactly one slash character ('/') is used to join the components, + * accounting for any trailing slash in @a base. + * + * Note that the contents of @a base are not examined, so it is possible to + * use this function for constructing URLs, or for relative URLs or + * repository paths. + * + * This function is NOT appropriate for native (local) file + * paths. Only for "internal" canonicalized paths, since it uses '/' + * for the separator. Further, an absolute path (for @a component) is + * based on a leading '/' character. Thus, an "absolute URI" for the + * @a component won't be detected. An absolute URI can only be used + * for the base. + */ +char * +svn_path_join(const char *base, const char *component, apr_pool_t *pool); + +/** Join multiple components onto a @a base path, allocated in @a pool. The + * components are terminated by a @c NULL. + * + * If any component is the empty string, it will be ignored. + * + * If any component is an absolute path, then it resets the base and + * further components will be appended to it. + * + * This function does not support URLs. + * + * See svn_path_join() for further notes about joining paths. + */ +char * +svn_path_join_many(apr_pool_t *pool, const char *base, ...); + + +/** Get the basename of the specified canonicalized @a path. The + * basename is defined as the last component of the path (ignoring any + * trailing slashes). If the @a path is root ("/"), then that is + * returned. Otherwise, the returned value will have no slashes in + * it. + * + * Example: svn_path_basename("/foo/bar") -> "bar" + * + * The returned basename will be allocated in @a pool. + * + * @note If an empty string is passed, then an empty string will be returned. + */ +char * +svn_path_basename(const char *path, apr_pool_t *pool); + +/** Get the dirname of the specified canonicalized @a path, defined as + * the path with its basename removed. If @a path is root ("/"), it is + * returned unchanged. + * + * The returned dirname will be allocated in @a pool. + */ +char * +svn_path_dirname(const char *path, apr_pool_t *pool); + +/** Split @a path into a root portion and an extension such that + * the root + the extension = the original path, and where the + * extension contains no period (.) characters. If not @c NULL, set + * @a *path_root to the root portion. If not @c NULL, set + * @a *path_ext to the extension (or "" if there is no extension + * found). Allocate both @a *path_root and @a *path_ext in @a pool. + * + * @since New in 1.5. + */ +void +svn_path_splitext(const char **path_root, const char **path_ext, + const char *path, apr_pool_t *pool); + +/** Return the number of components in the canonicalized @a path. + * + * @since New in 1.1. +*/ +apr_size_t +svn_path_component_count(const char *path); + +/** Add a @a component (a NULL-terminated C-string) to the + * canonicalized @a path. @a component is allowed to contain + * directory separators. + * + * If @a path is non-empty, append the appropriate directory separator + * character, and then @a component. If @a path is empty, simply set it to + * @a component; don't add any separator character. + * + * If the result ends in a separator character, then remove the separator. + */ +void +svn_path_add_component(svn_stringbuf_t *path, const char *component); + +/** Remove one component off the end of the canonicalized @a path. */ +void +svn_path_remove_component(svn_stringbuf_t *path); + +/** Remove @a n components off the end of the canonicalized @a path. + * Equivalent to calling svn_path_remove_component() @a n times. + * + * @since New in 1.1. + */ +void +svn_path_remove_components(svn_stringbuf_t *path, apr_size_t n); + +/** Divide the canonicalized @a path into @a *dirpath and @a + * *base_name, allocated in @a pool. + * + * If @a dirpath or @a base_name is NULL, then don't set that one. + * + * Either @a dirpath or @a base_name may be @a path's own address, but they + * may not both be the same address, or the results are undefined. + * + * If @a path has two or more components, the separator between @a dirpath + * and @a base_name is not included in either of the new names. + * + * examples: + * -
"/foo/bar/baz"  ==>  "/foo/bar" and "baz"
+ * -
"/bar"          ==>  "/"  and "bar"
+ * -
"/"             ==>  "/"  and "/"
+ * -
"X:/"           ==>  "X:/" and "X:/"
+ * -
"bar"           ==>  ""   and "bar"
+ * -
""              ==>  ""   and ""
+ */ +void +svn_path_split(const char *path, + const char **dirpath, + const char **base_name, + apr_pool_t *pool); + + +/** Return non-zero iff @a path is empty ("") or represents the current + * directory -- that is, if prepending it as a component to an existing + * path would result in no meaningful change. + */ +int +svn_path_is_empty(const char *path); + +#ifndef SVN_DIRENT_URI_H +/* This declaration has been moved to svn_dirent_uri.h, remains here only for + compatiblity reasons. */ +svn_boolean_t +svn_dirent_is_root(const char *dirent, apr_size_t len); +#endif /* SVN_DIRENT_URI_H */ + +/** Return a new path (or URL) like @a path, but transformed such that + * some types of path specification redundancies are removed. + * + * This involves collapsing redundant "/./" elements, removing + * multiple adjacent separator characters, removing trailing + * separator characters, and possibly other semantically inoperative + * transformations. + * + * Convert the scheme and hostname to lowercase (see issue #2475) + * + * The returned path may be statically allocated, equal to @a path, or + * allocated from @a pool. + */ +const char * +svn_path_canonicalize(const char *path, apr_pool_t *pool); + +/** Return @c TRUE iff path is canonical. Use @a pool for temporary + * allocations. + * + * @since New in 1.5. + */ +svn_boolean_t +svn_path_is_canonical(const char *path, apr_pool_t *pool); + + +/** Return an integer greater than, equal to, or less than 0, according + * as @a path1 is greater than, equal to, or less than @a path2. + */ +int +svn_path_compare_paths(const char *path1, const char *path2); + + +/** Return the longest common path shared by two canonicalized paths, + * @a path1 and @a path2. If there's no common ancestor, return the + * empty path. + * + * @a path1 and @a path2 may be URLs. In order for two URLs to have + * a common ancestor, they must (a) have the same protocol (since two URLs + * with the same path but different protocols may point at completely + * different resources), and (b) share a common ancestor in their path + * component, i.e. 'protocol://' is not a sufficient ancestor. + */ +char * +svn_path_get_longest_ancestor(const char *path1, + const char *path2, + apr_pool_t *pool); + +/** Convert @a relative canonicalized path to an absolute path and + * return the results in @a *pabsolute, allocated in @a pool. + * + * @a relative may be a URL, in which case no attempt is made to convert it, + * and a copy of the URL is returned. + */ +svn_error_t * +svn_path_get_absolute(const char **pabsolute, + const char *relative, + apr_pool_t *pool); + +/** Return the path part of the canonicalized @a path in @a + * *pdirectory, and the file part in @a *pfile. If @a path is a + * directory, set @a *pdirectory to @a path, and @a *pfile to the + * empty string. If @a path does not exist it is treated as if it is + * a file, since directories do not normally vanish. + */ +svn_error_t * +svn_path_split_if_file(const char *path, + const char **pdirectory, + const char **pfile, + apr_pool_t *pool); + +/** Find the common prefix of the canonicalized paths in @a targets + * (an array of const char *'s), and remove redundant paths if @a + * remove_redundancies is TRUE. + * + * - Set @a *pcommon to the absolute path of the path or URL common to + * all of the targets. If the targets have no common prefix, or + * are a mix of URLs and local paths, set @a *pcommon to the + * empty string. + * + * - If @a pcondensed_targets is non-NULL, set @a *pcondensed_targets + * to an array of targets relative to @a *pcommon, and if + * @a remove_redundancies is TRUE, omit any paths/URLs that are + * descendants of another path/URL in @a targets. If *pcommon + * is empty, @a *pcondensed_targets will contain full URLs and/or + * absolute paths; redundancies can still be removed (from both URLs + * and paths). If @a pcondensed_targets is NULL, leave it alone. + * + * Else if there is exactly one target, then + * + * - Set @a *pcommon to that target, and + * + * - If @a pcondensed_targets is non-NULL, set @a *pcondensed_targets + * to an array containing zero elements. Else if + * @a pcondensed_targets is NULL, leave it alone. + * + * If there are no items in @a targets, set @a *pcommon and (if + * applicable) @a *pcondensed_targets to @c NULL. + * + * @note There is no guarantee that @a *pcommon is within a working + * copy. */ +svn_error_t * +svn_path_condense_targets(const char **pcommon, + apr_array_header_t **pcondensed_targets, + const apr_array_header_t *targets, + svn_boolean_t remove_redundancies, + apr_pool_t *pool); + + +/** Copy a list of canonicalized @a targets, one at a time, into @a + * pcondensed_targets, omitting any targets that are found earlier in + * the list, or whose ancestor is found earlier in the list. Ordering + * of targets in the original list is preserved in the condensed list + * of targets. Use @a pool for any allocations. + * + * How does this differ in functionality from svn_path_condense_targets()? + * + * Here's the short version: + * + * 1. Disclaimer: if you wish to debate the following, talk to Karl. :-) + * Order matters for updates because a multi-arg update is not + * atomic, and CVS users are used to, when doing 'cvs up targetA + * targetB' seeing targetA get updated, then targetB. I think the + * idea is that if you're in a time-sensitive or flaky-network + * situation, a user can say, "I really *need* to update + * wc/A/D/G/tau, but I might as well update my whole working copy if + * I can." So that user will do 'svn up wc/A/D/G/tau wc', and if + * something dies in the middles of the 'wc' update, at least the + * user has 'tau' up-to-date. + * + * 2. Also, we have this notion of an anchor and a target for updates + * (the anchor is where the update editor is rooted, the target is + * the actual thing we want to update). I needed a function that + * would NOT screw with my input paths so that I could tell the + * difference between someone being in A/D and saying 'svn up G' and + * being in A/D/G and saying 'svn up .' -- believe it or not, these + * two things don't mean the same thing. svn_path_condense_targets() + * plays with absolute paths (which is fine, so does + * svn_path_remove_redundancies()), but the difference is that it + * actually tweaks those targets to be relative to the "grandfather + * path" common to all the targets. Updates don't require a + * "grandfather path" at all, and even if it did, the whole + * conversion to an absolute path drops the crucial difference + * between saying "i'm in foo, update bar" and "i'm in foo/bar, + * update '.'" + */ +svn_error_t * +svn_path_remove_redundancies(apr_array_header_t **pcondensed_targets, + const apr_array_header_t *targets, + apr_pool_t *pool); + + +/** Decompose the canonicalized @a path into an array of const + * char * components, allocated in @a pool. If @a path is + * absolute, the first component will be a lone dir separator (the + * root directory). + */ +apr_array_header_t * +svn_path_decompose(const char *path, apr_pool_t *pool); + +/** Join an array of const char * components into a '/' + * separated path, allocated in @a pool. The joined path is absolute if + * the first component is a lone dir separator. + * + * Calling svn_path_compose() on the output of svn_path_decompose() + * will return the exact same path. + * + * @since New in 1.5. + */ +const char * +svn_path_compose(const apr_array_header_t *components, apr_pool_t *pool); + +/** Test that @a name is a single path component, that is: + * - not @c NULL or empty. + * - not a `/'-separated directory path + * - not empty or `..' + */ +svn_boolean_t +svn_path_is_single_path_component(const char *name); + + +/** + * Test to see if a backpath, i.e. '..', is present in @a path. + * If not, return @c FALSE. + * If so, return @c TRUE. + * + * @since New in 1.1. + */ +svn_boolean_t +svn_path_is_backpath_present(const char *path); + + +/** + * Test to see if a dotpath, i.e. '.', is present in @a path. + * If not, return @c FALSE. + * If so, return @c TRUE. + * + * @since New in 1.6. + */ +svn_boolean_t +svn_path_is_dotpath_present(const char *path); + + +/** Test if @a path2 is a child of @a path1. + * If not, return @c NULL. + * If so, return a copy of the remainder path, allocated in @a pool. + * (The remainder is the component which, added to @a path1, yields + * @a path2. The remainder does not begin with a dir separator.) + * + * Both paths must be in canonical form, and must either be absolute, + * or contain no ".." components. + * + * If @a path2 is the same as @a path1, it is not considered a child, so the + * result is @c NULL; an empty string is never returned. + * + * @note In 1.5 this function has been extended to allow a @c NULL @a pool + * in which case a pointer into @a path2 will be returned to + * identify the remainder path. + * + * ### @todo the ".." restriction is unfortunate, and would ideally + * be lifted by making the implementation smarter. But this is not + * trivial: if the path is "../foo", how do you know whether or not + * the current directory is named "foo" in its parent? + */ +const char * +svn_path_is_child(const char *path1, const char *path2, apr_pool_t *pool); + +/** Return TRUE if @a path1 is an ancestor of @a path2 or the paths are equal + * and FALSE otherwise. + * + * @since New in 1.3. + */ +svn_boolean_t +svn_path_is_ancestor(const char *path1, const char *path2); + +/** + * Check whether @a path is a valid Subversion path. + * + * A valid Subversion pathname is a UTF-8 string without control + * characters. "Valid" means Subversion can store the pathname in + * a repository. There may be other, OS-specific, limitations on + * what paths can be represented in a working copy. + * + * ASSUMPTION: @a path is a valid UTF-8 string. This function does + * not check UTF-8 validity. + * + * Return @c SVN_NO_ERROR if valid and @c SVN_ERR_FS_PATH_SYNTAX if + * invalid. + * + * @note Despite returning an @c SVN_ERR_FS_* error, this function has + * nothing to do with the versioned filesystem's concept of validity. + * + * @since New in 1.2. + */ +svn_error_t * +svn_path_check_valid(const char *path, apr_pool_t *pool); + + +/** URI/URL stuff + * + * @defgroup svn_path_uri_stuff URI/URL conversion + * @{ + */ + +/** Return TRUE iff @a path looks like a valid absolute URL. */ +svn_boolean_t +svn_path_is_url(const char *path); + +/** Return @c TRUE iff @a path is URI-safe, @c FALSE otherwise. */ +svn_boolean_t +svn_path_is_uri_safe(const char *path); + +/** Return a URI-encoded copy of @a path, allocated in @a pool. (@a + path can be an arbitrary UTF-8 string and does not have to be a + canonical path.) */ +const char * +svn_path_uri_encode(const char *path, apr_pool_t *pool); + +/** Return a URI-decoded copy of @a path, allocated in @a pool. */ +const char * +svn_path_uri_decode(const char *path, apr_pool_t *pool); + +/** Extend @a url by @a component, URI-encoding that @a component + * before adding it to the @a url; return the new @a url, allocated in + * @a pool. If @a component is @c NULL, just return a copy of @a url, + * allocated in @a pool. + * + * @a component need not be a single path segment, but if it contains + * multiple segments, they must be separated by '/'. @a component + * should not begin with '/', however; if it does, the behavior is + * undefined. + * + * @a url must be in canonical format; it may not have a trailing '/'. + * + * @note To add a component that is already URI-encoded, use + * svn_path_join(url, component, pool) instead. + * + * @note gstein suggests this for when @a component begins with '/': + * + * "replace the path entirely + * https://example.com:4444/base/path joined with /leading/slash, + * should return: https://example.com:4444/leading/slash + * per the RFCs on combining URIs" + * + * We may implement that someday, which is why leading '/' is + * merely undefined right now. + * + * @since New in 1.6. + */ +const char * +svn_path_url_add_component2(const char *url, + const char *component, + apr_pool_t *pool); + +/** Like svn_path_url_add_component2, but allows path components that + * end with a trailing '/' + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +const char * +svn_path_url_add_component(const char *url, + const char *component, + apr_pool_t *pool); + +/** + * Convert @a iri (Internationalized URI) to an URI. + * The return value may be the same as @a iri if it was already + * a URI. Else, allocate the return value in @a pool. + * + * @since New in 1.1. + */ +const char * +svn_path_uri_from_iri(const char *iri, apr_pool_t *pool); + +/** + * URI-encode certain characters in @a uri that are not valid in an URI, but + * doesn't have any special meaning in @a uri at their positions. If no + * characters need escaping, just return @a uri. + * + * @note Currently, this function escapes <, >, ", space, {, }, |, \, ^, and `. + * This may be extended in the future to do context-dependent escaping. + * + * @since New in 1.1. + */ +const char * +svn_path_uri_autoescape(const char *uri, apr_pool_t *pool); + +/** @} */ + +/** Charset conversion stuff + * + * @defgroup svn_path_charset_stuff Charset conversion + * @{ + */ + +/** Convert @a path_utf8 from UTF-8 to the internal encoding used by APR. */ +svn_error_t * +svn_path_cstring_from_utf8(const char **path_apr, + const char *path_utf8, + apr_pool_t *pool); + +/** Convert @a path_apr from the internal encoding used by APR to UTF-8. */ +svn_error_t * +svn_path_cstring_to_utf8(const char **path_utf8, + const char *path_apr, + apr_pool_t *pool); + + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* SVN_PATH_H */ diff --git a/src/TortoiseMerge/svninclude/svn_pools.h b/src/TortoiseMerge/svninclude/svn_pools.h index 6d29bfb..a162151 100644 --- a/src/TortoiseMerge/svninclude/svn_pools.h +++ b/src/TortoiseMerge/svninclude/svn_pools.h @@ -1,8 +1,89 @@ -#ifndef SVN_POOLS_XX -#define SVN_POOLS_XX +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2004, 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_pools.h + * @brief APR pool management for Subversion + */ -typedef TCHAR * svn_stream_t; -typedef BOOL svn_boolean_t; + -#endif \ No newline at end of file +#ifndef SVN_POOLS_H +#define SVN_POOLS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +/* Wrappers around APR pools, so we get debugging. */ + +/** The recommended maximum amount of memory (4MB) to keep in an APR + * allocator on the free list, conveniently defined here to share + * between all our applications. + */ +#define SVN_ALLOCATOR_RECOMMENDED_MAX_FREE (4096 * 1024) + + +/** Wrapper around apr_pool_create_ex(), with a simpler interface. + * The return pool will have an abort function set, which will call + * abort() on OOM. + */ +apr_pool_t * +svn_pool_create_ex(apr_pool_t *parent_pool, + apr_allocator_t *allocator); + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +apr_pool_t * +svn_pool_create_ex_debug(apr_pool_t *parent_pool, + apr_allocator_t *allocator, + const char *file_line); + +#if APR_POOL_DEBUG +#define svn_pool_create_ex(pool, allocator) \ +svn_pool_create_ex_debug(pool, allocator, APR_POOL__FILE_LINE__) + +#endif /* APR_POOL_DEBUG */ +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + + +/** Create a pool as a subpool of @a parent_pool */ +#define svn_pool_create(parent_pool) svn_pool_create_ex(parent_pool, NULL) + +/** Clear a @a pool destroying its children. + * + * This define for @c svn_pool_clear exists for completeness. + */ +#define svn_pool_clear apr_pool_clear + + +/** Destroy a @a pool and all of its children. + * + * This define for @c svn_pool_destroy exists for symmetry and + * completeness. + */ +#define svn_pool_destroy apr_pool_destroy + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_POOLS_H */ diff --git a/src/TortoiseMerge/svninclude/svn_ra.h b/src/TortoiseMerge/svninclude/svn_ra.h new file mode 100644 index 0000000..0711619 --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_ra.h @@ -0,0 +1,2211 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_ra.h + * @brief Repository Access + */ + +#ifndef SVN_RA_H +#define SVN_RA_H + +#include +#include +#include +#include +#include +#include /* for apr_file_t */ + +#include "svn_types.h" +#include "svn_string.h" +#include "svn_delta.h" +#include "svn_auth.h" +#include "svn_mergeinfo.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + +/* Misc. declarations */ + +/** + * Get libsvn_ra version information. + * + * @since New in 1.1. + */ +const svn_version_t * +svn_ra_version(void); + + +/** This is a function type which allows the RA layer to fetch working + * copy (WC) properties. + * + * The @a baton is provided along with the function pointer and should + * be passed back in. This will be the @a callback_baton or the + * @a close_baton as appropriate. + * + * @a path is relative to the "root" of the session, defined by the + * @a repos_URL passed to svn_ra_open3() vtable call. + * + * @a name is the name of the property to fetch. If the property is present, + * then it is returned in @a value. Otherwise, @a *value is set to @c NULL. + */ +typedef svn_error_t *(*svn_ra_get_wc_prop_func_t)(void *baton, + const char *relpath, + const char *name, + const svn_string_t **value, + apr_pool_t *pool); + +/** This is a function type which allows the RA layer to store new + * working copy properties during update-like operations. See the + * comments for @c svn_ra_get_wc_prop_func_t for @a baton, @a path, and + * @a name. The @a value is the value that will be stored for the property; + * a NULL @a value means the property will be deleted. + */ +typedef svn_error_t *(*svn_ra_set_wc_prop_func_t)(void *baton, + const char *path, + const char *name, + const svn_string_t *value, + apr_pool_t *pool); + +/** This is a function type which allows the RA layer to store new + * working copy properties as part of a commit. See the comments for + * @c svn_ra_get_wc_prop_func_t for @a baton, @a path, and @a name. + * The @a value is the value that will be stored for the property; a + * @c NULL @a value means the property will be deleted. + * + * Note that this might not actually store the new property before + * returning, but instead schedule it to be changed as part of + * post-commit processing (in which case a successful commit means the + * properties got written). Thus, during the commit, it is possible + * to invoke this function to set a new value for a wc prop, then read + * the wc prop back from the working copy and get the *old* value. + * Callers beware. + */ +typedef svn_error_t *(*svn_ra_push_wc_prop_func_t)(void *baton, + const char *path, + const char *name, + const svn_string_t *value, + apr_pool_t *pool); + +/** This is a function type which allows the RA layer to invalidate + * (i.e., remove) wcprops recursively. See the documentation for + * @c svn_ra_get_wc_prop_func_t for @a baton, @a path, and @a name. + * + * Unlike @c svn_ra_push_wc_prop_func_t, this has immediate effect. If + * it returns success, the wcprops have been removed. + */ +typedef svn_error_t *(*svn_ra_invalidate_wc_props_func_t)(void *baton, + const char *path, + const char *name, + apr_pool_t *pool); + + +/** A function type for retrieving the youngest revision from a repos. */ +typedef svn_error_t *(*svn_ra_get_latest_revnum_func_t) + (void *session_baton, + svn_revnum_t *latest_revnum); + +/** A function type which allows the RA layer to ask about any + * customizations to the client name string. This is primarily used + * by HTTP-based RA layers wishing to extend the string reported to + * Apache/mod_dav_svn via the User-agent HTTP header. + */ +typedef svn_error_t *(*svn_ra_get_client_string_func_t)(void *baton, + const char **name, + apr_pool_t *pool); + + +/** + * A callback function type for use in @c get_file_revs. + * @a baton is provided by the caller, @a path is the pathname of the file + * in revision @a rev and @a rev_props are the revision properties. + * If @a delta_handler and @a delta_baton are non-NULL, they may be set to a + * handler/baton which will be called with the delta between the previous + * revision and this one after the return of this callback. They may be + * left as NULL/NULL. + * @a prop_diffs is an array of svn_prop_t elements indicating the property + * delta for this and the previous revision. + * @a pool may be used for temporary allocations, but you can't rely + * on objects allocated to live outside of this particular call and the + * immediately following calls to @a *delta_handler, if any. + * + * @since New in 1.1. + */ +typedef svn_error_t *(*svn_ra_file_rev_handler_t) + (void *baton, + const char *path, + svn_revnum_t rev, + apr_hash_t *rev_props, + svn_txdelta_window_handler_t *delta_handler, + void **delta_baton, + apr_array_header_t *prop_diffs, + apr_pool_t *pool); + +/** + * Callback function type for locking and unlocking actions. + * + * @since New in 1.2. + * + * @a do_lock is TRUE when locking @a path, and FALSE + * otherwise. + * + * @a lock is a lock for @a path or NULL if @a do_lock is FALSE or @a ra_err is + * non-NULL. + * + * @a ra_err is NULL unless the ra layer encounters a locking related + * error which it passes back for notification purposes. The caller + * is responsible for clearing @a ra_err after the callback is run. + * + * @a baton is a closure object; it should be provided by the + * implementation, and passed by the caller. @a pool may be used for + * temporary allocation. + */ +typedef svn_error_t *(*svn_ra_lock_callback_t)(void *baton, + const char *path, + svn_boolean_t do_lock, + const svn_lock_t *lock, + svn_error_t *ra_err, + apr_pool_t *pool); + +/** + * Callback function type for progress notification. + * + * @a progress is the number of bytes already transferred, @a total is + * the total number of bytes to transfer or -1 if it's not known, @a + * baton is the callback baton. + * + * @since New in 1.3. + */ +typedef void (*svn_ra_progress_notify_func_t)(apr_off_t progress, + apr_off_t total, + void *baton, + apr_pool_t *pool); + +/** + * Callback function type for replay_range actions. + * + * This callback function should provide replay_range with an editor which + * will be driven with the received replay reports from the master repository. + * + * @a revision is the target revision number of the received replay report. + * + * @a editor and @a edit_baton should provided by the callback implementation. + * + * @a replay_baton is the baton as originally passed to replay_range. + * + * @a revprops contains key/value pairs for each revision properties for this + * revision. + * + * @since New in 1.5. + */ +typedef svn_error_t *(*svn_ra_replay_revstart_callback_t) + (svn_revnum_t revision, + void *replay_baton, + const svn_delta_editor_t **editor, + void **edit_baton, + apr_hash_t *rev_props, + apr_pool_t *pool); + +/** + * Callback function type for replay_range actions. + * + * This callback function should close the editor. + * + * @a revision is the target revision number of the received replay report. + * + * @a editor and @a edit_baton should provided by the callback implementation. + * + * @a replay_baton is the baton as originally passed to replay_range. + * + * @a revprops contains key/value pairs for each revision properties for this + * revision. + * + * @since New in 1.5. + */ +typedef svn_error_t *(*svn_ra_replay_revfinish_callback_t) + (svn_revnum_t revision, + void *replay_baton, + const svn_delta_editor_t *editor, + void *edit_baton, + apr_hash_t *rev_props, + apr_pool_t *pool); + + +/** + * The update Reporter. + * + * A vtable structure which allows a working copy to describe a subset + * (or possibly all) of its working-copy to an RA layer, for the + * purposes of an update, switch, status, or diff operation. + * + * Paths for report calls are relative to the target (not the anchor) + * of the operation. Report calls must be made in depth-first order: + * parents before children, all children of a parent before any + * siblings of the parent. The first report call must be a set_path + * with a @a path argument of "" and a valid revision. (If the target + * of the operation is locally deleted or missing, use the anchor's + * revision.) If the target of the operation is deleted or switched + * relative to the anchor, follow up the initial set_path call with a + * link_path or delete_path call with a @a path argument of "" to + * indicate that. In no other case may there be two report + * descriptions for the same path. If the target of the operation is + * a locally added file or directory (which previously did not exist), + * it may be reported as having revision 0 or as having the parent + * directory's revision. + * + * @since New in 1.5. + */ +typedef struct svn_ra_reporter3_t +{ + /** Describe a working copy @a path as being at a particular + * @a revision and having depth @a depth. + * + * @a revision may be SVN_INVALID_REVNUM if (for example) @a path + * represents a locally-added path with no revision number, or @a + * depth is @c svn_depth_exclude. + * + * @a path may not be underneath a path on which set_path() was + * previously called with @c svn_depth_exclude in this report. + * + * If @a start_empty is set and @a path is a directory, the + * implementor should assume the directory has no entries or props. + * + * This will *override* any previous set_path() calls made on parent + * paths. @a path is relative to the URL specified in svn_ra_open3(). + * + * If @a lock_token is non-NULL, it is the lock token for @a path in the WC. + * + * All temporary allocations are done in @a pool. + */ + svn_error_t *(*set_path)(void *report_baton, + const char *path, + svn_revnum_t revision, + svn_depth_t depth, + svn_boolean_t start_empty, + const char *lock_token, + apr_pool_t *pool); + + /** Describing a working copy @a path as missing. + * + * @a path may not be underneath a path on which set_path() was + * previously called with @c svn_depth_exclude in this report. + * + * All temporary allocations are done in @a pool. + */ + svn_error_t *(*delete_path)(void *report_baton, + const char *path, + apr_pool_t *pool); + + /** Like set_path(), but differs in that @a path in the working copy + * (relative to the root of the report driver) isn't a reflection of + * @a path in the repository (relative to the URL specified when + * opening the RA layer), but is instead a reflection of a different + * repository @a url at @a revision, and has depth @a depth. + * + * @a path may not be underneath a path on which set_path() was + * previously called with @c svn_depth_exclude in this report. + * + * If @a start_empty is set and @a path is a directory, + * the implementor should assume the directory has no entries or props. + * + * If @a lock_token is non-NULL, it is the lock token for @a path in the WC. + * + * All temporary allocations are done in @a pool. + */ + svn_error_t *(*link_path)(void *report_baton, + const char *path, + const char *url, + svn_revnum_t revision, + svn_depth_t depth, + svn_boolean_t start_empty, + const char *lock_token, + apr_pool_t *pool); + + /** WC calls this when the state report is finished; any directories + * or files not explicitly `set' are assumed to be at the + * baseline revision originally passed into do_update(). No other + * reporting functions, including abort_report, should be called after + * calling this function. + */ + svn_error_t *(*finish_report)(void *report_baton, + apr_pool_t *pool); + + /** If an error occurs during a report, this routine should cause the + * filesystem transaction to be aborted & cleaned up. No other reporting + * functions should be called after calling this function. + */ + svn_error_t *(*abort_report)(void *report_baton, + apr_pool_t *pool); + +} svn_ra_reporter3_t; + +/** + * Similar to @c svn_ra_reporter3_t, but without support for depths. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +typedef struct svn_ra_reporter2_t +{ + /** Similar to the corresponding field in @c svn_ra_reporter3_t, but + * with @a depth always set to @c svn_depth_infinity. */ + svn_error_t *(*set_path)(void *report_baton, + const char *path, + svn_revnum_t revision, + svn_boolean_t start_empty, + const char *lock_token, + apr_pool_t *pool); + + /** Same as the corresponding field in @c svn_ra_reporter3_t. */ + svn_error_t *(*delete_path)(void *report_baton, + const char *path, + apr_pool_t *pool); + + /** Similar to the corresponding field in @c svn_ra_reporter3_t, but + * with @a depth always set to @c svn_depth_infinity. */ + svn_error_t *(*link_path)(void *report_baton, + const char *path, + const char *url, + svn_revnum_t revision, + svn_boolean_t start_empty, + const char *lock_token, + apr_pool_t *pool); + + /** Same as the corresponding field in @c svn_ra_reporter3_t. */ + svn_error_t *(*finish_report)(void *report_baton, + apr_pool_t *pool); + + /** Same as the corresponding field in @c svn_ra_reporter3_t. */ + svn_error_t *(*abort_report)(void *report_baton, + apr_pool_t *pool); + +} svn_ra_reporter2_t; + +/** + * Similar to @c svn_ra_reporter2_t, but without support for lock tokens. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +typedef struct svn_ra_reporter_t +{ + /** Similar to the corresponding field in @c svn_ra_reporter2_t, but + * with @a lock_token always set to NULL. */ + svn_error_t *(*set_path)(void *report_baton, + const char *path, + svn_revnum_t revision, + svn_boolean_t start_empty, + apr_pool_t *pool); + + /** Same as the corresponding field in @c svn_ra_reporter2_t. */ + svn_error_t *(*delete_path)(void *report_baton, + const char *path, + apr_pool_t *pool); + + /** Similar to the corresponding field in @c svn_ra_reporter2_t, but + * with @a lock_token always set to NULL. */ + svn_error_t *(*link_path)(void *report_baton, + const char *path, + const char *url, + svn_revnum_t revision, + svn_boolean_t start_empty, + apr_pool_t *pool); + + /** Same as the corresponding field in @c svn_ra_reporter2_t. */ + svn_error_t *(*finish_report)(void *report_baton, + apr_pool_t *pool); + + /** Same as the corresponding field in @c svn_ra_reporter2_t. */ + svn_error_t *(*abort_report)(void *report_baton, + apr_pool_t *pool); +} svn_ra_reporter_t; + + +/** A collection of callbacks implemented by libsvn_client which allows + * an RA layer to "pull" information from the client application, or + * possibly store information. libsvn_client passes this vtable to + * svn_ra_open3(). + * + * Each routine takes a @a callback_baton originally provided with the + * vtable. + * + * Clients must use svn_ra_create_callbacks() to allocate and + * initialize this structure. + * + * @since New in 1.3. + */ +typedef struct svn_ra_callbacks2_t +{ + /** Open a unique temporary file for writing in the working copy. + * This file will be automatically deleted when @a fp is closed. + * + * @deprecated This callback should no longer be used by RA layers. + */ + svn_error_t *(*open_tmp_file)(apr_file_t **fp, + void *callback_baton, + apr_pool_t *pool); + + /** An authentication baton, created by the application, which is + * capable of retrieving all known types of credentials. + */ + svn_auth_baton_t *auth_baton; + + /*** The following items may be set to NULL to disallow the RA layer + to perform the respective operations of the vtable functions. + Perhaps WC props are not defined or are in invalid for this + session, or perhaps the commit operation this RA session will + perform is a server-side only one that shouldn't do post-commit + processing on a working copy path. ***/ + + /** Fetch working copy properties. + * + *
 ### we might have a problem if the RA layer ever wants a property
+   * ### that corresponds to a different revision of the file than
+   * ### what is in the WC. we'll cross that bridge one day...
+ */ + svn_ra_get_wc_prop_func_t get_wc_prop; + + /** Immediately set new values for working copy properties. */ + svn_ra_set_wc_prop_func_t set_wc_prop; + + /** Schedule new values for working copy properties. */ + svn_ra_push_wc_prop_func_t push_wc_prop; + + /** Invalidate working copy properties. */ + svn_ra_invalidate_wc_props_func_t invalidate_wc_props; + + /** Notification callback used for progress information. + * May be NULL if not used. + */ + svn_ra_progress_notify_func_t progress_func; + + /** Notification callback baton, used with progress_func. */ + void *progress_baton; + + /** Cancelation function + * + * As its baton, the general callback baton is used + * + * @since New in 1.5 + */ + svn_cancel_func_t cancel_func; + + /** Client string customization callback function + * @since New in 1.5 + */ + svn_ra_get_client_string_func_t get_client_string; + +} svn_ra_callbacks2_t; + +/** Similar to svn_ra_callbacks2_t, except that the progress + * notification function and baton is missing. + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +typedef struct svn_ra_callbacks_t +{ + svn_error_t *(*open_tmp_file)(apr_file_t **fp, + void *callback_baton, + apr_pool_t *pool); + + svn_auth_baton_t *auth_baton; + + svn_ra_get_wc_prop_func_t get_wc_prop; + + svn_ra_set_wc_prop_func_t set_wc_prop; + + svn_ra_push_wc_prop_func_t push_wc_prop; + + svn_ra_invalidate_wc_props_func_t invalidate_wc_props; + +} svn_ra_callbacks_t; + + + +/*----------------------------------------------------------------------*/ + +/* Public Interfaces. */ + +/** + * Initialize the RA library. This function must be called before using + * any function in this header, except the deprecated APIs based on + * @c svn_ra_plugin_t, or svn_ra_version(). This function must not be called + * simultaneously in multiple threads. @a pool must live + * longer than any open RA sessions. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_initialize(apr_pool_t *pool); + +/** Initialize a callback structure. +* Set @a *callbacks to a ra callbacks object, allocated in @a pool. +* +* Clients must use this function to allocate and initialize @c +* svn_ra_callbacks2_t structures. +* +* @since New in 1.3. +*/ +svn_error_t * +svn_ra_create_callbacks(svn_ra_callbacks2_t **callbacks, + apr_pool_t *pool); + +/** + * A repository access session. This object is used to perform requests + * to a repository, identified by an URL. + * + * @since New in 1.2. + */ +typedef struct svn_ra_session_t svn_ra_session_t; + +/** + * Open a repository session to @a repos_URL. Return an opaque object + * representing this session in @a *session_p, allocated in @a pool. + * + * Return @c SVN_ERR_RA_UUID_MISMATCH if @a uuid is non-NULL and not equal + * to the UUID of the repository at @c repos_URL. + * + * @a callbacks/@a callback_baton is a table of callbacks provided by the + * client; see @c svn_ra_callbacks2_t. + * + * @a config is a hash mapping const char * keys to + * @c svn_config_t * values. For example, the @c svn_config_t for the + * "~/.subversion/config" file is under the key "config". + * + * All RA requests require a session; they will continue to + * use @a pool for memory allocation. + * + * @see svn_client_open_ra_session(). + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_open3(svn_ra_session_t **session_p, + const char *repos_URL, + const char *uuid, + const svn_ra_callbacks2_t *callbacks, + void *callback_baton, + apr_hash_t *config, + apr_pool_t *pool); + +/** + * Similiar to svn_ra_open3(), but with @a uuid set to @c NULL. + * + * @since New in 1.3. + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_open2(svn_ra_session_t **session_p, + const char *repos_URL, + const svn_ra_callbacks2_t *callbacks, + void *callback_baton, + apr_hash_t *config, + apr_pool_t *pool); + +/** + * @see svn_ra_open2(). + * @since New in 1.2. + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_open(svn_ra_session_t **session_p, + const char *repos_URL, + const svn_ra_callbacks_t *callbacks, + void *callback_baton, + apr_hash_t *config, + apr_pool_t *pool); + +/** Change the root URL of an open @a ra_session to point to a new path in the + * same repository. @a url is the new root URL. Use @a pool for + * temporary allocations. + * + * If @a url has a different repository root than the current session + * URL, return @c SVN_ERR_RA_ILLEGAL_URL. + * + * @since New in 1.4. + */ +svn_error_t * +svn_ra_reparent(svn_ra_session_t *ra_session, + const char *url, + apr_pool_t *pool); + +/** Set @a *url to the repository URL to which @a ra_session was + * opened or most recently reparented. + */ +svn_error_t * +svn_ra_get_session_url(svn_ra_session_t *ra_session, + const char **url, + apr_pool_t *pool); + + +/** + * Get the latest revision number from the repository of @a session. + * + * Use @a pool for memory allocation. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_get_latest_revnum(svn_ra_session_t *session, + svn_revnum_t *latest_revnum, + apr_pool_t *pool); + +/** + * Get the latest revision number at time @a tm in the repository of + * @a session. + * + * Use @a pool for memory allocation. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_get_dated_revision(svn_ra_session_t *session, + svn_revnum_t *revision, + apr_time_t tm, + apr_pool_t *pool); + +/** + * Set the property @a name to @a value on revision @a rev in the repository + * of @a session. + * + * If @a value is @c NULL, delete the named revision property. + * + * Please note that properties attached to revisions are @em unversioned. + * + * Use @a pool for memory allocation. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_change_rev_prop(svn_ra_session_t *session, + svn_revnum_t rev, + const char *name, + const svn_string_t *value, + apr_pool_t *pool); + +/** + * Set @a *props to the list of unversioned properties attached to revision + * @a rev in the repository of @a session. The hash maps + * (const char *) names to (@c svn_string_t *) values. + * + * Use @a pool for memory allocation. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_rev_proplist(svn_ra_session_t *session, + svn_revnum_t rev, + apr_hash_t **props, + apr_pool_t *pool); + +/** + * Set @a *value to the value of unversioned property @a name attached to + * revision @a rev in the repository of @a session. If @a rev has no + * property by that name, set @a *value to @c NULL. + * + * Use @a pool for memory allocation. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_rev_prop(svn_ra_session_t *session, + svn_revnum_t rev, + const char *name, + svn_string_t **value, + apr_pool_t *pool); + +/** + * Set @a *editor and @a *edit_baton to an editor for committing + * changes to the repository of @a session, setting the revision + * properties from @a revprop_table. The revisions being committed + * against are passed to the editor functions, starting with the rev + * argument to @c open_root. The path root of the commit is the @a + * session's URL. + * + * @a revprop_table is a hash mapping const char * property + * names to @c svn_string_t property values. The commit log message + * is expected to be in the @c SVN_PROP_REVISION_LOG element. @a + * revprop_table can not contain either of @c SVN_PROP_REVISION_DATE + * or @c SVN_PROP_REVISION_AUTHOR. + * + * Before @c close_edit returns, but after the commit has succeeded, + * it will invoke @a callback with the new revision number, the + * commit date (as a const char *), commit author (as a + * const char *), and @a callback_baton as arguments. If + * @a callback returns an error, that error will be returned from @c + * close_edit, otherwise @c close_edit will return successfully + * (unless it encountered an error before invoking @a callback). + * + * The callback will not be called if the commit was a no-op + * (i.e. nothing was committed); + * + * @a lock_tokens, if non-NULL, is a hash mapping const char + * * paths (relative to the URL of @a session) to + * const char * lock tokens. The server checks that the + * correct token is provided for each committed, locked path. @a lock_tokens + * must live during the whole commit operation. + * + * If @a keep_locks is @c TRUE, then do not release locks on + * committed objects. Else, automatically release such locks. + * + * The caller may not perform any RA operations using @a session before + * finishing the edit. + * + * Use @a pool for memory allocation. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_get_commit_editor3(svn_ra_session_t *session, + const svn_delta_editor_t **editor, + void **edit_baton, + apr_hash_t *revprop_table, + svn_commit_callback2_t callback, + void *callback_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + apr_pool_t *pool); + +/** + * Same as svn_ra_get_commit_editor3(), but with @c revprop_table set + * to a hash containing the @c SVN_PROP_REVISION_LOG property set + * to the value of @a log_msg. + * + * @since New in 1.4. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_get_commit_editor2(svn_ra_session_t *session, + const svn_delta_editor_t **editor, + void **edit_baton, + const char *log_msg, + svn_commit_callback2_t callback, + void *callback_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + apr_pool_t *pool); + +/** + * Same as svn_ra_get_commit_editor2(), but uses @c svn_commit_callback_t. + * + * @since New in 1.2. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_get_commit_editor(svn_ra_session_t *session, + const svn_delta_editor_t **editor, + void **edit_baton, + const char *log_msg, + svn_commit_callback_t callback, + void *callback_baton, + apr_hash_t *lock_tokens, + svn_boolean_t keep_locks, + apr_pool_t *pool); + +/** + * Fetch the contents and properties of file @a path at @a revision. + * @a revision may be SVN_INVALID_REVNUM, indicating that the HEAD + * revision should be used. Interpret @a path relative to the URL in + * @a session. Use @a pool for all allocations. + * + * If @a revision is @c SVN_INVALID_REVNUM and @a fetched_rev is not + * @c NULL, then set @a *fetched_rev to the actual revision that was + * retrieved. + * + * If @a stream is non @c NULL, push the contents of the file at @a + * stream, do not call svn_stream_close() when finished. + * + * If @a props is non @c NULL, set @a *props to contain the properties of + * the file. This means @em all properties: not just ones controlled by + * the user and stored in the repository fs, but non-tweakable ones + * generated by the SCM system itself (e.g. 'wcprops', 'entryprops', + * etc.) The keys are const char *, values are + * @c svn_string_t *. + * + * The stream handlers for @a stream may not perform any RA + * operations using @a session. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_get_file(svn_ra_session_t *session, + const char *path, + svn_revnum_t revision, + svn_stream_t *stream, + svn_revnum_t *fetched_rev, + apr_hash_t **props, + apr_pool_t *pool); + +/** + * If @a dirents is non @c NULL, set @a *dirents to contain all the entries + * of directory @a path at @a revision. The keys of @a dirents will be + * entry names (const char *), and the values dirents + * (@c svn_dirent_t *). Use @a pool for all allocations. + * + * @a dirent_fields controls which portions of the @c svn_dirent_t + * objects are filled in. To have them completely filled in just pass + * @c SVN_DIRENT_ALL, otherwise pass the bitwise OR of all the @c SVN_DIRENT_ + * fields you would like to have returned to you. + * + * @a path is interpreted relative to the URL in @a session. + * + * If @a revision is @c SVN_INVALID_REVNUM (meaning 'head') and + * @a *fetched_rev is not @c NULL, then this function will set + * @a *fetched_rev to the actual revision that was retrieved. (Some + * callers want to know, and some don't.) + * + * If @a props is non @c NULL, set @a *props to contain the properties of + * the directory. This means @em all properties: not just ones controlled by + * the user and stored in the repository fs, but non-tweakable ones + * generated by the SCM system itself (e.g. 'wcprops', 'entryprops', + * etc.) The keys are const char *, values are + * @c svn_string_t *. + * + * @since New in 1.4. + */ +svn_error_t * +svn_ra_get_dir2(svn_ra_session_t *session, + apr_hash_t **dirents, + svn_revnum_t *fetched_rev, + apr_hash_t **props, + const char *path, + svn_revnum_t revision, + apr_uint32_t dirent_fields, + apr_pool_t *pool); + +/** + * Similar to @c svn_ra_get_dir2, but with @c SVN_DIRENT_ALL for the + * @a dirent_fields parameter. + * + * @since New in 1.2. + * + * @deprecated Provided for compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_get_dir(svn_ra_session_t *session, + const char *path, + svn_revnum_t revision, + apr_hash_t **dirents, + svn_revnum_t *fetched_rev, + apr_hash_t **props, + apr_pool_t *pool); + +/** + * Set @a *catalog to a mergeinfo catalog for the paths in @a paths. + * If no mergeinfo is available, set @a *catalog to @c NULL. The + * requested mergeinfo hashes are for @a paths (which are relative to + * @a session's URL) in @a revision. If one of the paths does not exist + * in that revision, return SVN_ERR_FS_NOT_FOUND. + * + * @a inherit indicates whether explicit, explicit or inherited, or + * only inherited mergeinfo for @a paths is retrieved. + * + * If @a include_descendants is TRUE, then additionally return the + * mergeinfo for any descendant of any element of @a paths which has + * the @c SVN_PROP_MERGEINFO property explicitly set on it. (Note + * that inheritance is only taken into account for the elements in @a + * paths; descendants of the elements in @a paths which get their + * mergeinfo via inheritance are not included in @a *catalog.) + * + * Allocate the returned values in @a pool. + * + * If @a revision is @c SVN_INVALID_REVNUM, it defaults to youngest. + * + * If the server doesn't support retrieval of mergeinfo (which can + * happen even for file:// URLs, if the repository itself hasn't been + * upgraded), return @c SVN_ERR_UNSUPPORTED_FEATURE in preference to + * any other error that might otherwise be returned. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_get_mergeinfo(svn_ra_session_t *session, + svn_mergeinfo_catalog_t *catalog, + const apr_array_header_t *paths, + svn_revnum_t revision, + svn_mergeinfo_inheritance_t inherit, + svn_boolean_t include_descendants, + apr_pool_t *pool); + +/** + * Ask the RA layer to update a working copy. + * + * The client initially provides an @a update_editor/@a update_baton to the + * RA layer; this editor contains knowledge of where the change will + * begin in the working copy (when @c open_root() is called). + * + * In return, the client receives a @a reporter/@a report_baton. The + * client then describes its working copy by making calls into the + * @a reporter. + * + * When finished, the client calls @a reporter->finish_report(). The + * RA layer then does a complete drive of @a update_editor, ending with + * @a update_editor->close_edit(), to update the working copy. + * + * @a update_target is an optional single path component to restrict + * the scope of the update to just that entry (in the directory + * represented by the @a session's URL). If @a update_target is the + * empty string, the entire directory is updated. + * + * Update the target only as deeply as @a depth indicates. + * + * If @a send_copyfrom_args is TRUE, then ask the server to send + * copyfrom arguments to add_file() and add_directory() when possible. + * (Note: this means that any subsequent txdeltas coming from the + * server are presumed to apply against the copied file!) + * + * The working copy will be updated to @a revision_to_update_to, or the + * "latest" revision if this arg is invalid. + * + * The caller may not perform any RA operations using @a session before + * finishing the report, and may not perform any RA operations using + * @a session from within the editing operations of @a update_editor. + * + * Use @a pool for memory allocation. + * + * @note The reporter provided by this function does NOT supply copy- + * from information to the diff editor callbacks. + * + * @note In order to prevent pre-1.5 servers from doing more work than + * needed, and sending too much data back, a pre-1.5 'recurse' + * directive may be sent to the server, based on @a depth. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_do_update2(svn_ra_session_t *session, + const svn_ra_reporter3_t **reporter, + void **report_baton, + svn_revnum_t revision_to_update_to, + const char *update_target, + svn_depth_t depth, + svn_boolean_t send_copyfrom_args, + const svn_delta_editor_t *update_editor, + void *update_baton, + apr_pool_t *pool); + +/** + * Similar to svn_ra_do_update2(), but taking @c svn_ra_reporter2_t + * instead of @c svn_ra_reporter3_t; if @a recurse is true, pass @c + * svn_depth_infinity for @a depth, else pass @c svn_depth_files; and + * with @a send_copyfrom_args always false. + * + * @deprecated Provided for compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_do_update(svn_ra_session_t *session, + const svn_ra_reporter2_t **reporter, + void **report_baton, + svn_revnum_t revision_to_update_to, + const char *update_target, + svn_boolean_t recurse, + const svn_delta_editor_t *update_editor, + void *update_baton, + apr_pool_t *pool); + + +/** + * Ask the RA layer to 'switch' a working copy to a new + * @a switch_url; it's another form of svn_ra_do_update(). + * + * The client initially provides a @a switch_editor/@a switch_baton to the RA + * layer; this editor contains knowledge of where the change will + * begin in the working copy (when open_root() is called). + * + * In return, the client receives a @a reporter/@a report_baton. The + * client then describes its working copy by making calls into the + * @a reporter. + * + * When finished, the client calls @a reporter->finish_report(). The + * RA layer then does a complete drive of @a switch_editor, ending with + * close_edit(), to switch the working copy. + * + * @a switch_target is an optional single path component will restrict + * the scope of things affected by the switch to an entry in the + * directory represented by the @a session's URL, or empty if the + * entire directory is meant to be switched. + * + * Switch the target only as deeply as @a depth indicates. + * + * The working copy will be switched to @a revision_to_switch_to, or the + * "latest" revision if this arg is invalid. + * + * The caller may not perform any RA operations using + * @a session before finishing the report, and may not perform + * any RA operations using @a session from within the editing + * operations of @a switch_editor. + * + * Use @a pool for memory allocation. + * + * @note The reporter provided by this function does NOT supply copy- + * from information to the diff editor callbacks. + * + * @note In order to prevent pre-1.5 servers from doing more work than + * needed, and sending too much data back, a pre-1.5 'recurse' + * directive may be sent to the server, based on @a depth. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_do_switch2(svn_ra_session_t *session, + const svn_ra_reporter3_t **reporter, + void **report_baton, + svn_revnum_t revision_to_switch_to, + const char *switch_target, + svn_depth_t depth, + const char *switch_url, + const svn_delta_editor_t *switch_editor, + void *switch_baton, + apr_pool_t *pool); + +/** + * Similar to svn_ra_do_switch2(), but taking @c svn_ra_reporter2_t + * instead of @c svn_ra_reporter3_t, and therefore only able to report + * @c svn_depth_infinity for depths. The switch itself is performed + * according to @a recurse: if TRUE, then use @c svn_depth_infinity + * for @a depth, else use @c svn_depth_files. + * + * @deprecated Provided for compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_do_switch(svn_ra_session_t *session, + const svn_ra_reporter2_t **reporter, + void **report_baton, + svn_revnum_t revision_to_switch_to, + const char *switch_target, + svn_boolean_t recurse, + const char *switch_url, + const svn_delta_editor_t *switch_editor, + void *switch_baton, + apr_pool_t *pool); + +/** + * Ask the RA layer to describe the status of a working copy with respect + * to @a revision of the repository (or HEAD, if @a revision is invalid). + * + * The client initially provides a @a status_editor/@a status_baton to the RA + * layer; this editor contains knowledge of where the change will + * begin in the working copy (when open_root() is called). + * + * In return, the client receives a @a reporter/@a report_baton. The + * client then describes its working copy by making calls into the + * @a reporter. + * + * When finished, the client calls @a reporter->finish_report(). The RA + * layer then does a complete drive of @a status_editor, ending with + * close_edit(), to report, essentially, what would be modified in + * the working copy were the client to call do_update(). + * @a status_target is an optional single path component will restrict + * the scope of the status report to an entry in the directory + * represented by the @a session's URL, or empty if the entire directory + * is meant to be examined. + * + * Get status only as deeply as @a depth indicates. + * + * The caller may not perform any RA operations using @a session + * before finishing the report, and may not perform any RA operations + * using @a session from within the editing operations of @a status_editor. + * + * Use @a pool for memory allocation. + * + * @note The reporter provided by this function does NOT supply copy- + * from information to the diff editor callbacks. + * + * @note In order to prevent pre-1.5 servers from doing more work than + * needed, and sending too much data back, a pre-1.5 'recurse' + * directive may be sent to the server, based on @a depth. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_do_status2(svn_ra_session_t *session, + const svn_ra_reporter3_t **reporter, + void **report_baton, + const char *status_target, + svn_revnum_t revision, + svn_depth_t depth, + const svn_delta_editor_t *status_editor, + void *status_baton, + apr_pool_t *pool); + + +/** + * Similar to svn_ra_do_status2(), but taking @c svn_ra_reporter2_t + * instead of @c svn_ra_reporter3_t, and therefore only able to report + * @c svn_depth_infinity for depths. The status operation itself is + * performed according to @a recurse: if TRUE, then @a depth is + * @c svn_depth_infinity, else it is @c svn_depth_immediates. + * + * @deprecated Provided for compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_do_status(svn_ra_session_t *session, + const svn_ra_reporter2_t **reporter, + void **report_baton, + const char *status_target, + svn_revnum_t revision, + svn_boolean_t recurse, + const svn_delta_editor_t *status_editor, + void *status_baton, + apr_pool_t *pool); + +/** + * Ask the RA layer to 'diff' a working copy against @a versus_url; + * it's another form of svn_ra_do_update2(). + * + * @note This function cannot be used to diff a single file, only a + * working copy directory. See the svn_ra_do_switch2() function + * for more details. + * + * The client initially provides a @a diff_editor/@a diff_baton to the RA + * layer; this editor contains knowledge of where the common diff + * root is in the working copy (when open_root() is called). + * + * In return, the client receives a @a reporter/@a report_baton. The + * client then describes its working copy by making calls into the + * @a reporter. + * + * When finished, the client calls @a reporter->finish_report(). The + * RA layer then does a complete drive of @a diff_editor, ending with + * close_edit(), to transmit the diff. + * + * @a diff_target is an optional single path component will restrict + * the scope of the diff to an entry in the directory represented by + * the @a session's URL, or empty if the entire directory is meant to be + * one of the diff paths. + * + * The working copy will be diffed against @a versus_url as it exists + * in revision @a revision, or as it is in head if @a revision is + * @c SVN_INVALID_REVNUM. + * + * Use @a ignore_ancestry to control whether or not items being + * diffed will be checked for relatedness first. Unrelated items + * are typically transmitted to the editor as a deletion of one thing + * and the addition of another, but if this flag is @c TRUE, + * unrelated items will be diffed as if they were related. + * + * Diff only as deeply as @a depth indicates. + * + * The caller may not perform any RA operations using @a session before + * finishing the report, and may not perform any RA operations using + * @a session from within the editing operations of @a diff_editor. + * + * @a text_deltas instructs the driver of the @a diff_editor to enable + * the generation of text deltas. If @a text_deltas is FALSE the window + * handler returned by apply_textdelta will be called once with a NULL + * @c svn_txdelta_window_t pointer. + * + * Use @a pool for memory allocation. + * + * @note The reporter provided by this function does NOT supply copy- + * from information to the diff editor callbacks. + * + * @note In order to prevent pre-1.5 servers from doing more work than + * needed, and sending too much data back, a pre-1.5 'recurse' + * directive may be sent to the server, based on @a depth. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_do_diff3(svn_ra_session_t *session, + const svn_ra_reporter3_t **reporter, + void **report_baton, + svn_revnum_t revision, + const char *diff_target, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + svn_boolean_t text_deltas, + const char *versus_url, + const svn_delta_editor_t *diff_editor, + void *diff_baton, + apr_pool_t *pool); + +/** + * Similar to svn_ra_do_diff3(), but taking @c svn_ra_reporter2_t + * instead of @c svn_ra_reporter3_t, and therefore only able to report + * @c svn_depth_infinity for depths. Perform the diff according to + * @a recurse: if TRUE, then @a depth is @c svn_depth_infinity, else + * it is @c svn_depth_files. + * + * @deprecated Provided for compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_do_diff2(svn_ra_session_t *session, + const svn_ra_reporter2_t **reporter, + void **report_baton, + svn_revnum_t revision, + const char *diff_target, + svn_boolean_t recurse, + svn_boolean_t ignore_ancestry, + svn_boolean_t text_deltas, + const char *versus_url, + const svn_delta_editor_t *diff_editor, + void *diff_baton, + apr_pool_t *pool); + + +/** + * Similar to svn_ra_do_diff2(), but with @a text_deltas set to @c TRUE. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_do_diff(svn_ra_session_t *session, + const svn_ra_reporter2_t **reporter, + void **report_baton, + svn_revnum_t revision, + const char *diff_target, + svn_boolean_t recurse, + svn_boolean_t ignore_ancestry, + const char *versus_url, + const svn_delta_editor_t *diff_editor, + void *diff_baton, + apr_pool_t *pool); + +/** + * Invoke @a receiver with @a receiver_baton on each log message from + * @a start to @a end. @a start may be greater or less than @a end; + * this just controls whether the log messages are processed in descending + * or ascending revision number order. + * + * If @a start or @a end is @c SVN_INVALID_REVNUM, it defaults to youngest. + * + * If @a paths is non-NULL and has one or more elements, then only show + * revisions in which at least one of @a paths was changed (i.e., if + * file, text or props changed; if dir, props changed or an entry + * was added or deleted). Each path is an const char *, relative + * to the @a session's common parent. + * + * If @a limit is non-zero only invoke @a receiver on the first @a limit + * logs. + * + * If @a discover_changed_paths, then each call to receiver passes a + * const apr_hash_t * for the receiver's @a changed_paths argument; + * the hash's keys are all the paths committed in that revision. + * Otherwise, each call to receiver passes NULL for @a changed_paths. + * + * If @a strict_node_history is set, copy history will not be traversed + * (if any exists) when harvesting the revision logs for each path. + * + * If @a include_merged_revisions is set, log information for revisions + * which have been merged to @a targets will also be returned. + * + * If @a revprops is NULL, retrieve all revprops; else, retrieve only the + * revprops named in the array (i.e. retrieve none if the array is empty). + * + * If any invocation of @a receiver returns error, return that error + * immediately and without wrapping it. + * + * If @a start or @a end is a non-existent revision, return the error + * @c SVN_ERR_FS_NO_SUCH_REVISION, without ever invoking @a receiver. + * + * See also the documentation for @c svn_log_message_receiver_t. + * + * The caller may not invoke any RA operations using @a session from + * within @a receiver. + * + * Use @a pool for memory allocation. + * + * @note If @a paths is NULL or empty, the result depends on the + * server. Pre-1.5 servers will send nothing; 1.5 servers will + * effectively perform the log operation on the root of the + * repository. This behavior may be changed in the future to ensure + * consistency across all pedigrees of server. + * + * @note Pre-1.5 servers do not support custom revprop retrieval; if @a + * revprops is NULL or contains a revprop other than svn:author, svn:date, + * or svn:log, an @c SVN_ERR_RA_NOT_IMPLEMENTED error is returned. + * + * @since New in 1.5. + */ + +svn_error_t * +svn_ra_get_log2(svn_ra_session_t *session, + const apr_array_header_t *paths, + svn_revnum_t start, + svn_revnum_t end, + int limit, + svn_boolean_t discover_changed_paths, + svn_boolean_t strict_node_history, + svn_boolean_t include_merged_revisions, + const apr_array_header_t *revprops, + svn_log_entry_receiver_t receiver, + void *receiver_baton, + apr_pool_t *pool); + +/** + * Similar to svn_ra_get_log2(), but uses @c svn_log_message_receiver_t + * instead of @c svn_log_entry_receiver_t. Also, @a + * include_merged_revisions is set to @c FALSE and @a revprops is + * svn:author, svn:date, and svn:log. + * + * @since New in 1.2. + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_get_log(svn_ra_session_t *session, + const apr_array_header_t *paths, + svn_revnum_t start, + svn_revnum_t end, + int limit, + svn_boolean_t discover_changed_paths, + svn_boolean_t strict_node_history, + svn_log_message_receiver_t receiver, + void *receiver_baton, + apr_pool_t *pool); + +/** + * Set @a *kind to the node kind associated with @a path at @a revision. + * If @a path does not exist under @a revision, set @a *kind to + * @c svn_node_none. @a path is relative to the @a session's parent URL. + * + * Use @a pool for memory allocation. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_check_path(svn_ra_session_t *session, + const char *path, + svn_revnum_t revision, + svn_node_kind_t *kind, + apr_pool_t *pool); + +/** + * Set @a *dirent to an @c svn_dirent_t associated with @a path at @a + * revision. @a path is relative to the @a session's parent's URL. + * If @a path does not exist in @a revision, set @a *dirent to NULL. + * + * Use @a pool for memory allocation. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_stat(svn_ra_session_t *session, + const char *path, + svn_revnum_t revision, + svn_dirent_t **dirent, + apr_pool_t *pool); + + +/** + * Set @a *uuid to the repository's UUID, allocated in @a pool. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_get_uuid2(svn_ra_session_t *session, + const char **uuid, + apr_pool_t *pool); + +/** + * Similar to svn_ra_get_uuid2(), but returns the value allocated in + * @a session's pool. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + * @since New in 1.2. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_get_uuid(svn_ra_session_t *session, + const char **uuid, + apr_pool_t *pool); + +/** + * Set @a *url to the repository's root URL, allocated in @a pool. + * The value will not include a trailing '/'. The returned URL is + * guaranteed to be a prefix of the @a session's URL. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_get_repos_root2(svn_ra_session_t *session, + const char **url, + apr_pool_t *pool); + + +/** + * Similar to svn_ra_get_repos_root2(), but returns the value + * allocated in @a session's pool. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + * @since New in 1.2. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_get_repos_root(svn_ra_session_t *session, + const char **url, + apr_pool_t *pool); + +/** + * Set @a *locations to the locations (at the repository revisions + * @a location_revisions) of the file identified by @a path in + * @a peg_revision. @a path is relative to the URL to which + * @a session was opened. @a location_revisions is an array of + * @c svn_revnum_t's. @a *locations will be a mapping from the revisions to + * their appropriate absolute paths. If the file doesn't exist in a + * location_revision, that revision will be ignored. + * + * Use @a pool for all allocations. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_get_locations(svn_ra_session_t *session, + apr_hash_t **locations, + const char *path, + svn_revnum_t peg_revision, + apr_array_header_t *location_revisions, + apr_pool_t *pool); + + +/** + * Call @a receiver (with @a receiver_baton) for each segment in the + * location history of @a path in @a peg_revision, working backwards in + * time from @a start_rev to @a end_rev. + * + * @a end_rev may be @c SVN_INVALID_REVNUM to indicate that you want + * to trace the history of the object to its origin. + * + * @a start_rev may be @c SVN_INVALID_REVNUM to indicate "the HEAD + * revision". Otherwise, @a start_rev must be younger than @a end_rev + * (unless @a end_rev is @c SVN_INVALID_REVNUM). + * + * @a peg_revision may be @c SVN_INVALID_REVNUM to indicate "the HEAD + * revision", and must evaluate to be at least as young as @a start_rev. + * + * Use @a pool for all allocations. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_get_location_segments(svn_ra_session_t *session, + const char *path, + svn_revnum_t peg_revision, + svn_revnum_t start_rev, + svn_revnum_t end_rev, + svn_location_segment_receiver_t receiver, + void *receiver_baton, + apr_pool_t *pool); + +/** + * Retrieve a subset of the interesting revisions of a file @a path + * as seen in revision @a end (see svn_fs_history_prev() for a + * definition of "interesting revisions"). Invoke @a handler with + * @a handler_baton as its first argument for each such revision. + * @a session is an open RA session. Use @a pool for all allocations. + * + * If there is an interesting revision of the file that is less than or + * equal to @a start, the iteration will begin at that revision. + * Else, the iteration will begin at the first revision of the file in + * the repository, which has to be less than or equal to @a end. Note + * that if the function succeeds, @a handler will have been called at + * least once. + * + * In a series of calls to @a handler, the file contents for the first + * interesting revision will be provided as a text delta against the + * empty file. In the following calls, the delta will be against the + * fulltext contents for the previous call. + * + * If @a include_merged_revisions is TRUE, revisions which a included as a + * result of a merge between @a start and @a end will be included. + * + * @note This functionality is not available in pre-1.1 servers. If the + * server doesn't implement it, an alternative (but much slower) + * implementation based on svn_ra_get_log2() is used. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_get_file_revs2(svn_ra_session_t *session, + const char *path, + svn_revnum_t start, + svn_revnum_t end, + svn_boolean_t include_merged_revisions, + svn_file_rev_handler_t handler, + void *handler_baton, + apr_pool_t *pool); + +/** + * Similiar to svn_ra_get_file_revs2(), but with @a include_merged_revisions + * set to FALSE. + * + * @since New in 1.2. + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_get_file_revs(svn_ra_session_t *session, + const char *path, + svn_revnum_t start, + svn_revnum_t end, + svn_ra_file_rev_handler_t handler, + void *handler_baton, + apr_pool_t *pool); + +/** + * Lock each path in @a path_revs, which is a hash whose keys are the + * paths to be locked, and whose values are the corresponding base + * revisions for each path. + * + * Note that locking is never anonymous, so any server implementing + * this function will have to "pull" a username from the client, if + * it hasn't done so already. + * + * @a comment is optional: it's either an xml-escapable string + * which describes the lock, or it is NULL. + * + * If any path is already locked by a different user, then call @a + * lock_func/@a lock_baton with an error. If @a steal_lock is TRUE, + * then "steal" the existing lock(s) anyway, even if the RA username + * does not match the current lock's owner. Delete any lock on the + * path, and unconditionally create a new lock. + * + * For each path, if its base revision (in @a path_revs) is a valid + * revnum, then do an out-of-dateness check. If the revnum is less + * than the last-changed-revision of any path (or if a path doesn't + * exist in HEAD), call @a lock_func/@a lock_baton with an + * SVN_ERR_RA_OUT_OF_DATE error. + * + * After successfully locking a file, @a lock_func is called with the + * @a lock_baton. + * + * Use @a pool for temporary allocations. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_lock(svn_ra_session_t *session, + apr_hash_t *path_revs, + const char *comment, + svn_boolean_t steal_lock, + svn_ra_lock_callback_t lock_func, + void *lock_baton, + apr_pool_t *pool); + +/** + * Remove the repository lock for each path in @a path_tokens. + * @a path_tokens is a hash whose keys are the paths to be locked, and + * whose values are the corresponding lock tokens for each path. If + * the path has no corresponding lock token, or if @a break_lock is TRUE, + * then the corresponding value shall be "". + * + * Note that unlocking is never anonymous, so any server + * implementing this function will have to "pull" a username from + * the client, if it hasn't done so already. + * + * If @a token points to a lock, but the RA username doesn't match the + * lock's owner, call @a lock_func/@a lock_baton with an error. If @a + * break_lock is TRUE, however, instead allow the lock to be "broken" + * by the RA user. + * + * After successfully unlocking a path, @a lock_func is called with + * the @a lock_baton. + * + * Use @a pool for temporary allocations. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_unlock(svn_ra_session_t *session, + apr_hash_t *path_tokens, + svn_boolean_t break_lock, + svn_ra_lock_callback_t lock_func, + void *lock_baton, + apr_pool_t *pool); + +/** + * If @a path is locked, set @a *lock to an svn_lock_t which + * represents the lock, allocated in @a pool. If @a path is not + * locked, set @a *lock to NULL. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_get_lock(svn_ra_session_t *session, + svn_lock_t **lock, + const char *path, + apr_pool_t *pool); + +/** + * Set @a *locks to a hashtable which represents all locks on or + * below @a path. + * + * The hashtable maps (const char *) absolute fs paths to (const + * svn_lock_t *) structures. The hashtable -- and all keys and + * values -- are allocated in @a pool. + * + * @note It is not considered an error for @a path to not exist in HEAD. + * Such a search will simply return no locks. + * + * @note This functionality is not available in pre-1.2 servers. If the + * server doesn't implement it, an @c SVN_ERR_RA_NOT_IMPLEMENTED error is + * returned. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_get_locks(svn_ra_session_t *session, + apr_hash_t **locks, + const char *path, + apr_pool_t *pool); + + +/** + * Replay the changes from a range of revisions between @a start_revision + * and @a end_revision. + * + * When receiving information for one revision, a callback @a revstart_func is + * called; this callback will provide an editor and baton through which the + * revision will be replayed. + * When replaying the revision is finished, callback @a revfinish_func will be + * called so the editor can be closed. + * + * Changes will be limited to those that occur under @a session's URL, and + * the server will assume that the client has no knowledge of revisions + * prior to @a low_water_mark. These two limiting factors define the portion + * of the tree that the server will assume the client already has knowledge of, + * and thus any copies of data from outside that part of the tree will be + * sent in their entirety, not as simple copies or deltas against a previous + * version. + * + * If @a send_deltas is @c TRUE, the actual text and property changes in + * the revision will be sent, otherwise dummy text deltas and NULL property + * changes will be sent instead. + * + * @a pool is used for all allocation. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_replay_range(svn_ra_session_t *session, + svn_revnum_t start_revision, + svn_revnum_t end_revision, + svn_revnum_t low_water_mark, + svn_boolean_t send_deltas, + svn_ra_replay_revstart_callback_t revstart_func, + svn_ra_replay_revfinish_callback_t revfinish_func, + void *replay_baton, + apr_pool_t *pool); + +/** + * Replay the changes from @a revision through @a editor and @a edit_baton. + * + * Changes will be limited to those that occur under @a session's URL, and + * the server will assume that the client has no knowledge of revisions + * prior to @a low_water_mark. These two limiting factors define the portion + * of the tree that the server will assume the client already has knowledge of, + * and thus any copies of data from outside that part of the tree will be + * sent in their entirety, not as simple copies or deltas against a previous + * version. + * + * If @a send_deltas is @c TRUE, the actual text and property changes in + * the revision will be sent, otherwise dummy text deltas and null property + * changes will be sent instead. + * + * @a pool is used for all allocation. + * + * @since New in 1.4. + */ +svn_error_t * +svn_ra_replay(svn_ra_session_t *session, + svn_revnum_t revision, + svn_revnum_t low_water_mark, + svn_boolean_t send_deltas, + const svn_delta_editor_t *editor, + void *edit_baton, + apr_pool_t *pool); + +/** + * Set @a *has to TRUE if the server represented by @a session has + * @a capability (one of the capabilities beginning with + * @c "SVN_RA_CAPABILITY_"), else set @a *has to FALSE. + * + * If @a capability isn't recognized, throw @c SVN_ERR_UNKNOWN_CAPABILITY, + * with the effect on @a *has undefined. + * + * Use @a pool for all allocation. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_has_capability(svn_ra_session_t *session, + svn_boolean_t *has, + const char *capability, + apr_pool_t *pool); + +/** + * Given @a path at revision @a peg_revision, set @a *revision_deleted to the + * revision @a path was first deleted, within the inclusive revision range + * defined by @a peg_revision and @a end_revision. @a path is relative + * to the URL in @a session. + * + * If @a path does not exist at @a peg_revision or was not deleted within + * the specified range, then set @a *revision_deleted to @c SVN_INVALID_REVNUM. + * If @a peg_revision or @a end_revision are invalid or if @a peg_revision is + * greater than @a end_revision, then return @c SVN_ERR_CLIENT_BAD_REVISION. + * + * Use @a pool for all allocations. + * + * @since New in 1.6. + */ +svn_error_t * +svn_ra_get_deleted_rev(svn_ra_session_t *session, + const char *path, + svn_revnum_t peg_revision, + svn_revnum_t end_revision, + svn_revnum_t *revision_deleted, + apr_pool_t *pool); + +/** + * The capability of understanding @c svn_depth_t (e.g., the server + * understands what the client means when the client describes the + * depth of a working copy to the server.) + * + * @since New in 1.5. + */ +#define SVN_RA_CAPABILITY_DEPTH "depth" + +/** + * The capability of doing the right thing with merge-tracking + * information. This capability should be reported bidirectionally, + * because some repositories may want to reject clients that do not + * self-report as knowing how to handle merge-tracking. + * + * @since New in 1.5. + */ +#define SVN_RA_CAPABILITY_MERGEINFO "mergeinfo" + +/** + * The capability of retrieving arbitrary revprops in svn_ra_get_log2. + * + * @since New in 1.5. + */ +#define SVN_RA_CAPABILITY_LOG_REVPROPS "log-revprops" + +/** + * The capability of replaying a directory in the repository (partial replay). + * + * @since New in 1.5. + */ +#define SVN_RA_CAPABILITY_PARTIAL_REPLAY "partial-replay" + +/** + * The capability of including revision properties in a commit. + * + * @since New in 1.5. + */ +#define SVN_RA_CAPABILITY_COMMIT_REVPROPS "commit-revprops" + +/* *** PLEASE READ THIS IF YOU ADD A NEW CAPABILITY *** + * + * RA layers generally fetch all capabilities when asked about any + * capability, to save future round trips. So if you add a new + * capability here, make sure to update the RA layers to remember + * it after any capabilities query. + * + * Also note that capability strings should not include colons, + * because we pass a list of client capabilities to the start-commit + * hook as a single, colon-separated string. + */ + +/** + * Append a textual list of all available RA modules to the stringbuf + * @a output. + * + * @since New in 1.2. + */ +svn_error_t * +svn_ra_print_modules(svn_stringbuf_t *output, + apr_pool_t *pool); + + +/** + * Similar to svn_ra_print_modules(). + * @a ra_baton is ignored. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_print_ra_libraries(svn_stringbuf_t **descriptions, + void *ra_baton, + apr_pool_t *pool); + + + +/** + * Using this callback struct is similar to calling the newer public + * interface that is based on @c svn_ra_session_t. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +typedef struct svn_ra_plugin_t +{ + /** The proper name of the RA library, (like "ra_neon" or "ra_local") */ + const char *name; + + /** Short doc string printed out by `svn --version` */ + const char *description; + + /* The vtable hooks */ + + /** Call svn_ra_open() and set @a session_baton to an object representing + * the new session. All other arguments are passed to svn_ra_open(). + */ + svn_error_t *(*open)(void **session_baton, + const char *repos_URL, + const svn_ra_callbacks_t *callbacks, + void *callback_baton, + apr_hash_t *config, + apr_pool_t *pool); + + /** Call svn_ra_get_latest_revnum() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*get_latest_revnum)(void *session_baton, + svn_revnum_t *latest_revnum, + apr_pool_t *pool); + + /** Call svn_ra_get_dated_revision() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*get_dated_revision)(void *session_baton, + svn_revnum_t *revision, + apr_time_t tm, + apr_pool_t *pool); + + /** Call svn_ra_change_rev_prop() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*change_rev_prop)(void *session_baton, + svn_revnum_t rev, + const char *name, + const svn_string_t *value, + apr_pool_t *pool); + + /** Call svn_ra_rev_proplist() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*rev_proplist)(void *session_baton, + svn_revnum_t rev, + apr_hash_t **props, + apr_pool_t *pool); + + /** Call svn_ra_rev_prop() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*rev_prop)(void *session_baton, + svn_revnum_t rev, + const char *name, + svn_string_t **value, + apr_pool_t *pool); + + /** Call svn_ra_get_commit_editor() with the session associated with + * @a session_baton and all other arguments plus @a lock_tokens set to + * @c NULL and @a keep_locks set to @c TRUE. + */ + svn_error_t *(*get_commit_editor)(void *session_baton, + const svn_delta_editor_t **editor, + void **edit_baton, + const char *log_msg, + svn_commit_callback_t callback, + void *callback_baton, + apr_pool_t *pool); + + /** Call svn_ra_get_file() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*get_file)(void *session_baton, + const char *path, + svn_revnum_t revision, + svn_stream_t *stream, + svn_revnum_t *fetched_rev, + apr_hash_t **props, + apr_pool_t *pool); + + /** Call svn_ra_get_dir() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*get_dir)(void *session_baton, + const char *path, + svn_revnum_t revision, + apr_hash_t **dirents, + svn_revnum_t *fetched_rev, + apr_hash_t **props, + apr_pool_t *pool); + + /** Call svn_ra_do_update() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*do_update)(void *session_baton, + const svn_ra_reporter_t **reporter, + void **report_baton, + svn_revnum_t revision_to_update_to, + const char *update_target, + svn_boolean_t recurse, + const svn_delta_editor_t *update_editor, + void *update_baton, + apr_pool_t *pool); + + /** Call svn_ra_do_switch() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*do_switch)(void *session_baton, + const svn_ra_reporter_t **reporter, + void **report_baton, + svn_revnum_t revision_to_switch_to, + const char *switch_target, + svn_boolean_t recurse, + const char *switch_url, + const svn_delta_editor_t *switch_editor, + void *switch_baton, + apr_pool_t *pool); + + /** Call svn_ra_do_status() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*do_status)(void *session_baton, + const svn_ra_reporter_t **reporter, + void **report_baton, + const char *status_target, + svn_revnum_t revision, + svn_boolean_t recurse, + const svn_delta_editor_t *status_editor, + void *status_baton, + apr_pool_t *pool); + + /** Call svn_ra_do_diff() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*do_diff)(void *session_baton, + const svn_ra_reporter_t **reporter, + void **report_baton, + svn_revnum_t revision, + const char *diff_target, + svn_boolean_t recurse, + svn_boolean_t ignore_ancestry, + const char *versus_url, + const svn_delta_editor_t *diff_editor, + void *diff_baton, + apr_pool_t *pool); + + /** Call svn_ra_get_log() with the session associated with + * @a session_baton and all other arguments. @a limit is set to 0. + */ + svn_error_t *(*get_log)(void *session_baton, + const apr_array_header_t *paths, + svn_revnum_t start, + svn_revnum_t end, + svn_boolean_t discover_changed_paths, + svn_boolean_t strict_node_history, + svn_log_message_receiver_t receiver, + void *receiver_baton, + apr_pool_t *pool); + + /** Call svn_ra_check_path() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*check_path)(void *session_baton, + const char *path, + svn_revnum_t revision, + svn_node_kind_t *kind, + apr_pool_t *pool); + + /** Call svn_ra_get_uuid() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*get_uuid)(void *session_baton, + const char **uuid, + apr_pool_t *pool); + + /** Call svn_ra_get_repos_root() with the session associated with + * @a session_baton and all other arguments. + */ + svn_error_t *(*get_repos_root)(void *session_baton, + const char **url, + apr_pool_t *pool); + + /** + * Call svn_ra_get_locations() with the session associated with + * @a session_baton and all other arguments. + * + * @since New in 1.1. + */ + svn_error_t *(*get_locations)(void *session_baton, + apr_hash_t **locations, + const char *path, + svn_revnum_t peg_revision, + apr_array_header_t *location_revisions, + apr_pool_t *pool); + + /** + * Call svn_ra_get_file_revs() with the session associated with + * @a session_baton and all other arguments. + * + * @since New in 1.1. + */ + svn_error_t *(*get_file_revs)(void *session_baton, + const char *path, + svn_revnum_t start, + svn_revnum_t end, + svn_ra_file_rev_handler_t handler, + void *handler_baton, + apr_pool_t *pool); + + /** + * Return the plugin's version information. + * + * @since New in 1.1. + */ + const svn_version_t *(*get_version)(void); + + +} svn_ra_plugin_t; + +/** + * All "ra_FOO" implementations *must* export a function named + * svn_ra_FOO_init() of type @c svn_ra_init_func_t. + * + * When called by libsvn_client, this routine adds an entry (or + * entries) to the hash table for any URL schemes it handles. The hash + * value must be of type (@c svn_ra_plugin_t *). @a pool is a + * pool for allocating configuration / one-time data. + * + * This type is defined to use the "C Calling Conventions" to ensure that + * abi_version is the first parameter. The RA plugin must check that value + * before accessing the other parameters. + * + * ### need to force this to be __cdecl on Windows... how?? + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +typedef svn_error_t *(*svn_ra_init_func_t)(int abi_version, + apr_pool_t *pool, + apr_hash_t *hash); + +/** + * The current ABI (Application Binary Interface) version for the + * RA plugin model. This version number will change when the ABI + * between the SVN core (e.g. libsvn_client) and the RA plugin changes. + * + * An RA plugin should verify that the passed version number is acceptable + * before accessing the rest of the parameters, and before returning any + * information. + * + * It is entirely acceptable for an RA plugin to accept multiple ABI + * versions. It can simply interpret the parameters based on the version, + * and it can return different plugin structures. + * + * + *
+ * VSN  DATE        REASON FOR CHANGE
+ * ---  ----------  ------------------------------------------------
+ *   1  2001-02-17  Initial revision.
+ *   2  2004-06-29  Preparing for svn 1.1, which adds new RA vtable funcs.
+ *      2005-01-19  Rework the plugin interface and don't provide the vtable
+ *                  to the client.  Separate ABI versions are no longer used.
+ * 
+ * + * @deprecated Provided for backward compatibility with the 1.0 API. + */ +#define SVN_RA_ABI_VERSION 2 + +/* Public RA implementations. */ + +/** Initialize libsvn_ra_neon. + * + * @deprecated Provided for backward compatibility with the 1.1 API. */ +SVN_DEPRECATED +svn_error_t * +svn_ra_dav_init(int abi_version, + apr_pool_t *pool, + apr_hash_t *hash); + +/** Initialize libsvn_ra_local. + * + * @deprecated Provided for backward compatibility with the 1.1 API. */ +SVN_DEPRECATED +svn_error_t * +svn_ra_local_init(int abi_version, + apr_pool_t *pool, + apr_hash_t *hash); + +/** Initialize libsvn_ra_svn. + * + * @deprecated Provided for backward compatibility with the 1.1 API. */ +SVN_DEPRECATED +svn_error_t * +svn_ra_svn_init(int abi_version, + apr_pool_t *pool, + apr_hash_t *hash); + +/** Initialize libsvn_ra_serf. + * + * @since New in 1.4. + * @deprecated Provided for backward compatibility with the 1.1 API. */ +SVN_DEPRECATED +svn_error_t * +svn_ra_serf_init(int abi_version, + apr_pool_t *pool, + apr_hash_t *hash); + + +/** + * Initialize the compatibility wrapper, using @a pool for any allocations. + * The caller must hold on to @a ra_baton as long as the RA library is used. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_init_ra_libs(void **ra_baton, + apr_pool_t *pool); + +/** + * Return an RA vtable-@a library which can handle URL. A number of + * svn_client_* routines will call this internally, but client apps might + * use it too. $a ra_baton is a baton obtained by a call to + * svn_ra_init_ra_libs(). + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_get_ra_library(svn_ra_plugin_t **library, + void *ra_baton, + const char *url, + apr_pool_t *pool); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_RA_H */ + diff --git a/src/TortoiseMerge/svninclude/svn_ra_svn.h b/src/TortoiseMerge/svninclude/svn_ra_svn.h new file mode 100644 index 0000000..6171dd9 --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_ra_svn.h @@ -0,0 +1,495 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2006, 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_ra_svn.h + * @brief libsvn_ra_svn functions used by the server + */ + +#ifndef SVN_RA_SVN_H +#define SVN_RA_SVN_H + +#include +#include +#include +#include +#include /* for apr_file_t */ +#include /* for apr_socket_t */ + +#include "svn_types.h" +#include "svn_string.h" +#include "svn_config.h" +#include "svn_delta.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** The well-known svn port number. */ +#define SVN_RA_SVN_PORT 3690 + +/** Currently-defined capabilities. */ +#define SVN_RA_SVN_CAP_EDIT_PIPELINE "edit-pipeline" +#define SVN_RA_SVN_CAP_SVNDIFF1 "svndiff1" +#define SVN_RA_SVN_CAP_ABSENT_ENTRIES "absent-entries" +/* maps to SVN_RA_CAPABILITY_COMMIT_REVPROPS: */ +#define SVN_RA_SVN_CAP_COMMIT_REVPROPS "commit-revprops" +/* maps to SVN_RA_CAPABILITY_MERGEINFO: */ +#define SVN_RA_SVN_CAP_MERGEINFO "mergeinfo" +/* maps to SVN_RA_CAPABILITY_DEPTH: */ +#define SVN_RA_SVN_CAP_DEPTH "depth" +/* maps to SVN_RA_CAPABILITY_LOG_REVPROPS */ +#define SVN_RA_SVN_CAP_LOG_REVPROPS "log-revprops" +/* maps to SVN_RA_CAPABILITY_PARTIAL_REPLAY */ +#define SVN_RA_SVN_CAP_PARTIAL_REPLAY "partial-replay" + +/** ra_svn passes @c svn_dirent_t fields over the wire as a list of + * words, these are the values used to represent each field. + * + * @defgroup ra_svn_dirent_fields Definitions of ra_svn dirent fields + * @{ + */ + +/** The ra_svn way of saying @c SVN_DIRENT_KIND. */ +#define SVN_RA_SVN_DIRENT_KIND "kind" + +/** The ra_svn way of saying @c SVN_DIRENT_SIZE. */ +#define SVN_RA_SVN_DIRENT_SIZE "size" + +/** The ra_svn way of saying @c SVN_DIRENT_HAS_PROPS. */ +#define SVN_RA_SVN_DIRENT_HAS_PROPS "has-props" + +/** The ra_svn way of saying @c SVN_DIRENT_CREATED_REV. */ +#define SVN_RA_SVN_DIRENT_CREATED_REV "created-rev" + +/** The ra_svn way of saying @c SVN_DIRENT_TIME. */ +#define SVN_RA_SVN_DIRENT_TIME "time" + +/** The ra_svn way of saying @c SVN_DIRENT_LAST_AUTHOR. */ +#define SVN_RA_SVN_DIRENT_LAST_AUTHOR "last-author" + +/** @} */ + +/** A value used to indicate an optional number element in a tuple that was + * not received. + */ +#define SVN_RA_SVN_UNSPECIFIED_NUMBER ~((apr_uint64_t) 0) + +/** A specialized form of @c SVN_ERR to deal with errors which occur in an + * svn_ra_svn_command_handler(). + * + * An error returned with this macro will be passed back to the other side + * of the connection. Use this macro when performing the requested operation; + * use the regular @c SVN_ERR when performing I/O with the client. + */ +#define SVN_CMD_ERR(expr) \ + do { \ + svn_error_t *svn_err__temp = (expr); \ + if (svn_err__temp) \ + return svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, \ + svn_err__temp, NULL); \ + } while (0) + +/** an ra_svn connection. */ +typedef struct svn_ra_svn_conn_st svn_ra_svn_conn_t; + +/** Command handler, used by svn_ra_svn_handle_commands(). */ +typedef svn_error_t *(*svn_ra_svn_command_handler)(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + apr_array_header_t *params, + void *baton); + +/** Command table, used by svn_ra_svn_handle_commands(). + */ +typedef struct svn_ra_svn_cmd_entry_t +{ + /** Name of the command */ + const char *cmdname; + + /** Handler for the command */ + svn_ra_svn_command_handler handler; + + /** Termination flag. If set, command-handling will cease after + * command is processed. */ + svn_boolean_t terminate; +} svn_ra_svn_cmd_entry_t; + +/** Memory representation of an on-the-wire data item. */ +typedef struct svn_ra_svn_item_t +{ + /** Variant indicator. */ + enum { + SVN_RA_SVN_NUMBER, + SVN_RA_SVN_STRING, + SVN_RA_SVN_WORD, + SVN_RA_SVN_LIST + } kind; + /** Variant data. */ + union { + apr_uint64_t number; + svn_string_t *string; + const char *word; + + /** Contains @c svn_ra_svn_item_t's. */ + apr_array_header_t *list; + } u; +} svn_ra_svn_item_t; + +typedef svn_error_t *(*svn_ra_svn_edit_callback)(void *baton); + +/** Initialize a connection structure for the given socket or + * input/output files. + * + * Either @a sock or @a in_file/@a out_file must be set, not both. + */ +svn_ra_svn_conn_t * +svn_ra_svn_create_conn(apr_socket_t *sock, + apr_file_t *in_file, + apr_file_t *out_file, + apr_pool_t *pool); + +/** Add the capabilities in @a list to @a conn's capabilities. + * @a list contains svn_ra_svn_item_t entries (which should be of type + * SVN_RA_SVN_WORD; a malformed data error will result if any are not). + * + * This is idempotent: if a given capability was already set for + * @a conn, it remains set. + */ +svn_error_t * +svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn, + apr_array_header_t *list); + +/** Return @c TRUE if @a conn has the capability @a capability, or + * @c FALSE if it does not. */ +svn_boolean_t +svn_ra_svn_has_capability(svn_ra_svn_conn_t *conn, + const char *capability); + +/** Returns the remote address of the connection as a string, if known, + * or NULL if inapplicable. */ +const char * +svn_ra_svn_conn_remote_host(svn_ra_svn_conn_t *conn); + +/** Write a number over the net. + * + * Writes will be buffered until the next read or flush. + */ +svn_error_t * +svn_ra_svn_write_number(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + apr_uint64_t number); + +/** Write a string over the net. + * + * Writes will be buffered until the next read or flush. + */ +svn_error_t * +svn_ra_svn_write_string(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const svn_string_t *str); + +/** Write a cstring over the net. + * + * Writes will be buffered until the next read or flush. + */ +svn_error_t * +svn_ra_svn_write_cstring(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *s); + +/** Write a word over the net. + * + * Writes will be buffered until the next read or flush. + */ +svn_error_t * +svn_ra_svn_write_word(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *word); + +/** Write a list of properties over the net. @a props is allowed to be NULL, + * in which case an empty list will be written out. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_svn_write_proplist(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + apr_hash_t *props); + +/** Begin a list. Writes will be buffered until the next read or flush. */ +svn_error_t * +svn_ra_svn_start_list(svn_ra_svn_conn_t *conn, + apr_pool_t *pool); + +/** End a list. Writes will be buffered until the next read or flush. */ +svn_error_t * +svn_ra_svn_end_list(svn_ra_svn_conn_t *conn, + apr_pool_t *pool); + +/** Flush the write buffer. + * + * Normally this shouldn't be necessary, since the write buffer is flushed + * when a read is attempted. + */ +svn_error_t * +svn_ra_svn_flush(svn_ra_svn_conn_t *conn, + apr_pool_t *pool); + +/** Write a tuple, using a printf-like interface. + * + * The format string @a fmt may contain: + * + *@verbatim + Spec Argument type Item type + ---- -------------------- --------- + n apr_uint64_t Number + r svn_revnum_t Number + s const svn_string_t * String + c const char * String + w const char * Word + b svn_boolean_t Word ("true" or "false") + ( Begin tuple + ) End tuple + ? Remaining elements optional + ! (at beginning or end) Suppress opening or closing of tuple + @endverbatim + * + * Inside the optional part of a tuple, 'r' values may be @c + * SVN_INVALID_REVNUM, 'n' values may be + * SVN_RA_SVN_UNSPECIFIED_NUMBER, and 's', 'c', and 'w' values may be + * @c NULL; in these cases no data will be written. 'b' and '(' may + * not appear in the optional part of a tuple. Either all or none of + * the optional values should be valid. + * + * (If we ever have a need for an optional boolean value, we should + * invent a 'B' specifier which stores a boolean into an int, using -1 + * for unspecified. Right now there is no need for such a thing.) + * + * Use the '!' format specifier to write partial tuples when you have + * to transmit an array or other unusual data. For example, to write + * a tuple containing a revision, an array of words, and a boolean: + * @verbatim + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "r(!", rev)); + for (i = 0; i < n; i++) + SVN_ERR(svn_ra_svn_write_word(conn, pool, words[i])); + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!)b", flag)); @endverbatim + */ +svn_error_t * +svn_ra_svn_write_tuple(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *fmt, ...); + +/** Read an item from the network into @a *item. */ +svn_error_t * +svn_ra_svn_read_item(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_ra_svn_item_t **item); + +/** Scan data on @a conn until we find something which looks like the + * beginning of an svn server greeting (an open paren followed by a + * whitespace character). This function is appropriate for beginning + * a client connection opened in tunnel mode, since people's dotfiles + * sometimes write output to stdout. It may only be called at the + * beginning of a client connection. + */ +svn_error_t * +svn_ra_svn_skip_leading_garbage(svn_ra_svn_conn_t *conn, + apr_pool_t *pool); + +/** Parse an array of @c svn_sort__item_t structures as a tuple, using a + * printf-like interface. The format string @a fmt may contain: + * + *@verbatim + Spec Argument type Item type + ---- -------------------- --------- + n apr_uint64_t * Number + r svn_revnum_t * Number + s svn_string_t ** String + c const char ** String + w const char ** Word + b svn_boolean_t * Word ("true" or "false") + B apr_uint64_t * Word ("true" or "false") + l apr_array_header_t ** List + ( Begin tuple + ) End tuple + ? Tuple is allowed to end here + @endverbatim + * + * Note that a tuple is only allowed to end precisely at a '?', or at + * the end of the specification. So if @a fmt is "c?cc" and @a list + * contains two elements, an error will result. + * + * 'B' is similar to 'b', but may be used in the optional tuple specification. + * It returns TRUE, FALSE, or SVN_RA_SVN_UNSPECIFIED_NUMBER. + * + * If an optional part of a tuple contains no data, 'r' values will be + * set to @c SVN_INVALID_REVNUM, 'n' and 'B' values will be set to + * SVN_RA_SVN_UNSPECIFIED_NUMBER, and 's', 'c', 'w', and 'l' values + * will be set to @c NULL. 'b' may not appear inside an optional + * tuple specification; use 'B' instead. + */ +svn_error_t * +svn_ra_svn_parse_tuple(apr_array_header_t *list, + apr_pool_t *pool, + const char *fmt, ...); + +/** Read a tuple from the network and parse it as a tuple, using the + * format string notation from svn_ra_svn_parse_tuple(). + */ +svn_error_t * +svn_ra_svn_read_tuple(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *fmt, ...); + +/** Parse an array of @c svn_ra_svn_item_t structures as a list of + * properties, storing the properties in a hash table. + * + * @since New in 1.5. + */ +svn_error_t * +svn_ra_svn_parse_proplist(apr_array_header_t *list, + apr_pool_t *pool, + apr_hash_t **props); + +/** Read a command response from the network and parse it as a tuple, using + * the format string notation from svn_ra_svn_parse_tuple(). + */ +svn_error_t * +svn_ra_svn_read_cmd_response(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *fmt, ...); + +/** Accept commands over the network and handle them according to @a + * commands. Command handlers will be passed @a conn, a subpool of @a + * pool (cleared after each command is handled), the parameters of the + * command, and @a baton. Commands will be accepted until a + * terminating command is received (a command with "terminate" set in + * the command table). If a command handler returns an error wrapped + * in SVN_RA_SVN_CMD_ERR (see the @c SVN_CMD_ERR macro), the error + * will be reported to the other side of the connection and the + * command loop will continue; any other kind of error (typically a + * network or protocol error) is passed through to the caller. + * + * @since New in 1.6. + * + */ +svn_error_t * +svn_ra_svn_handle_commands2(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const svn_ra_svn_cmd_entry_t *commands, + void *baton, + svn_boolean_t error_on_disconnect); + +/** Similar to svn_ra_svn_handle_commands2 but @a error_on_disconnect + * is always @c FALSE. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_ra_svn_handle_commands(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const svn_ra_svn_cmd_entry_t *commands, + void *baton); + +/** Write a command over the network, using the same format string notation + * as svn_ra_svn_write_tuple(). + */ +svn_error_t * +svn_ra_svn_write_cmd(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *cmdname, + const char *fmt, ...); + +/** Write a successful command response over the network, using the + * same format string notation as svn_ra_svn_write_tuple(). Do not use + * partial tuples with this function; if you need to use partial + * tuples, just write out the "success" and argument tuple by hand. + */ +svn_error_t * +svn_ra_svn_write_cmd_response(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const char *fmt, ...); + +/** Write an unsuccessful command response over the network. */ +svn_error_t * +svn_ra_svn_write_cmd_failure(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_error_t *err); + +/** Set @a *editor and @a *edit_baton to an editor which will pass editing + * operations over the network, using @a conn and @a pool. + * + * Upon successful completion of the edit, the editor will invoke @a callback + * with @a callback_baton as an argument. + */ +void +svn_ra_svn_get_editor(const svn_delta_editor_t **editor, + void **edit_baton, + svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_ra_svn_edit_callback callback, + void *callback_baton); + +/** Receive edit commands over the network and use them to drive @a editor + * with @a edit_baton. On return, @a *aborted will be set if the edit was + * aborted. The drive can be terminated with a finish-replay command only + * if @a for_replay is TRUE. + */ +svn_error_t * +svn_ra_svn_drive_editor2(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const svn_delta_editor_t *editor, + void *edit_baton, + svn_boolean_t *aborted, + svn_boolean_t for_replay); + +/** Like svn_ra_svn_drive_editor2, but with @a for_replay always FALSE. + */ +svn_error_t * +svn_ra_svn_drive_editor(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + const svn_delta_editor_t *editor, + void *edit_baton, + svn_boolean_t *aborted); + +/** This function is only intended for use by svnserve. + * + * Perform CRAM-MD5 password authentication. On success, return + * SVN_NO_ERROR with *user set to the username and *success set to + * TRUE. On an error which can be reported to the client, report the + * error and return SVN_NO_ERROR with *success set to FALSE. On + * communications failure, return an error. + */ +svn_error_t * +svn_ra_svn_cram_server(svn_ra_svn_conn_t *conn, + apr_pool_t *pool, + svn_config_t *pwdb, + const char **user, + svn_boolean_t *success); + +/** + * Get libsvn_ra_svn version information. + * @since New in 1.1. + */ +const svn_version_t * +svn_ra_svn_version(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_RA_SVN_H */ diff --git a/src/TortoiseMerge/svninclude/svn_types.h b/src/TortoiseMerge/svninclude/svn_types.h index 2d80051..99dedb5 100644 --- a/src/TortoiseMerge/svninclude/svn_types.h +++ b/src/TortoiseMerge/svninclude/svn_types.h @@ -25,20 +25,20 @@ /* ### this should go away, but it causes too much breakage right now */ #include -#include /* for apr_size_t */ -#include -#include -#include -#include -#include -#include - +#include /* for apr_size_t, apr_int64_t, ... */ +#include /* for apr_status_t */ +#include /* for apr_pool_t */ +#include /* for apr_hash_t */ +#include /* for apr_array_push() */ +#include /* for apr_time_t */ +#include /* for apr_atoi64() */ + +#define _(x) x +#define N_(x) x #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -//porting -typedef int svn_version_t; /** Macro used to mark deprecated functions. @@ -78,7 +78,7 @@ typedef struct svn_error_t struct svn_error_t *child; /** The pool holding this error and any child errors it wraps */ - //apr_pool_t *pool; + apr_pool_t *pool; /** Source file where the error originated. Only used iff @c SVN_DEBUG. */ const char *file; @@ -124,6 +124,25 @@ typedef enum svn_node_unknown } svn_node_kind_t; +/** Return a constant string expressing @a kind as an English word, e.g., + * "file", "dir", etc. The string is not localized, as it may be used for + * client<->server communications. If the kind is not recognized, return + * "unknown". + * + * @since New in 1.6. + */ +const char * +svn_node_kind_to_word(svn_node_kind_t kind); + +/** Return the appropriate node_kind for @a word. @a word is as + * returned from svn_node_kind_to_word(). If @a word does not + * represent a recognized kind or is @c NULL, return @c svn_node_unknown. + * + * @since New in 1.6. + */ +svn_node_kind_t +svn_node_kind_from_word(const char *word); + /** About Special Files in Subversion * * Subversion denotes files that cannot be portably created or @@ -413,7 +432,7 @@ typedef struct svn_dirent_t svn_revnum_t created_rev; /** time of created_rev (mod-time) */ - //apr_time_t time; + apr_time_t time; /** author of created_rev */ const char *last_author; @@ -430,6 +449,7 @@ svn_dirent_t * svn_dirent_dup(const svn_dirent_t *dirent, apr_pool_t *pool); + /** Keyword substitution. * @@ -501,6 +521,10 @@ svn_dirent_dup(const svn_dirent_t *dirent, /** A compressed combination of the other four keywords. */ #define SVN_KEYWORD_ID "Id" +/** A full combination of the first four keywords. + * @since New in 1.6. */ +#define SVN_KEYWORD_HEADER "Header" + /** @} */ @@ -556,7 +580,62 @@ svn_commit_info_dup(const svn_commit_info_t *src_commit_info, apr_pool_t *pool); -/** A structure to represent a path that changed for a log entry. */ +/** + * A structure to represent a path that changed for a log entry. + * + * @note To allow for extending the @c svn_log_changed_path2_t structure in + * future releases, always use svn_log_changed_path2_create() to allocate + * the structure. + * + * @since New in 1.6. + */ +typedef struct svn_log_changed_path2_t +{ + /** 'A'dd, 'D'elete, 'R'eplace, 'M'odify */ + char action; + + /** Source path of copy (if any). */ + const char *copyfrom_path; + + /** Source revision of copy (if any). */ + svn_revnum_t copyfrom_rev; + + /** The type of the node, may be svn_node_unknown. */ + svn_node_kind_t node_kind; + + /* NOTE: Add new fields at the end to preserve binary compatibility. + Also, if you add fields here, you have to update + svn_log_changed_path2_dup(). */ +} svn_log_changed_path2_t; + +/** + * Returns an @c svn_log_changed_path2_t, allocated in @a pool with all fields + * initialized to NULL, None or empty values. + * + * @note To allow for extending the @c svn_log_changed_path2_t structure in + * future releases, this function should always be used to allocate the + * structure. + * + * @since New in 1.6. + */ +svn_log_changed_path2_t * +svn_log_changed_path2_create(apr_pool_t *pool); + +/** + * Return a deep copy of @a changed_path, allocated in @a pool. + * + * @since New in 1.6. + */ +svn_log_changed_path2_t * +svn_log_changed_path2_dup(const svn_log_changed_path2_t *changed_path, + apr_pool_t *pool); + +/** + * A structure to represent a path that changed for a log entry. Same as + * @c svn_log_changed_path2_t, but without the node kind. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ typedef struct svn_log_changed_path_t { /** 'A'dd, 'D'elete, 'R'eplace, 'M'odify */ @@ -575,7 +654,9 @@ typedef struct svn_log_changed_path_t * Return a deep copy of @a changed_path, allocated in @a pool. * * @since New in 1.3. + * @deprecated Provided for backward compatibility with the 1.5 API. */ +SVN_DEPRECATED svn_log_changed_path_t * svn_log_changed_path_dup(const svn_log_changed_path_t *changed_path, apr_pool_t *pool); @@ -585,27 +666,27 @@ svn_log_changed_path_dup(const svn_log_changed_path_t *changed_path, * * @note To allow for extending the @c svn_log_entry_t structure in future * releases, always use svn_log_entry_create() to allocate the structure. + * + * @since New in 1.5. */ typedef struct svn_log_entry_t { /** A hash containing as keys every path committed in @a revision; the * values are (@c svn_log_changed_path_t *) stuctures. * - * ### The only reason @a changed_paths is not qualified with `const' is - * that we usually want to loop over it, and apr_hash_first() doesn't - * take a const hash, for various reasons. I'm not sure that those - * "various reasons" are actually even relevant anymore, and if - * they're not, it might be nice to change apr_hash_first() so - * read-only uses of hashes can be protected via the type system. + * The subversion core libraries will always set this field to the same + * value as changed_paths2 for compatibity reasons. + * + * @deprecated Provided for backward compatibility with the 1.5 API. */ - //apr_hash_t *changed_paths; + apr_hash_t *changed_paths; /** The revision of the commit. */ svn_revnum_t revision; /** The hash of requested revision properties, which may be NULL if it * would contain no revprops. */ -// apr_hash_t *revprops; + apr_hash_t *revprops; /** * Whether or not this message has children. @@ -624,6 +705,24 @@ typedef struct svn_log_entry_t * http://subversion.tigris.org/merge-tracking/design.html#commutative-reporting */ svn_boolean_t has_children; + + /** A hash containing as keys every path committed in @a revision; the + * values are (@c svn_log_changed_path2_t *) stuctures. + * + * If this value is not @c NULL, it MUST have the same value as + * changed_paths or svn_log_entry_dup() will not create an identical copy. + * + * The subversion core libraries will always set this field to the same + * value as changed_paths for compatibity with users assuming an older + * version. + * + * @since New in 1.6. + */ + apr_hash_t *changed_paths2; + + /* NOTE: Add new fields at the end to preserve binary compatibility. + Also, if you add fields here, you have to update + svn_log_entry_dup(). */ } svn_log_entry_t; /** @@ -638,6 +737,17 @@ typedef struct svn_log_entry_t svn_log_entry_t * svn_log_entry_create(apr_pool_t *pool); +/** Return a deep copy of @a log_entry, allocated in @a pool. + * + * The resulting svn_log_entry_t has @c changed_paths set to the same + * value as @c changed_path2. @c changed_paths will be @c NULL if + * @c changed_paths2 was @c NULL. + * + * @since New in 1.6. + */ +svn_log_entry_t * +svn_log_entry_dup(svn_log_entry_t *log_entry, apr_pool_t *pool); + /** The callback invoked by log message loopers, such as * @c svn_ra_plugin_t.get_log() and svn_repos_get_logs(). * @@ -940,4 +1050,19 @@ svn_location_segment_dup(svn_location_segment_t *segment, } #endif /* __cplusplus */ + +/* + * Everybody and their brother needs to deal with svn_error_t, the error + * codes, and whatever else. While they *should* go and include svn_error.h + * in order to do that... bah. Let's just help everybody out and include + * that header whenever somebody grabs svn_types.h. + * + * Note that we do this at the END of this header so that its contents + * are available to svn_error.h (our guards will prevent the circular + * include). We also need to do the include *outside* of the cplusplus + * guard. + */ +#include "svn_error.h" + + #endif /* SVN_TYPES_H */ diff --git a/src/TortoiseMerge/svninclude/svn_utf.h b/src/TortoiseMerge/svninclude/svn_utf.h new file mode 100644 index 0000000..3a3b0ac --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_utf.h @@ -0,0 +1,221 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2004, 2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_utf.h + * @brief UTF-8 conversion routines + * Whenever a conversion routine cannot convert to or from UTF-8, the + * error returned has code @c APR_EINVAL. + */ + + + +#ifndef SVN_UTF_H +#define SVN_UTF_H + +#include +#include /* for APR_*_CHARSET */ + +#include "svn_types.h" +#include "svn_string.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define SVN_APR_LOCALE_CHARSET APR_LOCALE_CHARSET +#define SVN_APR_DEFAULT_CHARSET APR_DEFAULT_CHARSET + +/** + * Initialize the UTF-8 encoding/decoding routines. + * Allocate cached translation handles in a subpool of @a pool. + * + * @note It is optional to call this function, but if it is used, no other + * svn function may be in use in other threads during the call of this + * function or when @a pool is cleared or destroyed. + * Initializing the UTF-8 routines will improve performance. + * + * @since New in 1.1. + */ +void +svn_utf_initialize(apr_pool_t *pool); + +/** Set @a *dest to a utf8-encoded stringbuf from native stringbuf @a src; + * allocate @a *dest in @a pool. + */ +svn_error_t * +svn_utf_stringbuf_to_utf8(svn_stringbuf_t **dest, + const svn_stringbuf_t *src, + apr_pool_t *pool); + + +/** Set @a *dest to a utf8-encoded string from native string @a src; allocate + * @a *dest in @a pool. + */ +svn_error_t * +svn_utf_string_to_utf8(const svn_string_t **dest, + const svn_string_t *src, + apr_pool_t *pool); + + +/** Set @a *dest to a utf8-encoded C string from native C string @a src; + * allocate @a *dest in @a pool. + */ +svn_error_t * +svn_utf_cstring_to_utf8(const char **dest, + const char *src, + apr_pool_t *pool); + + +/** Set @a *dest to a utf8 encoded C string from @a frompage encoded C + * string @a src; allocate @a *dest in @a pool. + * + * @since New in 1.4. + */ +svn_error_t * +svn_utf_cstring_to_utf8_ex2(const char **dest, + const char *src, + const char *frompage, + apr_pool_t *pool); + + +/** Like svn_utf_cstring_to_utf8_ex2() but with @a convset_key which is + * ignored. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_utf_cstring_to_utf8_ex(const char **dest, + const char *src, + const char *frompage, + const char *convset_key, + apr_pool_t *pool); + + +/** Set @a *dest to a natively-encoded stringbuf from utf8 stringbuf @a src; + * allocate @a *dest in @a pool. + */ +svn_error_t * +svn_utf_stringbuf_from_utf8(svn_stringbuf_t **dest, + const svn_stringbuf_t *src, + apr_pool_t *pool); + + +/** Set @a *dest to a natively-encoded string from utf8 string @a src; + * allocate @a *dest in @a pool. + */ +svn_error_t * +svn_utf_string_from_utf8(const svn_string_t **dest, + const svn_string_t *src, + apr_pool_t *pool); + + +/** Set @a *dest to a natively-encoded C string from utf8 C string @a src; + * allocate @a *dest in @a pool. + */ +svn_error_t * +svn_utf_cstring_from_utf8(const char **dest, + const char *src, + apr_pool_t *pool); + + +/** Set @a *dest to a @a topage encoded C string from utf8 encoded C string + * @a src; allocate @a *dest in @a pool. + * + * @since New in 1.4. + */ +svn_error_t * +svn_utf_cstring_from_utf8_ex2(const char **dest, + const char *src, + const char *topage, + apr_pool_t *pool); + + +/** Like svn_utf_cstring_from_utf8_ex2() but with @a convset_key which is + * ignored. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_utf_cstring_from_utf8_ex(const char **dest, + const char *src, + const char *topage, + const char *convset_key, + apr_pool_t *pool); + + +/** Return a fuzzily native-encoded C string from utf8 C string @a src, + * allocated in @a pool. A fuzzy recoding leaves all 7-bit ascii + * characters the same, and substitutes "?\\XXX" for others, where XXX + * is the unsigned decimal code for that character. + * + * This function cannot error; it is guaranteed to return something. + * First it will recode as described above and then attempt to convert + * the (new) 7-bit UTF-8 string to native encoding. If that fails, it + * will return the raw fuzzily recoded string, which may or may not be + * meaningful in the client's locale, but is (presumably) better than + * nothing. + * + * ### Notes: + * + * Improvement is possible, even imminent. The original problem was + * that if you converted a UTF-8 string (say, a log message) into a + * locale that couldn't represent all the characters, you'd just get a + * static placeholder saying "[unconvertible log message]". Then + * Justin Erenkrantz pointed out how on platforms that didn't support + * conversion at all, "svn log" would still fail completely when it + * encountered unconvertible data. + * + * Now for both cases, the caller can at least fall back on this + * function, which converts the message as best it can, substituting + * "?\\XXX" escape codes for the non-ascii characters. + * + * Ultimately, some callers may prefer the iconv "//TRANSLIT" option, + * so when we can detect that at configure time, things will change. + * Also, this should (?) be moved to apr/apu eventually. + * + * See http://subversion.tigris.org/issues/show_bug.cgi?id=807 for + * details. + */ +const char * +svn_utf_cstring_from_utf8_fuzzy(const char *src, + apr_pool_t *pool); + + +/** Set @a *dest to a natively-encoded C string from utf8 stringbuf @a src; + * allocate @a *dest in @a pool. + */ +svn_error_t * +svn_utf_cstring_from_utf8_stringbuf(const char **dest, + const svn_stringbuf_t *src, + apr_pool_t *pool); + + +/** Set @a *dest to a natively-encoded C string from utf8 string @a src; + * allocate @a *dest in @a pool. + */ +svn_error_t * +svn_utf_cstring_from_utf8_string(const char **dest, + const svn_string_t *src, + apr_pool_t *pool); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_UTF_H */ diff --git a/src/TortoiseMerge/svninclude/svn_version.h b/src/TortoiseMerge/svninclude/svn_version.h new file mode 100644 index 0000000..cb13486 --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_version.h @@ -0,0 +1,258 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2001-2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_version.h + * @brief Version information. + */ + +#ifndef SVN_VERSION_H +#define SVN_VERSION_H + +/* Hack to prevent the resource compiler from including + apr_general.h. It doesn't resolve the include paths + correctly and blows up without this. + */ +#ifndef APR_STRINGIFY +#include +#endif + +#include "svn_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Symbols that define the version number. */ + +/* Version numbers: .. + * + * The version numbers in this file follow the rules established by: + * + * http://apr.apache.org/versioning.html + */ + +/** Major version number. + * + * Modify when incompatible changes are made to published interfaces. + */ +#define SVN_VER_MAJOR 1 + +/** Minor version number. + * + * Modify when new functionality is added or new interfaces are + * defined, but all changes are backward compatible. + */ +#define SVN_VER_MINOR 6 + +/** + * Patch number. + * + * Modify for every released patch. + * + * @since New in 1.1. + */ +#define SVN_VER_PATCH 1 + + +/** @deprecated Provided for backward compatibility with the 1.0 API. */ +#define SVN_VER_MICRO SVN_VER_PATCH + +/** @deprecated Provided for backward compatibility with the 1.0 API. */ +#define SVN_VER_LIBRARY SVN_VER_MAJOR + + +/** Version tag: a string describing the version. + * + * This tag remains " (dev build)" in the repository so that we can + * always see from "svn --version" that the software has been built + * from the repository rather than a "blessed" distribution. + * + * When rolling a tarball, we automatically replace this text with " (r1234)" + * (where 1234 is the last revision on the branch prior to the release) + * for final releases; in prereleases, it becomes " (Alpha 1)", + * " (Beta 1)", etc., as appropriate. + * + * Always change this at the same time as SVN_VER_NUMTAG. + */ +#define SVN_VER_TAG " (dev build)" + + +/** Number tag: a string describing the version. + * + * This tag is used to generate a version number string to identify + * the client and server in HTTP requests, for example. It must not + * contain any spaces. This value remains "-dev" in the repository. + * + * When rolling a tarball, we automatically replace this text with "" + * for final releases; in prereleases, it becomes "-alpha1, "-beta1", + * etc., as appropriate. + * + * Always change this at the same time as SVN_VER_TAG. + */ +#define SVN_VER_NUMTAG "-dev" + + +/** Revision number: The repository revision number of this release. + * + * This constant is used to generate the build number part of the Windows + * file version. Its value remains 0 in the repository. + * + * When rolling a tarball, we automatically replace it with what we + * guess to be the correct revision number. + */ +#define SVN_VER_REVISION 0 + + +/* Version strings composed from the above definitions. */ + +/** Version number */ +#define SVN_VER_NUM APR_STRINGIFY(SVN_VER_MAJOR) \ + "." APR_STRINGIFY(SVN_VER_MINOR) \ + "." APR_STRINGIFY(SVN_VER_PATCH) + +/** Version number with tag (contains no whitespace) */ +#define SVN_VER_NUMBER SVN_VER_NUM SVN_VER_NUMTAG + +/** Complete version string */ +#define SVN_VERSION SVN_VER_NUM SVN_VER_TAG + + + +/* Version queries and compatibility checks */ + +/** + * Version information. Each library contains a function called + * svn_libname_version() that returns a pointer to a statically + * allocated object of this type. + * + * @since New in 1.1. + */ +typedef struct svn_version_t +{ + int major; /**< Major version number */ + int minor; /**< Minor version number */ + int patch; /**< Patch number */ + + /** + * The version tag (#SVN_VER_NUMTAG).\ Must always point to a + * statically allocated string. + */ + const char *tag; +} svn_version_t; + +/** + * Define a static svn_version_t object. + * + * @since New in 1.1. + */ +#define SVN_VERSION_DEFINE(name) \ + static const svn_version_t name = \ + { \ + SVN_VER_MAJOR, \ + SVN_VER_MINOR, \ + SVN_VER_PATCH, \ + SVN_VER_NUMTAG \ + } \ + +/** + * Generate the implementation of a version query function. + * + * @since New in 1.1. + */ +#define SVN_VERSION_BODY \ + SVN_VERSION_DEFINE(versioninfo); \ + return &versioninfo + +/** + * Check library version compatibility. Return #TRUE if the client's + * version, given in @a my_version, is compatible with the library + * version, provided in @a lib_version. + * + * This function checks for version compatibility as per our + * guarantees, but requires an exact match when linking to an + * unreleased library. A development client is always compatible with + * a previous released library. + * + * @since New in 1.1. + */ +svn_boolean_t +svn_ver_compatible(const svn_version_t *my_version, + const svn_version_t *lib_version); + +/** + * Check if @a my_version and @a lib_version encode the same version number. + * + * @since New in 1.2. + */ +svn_boolean_t +svn_ver_equal(const svn_version_t *my_version, + const svn_version_t *lib_version); + + +/** + * An entry in the compatibility checklist. + * @see svn_ver_check_list() + * + * @since New in 1.1. + */ +typedef struct svn_version_checklist_t +{ + const char *label; /**< Entry label */ + + /** Version query function for this entry */ + const svn_version_t *(*version_query)(void); +} svn_version_checklist_t; + + +/** + * Perform a series of version compatibility checks. Checks if @a + * my_version is compatible with each entry in @a checklist. @a + * checklist must end with an entry whose label is @c NULL. + * + * @see svn_ver_compatible() + * + * @since New in 1.1. + */ +svn_error_t * +svn_ver_check_list(const svn_version_t *my_version, + const svn_version_checklist_t *checklist); + + +/** + * Type of function returning library version. + * + * @since New in 1.6. + */ +typedef const svn_version_t *(*svn_version_func_t)(void); + + +/* libsvn_subr doesn't have an svn_subr header, so put the prototype here. */ +/** + * Get libsvn_subr version information. + * + * @since New in 1.1. + */ +const svn_version_t * +svn_subr_version(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_VERSION_H */ diff --git a/src/TortoiseMerge/svninclude/svn_wc.h b/src/TortoiseMerge/svninclude/svn_wc.h new file mode 100644 index 0000000..bbba989 --- /dev/null +++ b/src/TortoiseMerge/svninclude/svn_wc.h @@ -0,0 +1,5607 @@ +/** + * @copyright + * ==================================================================== + * Copyright (c) 2000-2008 CollabNet. All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://subversion.tigris.org/license-1.html. + * If newer versions of this license are posted there, you may use a + * newer version instead, at your option. + * + * This software consists of voluntary contributions made by many + * individuals. For exact contribution history, see the revision + * history and logs, available at http://subversion.tigris.org/. + * ==================================================================== + * @endcopyright + * + * @file svn_wc.h + * @brief Subversion's working copy library + * + * Requires: + * - A working copy + * + * Provides: + * - Ability to manipulate working copy's versioned data. + * - Ability to manipulate working copy's administrative files. + * + * Used By: + * - Clients. + * + * Notes: + * The 'path' parameters to most of these functions can be + * absolute or relative (relative to current working + * directory). If there are any cases where they are + * relative to the path associated with the + * 'svn_wc_adm_access_t *adm_access' baton passed along + * with the path, those cases should be explicitly + * documented, and if they are not, please fix it. + */ + +#ifndef SVN_WC_H +#define SVN_WC_H + +#include +#include +#include +#include +#include +#include + +#include "svn_types.h" +#include "svn_string.h" +#include "svn_checksum.h" +#include "svn_io.h" +#include "svn_delta.h" /* for svn_stream_t */ +#include "svn_opt.h" +#include "svn_ra.h" /* for svn_ra_reporter_t type */ +#include "svn_version.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/** + * Get libsvn_wc version information. + * + * @since New in 1.1. + */ +const svn_version_t * +svn_wc_version(void); + +/** + * @defgroup svn_wc Working copy management + * @{ + */ + +/** Flags for use with svn_wc_translated_file2 + * + * @defgroup translate_flags Translation flags + * + * @{ + */ + + /** Translate from Normal Form. + * + * The working copy text bases and repository files are stored + * in normal form. Some files' contents - or ever representation - + * differs between the working copy and the normal form. This flag + * specifies to take the latter form as input and transform it + * to the former. + * + * Either this flag or @c SVN_WC_TRANSLATE_TO_NF should be specified, + * but not both. + */ +#define SVN_WC_TRANSLATE_FROM_NF 0x00000000 + + /** Translate to Normal Form. + * + * Either this flag or @c SVN_WC_TRANSLATE_FROM_NF should be specified, + * but not both. + */ +#define SVN_WC_TRANSLATE_TO_NF 0x00000001 + + /** Force repair of eol styles, making sure the output file consistently + * contains the one eol style as specified by the svn:eol-style + * property and the required translation direction. + * + */ +#define SVN_WC_TRANSLATE_FORCE_EOL_REPAIR 0x00000002 + + /** Don't register a pool cleanup to delete the output file */ +#define SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP 0x00000004 + + /** Guarantee a new file is created on successful return. + * The default shortcuts translation by returning the path + * of the untranslated file when no translation is required. + */ +#define SVN_WC_TRANSLATE_FORCE_COPY 0x00000008 + + /** Use a non-wc-local tmp directory for creating output files, + * instead of in the working copy admin tmp area which is the default. + * + * @since New in 1.4. + */ +#define SVN_WC_TRANSLATE_USE_GLOBAL_TMP 0x00000010 + +/** @} */ + + +/* Locking/Opening/Closing */ + +/** Baton for access to a working copy administrative area. + * + * One day all such access will require a baton, we're not there yet. + * + * Access batons can be grouped into sets, by passing an existing open + * baton when opening a new baton. Given one baton in a set, other batons + * may be retrieved. This allows an entire hierarchy to be locked, and + * then the set of batons can be passed around by passing a single baton. + */ +typedef struct svn_wc_adm_access_t svn_wc_adm_access_t; + + +/** + * Return, in @a *adm_access, a pointer to a new access baton for the working + * copy administrative area associated with the directory @a path. If + * @a write_lock is TRUE the baton will include a write lock, otherwise the + * baton can only be used for read access. If @a path refers to a directory + * that is already write locked then the error @c SVN_ERR_WC_LOCKED will be + * returned. The error @c SVN_ERR_WC_NOT_DIRECTORY will be returned if + * @a path is not a versioned directory. + * + * If @a associated is an open access baton then @a adm_access will be added + * to the set containing @a associated. @a associated can be @c NULL, in + * which case @a adm_access is the start of a new set. + * + * @a levels_to_lock specifies how far to lock. Zero means just the specified + * directory. Any negative value means to lock the entire working copy + * directory hierarchy under @a path. A positive value indicates the number of + * levels of directories to lock -- 1 means just immediate subdirectories, 2 + * means immediate subdirectories and their subdirectories, etc. All the + * access batons will become part of the set containing @a adm_access. This + * is an all-or-nothing option, if it is not possible to lock all the + * requested directories then an error will be returned and @a adm_access will + * be invalid, with the exception that subdirectories of @a path that are + * missing from the physical filesystem will not be locked and will not cause + * an error. The error @c SVN_ERR_WC_LOCKED will be returned if a + * subdirectory of @a path is already write locked. + * + * If @a cancel_func is non-NULL, call it with @a cancel_baton to determine + * if the client has cancelled the operation. + * + * @a pool will be used to allocate memory for the baton and any subsequently + * cached items. If @a adm_access has not been closed when the pool is + * cleared, it will be closed automatically at that point, and removed from + * its set. A baton closed in this way will not remove physical locks from + * the working copy if cleanup is required. + * + * The first baton in a set, with @a associated passed as @c NULL, must have + * the longest lifetime of all the batons in the set. This implies it must be + * the root of the hierarchy. + * + * @since New in 1.2. + */ +svn_error_t * +svn_wc_adm_open3(svn_wc_adm_access_t **adm_access, + svn_wc_adm_access_t *associated, + const char *path, + svn_boolean_t write_lock, + int levels_to_lock, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_adm_open3(), but without cancellation support. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_adm_open2(svn_wc_adm_access_t **adm_access, + svn_wc_adm_access_t *associated, + const char *path, + svn_boolean_t write_lock, + int levels_to_lock, + apr_pool_t *pool); + +/** + * Similar to svn_wc_adm_open2(), but with @a tree_lock instead of + * @a levels_to_lock. @a levels_to_lock is set to -1 if @a tree_lock + * is @c TRUE, else 0. + * + * @deprecated Provided for backward compatibility with the 1.0 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_adm_open(svn_wc_adm_access_t **adm_access, + svn_wc_adm_access_t *associated, + const char *path, + svn_boolean_t write_lock, + svn_boolean_t tree_lock, + apr_pool_t *pool); + +/** + * Checks the working copy to determine the node type of @a path. If + * @a path is a versioned directory then the behaviour is like that of + * svn_wc_adm_open3(), otherwise, if @a path is a file or does not + * exist, then the behaviour is like that of svn_wc_adm_open3() with + * @a path replaced by the parent directory of @a path. If @a path is + * an unversioned directory, the behaviour is also like that of + * svn_wc_adm_open3() on the parent, except that if the open fails, + * then the returned SVN_ERR_WC_NOT_DIRECTORY error refers to @a path, + * not to @a path's parent. + * + * @since New in 1.2. + */ +svn_error_t * +svn_wc_adm_probe_open3(svn_wc_adm_access_t **adm_access, + svn_wc_adm_access_t *associated, + const char *path, + svn_boolean_t write_lock, + int levels_to_lock, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_adm_probe_open3() without the cancel + * functionality. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_adm_probe_open2(svn_wc_adm_access_t **adm_access, + svn_wc_adm_access_t *associated, + const char *path, + svn_boolean_t write_lock, + int levels_to_lock, + apr_pool_t *pool); + +/** + * Similar to svn_wc_adm_probe_open2(), but with @a tree_lock instead of + * @a levels_to_lock. @a levels_to_lock is set to -1 if @a tree_lock + * is @c TRUE, else 0. + * + * @deprecated Provided for backward compatibility with the 1.0 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_adm_probe_open(svn_wc_adm_access_t **adm_access, + svn_wc_adm_access_t *associated, + const char *path, + svn_boolean_t write_lock, + svn_boolean_t tree_lock, + apr_pool_t *pool); + +/** + * Open access batons for @a path and return in @a *anchor_access and + * @a *target the anchor and target required to drive an editor. Return + * in @a *target_access the access baton for the target, which may be the + * same as @a *anchor_access (in which case @a *target is the empty + * string, never NULL). All the access batons will be in the + * @a *anchor_access set. + * + * @a levels_to_lock determines the levels_to_lock used when opening + * @a path if @a path is a versioned directory, @a levels_to_lock is + * ignored otherwise. If @a write_lock is @c TRUE the access batons + * will hold write locks. + * + * If @a cancel_func is non-NULL, call it with @a cancel_baton to determine + * if the client has cancelled the operation. + * + * This function is essentially a combination of svn_wc_adm_open3() and + * svn_wc_get_actual_target(), with the emphasis on reducing physical IO. + * + * @since New in 1.2. + */ +svn_error_t * +svn_wc_adm_open_anchor(svn_wc_adm_access_t **anchor_access, + svn_wc_adm_access_t **target_access, + const char **target, + const char *path, + svn_boolean_t write_lock, + int levels_to_lock, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** Return, in @a *adm_access, a pointer to an existing access baton associated + * with @a path. @a path must be a directory that is locked as part of the + * set containing the @a associated access baton. + * + * If the requested access baton is marked as missing in, or is simply + * absent from, @a associated, return SVN_ERR_WC_NOT_LOCKED. + * + * @a pool is used only for local processing, it is not used for the batons. + */ +svn_error_t * +svn_wc_adm_retrieve(svn_wc_adm_access_t **adm_access, + svn_wc_adm_access_t *associated, + const char *path, + apr_pool_t *pool); + +/** Check the working copy to determine the node type of @a path. If + * @a path is a versioned directory then the behaviour is like that of + * svn_wc_adm_retrieve(), otherwise, if @a path is a file, an unversioned + * directory, or does not exist, then the behaviour is like that of + * svn_wc_adm_retrieve() with @a path replaced by the parent directory of + * @a path. + */ +svn_error_t * +svn_wc_adm_probe_retrieve(svn_wc_adm_access_t **adm_access, + svn_wc_adm_access_t *associated, + const char *path, + apr_pool_t *pool); + +/** + * Try various ways to obtain an access baton for @a path. + * + * First, try to obtain @a *adm_access via svn_wc_adm_probe_retrieve(), + * but if this fails because @a associated can't give a baton for + * @a path or @a path's parent, then try svn_wc_adm_probe_open3(), + * this time passing @a write_lock and @a levels_to_lock. If there is + * still no access because @a path is not a versioned directory, then + * just set @a *adm_access to NULL and return success. But if it is + * because @a path is locked, then return the error @c SVN_ERR_WC_LOCKED, + * and the effect on @a *adm_access is undefined. (Or if the attempt + * fails for any other reason, return the corresponding error, and the + * effect on @a *adm_access is also undefined.) + * + * If svn_wc_adm_probe_open3() succeeds, then add @a *adm_access to + * @a associated. + * + * If @a cancel_func is non-NULL, call it with @a cancel_baton to determine + * if the client has cancelled the operation. + * + * Use @a pool only for local processing, not to allocate @a *adm_access. + * + * @since New in 1.2. + */ +svn_error_t * +svn_wc_adm_probe_try3(svn_wc_adm_access_t **adm_access, + svn_wc_adm_access_t *associated, + const char *path, + svn_boolean_t write_lock, + int levels_to_lock, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_adm_probe_try3() without the cancel + * functionality. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_adm_probe_try2(svn_wc_adm_access_t **adm_access, + svn_wc_adm_access_t *associated, + const char *path, + svn_boolean_t write_lock, + int levels_to_lock, + apr_pool_t *pool); + +/** + * Similar to svn_wc_adm_probe_try2(), but with @a tree_lock instead of + * @a levels_to_lock. @a levels_to_lock is set to -1 if @a tree_lock + * is @c TRUE, else 0. + * + * @deprecated Provided for backward compatibility with the 1.0 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_adm_probe_try(svn_wc_adm_access_t **adm_access, + svn_wc_adm_access_t *associated, + const char *path, + svn_boolean_t write_lock, + svn_boolean_t tree_lock, + apr_pool_t *pool); + + +/** Give up the access baton @a adm_access, and its lock if any. This will + * recursively close any batons in the same set that are direct + * subdirectories of @a adm_access. Any physical locks will be removed from + * the working copy. Lock removal is unconditional, there is no check to + * determine if cleanup is required. + * + * Any temporary allocations are performed using @a scratch_pool. + * + * @since New in 1.6 + */ +svn_error_t * +svn_wc_adm_close2(svn_wc_adm_access_t *adm_access, + apr_pool_t *scratch_pool); + +/* @deprecated Provided for backward compabibility with the 1.5 API. */ +SVN_DEPRECATED +svn_error_t * +svn_wc_adm_close(svn_wc_adm_access_t *adm_access); + +/** Return the path used to open the access baton @a adm_access */ +const char * +svn_wc_adm_access_path(const svn_wc_adm_access_t *adm_access); + +/** Return the pool used by access baton @a adm_access */ +apr_pool_t * +svn_wc_adm_access_pool(const svn_wc_adm_access_t *adm_access); + +/** Return @c TRUE is the access baton @a adm_access has a write lock, + * @c FALSE otherwise. Compared to svn_wc_locked() this is a cheap, fast + * function that doesn't access the filesystem. + */ +svn_boolean_t +svn_wc_adm_locked(const svn_wc_adm_access_t *adm_access); + +/** Set @a *locked to non-zero if @a path is locked, else set it to zero. */ +svn_error_t * +svn_wc_locked(svn_boolean_t *locked, + const char *path, + apr_pool_t *pool); + + +/** + * Return @c TRUE if @a name is the name of the WC administrative + * directory. Use @a pool for any temporary allocations. Only works + * with base directory names, not paths or URIs. + * + * For compatibility, the default name (.svn) will always be treated + * as an admin dir name, even if the working copy is actually using an + * alternative name. + * + * @since New in 1.3. + */ +svn_boolean_t +svn_wc_is_adm_dir(const char *name, apr_pool_t *pool); + + +/** + * Return the name of the administrative directory. + * Use @a pool for any temporary allocations. + * + * The returned pointer will refer to either a statically allocated + * string, or to a string allocated in @a pool. + * + * @since New in 1.3. + */ +const char * +svn_wc_get_adm_dir(apr_pool_t *pool); + + +/** + * Use @a name for the administrative directory in the working copy. + * Use @a pool for any temporary allocations. + * + * The list of valid names is limited. Currently only ".svn" (the + * default) and "_svn" are allowed. + * + * @note This function changes global (per-process) state and must be + * called in a single-threaded context during the initialization of a + * Subversion client. + * + * @since New in 1.3. + */ +svn_error_t * +svn_wc_set_adm_dir(const char *name, + apr_pool_t *pool); + + + +/** Traversal information is information gathered by a working copy + * crawl or update. For example, the before and after values of the + * svn:externals property are important after an update, and since + * we're traversing the working tree anyway (a complete traversal + * during the initial crawl, and a traversal of changed paths during + * the checkout/update/switch), it makes sense to gather the + * property's values then instead of making a second pass. + */ +typedef struct svn_wc_traversal_info_t svn_wc_traversal_info_t; + + +/** Return a new, empty traversal info object, allocated in @a pool. */ +svn_wc_traversal_info_t * +svn_wc_init_traversal_info(apr_pool_t *pool); + + +/** Set @a *externals_old and @a *externals_new to hash tables representing + * changes to values of the svn:externals property on directories + * traversed by @a traversal_info. + * + * @a traversal_info is obtained from svn_wc_init_traversal_info(), but is + * only useful after it has been passed through another function, such + * as svn_wc_crawl_revisions(), svn_wc_get_update_editor(), + * svn_wc_get_switch_editor(), etc. + * + * Each hash maps const char * directory names onto + * const char * values of the externals property for that directory. + * The dir names are full paths -- that is, anchor plus target, not target + * alone. The values are not parsed, they are simply copied raw, and are + * never NULL: directories that acquired or lost the property are + * simply omitted from the appropriate table. Directories whose value + * of the property did not change show the same value in each hash. + * + * The hashes, keys, and values have the same lifetime as @a traversal_info. + */ +void +svn_wc_edited_externals(apr_hash_t **externals_old, + apr_hash_t **externals_new, + svn_wc_traversal_info_t *traversal_info); + + +/** Set @a *depths to a hash table mapping const char * + * directory names (directories traversed by @a traversal_info) to + * const char * values (the depths of those directories, as + * converted by svn_depth_to_word()). + * + * @a traversal_info is obtained from svn_wc_init_traversal_info(), but is + * only useful after it has been passed through another function, such + * as svn_wc_crawl_revisions(), svn_wc_get_update_editor(), + * svn_wc_get_switch_editor(), etc. + * + * The dir names are full paths -- that is, anchor plus target, not target + * alone. The values are not allocated, they are static constant strings. + * Although the values are never NULL, not all directories traversed + * are necessarily listed. For example, directories which did not + * have an svn:externals property set or modified are not included. + * + * The hashes and keys have the same lifetime as @a traversal_info. + * + * @since New in 1.5. + */ +void +svn_wc_traversed_depths(apr_hash_t **depths, + svn_wc_traversal_info_t *traversal_info); + + +/** One external item. This usually represents one line from an + * svn:externals description but with the path and URL + * canonicalized. + * + * In order to avoid backwards compatibility problems clients should use + * svn_wc_external_item_create() to allocate and initialize this structure + * instead of doing so themselves. + * + * @since New in 1.5. + */ +typedef struct svn_wc_external_item2_t +{ + /** The name of the subdirectory into which this external should be + checked out. This is relative to the parent directory that + holds this external item. (Note that these structs are often + stored in hash tables with the target dirs as keys, so this + field will often be redundant.) */ + const char *target_dir; + + /** Where to check out from. */ + const char *url; + + /** What revision to check out. The only valid kinds for this are + svn_opt_revision_number, svn_opt_revision_date, and + svn_opt_revision_head. */ + svn_opt_revision_t revision; + + /** The peg revision to use when checking out. The only valid kinds are + svn_opt_revision_number, svn_opt_revision_date, and + svn_opt_revision_head. */ + svn_opt_revision_t peg_revision; + +} svn_wc_external_item2_t; + +/** + * Initialize an external item. + * Set @a *item to an external item object, allocated in @a pool. + * + * In order to avoid backwards compatibility problems, this function + * is used to initialize and allocate the @c svn_wc_external_item2_t + * structure rather than doing so explicitly, as the size of this + * structure may change in the future. + * + * The current implementation never returns error, but callers should + * still check for error, for compatibility with future versions. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_external_item_create(const svn_wc_external_item2_t **item, + apr_pool_t *pool); + +/** + * Return a duplicate of @a item, allocated in @a pool. No part of the new + * item will be shared with @a item. + * + * @since New in 1.5. + */ +svn_wc_external_item2_t * +svn_wc_external_item2_dup(const svn_wc_external_item2_t *item, + apr_pool_t *pool); + +/** + * One external item. Similar to svn_wc_external_item2_t, except + * @a revision is interpreted as both the operational revision and the + * peg revision. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +typedef struct svn_wc_external_item_t +{ + /** Same as @c svn_wc_external_item2_t.target_dir */ + const char *target_dir; + + /** Same as @c svn_wc_external_item2_t.url */ + const char *url; + + /** Same as @c svn_wc_external_item2_t.revision */ + svn_opt_revision_t revision; + +} svn_wc_external_item_t; + +/** + * Return a duplicate of @a item, allocated in @a pool. No part of the new + * item will be shared with @a item. + * + * @since New in 1.3. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_wc_external_item_t * +svn_wc_external_item_dup(const svn_wc_external_item_t *item, + apr_pool_t *pool); + +/** + * If @a externals_p is non-NULL, set @a *externals_p to an array of + * @c svn_wc_external_item2_t * objects based on @a desc. The @a url + * member of the objects will be canonicalized if @a canonicalize_url + * is @c TRUE. + * + * If the format of @a desc is invalid, don't touch @a *externals_p and + * return @c SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION. Thus, if + * you just want to check the validity of an externals description, + * and don't care about the parsed result, pass NULL for @a externals_p. + * + * The format of @a desc is the same as for values of the directory + * property @c SVN_PROP_EXTERNALS, which see. + * + * Allocate the table, keys, and values in @a pool. + * + * Use @a parent_directory only in constructing error strings. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_parse_externals_description3(apr_array_header_t **externals_p, + const char *parent_directory, + const char *desc, + svn_boolean_t canonicalize_url, + apr_pool_t *pool); + +/** + * Similar to svn_wc_parse_externals_description3() with @a + * canonicalize_url set to @c TRUE, but returns an array of @c + * svn_wc_external_item_t * objects instead of @c + * svn_wc_external_item2_t * objects + * + * @since New in 1.1. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_parse_externals_description2(apr_array_header_t **externals_p, + const char *parent_directory, + const char *desc, + apr_pool_t *pool); + +/** + * Similar to svn_wc_parse_externals_description2(), but returns the + * parsed externals in a hash instead of an array. This function + * should not be used, as storing the externals in a hash causes their + * order of evaluation to be not easily identifiable. + * + * @deprecated Provided for backward compatibility with the 1.0 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_parse_externals_description(apr_hash_t **externals_p, + const char *parent_directory, + const char *desc, + apr_pool_t *pool); + + + +/* Notification/callback handling. */ + +/** + * @defgroup svn_wc_notifications Notification callback handling + * @{ + * + * In many cases, the WC library will scan a working copy and make + * changes. The caller usually wants to know when each of these changes + * has been made, so that it can display some kind of notification to + * the user. + * + * These notifications have a standard callback function type, which + * takes the path of the file that was affected, and a caller- + * supplied baton. + * + * Note that the callback is a 'void' return -- this is a simple + * reporting mechanism, rather than an opportunity for the caller to + * alter the operation of the WC library. + * + * Note also that some of the actions are used across several + * different Subversion commands. For example, the update actions are + * also used for checkouts, switches, and merges. + */ + +/** The type of action occurring. */ +typedef enum svn_wc_notify_action_t +{ + /** Adding a path to revision control. */ + svn_wc_notify_add = 0, + + /** Copying a versioned path. */ + svn_wc_notify_copy, + + /** Deleting a versioned path. */ + svn_wc_notify_delete, + + /** Restoring a missing path from the pristine text-base. */ + svn_wc_notify_restore, + + /** Reverting a modified path. */ + svn_wc_notify_revert, + + /** A revert operation has failed. */ + svn_wc_notify_failed_revert, + + /** Resolving a conflict. */ + svn_wc_notify_resolved, + + /** Skipping a path. */ + svn_wc_notify_skip, + + /** Got a delete in an update. */ + svn_wc_notify_update_delete, + + /** Got an add in an update. */ + svn_wc_notify_update_add, + + /** Got any other action in an update. */ + svn_wc_notify_update_update, + + /** The last notification in an update (including updates of externals). */ + svn_wc_notify_update_completed, + + /** Updating an external module. */ + svn_wc_notify_update_external, + + /** The last notification in a status (including status on externals). */ + svn_wc_notify_status_completed, + + /** Running status on an external module. */ + svn_wc_notify_status_external, + + /** Committing a modification. */ + svn_wc_notify_commit_modified, + + /** Committing an addition. */ + svn_wc_notify_commit_added, + + /** Committing a deletion. */ + svn_wc_notify_commit_deleted, + + /** Committing a replacement. */ + svn_wc_notify_commit_replaced, + + /** Transmitting post-fix text-delta data for a file. */ + svn_wc_notify_commit_postfix_txdelta, + + /** Processed a single revision's blame. */ + svn_wc_notify_blame_revision, + + /** Locking a path. @since New in 1.2. */ + svn_wc_notify_locked, + + /** Unlocking a path. @since New in 1.2. */ + svn_wc_notify_unlocked, + + /** Failed to lock a path. @since New in 1.2. */ + svn_wc_notify_failed_lock, + + /** Failed to unlock a path. @since New in 1.2. */ + svn_wc_notify_failed_unlock, + + /** Tried adding a path that already exists. @since New in 1.5. */ + svn_wc_notify_exists, + + /** Changelist name set. @since New in 1.5. */ + svn_wc_notify_changelist_set, + + /** Changelist name cleared. @since New in 1.5. */ + svn_wc_notify_changelist_clear, + + /** Warn user that a path has moved from one changelist to another. + @since New in 1.5. */ + svn_wc_notify_changelist_moved, + + /** A merge operation (to path) has begun. See @c merge_range in + @c svn_wc_notify_t. @since New in 1.5. */ + svn_wc_notify_merge_begin, + + /** A merge operation (to path) from a foreign repository has begun. + See @c merge_range in @c svn_wc_notify_t. @since New in 1.5. */ + svn_wc_notify_foreign_merge_begin, + + /** Replace notification. @since New in 1.5. */ + svn_wc_notify_update_replace, + + /** Property added. @since New in 1.6. */ + svn_wc_notify_property_added, + + /** Property updated. @since New in 1.6. */ + svn_wc_notify_property_modified, + + /** Property deleted. @since New in 1.6. */ + svn_wc_notify_property_deleted, + + /** Nonexistent property deleted. @since New in 1.6. */ + svn_wc_notify_property_deleted_nonexistent, + + /** Revprop set. @since New in 1.6. */ + svn_wc_notify_revprop_set, + + /** Revprop deleted. @since New in 1.6. */ + svn_wc_notify_revprop_deleted, + + /** The last notification in a merge. @since New in 1.6. */ + svn_wc_notify_merge_completed, + + /** The path is a tree-conflict victim of the intended action (*not* + * a persistent tree-conflict from an earlier operation, but *this* + * operation caused the tree-conflict). @since New in 1.6. */ + svn_wc_notify_tree_conflict, + + /** The path is a subdirectory referenced in an externals definition + * which is unable to be operated on. @since New in 1.6. */ + svn_wc_notify_failed_external + +} svn_wc_notify_action_t; + + +/** The type of notification that is occurring. */ +typedef enum svn_wc_notify_state_t +{ + svn_wc_notify_state_inapplicable = 0, + + /** Notifier doesn't know or isn't saying. */ + svn_wc_notify_state_unknown, + + /** The state did not change. */ + svn_wc_notify_state_unchanged, + + /** The item wasn't present. */ + svn_wc_notify_state_missing, + + /** An unversioned item obstructed work. */ + svn_wc_notify_state_obstructed, + + /** Pristine state was modified. */ + svn_wc_notify_state_changed, + + /** Modified state had mods merged in. */ + svn_wc_notify_state_merged, + + /** Modified state got conflicting mods. */ + svn_wc_notify_state_conflicted + +} svn_wc_notify_state_t; + +/** + * What happened to a lock during an operation. + * + * @since New in 1.2. + */ +typedef enum svn_wc_notify_lock_state_t +{ + svn_wc_notify_lock_state_inapplicable = 0, + + svn_wc_notify_lock_state_unknown, + + /** The lock wasn't changed. */ + svn_wc_notify_lock_state_unchanged, + + /** The item was locked. */ + svn_wc_notify_lock_state_locked, + + /** The item was unlocked. */ + svn_wc_notify_lock_state_unlocked + +} svn_wc_notify_lock_state_t; + +/** + * Structure used in the @c svn_wc_notify_func2_t function. + * + * @c kind, @c content_state, @c prop_state and @c lock_state are from + * after @c action, not before. + * + * @note If @c action is @c svn_wc_notify_update, then @c path has + * already been installed, so it is legitimate for an implementation of + * @c svn_wc_notify_func2_t to examine @c path in the working copy. + * + * @note The purpose of the @c kind, @c mime_type, @c content_state, and + * @c prop_state fields is to provide "for free" information that an + * implementation is likely to want, and which it would otherwise be + * forced to deduce via expensive operations such as reading entries + * and properties. However, if the caller does not have this + * information, it will simply pass the corresponding `*_unknown' + * values, and it is up to the implementation how to handle that + * (i.e., whether to attempt deduction, or just to punt and + * give a less informative notification). + * + * @note Callers of notification functions should use svn_wc_create_notify() + * or svn_wc_create_notify_url() to create structures of this type to allow + * for extensibility. + * + * @since New in 1.2. + */ +typedef struct svn_wc_notify_t { + + /** Path, either absolute or relative to the current working directory + * (i.e., not relative to an anchor).@c path is "." or another valid path + * value for compatibilty reasons when the real target is an url that + * is available in @c url. */ + const char *path; + + /** Action that describes what happened to @c path. */ + svn_wc_notify_action_t action; + + /** Node kind of @c path. */ + svn_node_kind_t kind; + + /** If non-NULL, indicates the mime-type of @c path. + * It is always @c NULL for directories. */ + const char *mime_type; + + /** Points to the lock structure received from the repository when + * @c action is @c svn_wc_notify_locked. For other actions, it is + * @c NULL. */ + const svn_lock_t *lock; + + /** Points to an error describing the reason for the failure when @c + * action is one of the following: @c svn_wc_notify_failed_lock, @c + * svn_wc_notify_failed_unlock, @c svn_wc_notify_failed_external. + * Is @c NULL otherwise. */ + svn_error_t *err; + + /** The type of notification that is occurring about node content. */ + svn_wc_notify_state_t content_state; + + /** The type of notification that is occurring about node properties. */ + svn_wc_notify_state_t prop_state; + + /** Reflects the addition or removal of a lock token in the working copy. */ + svn_wc_notify_lock_state_t lock_state; + + /** When @c action is @c svn_wc_notify_update_completed, target revision + * of the update, or @c SVN_INVALID_REVNUM if not available; when @c + * action is @c svn_wc_notify_blame_revision, processed revision. + * In all other cases, it is @c SVN_INVALID_REVNUM. */ + svn_revnum_t revision; + + /** When @c action is @c svn_wc_notify_changelist_add or name. In all other + * cases, it is @c NULL. @since New in 1.5 */ + const char *changelist_name; + + /** When @c action is @c svn_wc_notify_merge_begin, and both the + * left and right sides of the merge are from the same URL. In all + * other cases, it is @c NULL. @since New in 1.5 */ + svn_merge_range_t *merge_range; + + /** Similar to @c path, but if non-NULL the notification is about a url. + * @since New in 1.6 */ + const char *url; + + /** If non-NULL, specifies an absolute path prefix that can be subtracted + * from the start of the absolute path in @c path or @c url. Its purpose + * is to allow notification to remove a common prefix from all the paths + * displayed for an operation. @since New in 1.6 */ + const char *path_prefix; + + /** If @c action relates to properties, specifies the name of the property. + * @since New in 1.6 */ + const char *prop_name; + + /** If @c action is @c svn_wc_notify_blame_revision, contains a list of + * revision properties for the specified revision */ + apr_hash_t *rev_props; + + /* NOTE: Add new fields at the end to preserve binary compatibility. + Also, if you add fields here, you have to update svn_wc_create_notify + and svn_wc_dup_notify. */ +} svn_wc_notify_t; + +/** + * Allocate an @c svn_wc_notify_t structure in @a pool, initialize and return + * it. + * + * Set the @c path field of the created struct to @a path, and @c action to + * @a action. Set all other fields to their @c _unknown, @c NULL or + * invalid value, respectively. Make only a shallow copy of the pointer + * @a path. + * + * @since New in 1.2. + */ +svn_wc_notify_t * +svn_wc_create_notify(const char *path, + svn_wc_notify_action_t action, + apr_pool_t *pool); + +/** + * Allocate an @c svn_wc_notify_t structure in @a pool, initialize and return + * it. + * + * Set the @c url field of the created struct to @a url, @c action to, @c path + * to "." and @a action. Set all other fields to their @c _unknown, @c NULL or + * invalid value, respectively. Make only a shallow copy of the pointer + * @a url. + * + * @since New in 1.6. + */ +svn_wc_notify_t * +svn_wc_create_notify_url(const char *url, + svn_wc_notify_action_t action, + apr_pool_t *pool); + +/** + * Return a deep copy of @a notify, allocated in @a pool. + * + * @since New in 1.2. + */ +svn_wc_notify_t * +svn_wc_dup_notify(const svn_wc_notify_t *notify, + apr_pool_t *pool); + +/** + * Notify the world that @a notify->action has happened to @a notify->path. + * + * Recommendation: callers of @c svn_wc_notify_func2_t should avoid + * invoking it multiple times on the same path within a given + * operation, and implementations should not bother checking for such + * duplicate calls. For example, in an update, the caller should not + * invoke the notify func on receiving a prop change and then again + * on receiving a text change. Instead, wait until all changes have + * been received, and then invoke the notify func once (from within + * an @c svn_delta_editor_t's close_file(), for example), passing + * the appropriate @a notify->content_state and @a notify->prop_state flags. + * + * @since New in 1.2. + */ +typedef void (*svn_wc_notify_func2_t)(void *baton, + const svn_wc_notify_t *notify, + apr_pool_t *pool); + +/** + * Similar to @c svn_wc_notify_func2_t, but takes the information as arguments + * instead of struct fields. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +typedef void (*svn_wc_notify_func_t)(void *baton, + const char *path, + svn_wc_notify_action_t action, + svn_node_kind_t kind, + const char *mime_type, + svn_wc_notify_state_t content_state, + svn_wc_notify_state_t prop_state, + svn_revnum_t revision); + +/** @} */ + + +/** + * A simple callback type to wrap svn_ra_get_file(); see that + * docstring for more information. + * + * This technique allows libsvn_client to 'wrap' svn_ra_get_file() and + * pass it down into libsvn_wc functions, thus allowing the WC layer + * to legally call the RA function via (blind) callback. + * + * @since New in 1.5 + */ +typedef svn_error_t *(*svn_wc_get_file_t)(void *baton, + const char *path, + svn_revnum_t revision, + svn_stream_t *stream, + svn_revnum_t *fetched_rev, + apr_hash_t **props, + apr_pool_t *pool); + + +/** + * Interactive conflict handling + * + * @defgroup svn_wc_conflict Conflict callback functionality + * + * @{ + * + * This API gives a Subversion client application the opportunity to + * define a callback that allows the user to resolve conflicts + * interactively during updates and merges. + * + * If a conflict is discovered, libsvn_wc invokes the callback with an + * @c svn_wc_conflict_description_t. This structure describes the + * path in conflict, whether it's a text or property conflict, and may + * also present up to three files that can be used to resolve the + * conflict (perhaps by launching an editor or 3rd-party merging + * tool). The structure also provides a possible fourth file (@c + * merged_file) which, if not NULL, represents libsvn_wc's attempt to + * contextually merge the first three files. (Note that libsvn_wc + * will not attempt to merge a file that it believes is binary, and it + * will only attempt to merge property values it believes to be a + * series of multi-line text.) + * + * When the callback is finished interacting with the user, it + * responds by returning a @c svn_wc_conflict_result_t. This + * structure indicates whether the user wants to postpone the conflict + * for later (allowing libsvn_wc to mark the path "conflicted" as + * usual), or whether the user wants libsvn_wc to use one of the four + * files as the "final" state for resolving the conflict immediately. + * + * Note that the callback is at liberty (and encouraged) to merge the + * three files itself. If it does so, it signals this to libsvn_wc by + * returning a choice of @c svn_wc_conflict_choose_merged. To return + * the 'final' merged file to libsvn_wc, the callback has the option of + * either: + * + * - editing the original @c merged_file in-place + * + * or, if libsvn_wc never supplied a merged_file in the + * description structure (i.e. passed NULL for that field), + * + * - return the merged file in the @c svn_wc_conflict_result_t. + * + */ + +/** The type of action being attempted on an object. + * + * @since New in 1.5. + */ +typedef enum svn_wc_conflict_action_t +{ + svn_wc_conflict_action_edit, /* attempting to change text or props */ + svn_wc_conflict_action_add, /* attempting to add object */ + svn_wc_conflict_action_delete /* attempting to delete object */ + +} svn_wc_conflict_action_t; + + +/** The pre-existing condition which is causing a state of conflict. + * + * @since New in 1.5. + */ +typedef enum svn_wc_conflict_reason_t +{ + /** Local edits are already present */ + svn_wc_conflict_reason_edited, + /** Another object is in the way */ + svn_wc_conflict_reason_obstructed, + /** Object is already schedule-delete */ + svn_wc_conflict_reason_deleted, + /** Object is unknown or missing */ + svn_wc_conflict_reason_missing, + /** Object is unversioned */ + svn_wc_conflict_reason_unversioned, + /** Object is already added or schedule-add. @since New in 1.6. */ + svn_wc_conflict_reason_added + +} svn_wc_conflict_reason_t; + + +/** The type of conflict being described by an @c + * svn_wc_conflict_description_t (see below). + * + * @since New in 1.5. + */ +typedef enum svn_wc_conflict_kind_t +{ + /** textual conflict (on a file) */ + svn_wc_conflict_kind_text, + /** property conflict (on a file or dir) */ + svn_wc_conflict_kind_property, + /** tree conflict (on a dir) @since New in 1.6. */ + svn_wc_conflict_kind_tree +} svn_wc_conflict_kind_t; + + +/** The user operation that exposed a conflict. + * + * @since New in 1.6. + */ +typedef enum svn_wc_operation_t +{ + svn_wc_operation_none = 0, + svn_wc_operation_update, + svn_wc_operation_switch, + svn_wc_operation_merge + +} svn_wc_operation_t; + + +/** Info about one of the conflicting versions of a node. Each field may + * have its respective null/invalid/unknown value if the corresponding + * information is not relevant or not available. + * + * @todo Consider making some or all of the info mandatory, to reduce + * complexity. + * + * @note Fields may be added to the end of this structure in future + * versions. Therefore, to preserve binary compatibility, users + * should not directly allocate structures of this type. + * + * @see svn_wc_conflict_version_create() + * @see svn_wc_conflict_version_dup() + * + * @since New in 1.6. +*/ +typedef struct svn_wc_conflict_version_t +{ + /** @name Where to find this node version in a repository */ + /**@{*/ + + /** URL of repository root */ + const char *repos_url; + + /** revision at which to look up path_in_repos */ + svn_revnum_t peg_rev; + + /** path within repos; must not start with '/' */ + const char *path_in_repos; + /* @todo We may decide to add the repository UUID, to handle conflicts + * properly during a repository move. */ + /** @} */ + + /** Info about this node */ + svn_node_kind_t node_kind; /* note that 'none' is a legitimate value */ + + /* @todo Add metadata about a local copy of the node, if and when + * we store one. */ + + /* Remember to update svn_wc_conflict_version_create() and + * svn_wc_conflict_version_dup() in case you add fields to this struct. */ +} svn_wc_conflict_version_t; + +/** + * Allocate an @c svn_wc_conflict_version_t structure in @a pool, + * initialize to contain a conflict origin, and return it. + * + * Set the @c repos_url field of the created struct to @a repos_url, the + * @c path_in_repos field to @a path_in_repos, the @c peg_rev field to + * @a peg_rev and the the @c node_kind to @c node_kind. Make only shallow + * copies of the pointer arguments. + * + * @since New in 1.6. + */ +svn_wc_conflict_version_t * +svn_wc_conflict_version_create(const char *repos_url, + const char* path_in_repos, + svn_revnum_t peg_rev, + svn_node_kind_t node_kind, + apr_pool_t *pool); + +/** Return a duplicate of @a version, allocated in @a pool. + * No part of the new version will be shared with @a version. + * + * @since New in 1.6. + */ +svn_wc_conflict_version_t * +svn_wc_conflict_version_dup(const svn_wc_conflict_version_t *version, + apr_pool_t *pool); + + +/** A struct that describes a conflict that has occurred in the + * working copy. Passed to @c svn_wc_conflict_resolver_func_t. + * + * The conflict described by this structure is one of: + * - a conflict on the content of the file node @a path + * - a conflict on the property @a property_name of @a path + * + * @note Fields may be added to the end of this structure in future + * versions. Therefore, to preserve binary compatibility, users + * should not directly allocate structures of this type but should use + * svn_wc_create_conflict_description_text() or + * svn_wc_create_conflict_description_prop() or + * svn_wc_create_conflict_description_tree() instead. + * + * @since New in 1.5. + */ +typedef struct svn_wc_conflict_description_t +{ + /** The path that is in conflict (for a tree conflict, it is the victim) */ + const char *path; + + /** The node type of the path being operated on (for a tree conflict, + * ### which version?) */ + svn_node_kind_t node_kind; + + /** What sort of conflict are we describing? */ + svn_wc_conflict_kind_t kind; + + /** The name of the property whose conflict is being described. + * (Only if @a kind is 'property'; else undefined.) */ + const char *property_name; + + /** Whether svn thinks ('my' version of) @c path is a 'binary' file. + * (Only if @c kind is 'text', else undefined.) */ + svn_boolean_t is_binary; + + /** The svn:mime-type property of ('my' version of) @c path, if available, + * else NULL. + * (Only if @c kind is 'text', else undefined.) */ + const char *mime_type; + + /** If not NULL, an open working copy access baton to either the + * path itself (if @c path is a directory), or to the parent + * directory (if @c path is a file.) + * For a tree conflict, this will always be an access baton + * to the parent directory of the path, even if the path is + * a directory. */ + svn_wc_adm_access_t *access; + + /** The action being attempted on the conflicted node or property. + * (When @c kind is 'text', this action must be 'edit'.) */ + svn_wc_conflict_action_t action; + + /** The state of the target node or property, relative to its merge-left + * source, that is the reason for the conflict. + * (When @c kind is 'text', this reason must be 'edited'.) */ + svn_wc_conflict_reason_t reason; + + /** If this is text-conflict and involves the merging of two files + * descended from a common ancestor, here are the paths of up to + * four fulltext files that can be used to interactively resolve the + * conflict. All four files will be in repository-normal form -- LF + * line endings and contracted keywords. (If any of these files are + * not available, they default to NULL.) + * + * On the other hand, if this is a property-conflict, then these + * paths represent temporary files that contain the three different + * property-values in conflict. The fourth path (@c merged_file) + * may or may not be NULL; if set, it represents libsvn_wc's + * attempt to merge the property values together. (Remember that + * property values are technically binary values, and thus can't + * always be merged.) + */ + const char *base_file; /* common ancestor of the two files being merged */ + + /** their version of the file */ + const char *their_file; + + /** my locally-edited version of the file */ + const char *my_file; + + /** merged version; may contain conflict markers */ + const char *merged_file; + + /** The operation that exposed the conflict. + * Used only for tree conflicts. + * + * @since New in 1.6. + */ + svn_wc_operation_t operation; + + /** Info on the "merge-left source" or "older" version of incoming change. + * @since New in 1.6. */ + svn_wc_conflict_version_t *src_left_version; + + /** Info on the "merge-right source" or "their" version of incoming change. + * @since New in 1.6. */ + svn_wc_conflict_version_t *src_right_version; + + /* Remember to adjust svn_wc__conflict_description_dup() + * if you add new fields to this struct. */ +} svn_wc_conflict_description_t; + +/** + * Allocate an @c svn_wc_conflict_description_t structure in @a pool, + * initialize to represent a text conflict, and return it. + * + * Set the @c path field of the created struct to @a path, the @c access + * field to @a adm_access, the @c kind field to @c + * svn_wc_conflict_kind_text, the @c node_kind to @c svn_node_file, the @c + * action to @c svn_wc_conflict_action_edit, and the @c reason to @c + * svn_wc_conflict_reason_edited. Make only shallow copies of the pointer + * arguments. + * + * @note: It is the caller's responsibility to set the other required fields + * (such as the four file names and @c mime_type and @c is_binary). + * + * @since New in 1.6. + */ +svn_wc_conflict_description_t * +svn_wc_conflict_description_create_text(const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + +/** + * Allocate an @c svn_wc_conflict_description_t structure in @a pool, + * initialize to represent a property conflict, and return it. + * + * Set the @c path field of the created struct to @a path, the @c access + * field to @a adm_access, the @c kind field to @c + * svn_wc_conflict_kind_prop, the @c node_kind to @a node_kind, and the @c + * property_name to @a property_name. Make only shallow copies of the pointer + * arguments. + * + * @note: It is the caller's responsibility to set the other required fields + * (such as the four file names and @c action and @c reason). + * + * @since New in 1.6. + */ +svn_wc_conflict_description_t * +svn_wc_conflict_description_create_prop(const char *path, + svn_wc_adm_access_t *adm_access, + svn_node_kind_t node_kind, + const char *property_name, + apr_pool_t *pool); + +/** + * Allocate an @c svn_wc_conflict_description_t structure in @a pool, + * initialize to represent a tree conflict, and return it. + * + * Set the @c path field of the created struct to @a path, the @c access + * field to @a adm_access, the @c kind field to @c + * svn_wc_conflict_kind_tree, the @c node_kind to @a node_kind, the @c + * operation to @a operation, the @c src_left_version field to + * @a src_left_version, and the @c src_right_version field to + * @a src_right_version. + * Make only shallow copies of the pointer arguments. + * + * @note: It is the caller's responsibility to set the other required fields + * (such as the four file names and @c action and @c reason). + * + * @since New in 1.6. + */ +svn_wc_conflict_description_t * +svn_wc_conflict_description_create_tree(const char *path, + svn_wc_adm_access_t *adm_access, + svn_node_kind_t node_kind, + svn_wc_operation_t operation, + svn_wc_conflict_version_t + *src_left_version, + svn_wc_conflict_version_t + *src_right_version, + apr_pool_t *pool); + + +/** The way in which the conflict callback chooses a course of action. + * + * @since New in 1.5. + */ +typedef enum svn_wc_conflict_choice_t +{ + /* Don't resolve the conflict now. Let libsvn_wc mark the path + 'conflicted', so user can run 'svn resolved' later. */ + svn_wc_conflict_choose_postpone, + + /* If their were files to choose from, select one as a way of + resolving the conflict here and now. libsvn_wc will then do the + work of "installing" the chosen file. + */ + svn_wc_conflict_choose_base, /* original version */ + svn_wc_conflict_choose_theirs_full, /* incoming version */ + svn_wc_conflict_choose_mine_full, /* own version */ + svn_wc_conflict_choose_theirs_conflict, /* incoming (for conflicted hunks) */ + svn_wc_conflict_choose_mine_conflict, /* own (for conflicted hunks) */ + svn_wc_conflict_choose_merged /* merged version */ + +} svn_wc_conflict_choice_t; + + +/** The final result returned by @c svn_wc_conflict_resolver_func_t. + * + * @note Fields may be added to the end of this structure in future + * versions. Therefore, to preserve binary compatibility, users + * should not directly allocate structures of this type. Instead, + * construct this structure using @c svn_wc_create_conflict_result() + * below. + * + * @since New in 1.5. + */ +typedef struct svn_wc_conflict_result_t +{ + /** A choice to either delay the conflict resolution or select a + particular file to resolve the conflict. */ + svn_wc_conflict_choice_t choice; + + /** If not NULL, this is a path to a file which contains the client's + (or more likely, the user's) merging of the three values in + conflict. libsvn_wc accepts this file if (and only if) @c choice + is set to @c svn_wc_conflict_choose_merged.*/ + const char *merged_file; + + /** If true, save a backup copy of merged_file (or the original + merged_file from the conflict description, if merged_file is + NULL) in the user's working copy. */ + svn_boolean_t save_merged; + +} svn_wc_conflict_result_t; + + +/** + * Allocate an @c svn_wc_conflict_result_t structure in @a pool, + * initialize and return it. + * + * Set the @c choice field of the structure to @a choice, and @c + * merged_file to @a merged_file. Set all other fields to their @c + * _unknown, @c NULL or invalid value, respectively. Make only a shallow + * copy of the pointer argument @a merged_file. + * + * @since New in 1.5. + */ +svn_wc_conflict_result_t * +svn_wc_create_conflict_result(svn_wc_conflict_choice_t choice, + const char *merged_file, + apr_pool_t *pool); + + +/** A callback used in svn_client_merge3(), svn_client_update3(), and + * svn_client_switch2() for resolving conflicts during the application + * of a tree delta to a working copy. + * + * @a description describes the exact nature of the conflict, and + * provides information to help resolve it. @a baton is a closure + * object; it should be provided by the implementation, and passed by + * the caller. All allocations should be performed in @a pool. When + * finished, the callback signals its resolution by returning a + * structure in @a *result. (See @c svn_wc_conflict_result_t.) + * + * The values @c svn_wc_conflict_choose_mine_conflict and @c + * svn_wc_conflict_choose_theirs_conflict are not legal for conflicts + * in binary files or properties. + * + * Implementations of this callback are free to present the conflict + * using any user interface. This may include simple contextual + * conflicts in a file's text or properties, or more complex + * 'tree'-based conflcts related to obstructed additions, deletions, + * and edits. The callback implementation is free to decide which + * sorts of conflicts to handle; it's also free to decide which types + * of conflicts are automatically resolvable and which require user + * interaction. + * + * @since New in 1.5. + */ +typedef svn_error_t *(*svn_wc_conflict_resolver_func_t) + (svn_wc_conflict_result_t **result, + const svn_wc_conflict_description_t *description, + void *baton, + apr_pool_t *pool); + +/** @} */ + + + +/** + * A callback vtable invoked by our diff-editors, as they receive + * diffs from the server. 'svn diff' and 'svn merge' both implement + * their own versions of this table. + * + * Common parameters: + * + * @a adm_access will be an access baton for the directory containing + * @a path, or @c NULL if the diff editor is not using access batons. + * + * If @a state is non-NULL, set @a *state to the state of the item + * after the operation has been performed. (In practice, this is only + * useful with merge, not diff; diff callbacks will probably set + * @a *state to @c svn_wc_notify_state_unknown, since they do not change + * the state and therefore do not bother to know the state after the + * operation.) By default, @a state refers to the item's content + * state. Functions concerned with property state have separate + * @a contentstate and @a propstate arguments. + * + * If @a tree_conflicted is non-NULL, set @a *tree_conflicted to true if + * this operation caused a tree conflict, else to false. (Like with @a + * state, this is only useful with merge, not diff; diff callbacks + * should set this to false.) + * + * @since New in 1.6. + */ +typedef struct svn_wc_diff_callbacks3_t +{ + /** + * A file @a path has changed. If @a tmpfile2 is non-NULL, the + * contents have changed and those changes can be seen by comparing + * @a tmpfile1 and @a tmpfile2, which represent @a rev1 and @a rev2 of + * the file, respectively. + * + * If known, the @c svn:mime-type value of each file is passed into + * @a mimetype1 and @a mimetype2; either or both of the values can + * be NULL. The implementor can use this information to decide if + * (or how) to generate differences. + * + * @a propchanges is an array of (@c svn_prop_t) structures. If it contains + * any elements, the original list of properties is provided in + * @a originalprops, which is a hash of @c svn_string_t values, keyed on the + * property name. + * + */ + svn_error_t *(*file_changed)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *contentstate, + svn_wc_notify_state_t *propstate, + svn_boolean_t *tree_conflicted, + const char *path, + const char *tmpfile1, + const char *tmpfile2, + svn_revnum_t rev1, + svn_revnum_t rev2, + const char *mimetype1, + const char *mimetype2, + const apr_array_header_t *propchanges, + apr_hash_t *originalprops, + void *diff_baton); + + /** + * A file @a path was added. The contents can be seen by comparing + * @a tmpfile1 and @a tmpfile2, which represent @a rev1 and @a rev2 + * of the file, respectively. (If either file is empty, the rev + * will be 0.) + * + * If known, the @c svn:mime-type value of each file is passed into + * @a mimetype1 and @a mimetype2; either or both of the values can + * be NULL. The implementor can use this information to decide if + * (or how) to generate differences. + * + * @a propchanges is an array of (@c svn_prop_t) structures. If it contains + * any elements, the original list of properties is provided in + * @a originalprops, which is a hash of @c svn_string_t values, keyed on the + * property name. + */ + svn_error_t *(*file_added)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *contentstate, + svn_wc_notify_state_t *propstate, + svn_boolean_t *tree_conflicted, + const char *path, + const char *tmpfile1, + const char *tmpfile2, + svn_revnum_t rev1, + svn_revnum_t rev2, + const char *mimetype1, + const char *mimetype2, + const apr_array_header_t *propchanges, + apr_hash_t *originalprops, + void *diff_baton); + + /** + * A file @a path was deleted. The [loss of] contents can be seen by + * comparing @a tmpfile1 and @a tmpfile2. @a originalprops provides + * the properties of the file. + * ### Some existing callers include WC "entry props" in @a originalprops. + * + * If known, the @c svn:mime-type value of each file is passed into + * @a mimetype1 and @a mimetype2; either or both of the values can + * be NULL. The implementor can use this information to decide if + * (or how) to generate differences. + */ + svn_error_t *(*file_deleted)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + svn_boolean_t *tree_conflicted, + const char *path, + const char *tmpfile1, + const char *tmpfile2, + const char *mimetype1, + const char *mimetype2, + apr_hash_t *originalprops, + void *diff_baton); + + /** + * A directory @a path was added. @a rev is the revision that the + * directory came from. + */ + svn_error_t *(*dir_added)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + svn_boolean_t *tree_conflicted, + const char *path, + svn_revnum_t rev, + void *diff_baton); + + /** + * A directory @a path was deleted. + */ + svn_error_t *(*dir_deleted)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + svn_boolean_t *tree_conflicted, + const char *path, + void *diff_baton); + + /** + * A list of property changes (@a propchanges) was applied to the + * directory @a path. + * + * The array is a list of (@c svn_prop_t) structures. + * + * The original list of properties is provided in @a original_props, + * which is a hash of @c svn_string_t values, keyed on the property + * name. + */ + svn_error_t *(*dir_props_changed)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *propstate, + svn_boolean_t *tree_conflicted, + const char *path, + const apr_array_header_t *propchanges, + apr_hash_t *original_props, + void *diff_baton); + + /** + * A directory @a path has been opened. @a rev is the revision that the + * directory came from. + * + * This function is called for @a path before any of the callbacks are + * called for a child of @a path. + */ + svn_error_t *(*dir_opened)(svn_wc_adm_access_t *adm_access, + svn_boolean_t *tree_conflicted, + const char *path, + svn_revnum_t rev, + void *diff_baton); + + /** + * A directory @a path has been closed. + */ + svn_error_t *(*dir_closed)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *contentstate, + svn_wc_notify_state_t *propstate, + svn_boolean_t *tree_conflicted, + const char *path, + void *diff_baton); + +} svn_wc_diff_callbacks3_t; + +/** + * Similar to @c svn_wc_diff_callbacks3_t, but without the dir_opened() + * function, and without the 'tree_conflicted' argument to the functions. + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +typedef struct svn_wc_diff_callbacks2_t +{ + /** The same as @c file_changed in @c svn_wc_diff_callbacks3_t. */ + svn_error_t *(*file_changed)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *contentstate, + svn_wc_notify_state_t *propstate, + const char *path, + const char *tmpfile1, + const char *tmpfile2, + svn_revnum_t rev1, + svn_revnum_t rev2, + const char *mimetype1, + const char *mimetype2, + const apr_array_header_t *propchanges, + apr_hash_t *originalprops, + void *diff_baton); + + /** The same as @c file_added in @c svn_wc_diff_callbacks3_t. */ + svn_error_t *(*file_added)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *contentstate, + svn_wc_notify_state_t *propstate, + const char *path, + const char *tmpfile1, + const char *tmpfile2, + svn_revnum_t rev1, + svn_revnum_t rev2, + const char *mimetype1, + const char *mimetype2, + const apr_array_header_t *propchanges, + apr_hash_t *originalprops, + void *diff_baton); + + /** The same as @c file_deleted in @c svn_wc_diff_callbacks3_t. */ + svn_error_t *(*file_deleted)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + const char *path, + const char *tmpfile1, + const char *tmpfile2, + const char *mimetype1, + const char *mimetype2, + apr_hash_t *originalprops, + void *diff_baton); + + /** The same as @c dir_added in @c svn_wc_diff_callbacks3_t. */ + svn_error_t *(*dir_added)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + const char *path, + svn_revnum_t rev, + void *diff_baton); + + /** The same as @c dir_deleted in @c svn_wc_diff_callbacks3_t. */ + svn_error_t *(*dir_deleted)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + const char *path, + void *diff_baton); + + /** The same as @c dir_props_changed in @c svn_wc_diff_callbacks3_t. */ + svn_error_t *(*dir_props_changed)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + const char *path, + const apr_array_header_t *propchanges, + apr_hash_t *original_props, + void *diff_baton); + +} svn_wc_diff_callbacks2_t; + +/** + * Similar to @c svn_wc_diff_callbacks2_t, but with file additions/content + * changes and property changes split into different functions. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +typedef struct svn_wc_diff_callbacks_t +{ + /** Similar to @c file_changed in @c svn_wc_diff_callbacks2_t, but without + * property change information. @a tmpfile2 is never NULL. @a state applies + * to the file contents. */ + svn_error_t *(*file_changed)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + const char *path, + const char *tmpfile1, + const char *tmpfile2, + svn_revnum_t rev1, + svn_revnum_t rev2, + const char *mimetype1, + const char *mimetype2, + void *diff_baton); + + /** Similar to @c file_added in @c svn_wc_diff_callbacks2_t, but without + * property change information. @a *state applies to the file contents. */ + svn_error_t *(*file_added)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + const char *path, + const char *tmpfile1, + const char *tmpfile2, + svn_revnum_t rev1, + svn_revnum_t rev2, + const char *mimetype1, + const char *mimetype2, + void *diff_baton); + + /** Similar to @c file_deleted in @c svn_wc_diff_callbacks2_t, but without + * the properties. */ + svn_error_t *(*file_deleted)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + const char *path, + const char *tmpfile1, + const char *tmpfile2, + const char *mimetype1, + const char *mimetype2, + void *diff_baton); + + /** The same as @c dir_added in @c svn_wc_diff_callbacks2_t. */ + svn_error_t *(*dir_added)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + const char *path, + svn_revnum_t rev, + void *diff_baton); + + /** The same as @c dir_deleted in @c svn_wc_diff_callbacks2_t. */ + svn_error_t *(*dir_deleted)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + const char *path, + void *diff_baton); + + /** Similar to @c dir_props_changed in @c svn_wc_diff_callbacks2_t, but this + * function is called for files as well as directories. */ + svn_error_t *(*props_changed)(svn_wc_adm_access_t *adm_access, + svn_wc_notify_state_t *state, + const char *path, + const apr_array_header_t *propchanges, + apr_hash_t *original_props, + void *diff_baton); + +} svn_wc_diff_callbacks_t; + + +/* Asking questions about a working copy. */ + +/** Set @a *wc_format to @a path's working copy format version number if + * @a path is a valid working copy directory, else set it to 0. + * Return error @c APR_ENOENT if @a path does not exist at all. + */ +svn_error_t * +svn_wc_check_wc(const char *path, + int *wc_format, + apr_pool_t *pool); + + +/** Set @a *has_binary_prop to @c TRUE iff @a path has been marked + * with a property indicating that it is non-text (in other words, binary). + * @a adm_access is an access baton set that contains @a path. + */ +svn_error_t * +svn_wc_has_binary_prop(svn_boolean_t *has_binary_prop, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + + +/* Detecting modification. */ + +/** Set @a *modified_p to non-zero if @a filename's text is modified + * with regard to the base revision, else set @a *modified_p to zero. + * @a filename is a path to the file, not just a basename. @a adm_access + * must be an access baton for @a filename. + * + * If @a force_comparison is @c TRUE, this function will not allow + * early return mechanisms that avoid actual content comparison. + * Instead, if there is a text base, a full byte-by-byte comparison + * will be done, and the entry checksum verified as well. (This means + * that if the text base is much longer than the working file, every + * byte of the text base will still be examined.) + * + * If @a filename does not exist, consider it unmodified. If it exists + * but is not under revision control (not even scheduled for + * addition), return the error @c SVN_ERR_ENTRY_NOT_FOUND. + * + * If @a filename is unmodified but has a timestamp variation then this + * function may "repair" @a filename's text-time by setting it to + * @a filename's last modification time. + */ +svn_error_t * +svn_wc_text_modified_p(svn_boolean_t *modified_p, + const char *filename, + svn_boolean_t force_comparison, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + + +/** Set @a *modified_p to non-zero if @a path's properties are modified + * with regard to the base revision, else set @a modified_p to zero. + * @a adm_access must be an access baton for @a path. + */ +svn_error_t * +svn_wc_props_modified_p(svn_boolean_t *modified_p, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + + + + +/** Administrative subdir. + * + * Ideally, this would be completely private to wc internals (in fact, + * it used to be that adm_subdir() in adm_files.c was the only function + * who knew the adm subdir's name). However, import wants to protect + * against importing administrative subdirs, so now the name is a + * matter of public record. + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +#define SVN_WC_ADM_DIR_NAME ".svn" + + + +/* Entries and status. */ + +/** The schedule states an entry can be in. */ +typedef enum svn_wc_schedule_t +{ + /** Nothing special here */ + svn_wc_schedule_normal, + + /** Slated for addition */ + svn_wc_schedule_add, + + /** Slated for deletion */ + svn_wc_schedule_delete, + + /** Slated for replacement (delete + add) */ + svn_wc_schedule_replace + +} svn_wc_schedule_t; + + +/** + * Values for the working_size field in svn_wc_entry_t + * when it isn't set to the actual size value of the unchanged + * working file. + * + * @defgroup svn_wc_entry_working_size_constants Working size constants + * + * @{ + */ + +/** The value of the working size is unknown (hasn't been + * calculated and stored in the past for whatever reason). + * + * @since New in 1.5 + */ +#define SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN (-1) + +/** @} */ + +/** A working copy entry -- that is, revision control information about + * one versioned entity. + */ +typedef struct svn_wc_entry_t +{ + /* IMPORTANT: If you extend this structure, add new fields to the end. */ + + /* General Attributes */ + + /** entry's name */ + const char *name; + + /** base revision */ + svn_revnum_t revision; + + /** url in repository */ + const char *url; + + /** canonical repository URL or NULL if not known */ + const char *repos; + + /** repository uuid */ + const char *uuid; + + /** node kind (file, dir, ...) */ + svn_node_kind_t kind; + + /* State information */ + + /** scheduling (add, delete, replace ...) */ + svn_wc_schedule_t schedule; + + /** in a copied state (possibly because the entry is a child of a + * path that is @c svn_wc_schedule_add or @c svn_wc_schedule_replace, + * when the entry itself is @c svn_wc_schedule_normal). + * COPIED is true for nodes under a directory that was copied, but + * COPYFROM_URL is null there. They are both set for the root + * destination of the copy. + */ + svn_boolean_t copied; + + /** The directory containing this entry had a versioned child of this + * name, but this entry represents a different revision or a switched + * path at which no item exists in the repository. This typically + * arises from committing or updating to a deletion of this entry + * without committing or updating the parent directory. + * + * The schedule can be 'normal' or 'add'. */ + svn_boolean_t deleted; + + /** absent -- we know an entry of this name exists, but that's all + (usually this happens because of authz restrictions) */ + svn_boolean_t absent; + + /** for THIS_DIR entry, implies whole entries file is incomplete */ + svn_boolean_t incomplete; + + /** copyfrom location */ + const char *copyfrom_url; + + /** copyfrom revision */ + svn_revnum_t copyfrom_rev; + + /** old version of conflicted file. A file basename, relative to the + * user's directory that the THIS_DIR entry refers to. */ + const char *conflict_old; + + /** new version of conflicted file. A file basename, relative to the + * user's directory that the THIS_DIR entry refers to. */ + const char *conflict_new; + + /** working version of conflicted file. A file basename, relative to the + * user's directory that the THIS_DIR entry refers to. */ + const char *conflict_wrk; + + /** property reject file. A file basename, relative to the user's + * directory that the THIS_DIR entry refers to. */ + const char *prejfile; + + /** last up-to-date time for text contents (0 means no information available) + */ + apr_time_t text_time; + + /** last up-to-date time for properties (0 means no information available) + * + * @deprecated This value will always be 0 in version 1.4 and later. + */ + apr_time_t prop_time; + + /** Hex MD5 checksum for the untranslated text base file, + * can be @c NULL for backwards compatibility. + */ + const char *checksum; + + /* "Entry props" */ + + /** last revision this was changed */ + svn_revnum_t cmt_rev; + + /** last date this was changed */ + apr_time_t cmt_date; + + /** last commit author of this item */ + const char *cmt_author; + + /** lock token or NULL if path not locked in this WC + * @since New in 1.2. + */ + const char *lock_token; + + /** lock owner, or NULL if not locked in this WC + * @since New in 1.2. + */ + const char *lock_owner; + + /** lock comment or NULL if not locked in this WC or no comment + * @since New in 1.2. + */ + const char *lock_comment; + + /** Lock creation date or 0 if not locked in this WC + * @since New in 1.2. + */ + apr_time_t lock_creation_date; + + /** Whether this entry has any working properties. + * False if this information is not stored in the entry. + * + * @since New in 1.4. */ + svn_boolean_t has_props; + + /** Whether this entry has property modifications. + * + * @note For working copies in older formats, this flag is not valid. + * + * @see svn_wc_props_modified_p(). + * + * @since New in 1.4. */ + svn_boolean_t has_prop_mods; + + /** A space-separated list of all properties whose presence/absence is cached + * in this entry. + * + * @see @c present_props. + * + * @since New in 1.4. + * @deprecated This value will always be "" in version 1.7 and later. */ + const char *cachable_props; + + /** Cached property existence for this entry. + * This is a space-separated list of property names. If a name exists in + * @c cachable_props but not in this list, this entry does not have that + * property. If a name exists in both lists, the property is present on this + * entry. + * + * @since New in 1.4. + * @deprecated This value will always be "" in version 1.7 and later. */ + const char *present_props; + + /** which changelist this item is part of, or NULL if not part of any. + * @since New in 1.5. + */ + const char *changelist; + + /** Size of the file after being translated into local + * representation, or @c SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN if + * unknown. + * + * @since New in 1.5. + */ + apr_off_t working_size; + + /** Whether a local copy of this entry should be kept in the working copy + * after a deletion has been committed, Only valid for the this-dir entry + * when it is scheduled for deletion. + * + * @since New in 1.5. */ + svn_boolean_t keep_local; + + /** The depth of this entry. + * + * ### It's a bit annoying that we only use this on this_dir + * ### entries, yet it will exist (with value svn_depth_infinity) on + * ### all entries. Maybe some future extensibility would make this + * ### field meaningful on entries besides this_dir. + * + * @since New in 1.5. */ + svn_depth_t depth; + + /** Serialized data for all of the tree conflicts detected in this_dir. + * + * @since New in 1.6. */ + const char *tree_conflict_data; + + /** The entry is a intra-repository file external and this is the + * repository root relative path to the file specified in the + * externals definition, otherwise NULL if the entry is not a file + * external. + * + * @since New in 1.6. */ + const char *file_external_path; + + /** The entry is a intra-repository file external and this is the + * peg revision number specified in the externals definition. This + * field is only valid when the file_external_path field is + * non-NULL. The only permissible values are + * svn_opt_revision_unspecified if the entry is not an external, + * svn_opt_revision_head if the external revision is unspecified or + * specified with -r HEAD or svn_opt_revision_number for a specific + * revision number. + * + * @since New in 1.6. */ + svn_opt_revision_t file_external_peg_rev; + + /** The entry is a intra-repository file external and this is the + * operative revision number specified in the externals definition. + * This field is only valid when the file_external_path field is + * non-NULL. The only permissible values are + * svn_opt_revision_unspecified if the entry is not an external, + * svn_opt_revision_head if the external revision is unspecified or + * specified with -r HEAD or svn_opt_revision_number for a specific + * revision number. + * + * @since New in 1.6. */ + svn_opt_revision_t file_external_rev; + + /* IMPORTANT: If you extend this structure, check the following functions in + * subversion/libsvn_wc/entries.c, to see if you need to extend them as well. + * + * svn_wc__atts_to_entry() + * svn_wc_entry_dup() + * alloc_entry() + * read_entry() + * write_entry() + * fold_entry() + */ +} svn_wc_entry_t; + + +/** How an entries file's owner dir is named in the entries file. */ +#define SVN_WC_ENTRY_THIS_DIR "" + + +/** Set @a *entry to an entry for @a path, allocated in the access baton pool. + * If @a show_hidden is TRUE, return the entry even if it's in 'excluded', + * 'deleted' or 'absent' state. Excluded entries are those with their depth + * set to @c svn_depth_exclude. If @a path is not under revision control, or + * if entry is hidden, not scheduled for re-addition, and @a show_hidden is @c + * FALSE, then set @a *entry to @c NULL. + * + * @a *entry should not be modified, since doing so modifies the entries + * cache in @a adm_access without changing the entries file on disk. + * + * If @a path is not a directory then @a adm_access must be an access baton + * for the parent directory of @a path. To avoid needing to know whether + * @a path is a directory or not, if @a path is a directory @a adm_access + * can still be an access baton for the parent of @a path so long as the + * access baton for @a path itself is in the same access baton set. + * + * @a path can be relative or absolute but must share the same base used + * to open @a adm_access. + * + * Note that it is possible for @a path to be absent from disk but still + * under revision control; and conversely, it is possible for @a path to + * be present, but not under revision control. + * + * Use @a pool only for local processing. + */ +svn_error_t * +svn_wc_entry(const svn_wc_entry_t **entry, + const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t show_hidden, + apr_pool_t *pool); + + +/** Parse the `entries' file for @a adm_access and return a hash @a entries, + * whose keys are (const char *) entry names and values are + * (svn_wc_entry_t *). The hash @a entries, and its keys and + * values, are allocated from the pool used to open the @a adm_access + * baton (that's how the entries caching works). @a pool is used for + * transient allocations. + * + * Entries that are in a 'excluded', 'deleted' or 'absent' state (and not + * scheduled for re-addition) are not returned in the hash, unless + * @a show_hidden is TRUE. Excluded entries are those with their depth set to + * @c svn_depth_exclude. + * + * @par Important: + * The @a entries hash is the entries cache in @a adm_access + * and so usually the hash itself, the keys and the values should be treated + * as read-only. If any of these are modified then it is the caller's + * responsibility to ensure that the entries file on disk is updated. Treat + * the hash values as type (const svn_wc_entry_t *) if you wish to + * avoid accidental modification. Modifying the schedule member is a + * particularly bad idea, as the entries writing process relies on having + * access to the original schedule. Use a duplicate entry to modify the + * schedule. + * + * @par Important: + * Only the entry structures representing files and + * @c SVN_WC_ENTRY_THIS_DIR contain complete information. The entry + * structures representing subdirs have only the `kind' and `state' + * fields filled in. If you want info on a subdir, you must use this + * routine to open its @a path and read the @c SVN_WC_ENTRY_THIS_DIR + * structure, or call svn_wc_entry() on its @a path. + */ +svn_error_t * +svn_wc_entries_read(apr_hash_t **entries, + svn_wc_adm_access_t *adm_access, + svn_boolean_t show_hidden, + apr_pool_t *pool); + + +/** Return a duplicate of @a entry, allocated in @a pool. No part of the new + * entry will be shared with @a entry. + */ +svn_wc_entry_t * +svn_wc_entry_dup(const svn_wc_entry_t *entry, + apr_pool_t *pool); + + +/** Given a @a path in a dir under version control, decide if it is in a + * state of conflict; return the answers in @a *text_conflicted_p, @a + * *prop_conflicted_p, and @a *tree_conflicted_p. If one or two of the + * answers are uninteresting, simply pass @c NULL pointers for those. + * + * If @a path is unversioned or does not exist, @a *text_conflicted_p and + * @a *prop_conflicted_p will be @c FALSE if non-NULL. + * + * @a adm_access is the admin access baton of the parent directory. + * + * If the @a path has corresponding text conflict files (with suffix .mine, + * .theirs, etc.) that cannot be found, assume that the text conflict has + * been resolved by the user and return @c FALSE in @a *text_conflicted_p. + * + * Similarly, if a property conflicts file (.prej suffix) is said to exist, + * but it cannot be found, assume that the property conflicts have been + * resolved by the user and return @c FALSE in @a *prop_conflicted_p. + * + * @a *tree_conflicted_p can't be auto-resolved in this fashion. An + * explicit `resolved' is needed. + * + * @since New in 1.6. + */ +svn_error_t * +svn_wc_conflicted_p2(svn_boolean_t *text_conflicted_p, + svn_boolean_t *prop_conflicted_p, + svn_boolean_t *tree_conflicted_p, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + +/** Given a @a dir_path under version control, decide if one of its entries + * (@a entry) is in a state of conflict; return the answers in @a + * text_conflicted_p and @a prop_conflicted_p. These pointers must not be + * null. + * + * If the @a entry mentions that text conflict files (with suffix .mine, + * .theirs, etc.) exist, but they cannot be found, assume the text conflict + * has been resolved by the user and return FALSE in @a *text_conflicted_p. + * + * Similarly, if the @a entry mentions that a property conflicts file (.prej + * suffix) exists, but it cannot be found, assume the property conflicts + * have been resolved by the user and return FALSE in @a *prop_conflicted_p. + * + * The @a entry is not updated. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_conflicted_p(svn_boolean_t *text_conflicted_p, + svn_boolean_t *prop_conflicted_p, + const char *dir_path, + const svn_wc_entry_t *entry, + apr_pool_t *pool); + +/** Set @a *url and @a *rev to the ancestor URL and revision for @a path, + * allocating in @a pool. @a adm_access must be an access baton for @a path. + * + * If @a url or @a rev is NULL, then ignore it (just don't return the + * corresponding information). + */ +svn_error_t * +svn_wc_get_ancestry(char **url, + svn_revnum_t *rev, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + + +/** A callback vtable invoked by the generic entry-walker function. + * @since New in 1.5. + */ +typedef struct svn_wc_entry_callbacks2_t +{ + /** An @a entry was found at @a path. */ + svn_error_t *(*found_entry)(const char *path, + const svn_wc_entry_t *entry, + void *walk_baton, + apr_pool_t *pool); + + /** Handle the error @a err encountered while processing @a path. + * Wrap or squelch @a err as desired, and return an @c svn_error_t + * *, or @c SVN_NO_ERROR. + */ + svn_error_t *(*handle_error)(const char *path, + svn_error_t *err, + void *walk_baton, + apr_pool_t *pool); + +} svn_wc_entry_callbacks2_t; + +/** @deprecated Provided for backward compatibility with the 1.4 API. */ +typedef struct svn_wc_entry_callbacks_t +{ + /** An @a entry was found at @a path. */ + svn_error_t *(*found_entry)(const char *path, + const svn_wc_entry_t *entry, + void *walk_baton, + apr_pool_t *pool); + +} svn_wc_entry_callbacks_t; + +/** + * A generic entry-walker. + * + * Do a potentially recursive depth-first entry-walk beginning on + * @a path, which can be a file or dir. Call callbacks in + * @a walk_callbacks, passing @a walk_baton to each. Use @a pool for + * looping, recursion, and to allocate all entries returned. + * @a adm_access must be an access baton for @a path. + * + * If @a depth is @c svn_depth_empty, invoke the callbacks on @a path + * and return without recursing further. If @c svn_depth_files, do + * the same and invoke the callbacks on file children (if any) of + * @a path, then return. If @c svn_depth_immediates, do the preceding + * but also invoke callbacks on immediate subdirectories, then return. + * If @c svn_depth_infinity, recurse fully starting from @a path. + * + * If @a cancel_func is non-NULL, call it with @a cancel_baton to determine + * if the client has cancelled the operation. + * + * Like our other entries interfaces, entries that are in a 'excluded', + * 'deleted' or 'absent' state (and not scheduled for re-addition) are not + * discovered, unless @a show_hidden is TRUE. Excluded entries are those with + * their depth set to @c svn_depth_exclude. + * + * When a new directory is entered, @c SVN_WC_ENTRY_THIS_DIR will always + * be returned first. + * + * @note Callers should be aware that each directory will be + * returned *twice*: first as an entry within its parent, and + * subsequently as the '.' entry within itself. The two calls can be + * distinguished by looking for @c SVN_WC_ENTRY_THIS_DIR in the 'name' + * field of the entry. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_walk_entries3(const char *path, + svn_wc_adm_access_t *adm_access, + const svn_wc_entry_callbacks2_t *walk_callbacks, + void *walk_baton, + svn_depth_t depth, + svn_boolean_t show_hidden, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_walk_entries3(), but without cancellation support + * or error handling from @a walk_callbacks, and with @a depth always + * set to @c svn_depth_infinity. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_walk_entries2(const char *path, + svn_wc_adm_access_t *adm_access, + const svn_wc_entry_callbacks_t *walk_callbacks, + void *walk_baton, + svn_boolean_t show_hidden, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_walk_entries2(), but without cancellation support. + * + * @deprecated Provided for backward compatibility with the 1.0 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_walk_entries(const char *path, + svn_wc_adm_access_t *adm_access, + const svn_wc_entry_callbacks_t *walk_callbacks, + void *walk_baton, + svn_boolean_t show_hidden, + apr_pool_t *pool); + + +/** Mark missing @a path as 'deleted' in its @a parent's list of entries. + * + * Return @c SVN_ERR_WC_PATH_FOUND if @a path isn't actually missing. + */ +svn_error_t * +svn_wc_mark_missing_deleted(const char *path, + svn_wc_adm_access_t *parent, + apr_pool_t *pool); + + +/** Ensure that an administrative area exists for @a path, so that @a + * path is a working copy subdir based on @a url at @a revision, with + * depth @a depth, and with repository UUID @a uuid and repository + * root URL @a repos. + * + * @a depth must be a definite depth, it cannot be @c svn_depth_unknown. + * @a uuid and @a repos may be @c NULL. If non-@c NULL, @a repos must + * be a prefix of @a url. + * + * If the administrative area does not exist, then create it and + * initialize it to an unlocked state. + * + * If the administrative area already exists then the given @a url + * must match the URL in the administrative area and the given + * @a revision must match the BASE of the working copy dir unless + * the admin directory is scheduled for deletion or the + * SVN_ERR_WC_OBSTRUCTED_UPDATE error will be returned. + * + * Do not ensure existence of @a path itself; if @a path does not + * exist, return error. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_ensure_adm3(const char *path, + const char *uuid, + const char *url, + const char *repos, + svn_revnum_t revision, + svn_depth_t depth, + apr_pool_t *pool); + + +/** + * Similar to svn_wc_ensure_adm3(), but with @a depth set to + * @c svn_depth_infinity. + * + * @deprecated Provided for backwards compatibility with the 1.4 API. + * + * @since New in 1.3. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_ensure_adm2(const char *path, + const char *uuid, + const char *url, + const char *repos, + svn_revnum_t revision, + apr_pool_t *pool); + + +/** + * Similar to svn_wc_ensure_adm2(), but with @a repos set to @c NULL. + * + * @deprecated Provided for backwards compatibility with the 1.2 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_ensure_adm(const char *path, + const char *uuid, + const char *url, + svn_revnum_t revision, + apr_pool_t *pool); + + +/** Set the repository root URL of @a path to @a repos, if possible. + * + * @a adm_access must contain @a path and be write-locked, if @a path + * is versioned. Return no error if path is missing or unversioned. + * Use @a pool for temporary allocations. + * + * @note In some circumstances, the repository root can't be set + * without making the working copy corrupt. In such cases, this + * function just returns no error, without modifying the @a path entry. + * + * @note This function exists to make it possible to try to set the repository + * root in old working copies; new working copies normally get this set at + * creation time. + * + * @since New in 1.3. + */ +svn_error_t * +svn_wc_maybe_set_repos_root(svn_wc_adm_access_t *adm_access, + const char *path, + const char *repos, + apr_pool_t *pool); + + +/** + * @defgroup svn_wc_status Working copy status. + * @{ + * + * We have two functions for getting working copy status: one function + * for getting the status of exactly one thing, and another for + * getting the statuses of (potentially) multiple things. + * + * The concept of depth, as explained in the documentation for + * svn_depth_t, may be useful in understanding this. Suppose we're + * getting the status of directory D: + * + * To offer all three levels, we could have one unified function, + * taking a `depth' parameter. Unfortunately, because this function + * would have to handle multiple return values as well as the single + * return value case, getting the status of just one entity would + * become cumbersome: you'd have to roll through a hash to find one + * lone status. + * + * So we have svn_wc_status() for depth-empty (just D itself), and + * svn_wc_get_status_editor() for depth-immediates and depth-infinity, + * since the latter two involve multiple return values. + * + * @note The status structures may contain a @c NULL ->entry field. + * This indicates an item that is not versioned in the working copy. + */ + +/** The type of status for the working copy. */ +enum svn_wc_status_kind +{ + /** does not exist */ + svn_wc_status_none = 1, + + /** is not a versioned thing in this wc */ + svn_wc_status_unversioned, + + /** exists, but uninteresting */ + svn_wc_status_normal, + + /** is scheduled for addition */ + svn_wc_status_added, + + /** under v.c., but is missing */ + svn_wc_status_missing, + + /** scheduled for deletion */ + svn_wc_status_deleted, + + /** was deleted and then re-added */ + svn_wc_status_replaced, + + /** text or props have been modified */ + svn_wc_status_modified, + + /** local mods received repos mods */ + svn_wc_status_merged, + + /** local mods received conflicting repos mods */ + svn_wc_status_conflicted, + + /** is unversioned but configured to be ignored */ + svn_wc_status_ignored, + + /** an unversioned resource is in the way of the versioned resource */ + svn_wc_status_obstructed, + + /** an unversioned directory path populated by an svn:externals + property; this status is not used for file externals */ + svn_wc_status_external, + + /** a directory doesn't contain a complete entries list */ + svn_wc_status_incomplete +}; + +/** + * Structure for holding the "status" of a working copy item. + * + * The item's entry data is in @a entry, augmented and possibly shadowed + * by the other fields. @a entry is @c NULL if this item is not under + * version control. + * + * @note Fields may be added to the end of this structure in future + * versions. Therefore, to preserve binary compatibility, users + * should not directly allocate structures of this type. + * + * @since New in 1.2. + */ +typedef struct svn_wc_status2_t +{ + /** Can be @c NULL if not under version control. */ + svn_wc_entry_t *entry; + + /** The status of the entries text. */ + enum svn_wc_status_kind text_status; + + /** The status of the entries properties. */ + enum svn_wc_status_kind prop_status; + + /** a directory can be 'locked' if a working copy update was interrupted. */ + svn_boolean_t locked; + + /** a file or directory can be 'copied' if it's scheduled for + * addition-with-history (or part of a subtree that is scheduled as such.). + */ + svn_boolean_t copied; + + /** a file or directory can be 'switched' if the switch command has been + * used. If this is TRUE, then file_external will be FALSE. + */ + svn_boolean_t switched; + + /** The entry's text status in the repository. */ + enum svn_wc_status_kind repos_text_status; + + /** The entry's property status in the repository. */ + enum svn_wc_status_kind repos_prop_status; + + /** The entry's lock in the repository, if any. */ + svn_lock_t *repos_lock; + + /** Set to the URI (actual or expected) of the item. + * @since New in 1.3 + */ + const char *url; + + /** + * @defgroup svn_wc_status_ood WC out-of-date info from the repository + * @{ + * + * When the working copy item is out-of-date compared to the + * repository, the following fields represent the state of the + * youngest revision of the item in the repository. If the working + * copy is not out of date, the fields are initialized as described + * below. + */ + + /** Set to the youngest committed revision, or @c SVN_INVALID_REVNUM + * if not out of date. + * @since New in 1.3 + */ + svn_revnum_t ood_last_cmt_rev; + + /** Set to the most recent commit date, or @c 0 if not out of date. + * @since New in 1.3 + */ + apr_time_t ood_last_cmt_date; + + /** Set to the node kind of the youngest commit, or @c svn_node_none + * if not out of date. + * @since New in 1.3 + */ + svn_node_kind_t ood_kind; + + /** Set to the user name of the youngest commit, or @c NULL if not + * out of date or non-existent. Because a non-existent @c + * svn:author property has the same behavior as an out-of-date + * working copy, examine @c ood_last_cmt_rev to determine whether + * the working copy is out of date. + * @since New in 1.3 + */ + const char *ood_last_cmt_author; + + /** @} */ + + /** Non-NULL if the entry is the victim of a tree conflict. + * @since New in 1.6 + */ + svn_wc_conflict_description_t *tree_conflict; + + /** If the item is a file that was added to the working copy with an + * svn:externals; if file_external is TRUE, then switched is always + * FALSE. + * @since New in 1.6 + */ + svn_boolean_t file_external; + + /** The actual status of the text compared to the pristine base of the + * file. This value isn't masked by other working copy statuses. + * @c pristine_text_status is @c svn_wc_status_none if this value was + * not calculated during the status walk. + * @since New in 1.6 + */ + enum svn_wc_status_kind pristine_text_status; + + /** The actual status of the properties compared to the pristine base of + * the node. This value isn't masked by other working copy statuses. + * @c pristine_prop_status is @c svn_wc_status_none if this value was + * not calculated during the status walk. + * @since New in 1.6 + */ + enum svn_wc_status_kind pristine_prop_status; + + /* NOTE! Please update svn_wc_dup_status2() when adding new fields here. */ +} svn_wc_status2_t; + + + +/** + * Same as @c svn_wc_status2_t, but without the svn_lock_t 'repos_lock' field. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +typedef struct svn_wc_status_t +{ + /** Can be @c NULL if not under version control. */ + svn_wc_entry_t *entry; + + /** The status of the entries text. */ + enum svn_wc_status_kind text_status; + + /** The status of the entries properties. */ + enum svn_wc_status_kind prop_status; + + /** a directory can be 'locked' if a working copy update was interrupted. */ + svn_boolean_t locked; + + /** a file or directory can be 'copied' if it's scheduled for + * addition-with-history (or part of a subtree that is scheduled as such.). + */ + svn_boolean_t copied; + + /** a file or directory can be 'switched' if the switch command has been + * used. + */ + svn_boolean_t switched; + + /** The entry's text status in the repository. */ + enum svn_wc_status_kind repos_text_status; + + /** The entry's property status in the repository. */ + enum svn_wc_status_kind repos_prop_status; + +} svn_wc_status_t; + + + +/** + * Return a deep copy of the @a orig_stat status structure, allocated + * in @a pool. + * + * @since New in 1.2. + */ +svn_wc_status2_t * +svn_wc_dup_status2(const svn_wc_status2_t *orig_stat, + apr_pool_t *pool); + + +/** + * Same as svn_wc_dup_status2(), but for older svn_wc_status_t structures. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_wc_status_t * +svn_wc_dup_status(const svn_wc_status_t *orig_stat, + apr_pool_t *pool); + + +/** + * Fill @a *status for @a path, allocating in @a pool. + * @a adm_access must be an access baton for @a path. + * + * Here are some things to note about the returned structure. A quick + * examination of the @c status->text_status after a successful return of + * this function can reveal the following things: + * + * - @c svn_wc_status_none : @a path is not versioned, and is either not + * present on disk, or is ignored by svn's + * default ignore regular expressions or the + * svn:ignore property setting for @a path's + * parent directory. + * + * - @c svn_wc_status_missing : @a path is versioned, but is missing from + * the working copy. + * + * - @c svn_wc_status_unversioned : @a path is not versioned, but is + * present on disk and not being + * ignored (see above). + * + * The other available results for the @c text_status field are more + * straightforward in their meanings. See the comments on the + * @c svn_wc_status_kind structure for some hints. + * + * @since New in 1.2. + */ +svn_error_t * +svn_wc_status2(svn_wc_status2_t **status, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + + +/** + * Same as svn_wc_status2(), but for older svn_wc_status_t structures. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_status(svn_wc_status_t **status, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + + + + +/** + * A callback for reporting a @a status about @a path. + * + * @a baton is a closure object; it should be provided by the + * implementation, and passed by the caller. + * + * @a pool will be cleared between invocations to the callback. + * + * @since New in 1.6. + */ +typedef svn_error_t *(*svn_wc_status_func3_t)(void *baton, + const char *path, + svn_wc_status2_t *status, + apr_pool_t *pool); + +/** + * Same as svn_wc_status_func3_t(), but without a provided pool or + * the ability to propagate errors. + * + * @since New in 1.2. + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +typedef void (*svn_wc_status_func2_t)(void *baton, + const char *path, + svn_wc_status2_t *status); + +/** + * Same as svn_wc_status_func2_t(), but for older svn_wc_status_t structures. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +typedef void (*svn_wc_status_func_t)(void *baton, + const char *path, + svn_wc_status_t *status); + + +/** + * Set @a *editor and @a *edit_baton to an editor that generates @c + * svn_wc_status2_t structures and sends them through @a status_func / + * @a status_baton. @a anchor is an access baton, with a tree lock, + * for the local path to the working copy which will be used as the + * root of our editor. If @a target is not empty, it represents an + * entry in the @a anchor path which is the subject of the editor + * drive (otherwise, the @a anchor is the subject). + * + * If @a set_locks_baton is non-@c NULL, it will be set to a baton that can + * be used in a call to the svn_wc_status_set_repos_locks() function. + * + * Callers drive this editor to describe working copy out-of-dateness + * with respect to the repository. If this information is not + * available or not desired, callers should simply call the + * close_edit() function of the @a editor vtable. + * + * If the editor driver calls @a editor's set_target_revision() vtable + * function, then when the edit drive is completed, @a *edit_revision + * will contain the revision delivered via that interface. + * + * Assuming the target is a directory, then: + * + * - If @a get_all is FALSE, then only locally-modified entries will be + * returned. If TRUE, then all entries will be returned. + * + * - If @a depth is @c svn_depth_empty, a status structure will + * be returned for the target only; if @c svn_depth_files, for the + * target and its immediate file children; if + * @c svn_depth_immediates, for the target and its immediate + * children; if @c svn_depth_infinity, for the target and + * everything underneath it, fully recursively. + * + * If @a depth is @c svn_depth_unknown, take depths from the + * working copy and behave as above in each directory's case. + * + * If the given @a depth is incompatible with the depth found in a + * working copy directory, the found depth always governs. + * + * If @a no_ignore is set, statuses that would typically be ignored + * will instead be reported. + * + * @a ignore_patterns is an array of file patterns matching + * unversioned files to ignore for the purposes of status reporting, + * or @c NULL if the default set of ignorable file patterns should be used. + * + * If @a cancel_func is non-NULL, call it with @a cancel_baton while building + * the @a statushash to determine if the client has cancelled the operation. + * + * If @a traversal_info is non-NULL, then record pre-update traversal + * state in it. (Caller should obtain @a traversal_info from + * svn_wc_init_traversal_info().) + * + * Allocate the editor itself in @a pool, but the editor does temporary + * allocations in a subpool of @a pool. + * + * @since New in 1.6. + */ +svn_error_t * +svn_wc_get_status_editor4(const svn_delta_editor_t **editor, + void **edit_baton, + void **set_locks_baton, + svn_revnum_t *edit_revision, + svn_wc_adm_access_t *anchor, + const char *target, + svn_depth_t depth, + svn_boolean_t get_all, + svn_boolean_t no_ignore, + const apr_array_header_t *ignore_patterns, + svn_wc_status_func3_t status_func, + void *status_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_traversal_info_t *traversal_info, + apr_pool_t *pool); + +/** + * Same as svn_wc_get_status_editor4(), but using @c svn_wc_status_func2_t + * instead of @c svn_wc_status_func3_t. + * + * @since New in 1.5. + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_status_editor3(const svn_delta_editor_t **editor, + void **edit_baton, + void **set_locks_baton, + svn_revnum_t *edit_revision, + svn_wc_adm_access_t *anchor, + const char *target, + svn_depth_t depth, + svn_boolean_t get_all, + svn_boolean_t no_ignore, + apr_array_header_t *ignore_patterns, + svn_wc_status_func2_t status_func, + void *status_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_traversal_info_t *traversal_info, + apr_pool_t *pool); + +/** + * Like svn_wc_get_status_editor3(), but with @a ignore_patterns + * provided from the corresponding value in @a config, and @a recurse + * instead of @a depth. If @a recurse is TRUE, behave as if for @c + * svn_depth_infinity; else if @a recurse is FALSE, behave as if for + * @c svn_depth_immediates. + * + * @since New in 1.2. + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_status_editor2(const svn_delta_editor_t **editor, + void **edit_baton, + void **set_locks_baton, + svn_revnum_t *edit_revision, + svn_wc_adm_access_t *anchor, + const char *target, + apr_hash_t *config, + svn_boolean_t recurse, + svn_boolean_t get_all, + svn_boolean_t no_ignore, + svn_wc_status_func2_t status_func, + void *status_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_traversal_info_t *traversal_info, + apr_pool_t *pool); + +/** + * Same as svn_wc_get_status_editor2(), but with @a set_locks_baton set + * to @c NULL, and taking a deprecated svn_wc_status_func_t argument. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_status_editor(const svn_delta_editor_t **editor, + void **edit_baton, + svn_revnum_t *edit_revision, + svn_wc_adm_access_t *anchor, + const char *target, + apr_hash_t *config, + svn_boolean_t recurse, + svn_boolean_t get_all, + svn_boolean_t no_ignore, + svn_wc_status_func_t status_func, + void *status_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_traversal_info_t *traversal_info, + apr_pool_t *pool); + + +/** + * Associate @a locks, a hash table mapping const char* + * absolute repository paths to svn_lock_t objects, with a + * @a set_locks_baton returned by an earlier call to + * svn_wc_get_status_editor3(). @a repos_root is the repository root URL. + * Perform all allocations in @a pool. + * + * @note @a locks will not be copied, so it must be valid throughout the + * edit. @a pool must also not be destroyed or cleared before the edit is + * finished. + * + * @since New in 1.2. + */ +svn_error_t * +svn_wc_status_set_repos_locks(void *set_locks_baton, + apr_hash_t *locks, + const char *repos_root, + apr_pool_t *pool); + +/** @} */ + + +/** + * Copy @a src to @a dst_basename in @a dst_parent, and schedule + * @a dst_basename for addition to the repository, remembering the copy + * history. + * + * @a src must be a file or directory under version control; @a dst_parent + * must be a directory under version control in the same working copy; + * @a dst_basename will be the name of the copied item, and it must not + * exist already. + * + * If @a cancel_func is non-NULL, call it with @a cancel_baton at + * various points during the operation. If it returns an error + * (typically @c SVN_ERR_CANCELLED), return that error immediately. + * + * For each file or directory copied, @a notify_func will be called + * with its path and the @a notify_baton. @a notify_func may be @c NULL + * if you are not interested in this information. + * + * @par Important: + * This is a variant of svn_wc_add(). No changes will happen + * to the repository until a commit occurs. This scheduling can be + * removed with svn_client_revert2(). + * + * @since New in 1.2. + */ +svn_error_t * +svn_wc_copy2(const char *src, + svn_wc_adm_access_t *dst_parent, + const char *dst_basename, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_copy2(), but takes an @c svn_wc_notify_func_t instead. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_copy(const char *src, + svn_wc_adm_access_t *dst_parent, + const char *dst_basename, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func_t notify_func, + void *notify_baton, + apr_pool_t *pool); + +/** + * Schedule @a path for deletion, it will be deleted from the repository on + * the next commit. If @a path refers to a directory, then a recursive + * deletion will occur. @a adm_access must hold a write lock for the parent + * of @a path. + * + * If @a keep_local is FALSE, this function immediately deletes all files, + * modified and unmodified, versioned and unversioned from the working copy. + * It also immediately deletes unversioned directories and directories that + * are scheduled to be added. Only versioned directories will remain in the + * working copy, these get deleted by the update following the commit. + * + * If @a keep_local is TRUE, all files and directories will be kept in the + * working copy (and will become unversioned on the next commit). + * + * If @a cancel_func is non-NULL, call it with @a cancel_baton at + * various points during the operation. If it returns an error + * (typically @c SVN_ERR_CANCELLED), return that error immediately. + * + * For each path marked for deletion, @a notify_func will be called with + * the @a notify_baton and that path. The @a notify_func callback may be + * @c NULL if notification is not needed. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_delete3(const char *path, + svn_wc_adm_access_t *adm_access, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_boolean_t keep_local, + apr_pool_t *pool); + +/** + * Similar to svn_wc_delete3(), but with @a keep_local always set to FALSE. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_delete2(const char *path, + svn_wc_adm_access_t *adm_access, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_delete2(), but takes an @c svn_wc_notify_func_t instead. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_delete(const char *path, + svn_wc_adm_access_t *adm_access, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func_t notify_func, + void *notify_baton, + apr_pool_t *pool); + + +/** + * Put @a path under version control by adding an entry in its parent, + * and, if @a path is a directory, adding an administrative area. The + * new entry and anything under it is scheduled for addition to the + * repository. @a parent_access should hold a write lock for the parent + * directory of @a path. If @a path is a directory then an access baton + * for @a path will be added to the set containing @a parent_access. + * + * If @a path does not exist, return @c SVN_ERR_WC_PATH_NOT_FOUND. + * + * If @a path is a directory, add it at @a depth; otherwise, ignore + * @a depth. + * + * If @a copyfrom_url is non-NULL, it and @a copyfrom_rev are used as + * `copyfrom' args. This is for copy operations, where one wants + * to schedule @a path for addition with a particular history. + * + * If @a cancel_func is non-NULL, call it with @a cancel_baton at + * various points during the operation. If it returns an error + * (typically @c SVN_ERR_CANCELLED), return that error immediately. + * + * When the @a path has been added, then @a notify_func will be called + * (if it is not @c NULL) with the @a notify_baton and the path. + * + * Return @c SVN_ERR_WC_NODE_KIND_CHANGE if @a path is both an unversioned + * directory and a file that is scheduled for deletion or in state deleted. + * + *
 ### This function currently does double duty -- it is also
+ * ### responsible for "switching" a working copy directory over to a
+ * ### new copyfrom ancestry and scheduling it for addition.  Here is
+ * ### the old doc string from Ben, lightly edited to bring it
+ * ### up-to-date, explaining the TRUE, secret life of this function:
+ * + * Given a @a path within a working copy of type KIND, follow this algorithm: + * + * - if @a path is not under version control: + * - Place it under version control and schedule for addition; + * if @a copyfrom_url is non-NULL, use it and @a copyfrom_rev as + * 'copyfrom' history + * + * - if @a path is already under version control: + * (This can only happen when a directory is copied, in which + * case ancestry must have been supplied as well.) + * + * - Schedule the directory itself for addition with copyfrom history. + * - Mark all its children with a 'copied' flag + * - Rewrite all the URLs to what they will be after a commit. + * - ### @todo Remove old wcprops too, see the '###' below. + * + *
 ### I think possibly the "switchover" functionality should be
+ * ### broken out into a separate function, but its all intertwined in
+ * ### the code right now.  Ben, thoughts?  Hard?  Easy?  Mauve?
+ * + * ### Update: see "###" comment in svn_wc_add_repos_file3()'s doc + * string about this. + * + * @since New in 1.6. + */ +svn_error_t * +svn_wc_add3(const char *path, + svn_wc_adm_access_t *parent_access, + svn_depth_t depth, + const char *copyfrom_url, + svn_revnum_t copyfrom_rev, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_add3(), but with the @a depth parameter always + * @c svn_depth_infinity. + * + * @since New in 1.2. + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_add2(const char *path, + svn_wc_adm_access_t *parent_access, + const char *copyfrom_url, + svn_revnum_t copyfrom_rev, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_add2(), but takes an @c svn_wc_notify_func_t instead. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_add(const char *path, + svn_wc_adm_access_t *parent_access, + const char *copyfrom_url, + svn_revnum_t copyfrom_rev, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func_t notify_func, + void *notify_baton, + apr_pool_t *pool); + +/** Add a file to a working copy at @a dst_path, obtaining the text-base's + * contents from @a new_base_contents, the wc file's content from + * @a new_contents, its base properties from @a new_base_props and + * wc properties from @a new_props. + * + * The base text and props normally come from the repository file + * represented by the copyfrom args, see below. The new file will + * be scheduled for addition with history. + * + * @a new_contents and @a new_props may be NULL, in which case + * the working copy text and props are taken from the base files with + * appropriate translation of the file's content. + * + * @a new_contents must be provided in Normal Form. This is required + * in order to pass both special and non-special files through a stream. + * + * @a adm_access, or an access baton in its associated set, must + * contain a write lock for the parent of @a dst_path. + * + * If @a copyfrom_url is non-NULL, then @a copyfrom_rev must be a + * valid revision number, and together they are the copyfrom history + * for the new file. + * + * The @a cancel_func and @a cancel_baton are a standard cancellation + * callback, or NULL if no callback is needed. @a notify_func and + * @a notify_baton are a notification callback, and will be notified + * of the addition of this file. + * + * Use @a scratch_pool for temporary allocations. + * + * ### NOTE: the notification callback/baton is not yet used. + * + * ### This function is very redundant with svn_wc_add(). Ideally, + * we'd merge them, so that svn_wc_add() would just take optional + * new_props and optional copyfrom information. That way it could be + * used for both 'svn add somefilesittingonmydisk' and for adding + * files from repositories, with or without copyfrom history. + * + * The problem with this Ideal Plan is that svn_wc_add() also takes + * care of recursive URL-rewriting. There's a whole comment in its + * doc string about how that's really weird, outside its core mission, + * etc, etc. So another part of the Ideal Plan is that that + * functionality of svn_wc_add() would move into a separate function. + * + * @since New in 1.6 + */ +svn_error_t * +svn_wc_add_repos_file3(const char *dst_path, + svn_wc_adm_access_t *adm_access, + svn_stream_t *new_base_contents, + svn_stream_t *new_contents, + apr_hash_t *new_base_props, + apr_hash_t *new_props, + const char *copyfrom_url, + svn_revnum_t copyfrom_rev, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool); + + +/** Same as svn_wc_add_repos_file3(), except that it has pathnames rather + * than streams for the text base, and actual text, and has no cancellation. + * + * @since New in 1.4. + * @deprecated Provided for compatibility with the 1.5 API + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_add_repos_file2(const char *dst_path, + svn_wc_adm_access_t *adm_access, + const char *new_text_base_path, + const char *new_text_path, + apr_hash_t *new_base_props, + apr_hash_t *new_props, + const char *copyfrom_url, + svn_revnum_t copyfrom_rev, + apr_pool_t *pool); + +/** Same as svn_wc_add_repos_file3(), except that it doesn't have the + * BASE arguments or cancellation. + * + * @deprecated Provided for compatibility with the 1.3 API + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_add_repos_file(const char *dst_path, + svn_wc_adm_access_t *adm_access, + const char *new_text_path, + apr_hash_t *new_props, + const char *copyfrom_url, + svn_revnum_t copyfrom_rev, + apr_pool_t *pool); + + +/** Remove entry @a name in @a adm_access from revision control. @a name + * must be either a file or @c SVN_WC_ENTRY_THIS_DIR. @a adm_access must + * hold a write lock. + * + * If @a name is a file, all its info will be removed from @a adm_access's + * administrative directory. If @a name is @c SVN_WC_ENTRY_THIS_DIR, then + * @a adm_access's entire administrative area will be deleted, along with + * *all* the administrative areas anywhere in the tree below @a adm_access. + * + * Normally, only administrative data is removed. However, if + * @a destroy_wf is TRUE, then all working file(s) and dirs are deleted + * from disk as well. When called with @a destroy_wf, any locally + * modified files will *not* be deleted, and the special error + * @c SVN_ERR_WC_LEFT_LOCAL_MOD might be returned. (Callers only need to + * check for this special return value if @a destroy_wf is TRUE.) + * + * If @a instant_error is TRUE, then return @c + * SVN_ERR_WC_LEFT_LOCAL_MOD the instant a locally modified file is + * encountered. Otherwise, leave locally modified files in place and + * return the error only after all the recursion is complete. + * + * If @a cancel_func is non-NULL, call it with @a cancel_baton at + * various points during the removal. If it returns an error + * (typically @c SVN_ERR_CANCELLED), return that error immediately. + * + * WARNING: This routine is exported for careful, measured use by + * libsvn_client. Do *not* call this routine unless you really + * understand what the heck you're doing. + */ +svn_error_t * +svn_wc_remove_from_revision_control(svn_wc_adm_access_t *adm_access, + const char *name, + svn_boolean_t destroy_wf, + svn_boolean_t instant_error, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + + +/** + * Assuming @a path is under version control and in a state of conflict, + * then take @a path *out* of this state. If @a resolve_text is TRUE then + * any text conflict is resolved, if @a resolve_props is TRUE then any + * property conflicts are resolved, if @a resolve_tree is TRUE then any + * tree conflicts are resolved. + * + * If @a depth is @c svn_depth_empty, act only on @a path; if + * @c svn_depth_files, resolve @a path and its conflicted file + * children (if any); if @c svn_depth_immediates, resolve @a path and + * all its immediate conflicted children (both files and directories, + * if any); if @c svn_depth_infinity, resolve @a path and every + * conflicted file or directory anywhere beneath it. + * + * If @a conflict_choice is @c svn_wc_conflict_choose_base, resolve the + * conflict with the old file contents; if + * @c svn_wc_conflict_choose_mine_full, use the original working contents; + * if @c svn_wc_conflict_choose_theirs_full, the new contents; and if + * @c svn_wc_conflict_choose_merged, don't change the contents at all, + * just remove the conflict status, which is the pre-1.5 behavior. + * + * @c svn_wc_conflict_choose_theirs_conflict and @c + * svn_wc_conflict_choose_mine_conflict are not legal for binary + * files or properties. + * + * @a adm_access is an access baton, with a write lock, for @a path. + * + * Needless to say, this function doesn't touch conflict markers or + * anything of that sort -- only a human can semantically resolve a + * conflict. Instead, this function simply marks a file as "having + * been resolved", clearing the way for a commit. + * + * The implementation details are opaque, as our "conflicted" criteria + * might change over time. (At the moment, this routine removes the + * three fulltext 'backup' files and any .prej file created in a conflict, + * and modifies @a path's entry.) + * + * If @a path is not under version control, return @c SVN_ERR_ENTRY_NOT_FOUND. + * If @a path isn't in a state of conflict to begin with, do nothing, and + * return @c SVN_NO_ERROR. + * + * If @c path was successfully taken out of a state of conflict, report this + * information to @c notify_func (if non-@c NULL.) If only text, only + * property, or only tree conflict resolution was requested, and it was + * successful, then success gets reported. + * + * @since New in 1.6. + */ +svn_error_t * +svn_wc_resolved_conflict4(const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t resolve_text, + svn_boolean_t resolve_props, + svn_boolean_t resolve_tree, + svn_depth_t depth, + svn_wc_conflict_choice_t conflict_choice, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + + +/** + * Similar to svn_wc_resolved_conflict4(), but without tree-conflict + * resolution support. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_resolved_conflict3(const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t resolve_text, + svn_boolean_t resolve_props, + svn_depth_t depth, + svn_wc_conflict_choice_t conflict_choice, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + + +/** + * Similar to svn_wc_resolved_conflict3(), but without automatic conflict + * resolution support, and with @a depth set according to @a recurse: + * if @a recurse is TRUE, @a depth is @c svn_depth_infinity, else it is + * @c svn_depth_files. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_resolved_conflict2(const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t resolve_text, + svn_boolean_t resolve_props, + svn_boolean_t recurse, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_resolved_conflict2(), but takes an + * svn_wc_notify_func_t and doesn't have cancellation support. + * + * @deprecated Provided for backward compatibility with the 1.0 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_resolved_conflict(const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t resolve_text, + svn_boolean_t resolve_props, + svn_boolean_t recurse, + svn_wc_notify_func_t notify_func, + void *notify_baton, + apr_pool_t *pool); + + +/* Commits. */ + + +/** + * Storage type for queued post-commit data. + * + * @since New in 1.5. + */ +typedef struct svn_wc_committed_queue_t svn_wc_committed_queue_t; + + +/** + * Create a queue for use with svn_wc_queue_committed() and + * svn_wc_process_committed_queue(). + * + * The returned queue and all further allocations required for queueing + * new items will also be done from @a pool. + * + * @since New in 1.5. + */ +svn_wc_committed_queue_t * +svn_wc_committed_queue_create(apr_pool_t *pool); + + +/** + * Queue committed items to be processed later by + * svn_wc_process_committed_queue(). + * + * All pointer data passed to this function (@a path, @a adm_access, + * @a wcprop_changes and @a checksum) should remain valid until the queue + * has been processed by svn_wc_process_committed_queue(). + * + * Record in @a queue that @a path will need to be bumped after a commit + * succeeds. @a adm_access must hold a write lock appropriate for @a path. + * + * If non-NULL, @a wcprop_changes is an array of svn_prop_t * + * changes to wc properties; if an @c svn_prop_t->value is NULL, then + * that property is deleted. + * + * If @a remove_lock is @c TRUE, any entryprops related to a repository + * lock will be removed. + * + * If @a remove_changelist is @c TRUE, any association with a + * changelist will be removed. + * + * If @a path is a file and @a checksum is non-NULL, use @a checksum as + * the checksum for the new text base. Otherwise, calculate the checksum + * if needed. + * + * If @a recurse is TRUE and @a path is a directory, then bump every + * versioned object at or under @a path. This is usually done for + * copied trees. + * + * Temporary allocations will be performed in @a scratch_pool, and persistent + * allocations will use the same pool as @a queue used when it was created. + * + * @note the @a recurse parameter should be used with extreme care since + * it will bump ALL nodes under the directory, regardless of their + * actual inclusion in the new revision. + * + * @since New in 1.6. + */ +svn_error_t * +svn_wc_queue_committed2(svn_wc_committed_queue_t *queue, + const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t recurse, + apr_array_header_t *wcprop_changes, + svn_boolean_t remove_lock, + svn_boolean_t remove_changelist, + svn_checksum_t *checksum, + apr_pool_t *scratch_pool); + + +/** Same as svn_wc_queue_committed2() but the @a queue parameter has an + * extra indirection and @a digest is supplied instead of a checksum type. + * + * @note despite the extra indirection, this function does NOT allocate + * the queue for you. svn_wc_committed_queue_create() must be called. + * + * @since New in 1.5 + * + * @deprecated Provided for backwards compatibility with 1.5 + */ +svn_error_t * +svn_wc_queue_committed(svn_wc_committed_queue_t **queue, + const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t recurse, + apr_array_header_t *wcprop_changes, + svn_boolean_t remove_lock, + svn_boolean_t remove_changelist, + const unsigned char *digest, + apr_pool_t *pool); + + +/** + * Bump all items in @a queue to @a new_revnum after a commit succeeds. + * @a rev_date and @a rev_author are the (server-side) date and author + * of the new revision; one or both may be @c NULL. + * + * @a adm_access must be associated with all affected directories, and + * must hold a write lock in each one. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_process_committed_queue(svn_wc_committed_queue_t *queue, + svn_wc_adm_access_t *adm_access, + svn_revnum_t new_revnum, + const char *rev_date, + const char *rev_author, + apr_pool_t *pool); + + +/** + * @note this function has improper expectations around the operation and + * execution of other parts of the Subversion WC library. The resulting + * coupling makes this interface near-impossible to support. Documentation + * has been removed, as a result. + * + * @deprecated Use the svn_wc_committed_queue_* functions instead. Provided + * for backwards compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_process_committed4(const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t recurse, + svn_revnum_t new_revnum, + const char *rev_date, + const char *rev_author, + apr_array_header_t *wcprop_changes, + svn_boolean_t remove_lock, + svn_boolean_t remove_changelist, + const unsigned char *digest, + apr_pool_t *pool); + +/** @see svn_wc_process_committed4() + * + * @deprecated Use the svn_wc_committed_queue_* functions instead. Provided + * for backwards compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_process_committed3(const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t recurse, + svn_revnum_t new_revnum, + const char *rev_date, + const char *rev_author, + apr_array_header_t *wcprop_changes, + svn_boolean_t remove_lock, + const unsigned char *digest, + apr_pool_t *pool); + +/** @see svn_wc_process_committed4() + * + * @deprecated Use the svn_wc_committed_queue_* functions instead. Provided + * for backwards compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_process_committed2(const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t recurse, + svn_revnum_t new_revnum, + const char *rev_date, + const char *rev_author, + apr_array_header_t *wcprop_changes, + svn_boolean_t remove_lock, + apr_pool_t *pool); + +/** @see svn_wc_process_committed4() + * + * @deprecated Use the svn_wc_committed_queue_* functions instead. Provided + * for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_process_committed(const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t recurse, + svn_revnum_t new_revnum, + const char *rev_date, + const char *rev_author, + apr_array_header_t *wcprop_changes, + apr_pool_t *pool); + + + + + +/** + * Do a depth-first crawl in a working copy, beginning at @a path. + * + * Communicate the `state' of the working copy's revisions and depths + * to @a reporter/@a report_baton. Obviously, if @a path is a file + * instead of a directory, this depth-first crawl will be a short one. + * + * No locks are or logs are created, nor are any animals harmed in the + * process. No cleanup is necessary. @a adm_access must be an access + * baton for the @a path hierarchy, it does not require a write lock. + * + * After all revisions are reported, @a reporter->finish_report() is + * called, which immediately causes the RA layer to update the working + * copy. Thus the return value may very well reflect the result of + * the update! + * + * If @a depth is @c svn_depth_empty, then report state only for + * @a path itself. If @c svn_depth_files, do the same and include + * immediate file children of @a path. If @c svn_depth_immediates, + * then behave as if for @c svn_depth_files but also report the + * property states of immediate subdirectories. If @a depth is + * @c svn_depth_infinity, then report state fully recursively. All + * descents are only as deep as @a path's own depth permits, of + * course. If @a depth is @c svn_depth_unknown, then just use + * @c svn_depth_infinity, which in practice means depth of @a path. + * + * Iff @a honor_depth_exclude is TRUE, the crawler will report paths + * whose ambient depth is @c svn_depth_exclude as being excluded, and + * thus prevent the server from pushing update data for those paths; + * therefore, don't set this flag if you wish to pull in excluded paths. + * Note that @c svn_depth_exclude on the target @a path is never + * honored, even if @a honor_depth_exclude is TRUE, because we need to + * be able to explicitly pull in a target. For example, if this is + * the working copy... + * + * svn co greek_tree_repos wc_dir + * svn up --set-depth exclude wc_dir/A/B/E # now A/B/E is excluded + * + * ...then 'svn up wc_dir/A/B' would report E as excluded (assuming + * @a honor_depth_exclude is TRUE), but 'svn up wc_dir/A/B/E' would + * not, because the latter is trying to explicitly pull in E. In + * general, we never report the update target as excluded. + * + * Iff @a depth_compatibility_trick is TRUE, then set the @c start_empty + * flag on @a reporter->set_path() and @a reporter->link_path() calls + * as necessary to trick a pre-1.5 (i.e., depth-unaware) server into + * sending back all the items the client might need to upgrade a + * working copy from a shallower depth to a deeper one. + * + * If @a restore_files is TRUE, then unexpectedly missing working files + * will be restored from the administrative directory's cache. For each + * file restored, the @a notify_func function will be called with the + * @a notify_baton and the path of the restored file. @a notify_func may + * be @c NULL if this notification is not required. If @a + * use_commit_times is TRUE, then set restored files' timestamps to + * their last-commit-times. + * + * If @a traversal_info is non-NULL, then record pre-update traversal + * state in it. (Caller should obtain @a traversal_info from + * svn_wc_init_traversal_info().) + * + * @since New in 1.6. + */ +svn_error_t * +svn_wc_crawl_revisions4(const char *path, + svn_wc_adm_access_t *adm_access, + const svn_ra_reporter3_t *reporter, + void *report_baton, + svn_boolean_t restore_files, + svn_depth_t depth, + svn_boolean_t honor_depth_exclude, + svn_boolean_t depth_compatibility_trick, + svn_boolean_t use_commit_times, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_wc_traversal_info_t *traversal_info, + apr_pool_t *pool); + +/** + * Similar to svn_wc_crawl_revisions4, but with @a honor_depth_exclude always + * set to false. + * + * @deprecated Provided for compatibility with the 1.5 API. + */ +svn_error_t * +svn_wc_crawl_revisions3(const char *path, + svn_wc_adm_access_t *adm_access, + const svn_ra_reporter3_t *reporter, + void *report_baton, + svn_boolean_t restore_files, + svn_depth_t depth, + svn_boolean_t depth_compatibility_trick, + svn_boolean_t use_commit_times, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_wc_traversal_info_t *traversal_info, + apr_pool_t *pool); + +/** + * Similar to svn_wc_crawl_revisions3, but taking svn_ra_reporter2_t + * instead of svn_ra_reporter3_t, and therefore only able to report @c + * svn_depth_infinity for depths; and taking @a recurse instead of @a + * depth; and with @a depth_compatibility_trick always false. + * + * @deprecated Provided for compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_crawl_revisions2(const char *path, + svn_wc_adm_access_t *adm_access, + const svn_ra_reporter2_t *reporter, + void *report_baton, + svn_boolean_t restore_files, + svn_boolean_t recurse, + svn_boolean_t use_commit_times, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_wc_traversal_info_t *traversal_info, + apr_pool_t *pool); + +/** + * Similar to svn_wc_crawl_revisions2(), but takes an svn_wc_notify_func_t + * and a @c svn_reporter_t instead. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_crawl_revisions(const char *path, + svn_wc_adm_access_t *adm_access, + const svn_ra_reporter_t *reporter, + void *report_baton, + svn_boolean_t restore_files, + svn_boolean_t recurse, + svn_boolean_t use_commit_times, + svn_wc_notify_func_t notify_func, + void *notify_baton, + svn_wc_traversal_info_t *traversal_info, + apr_pool_t *pool); + + +/* Updates. */ + +/** Set @a *wc_root to @c TRUE if @a path represents a "working copy root", + * @c FALSE otherwise. Here, @a path is a "working copy root" if its parent + * directory is not a WC or if its parent directory's repository URL is not + * the parent of its own repository URL. Thus, a switched subtree is + * considered to be a working copy root. Also, a deleted tree-conflict + * victim is considered a "working copy root" because it has no URL. + * + * If @a path is not found, return the error @c SVN_ERR_ENTRY_NOT_FOUND. + * + * Use @a pool for any intermediate allocations. + * + * @note Due to the way in which "WC-root-ness" is calculated, passing + * a @a path of `.' to this function will always return @c TRUE. + */ +svn_error_t * +svn_wc_is_wc_root(svn_boolean_t *wc_root, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + + +/** Conditionally split @a path into an @a anchor and @a target for the + * purpose of updating and committing. + * + * @a anchor is the directory at which the update or commit editor + * should be rooted. + * + * @a target is the actual subject (relative to the @a anchor) of the + * update/commit, or "" if the @a anchor itself is the subject. + * + * Allocate @a anchor and @a target in @a pool. + */ +svn_error_t * +svn_wc_get_actual_target(const char *path, + const char **anchor, + const char **target, + apr_pool_t *pool); + + + +/* Update and update-like functionality. */ + +/** + * Set @a *editor and @a *edit_baton to an editor and baton for updating a + * working copy. + * + * If @a ti is non-NULL, record traversal info in @a ti, for use by + * post-traversal accessors such as svn_wc_edited_externals(). + * + * @a anchor is an access baton, with a write lock, for the local path to the + * working copy which will be used as the root of our editor. Further + * locks will be acquired if the update creates new directories. All + * locks, both those in @a anchor and newly acquired ones, will be released + * when the editor driver calls @c close_edit. + * + * @a target is the entry in @a anchor that will actually be updated, or + * the empty string if all of @a anchor should be updated. + * + * The editor invokes @a notify_func with @a notify_baton as the update + * progresses, if @a notify_func is non-NULL. + * + * If @a cancel_func is non-NULL, the editor will invoke @a cancel_func with + * @a cancel_baton as the update progresses to see if it should continue. + * + * If @a conflict_func is non-NULL, then invoke it with @a + * conflict_baton whenever a conflict is encountered, giving the + * callback a chance to resolve the conflict before the editor takes + * more drastic measures (such as marking a file conflicted, or + * bailing out of the update). + * + * If @a fetch_func is non-NULL, then use it (with @a fetch_baton) as + * a fallback for retrieving repository files whenever 'copyfrom' args + * are sent into editor->add_file(). + * + * If @a diff3_cmd is non-NULL, then use it as the diff3 command for + * any merging; otherwise, use the built-in merge code. + * + * @a preserved_exts is an array of filename patterns which, when + * matched against the extensions of versioned files, determine for + * which such files any related generated conflict files will preserve + * the original file's extension as their own. If a file's extension + * does not match any of the patterns in @a preserved_exts (which is + * certainly the case if @a preserved_exts is @c NULL or empty), + * generated conflict files will carry Subversion's custom extensions. + * + * @a target_revision is a pointer to a revision location which, after + * successful completion of the drive of this editor, will be + * populated with the revision to which the working copy was updated. + * + * If @a use_commit_times is TRUE, then all edited/added files will + * have their working timestamp set to the last-committed-time. If + * FALSE, the working files will be touched with the 'now' time. + * + * If @a allow_unver_obstructions is TRUE, then allow unversioned + * obstructions when adding a path. + * + * If @a depth is @c svn_depth_infinity, update fully recursively. + * Else if it is @c svn_depth_immediates, update the uppermost + * directory, its file entries, and the presence or absence of + * subdirectories (but do not descend into the subdirectories). + * Else if it is @c svn_depth_files, update the uppermost directory + * and its immediate file entries, but not subdirectories. + * Else if it is @c svn_depth_empty, update exactly the uppermost + * target, and don't touch its entries. + * + * If @a depth_is_sticky is set and @a depth is not @c + * svn_depth_unknown, then in addition to updating PATHS, also set + * their sticky ambient depth value to @a depth. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_get_update_editor3(svn_revnum_t *target_revision, + svn_wc_adm_access_t *anchor, + const char *target, + svn_boolean_t use_commit_times, + svn_depth_t depth, + svn_boolean_t depth_is_sticky, + svn_boolean_t allow_unver_obstructions, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_conflict_resolver_func_t conflict_func, + void *conflict_baton, + svn_wc_get_file_t fetch_func, + void *fetch_baton, + const char *diff3_cmd, + apr_array_header_t *preserved_exts, + const svn_delta_editor_t **editor, + void **edit_baton, + svn_wc_traversal_info_t *ti, + apr_pool_t *pool); + + +/** + * Similar to svn_wc_get_update_editor3() but with the @a + * allow_unver_obstructions parameter always set to FALSE, @a + * conflict_func and baton set to NULL, @a fetch_func and baton set to + * NULL, @a preserved_exts set to NULL, @a depth_is_sticky set to + * FALSE, and @a depth set according to @a recurse: if @a recurse is + * TRUE, pass @c svn_depth_infinity, if FALSE, pass @c + * svn_depth_files. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_update_editor2(svn_revnum_t *target_revision, + svn_wc_adm_access_t *anchor, + const char *target, + svn_boolean_t use_commit_times, + svn_boolean_t recurse, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + const char *diff3_cmd, + const svn_delta_editor_t **editor, + void **edit_baton, + svn_wc_traversal_info_t *ti, + apr_pool_t *pool); + +/** + * Similar to svn_wc_get_update_editor2(), but takes an svn_wc_notify_func_t + * instead. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_update_editor(svn_revnum_t *target_revision, + svn_wc_adm_access_t *anchor, + const char *target, + svn_boolean_t use_commit_times, + svn_boolean_t recurse, + svn_wc_notify_func_t notify_func, + void *notify_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + const char *diff3_cmd, + const svn_delta_editor_t **editor, + void **edit_baton, + svn_wc_traversal_info_t *ti, + apr_pool_t *pool); + +/** + * A variant of svn_wc_get_update_editor(). + * + * Set @a *editor and @a *edit_baton to an editor and baton for "switching" + * a working copy to a new @a switch_url. (Right now, this URL must be + * within the same repository that the working copy already comes + * from.) @a switch_url must not be @c NULL. + * + * If @a ti is non-NULL, record traversal info in @a ti, for use by + * post-traversal accessors such as svn_wc_edited_externals(). + * + * @a anchor is an access baton, with a write lock, for the local path to the + * working copy which will be used as the root of our editor. Further + * locks will be acquired if the switch creates new directories. All + * locks, both those in @a anchor and newly acquired ones, will be released + * when the editor driver calls @c close_edit. + * + * @a target is the entry in @a anchor that will actually be updated, or + * empty if all of @a anchor should be updated. + * + * The editor invokes @a notify_func with @a notify_baton as the switch + * progresses, if @a notify_func is non-NULL. + * + * If @a cancel_func is non-NULL, it will be called with @a cancel_baton as + * the switch progresses to determine if it should continue. + * + * If @a conflict_func is non-NULL, then invoke it with @a + * conflict_baton whenever a conflict is encountered, giving the + * callback a chance to resolve the conflict before the editor takes + * more drastic measures (such as marking a file conflicted, or + * bailing out of the switch). + * + * If @a diff3_cmd is non-NULL, then use it as the diff3 command for + * any merging; otherwise, use the built-in merge code. + * + * @a preserved_exts is an array of filename patterns which, when + * matched against the extensions of versioned files, determine for + * which such files any related generated conflict files will preserve + * the original file's extension as their own. If a file's extension + * does not match any of the patterns in @a preserved_exts (which is + * certainly the case if @a preserved_exts is @c NULL or empty), + * generated conflict files will carry Subversion's custom extensions. + * + * @a target_revision is a pointer to a revision location which, after + * successful completion of the drive of this editor, will be + * populated with the revision to which the working copy was updated. + * + * If @a use_commit_times is TRUE, then all edited/added files will + * have their working timestamp set to the last-committed-time. If + * FALSE, the working files will be touched with the 'now' time. + * + * @a depth and @a depth_is_sticky behave as for svn_wc_get_update_editor3(). + * + * If @a allow_unver_obstructions is TRUE, then allow unversioned + * obstructions when adding a path. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_get_switch_editor3(svn_revnum_t *target_revision, + svn_wc_adm_access_t *anchor, + const char *target, + const char *switch_url, + svn_boolean_t use_commit_times, + svn_depth_t depth, + svn_boolean_t depth_is_sticky, + svn_boolean_t allow_unver_obstructions, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_conflict_resolver_func_t conflict_func, + void *conflict_baton, + const char *diff3_cmd, + apr_array_header_t *preserved_exts, + const svn_delta_editor_t **editor, + void **edit_baton, + svn_wc_traversal_info_t *ti, + apr_pool_t *pool); + +/** + * Similar to svn_wc_get_switch_editor3() but with the + * @a allow_unver_obstructions parameter always set to FALSE, + * @a preserved_exts set to NULL, @a conflict_func and baton set to NULL, + * @a depth_is_sticky set to FALSE, and @a depth set according to @a + * recurse: if @a recurse is TRUE, pass @c svn_depth_infinity, if + * FALSE, pass @c svn_depth_files. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_switch_editor2(svn_revnum_t *target_revision, + svn_wc_adm_access_t *anchor, + const char *target, + const char *switch_url, + svn_boolean_t use_commit_times, + svn_boolean_t recurse, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + const char *diff3_cmd, + const svn_delta_editor_t **editor, + void **edit_baton, + svn_wc_traversal_info_t *ti, + apr_pool_t *pool); + +/** + * Similar to svn_wc_get_switch_editor2(), but takes an + * @c svn_wc_notify_func_t instead. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_switch_editor(svn_revnum_t *target_revision, + svn_wc_adm_access_t *anchor, + const char *target, + const char *switch_url, + svn_boolean_t use_commit_times, + svn_boolean_t recurse, + svn_wc_notify_func_t notify_func, + void *notify_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + const char *diff3_cmd, + const svn_delta_editor_t **editor, + void **edit_baton, + svn_wc_traversal_info_t *ti, + apr_pool_t *pool); + + + +/* A word about the implementation of working copy property storage: + * + * Since properties are key/val pairs, you'd think we store them in + * some sort of Berkeley DB-ish format, and even store pending changes + * to them that way too. + * + * However, we already have libsvn_subr/hashdump.c working, and it + * uses a human-readable format. That will be very handy when we're + * debugging, and presumably we will not be dealing with any huge + * properties or property lists initially. Therefore, we will + * continue to use hashdump as the internal mechanism for storing and + * reading from property lists, but note that the interface here is + * _not_ dependent on that. We can swap in a DB-based implementation + * at any time and users of this library will never know the + * difference. + */ + +/** Set @a *props to a hash table mapping char * names onto + * svn_string_t * values for all the regular properties of + * @a path. Allocate the table, names, and values in @a pool. If + * the node has no properties, or does not exist in the working copy, + * then an empty hash is returned. @a adm_access is an access baton + * set that contains @a path. + */ +svn_error_t * +svn_wc_prop_list(apr_hash_t **props, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + + +/** Set @a *value to the value of property @a name for @a path, allocating + * @a *value in @a pool. If no such prop, set @a *value to @c NULL. + * @a name may be a regular or wc property; if it is an entry property, + * return the error @c SVN_ERR_BAD_PROP_KIND. @a adm_access is an access + * baton set that contains @a path. + */ +svn_error_t * +svn_wc_prop_get(const svn_string_t **value, + const char *name, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + +/** + * Set property @a name to @a value for @a path, or if @a value is + * NULL, remove property @a name from @a path. @a adm_access is an + * access baton with a write lock for @a path. + * + * If @a skip_checks is TRUE, do no validity checking. But if @a + * skip_checks is FALSE, and @a name is not a valid property for @a + * path, return an error, either @c SVN_ERR_ILLEGAL_TARGET (if the + * property is not appropriate for @a path), or @c + * SVN_ERR_BAD_MIME_TYPE (if @a name is "svn:mime-type", but @a value + * is not a valid mime-type). + * + * @a name may be a wc property or a regular property; but if it is an + * entry property, return the error @c SVN_ERR_BAD_PROP_KIND, even if + * @a skip_checks is TRUE. + * + * For each file or directory operated on, @a notify_func will be called + * with its path and the @a notify_baton. @a notify_func may be @c NULL + * if you are not interested in this information. + * + * Use @a pool for temporary allocation. + * + * @since New in 1.6. + */ +svn_error_t * +svn_wc_prop_set3(const char *name, + const svn_string_t *value, + const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t skip_checks, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *pool); + + +/** + * Like svn_wc_prop_set3(), but without the notification callbacks. + * + * @since New in 1.2. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_prop_set2(const char *name, + const svn_string_t *value, + const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t skip_checks, + apr_pool_t *pool); + + +/** + * Like svn_wc_prop_set2(), but with @a skip_checks always FALSE. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_prop_set(const char *name, + const svn_string_t *value, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + + +/** Return TRUE iff @a name is a 'normal' property name. 'Normal' is + * defined as a user-visible and user-tweakable property that shows up + * when you fetch a proplist. + * + * The function currently parses the namespace like so: + * + * - 'svn:wc:' ==> a wcprop, stored/accessed separately via different API. + * + * - 'svn:entry:' ==> an "entry" prop, shunted into the 'entries' file. + * + * If these patterns aren't found, then the property is assumed to be + * Normal. + */ +svn_boolean_t +svn_wc_is_normal_prop(const char *name); + + + +/** Return TRUE iff @a name is a 'wc' property name. */ +svn_boolean_t +svn_wc_is_wc_prop(const char *name); + +/** Return TRUE iff @a name is a 'entry' property name. */ +svn_boolean_t +svn_wc_is_entry_prop(const char *name); + +/** Callback type used by @c svn_wc_canonicalize_svn_prop. + * + * If @a mime_type is non-null, it sets @a *mime_type to the value of + * @c SVN_PROP_MIME_TYPE for the path passed to @c + * svn_wc_canonicalize_svn_prop (allocated from @a pool). If @a + * stream is non-null, it writes the contents of the file to @a + * stream. + * + * (Currently, this is used if you are attempting to set the @c + * SVN_PROP_EOL_STYLE property, to make sure that the value matches + * the mime type and contents.) + */ +typedef svn_error_t *(*svn_wc_canonicalize_svn_prop_get_file_t) + (const svn_string_t **mime_type, + svn_stream_t *stream, + void *baton, + apr_pool_t *pool); + + +/** Canonicalize the value of an svn:* property @a propname with + * value @a propval. + * + * If the property is not appropriate for a node of kind @a kind, or + * is otherwise invalid, throw an error. Otherwise, set @a *propval_p + * to a canonicalized version of the property value. If @a + * skip_some_checks is TRUE, only some validity checks are taken. + * + * Some validity checks require access to the contents and MIME type + * of the target if it is a file; they will call @a prop_getter with @a + * getter_baton, which then needs to set the MIME type and print the + * contents of the file to the given stream. + * + * @a path should be the path of the file in question; it is only used + * for error messages. + * + * ### This is not actually related to the WC, but it does need to call + * ### svn_wc_parse_externals_description2. + */ +svn_error_t * +svn_wc_canonicalize_svn_prop(const svn_string_t **propval_p, + const char *propname, + const svn_string_t *propval, + const char *path, + svn_node_kind_t kind, + svn_boolean_t skip_some_checks, + svn_wc_canonicalize_svn_prop_get_file_t prop_getter, + void *getter_baton, + apr_pool_t *pool); + + + +/* Diffs */ + + +/** + * Return an @a editor/@a edit_baton for diffing a working copy against the + * repository. + * + * @a anchor/@a target represent the base of the hierarchy to be compared. + * + * @a callbacks/@a callback_baton is the callback table to use when two + * files are to be compared. + * + * If @a depth is @c svn_depth_empty, just diff exactly @a target or + * @a anchor if @a target is empty. If @c svn_depth_files then do the same + * and for top-level file entries as well (if any). If + * @c svn_depth_immediates, do the same as @c svn_depth_files but also diff + * top-level subdirectories at @c svn_depth_empty. If @c svn_depth_infinity, + * then diff fully recursively. In the latter case, @a anchor should be part + * of an access baton set for the @a target hierarchy. + * + * @a ignore_ancestry determines whether paths that have discontinuous node + * ancestry are treated as delete/add or as simple modifications. If + * @a ignore_ancestry is @c FALSE, then any discontinuous node ancestry will + * result in the diff given as a full delete followed by an add. + * + * If @a use_text_base is TRUE, then compare the repository against + * the working copy's text-base files, rather than the working files. + * + * Normally, the difference from repository->working_copy is shown. + * If @a reverse_order is TRUE, then show working_copy->repository diffs. + * + * If @a cancel_func is non-NULL, it will be used along with @a cancel_baton + * to periodically check if the client has canceled the operation. + * + * @a changelists is an array of const char * changelist + * names, used as a restrictive filter on items whose differences are + * reported; that is, don't generate diffs about any item unless + * it's a member of one of those changelists. If @a changelists is + * empty (or altogether @c NULL), no changelist filtering occurs. + * + * @since New in 1.6. + */ +svn_error_t * +svn_wc_get_diff_editor5(svn_wc_adm_access_t *anchor, + const char *target, + const svn_wc_diff_callbacks3_t *callbacks, + void *callback_baton, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + svn_boolean_t use_text_base, + svn_boolean_t reverse_order, + svn_cancel_func_t cancel_func, + void *cancel_baton, + const apr_array_header_t *changelists, + const svn_delta_editor_t **editor, + void **edit_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_get_diff_editor5(), but with an + * @c svn_wc_diff_callbacks2_t instead of @c svn_wc_diff_callbacks3_t. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_diff_editor4(svn_wc_adm_access_t *anchor, + const char *target, + const svn_wc_diff_callbacks2_t *callbacks, + void *callback_baton, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + svn_boolean_t use_text_base, + svn_boolean_t reverse_order, + svn_cancel_func_t cancel_func, + void *cancel_baton, + const apr_array_header_t *changelists, + const svn_delta_editor_t **editor, + void **edit_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_get_diff_editor4(), but with @a changelists + * passed as @c NULL, and @a depth set to @c svn_depth_infinity if @a + * recurse is TRUE, or @c svn_depth_files if @a recurse is FALSE. + * + * @deprecated Provided for backward compatibility with the 1.4 API. + + * @since New in 1.2. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_diff_editor3(svn_wc_adm_access_t *anchor, + const char *target, + const svn_wc_diff_callbacks2_t *callbacks, + void *callback_baton, + svn_boolean_t recurse, + svn_boolean_t ignore_ancestry, + svn_boolean_t use_text_base, + svn_boolean_t reverse_order, + svn_cancel_func_t cancel_func, + void *cancel_baton, + const svn_delta_editor_t **editor, + void **edit_baton, + apr_pool_t *pool); + + +/** + * Similar to svn_wc_get_diff_editor3(), but with an + * @c svn_wc_diff_callbacks_t instead of @c svn_wc_diff_callbacks2_t. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_diff_editor2(svn_wc_adm_access_t *anchor, + const char *target, + const svn_wc_diff_callbacks_t *callbacks, + void *callback_baton, + svn_boolean_t recurse, + svn_boolean_t ignore_ancestry, + svn_boolean_t use_text_base, + svn_boolean_t reverse_order, + svn_cancel_func_t cancel_func, + void *cancel_baton, + const svn_delta_editor_t **editor, + void **edit_baton, + apr_pool_t *pool); + + +/** + * Similar to svn_wc_get_diff_editor2(), but with @a ignore_ancestry + * always set to @c FALSE. + * + * @deprecated Provided for backward compatibility with the 1.0 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_diff_editor(svn_wc_adm_access_t *anchor, + const char *target, + const svn_wc_diff_callbacks_t *callbacks, + void *callback_baton, + svn_boolean_t recurse, + svn_boolean_t use_text_base, + svn_boolean_t reverse_order, + svn_cancel_func_t cancel_func, + void *cancel_baton, + const svn_delta_editor_t **editor, + void **edit_baton, + apr_pool_t *pool); + + +/** + * Compare working copy against the text-base. + * + * @a anchor/@a target represent the base of the hierarchy to be compared. + * + * @a callbacks/@a callback_baton is the callback table to use when two + * files are to be compared. + * + * If @a depth is @c svn_depth_empty, just diff exactly @a target or + * @a anchor if @a target is empty. If @c svn_depth_files then do the same + * and for top-level file entries as well (if any). If + * @c svn_depth_immediates, do the same as @c svn_depth_files but also diff + * top-level subdirectories at @c svn_depth_empty. If @c svn_depth_infinity, + * then diff fully recursively. In the latter case, @a anchor should be part + * of an access baton set for the @a target hierarchy. + * + * @a ignore_ancestry determines whether paths that have discontinuous node + * ancestry are treated as delete/add or as simple modifications. If + * @a ignore_ancestry is @c FALSE, then any discontinuous node ancestry will + * result in the diff given as a full delete followed by an add. + * + * @a changelists is an array of const char * changelist + * names, used as a restrictive filter on items whose differences are + * reported; that is, don't generate diffs about any item unless + * it's a member of one of those changelists. If @a changelists is + * empty (or altogether @c NULL), no changelist filtering occurs. + * + * @since New in 1.6. + */ +svn_error_t * +svn_wc_diff5(svn_wc_adm_access_t *anchor, + const char *target, + const svn_wc_diff_callbacks3_t *callbacks, + void *callback_baton, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + const apr_array_header_t *changelists, + apr_pool_t *pool); + +/** + * Similar to svn_wc_diff5(), but with a @c svn_wc_diff_callbacks2_t argument + * instead of @c svn_wc_diff_callbacks3_t. + * + * @deprecated Provided for backward compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_diff4(svn_wc_adm_access_t *anchor, + const char *target, + const svn_wc_diff_callbacks2_t *callbacks, + void *callback_baton, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + const apr_array_header_t *changelists, + apr_pool_t *pool); + + +/** + * Similar to svn_wc_diff4(), but with @a changelists passed @c NULL, + * and @a depth set to @c svn_depth_infinity if @a recurse is TRUE, or + * @c svn_depth_files if @a recurse is FALSE. + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_diff3(svn_wc_adm_access_t *anchor, + const char *target, + const svn_wc_diff_callbacks2_t *callbacks, + void *callback_baton, + svn_boolean_t recurse, + svn_boolean_t ignore_ancestry, + apr_pool_t *pool); + +/** + * Similar to svn_wc_diff3(), but with a @c svn_wc_diff_callbacks_t argument + * instead of @c svn_wc_diff_callbacks2_t. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_diff2(svn_wc_adm_access_t *anchor, + const char *target, + const svn_wc_diff_callbacks_t *callbacks, + void *callback_baton, + svn_boolean_t recurse, + svn_boolean_t ignore_ancestry, + apr_pool_t *pool); + +/** + * Similar to svn_wc_diff2(), but with @a ignore_ancestry always set + * to @c FALSE. + * + * @deprecated Provided for backward compatibility with the 1.0 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_diff(svn_wc_adm_access_t *anchor, + const char *target, + const svn_wc_diff_callbacks_t *callbacks, + void *callback_baton, + svn_boolean_t recurse, + apr_pool_t *pool); + + +/** Given a @a path to a file or directory under version control, discover + * any local changes made to properties and/or the set of 'pristine' + * properties. @a adm_access is an access baton set for @a path. + * + * If @a propchanges is non-@c NULL, return these changes as an array of + * @c svn_prop_t structures stored in @a *propchanges. The structures and + * array will be allocated in @a pool. If there are no local property + * modifications on @a path, then set @a *propchanges to @c NULL. + * + * If @a original_props is non-@c NULL, then set @a *original_props to + * hashtable (const char *name -> const svn_string_t *value) + * that represents the 'pristine' property list of @a path. This hashtable is + * allocated in @a pool, and can be used to compare old and new values of + * properties. + */ +svn_error_t * +svn_wc_get_prop_diffs(apr_array_header_t **propchanges, + apr_hash_t **original_props, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + + +/** The outcome of a merge carried out (or tried as a dry-run) by + * svn_wc_merge() + */ +typedef enum svn_wc_merge_outcome_t +{ + /** The working copy is (or would be) unchanged. The changes to be + * merged were already present in the working copy + */ + svn_wc_merge_unchanged, + + /** The working copy has been (or would be) changed. */ + svn_wc_merge_merged, + + /** The working copy has been (or would be) changed, but there was (or + * would be) a conflict + */ + svn_wc_merge_conflict, + + /** No merge was performed, probably because the target file was + * either absent or not under version control. + */ + svn_wc_merge_no_merge + +} svn_wc_merge_outcome_t; + +/** Given paths to three fulltexts, merge the differences between @a left + * and @a right into @a merge_target. (It may help to know that @a left, + * @a right, and @a merge_target correspond to "OLDER", "YOURS", and "MINE", + * respectively, in the diff3 documentation.) Use @a pool for any + * temporary allocation. + * + * @a adm_access is an access baton with a write lock for the directory + * containing @a merge_target. + * + * This function assumes that @a left and @a right are in repository-normal + * form (linefeeds, with keywords contracted); if necessary, + * @a merge_target is temporarily converted to this form to receive the + * changes, then translated back again. + * + * If @a merge_target is absent, or present but not under version + * control, then set @a *merge_outcome to @c svn_wc_merge_no_merge and + * return success without merging anything. (The reasoning is that if + * the file is not versioned, then it is probably unrelated to the + * changes being considered, so they should not be merged into it.) + * + * @a dry_run determines whether the working copy is modified. When it + * is @c FALSE the merge will cause @a merge_target to be modified, when it + * is @c TRUE the merge will be carried out to determine the result but + * @a merge_target will not be modified. + * + * If @a diff3_cmd is non-NULL, then use it as the diff3 command for + * any merging; otherwise, use the built-in merge code. If @a + * merge_options is non-NULL, either pass its elements to @a diff3_cmd or + * parse it and use as options to the internal merge code (see + * svn_diff_file_options_parse()). @a merge_options must contain + * const char * elements. + * + * The outcome of the merge is returned in @a *merge_outcome. If there + * is a conflict and @a dry_run is @c FALSE, then attempt to call @a + * conflict_func with @a conflict_baton (if non-NULL). If the + * conflict callback cannot resolve the conflict, then: + * + * * Put conflict markers around the conflicting regions in + * @a merge_target, labeled with @a left_label, @a right_label, and + * @a target_label. (If any of these labels are @c NULL, default + * values will be used.) + * + * * Copy @a left, @a right, and the original @a merge_target to unique + * names in the same directory as @a merge_target, ending with the + * suffixes ".LEFT_LABEL", ".RIGHT_LABEL", and ".TARGET_LABEL" + * respectively. + * + * * Mark the entry for @a merge_target as "conflicted", and track the + * above mentioned backup files in the entry as well. + * + * Binary case: + * + * If @a merge_target is a binary file, then no merging is attempted, + * the merge is deemed to be a conflict. If @a dry_run is @c FALSE the + * working @a merge_target is untouched, and copies of @a left and + * @a right are created next to it using @a left_label and @a right_label. + * @a merge_target's entry is marked as "conflicted", and begins + * tracking the two backup files. If @a dry_run is @c TRUE no files are + * changed. The outcome of the merge is returned in @a *merge_outcome. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_merge3(enum svn_wc_merge_outcome_t *merge_outcome, + const char *left, + const char *right, + const char *merge_target, + svn_wc_adm_access_t *adm_access, + const char *left_label, + const char *right_label, + const char *target_label, + svn_boolean_t dry_run, + const char *diff3_cmd, + const apr_array_header_t *merge_options, + const apr_array_header_t *prop_diff, + svn_wc_conflict_resolver_func_t conflict_func, + void *conflict_baton, + apr_pool_t *pool); + +/** Similar to svn_wc_merge3(), but with @a prop_diff, @a + * conflict_func, @a conflict_baton set to NULL. + * + * @deprecated Provided for backwards compatibility with the 1.4 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_merge2(enum svn_wc_merge_outcome_t *merge_outcome, + const char *left, + const char *right, + const char *merge_target, + svn_wc_adm_access_t *adm_access, + const char *left_label, + const char *right_label, + const char *target_label, + svn_boolean_t dry_run, + const char *diff3_cmd, + const apr_array_header_t *merge_options, + apr_pool_t *pool); + + +/** Similar to svn_wc_merge2(), but with @a merge_options set to NULL. + * + * @deprecated Provided for backwards compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_merge(const char *left, + const char *right, + const char *merge_target, + svn_wc_adm_access_t *adm_access, + const char *left_label, + const char *right_label, + const char *target_label, + svn_boolean_t dry_run, + enum svn_wc_merge_outcome_t *merge_outcome, + const char *diff3_cmd, + apr_pool_t *pool); + + +/** Given a @a path under version control, merge an array of @a + * propchanges into the path's existing properties. @a propchanges is + * an array of @c svn_prop_t objects, and @a baseprops is a hash + * representing the original set of properties that @a propchanges is + * working against. @a adm_access is an access baton for the directory + * containing @a path. + * + * If @a base_merge is @c FALSE only the working properties will be changed, + * if it is @c TRUE both the base and working properties will be changed. + * + * If @a state is non-NULL, set @a *state to the state of the properties + * after the merge. + * + * If conflicts are found when merging working properties, they are + * described in a temporary .prej file (or appended to an already-existing + * .prej file), and the entry is marked "conflicted". Base properties + * are changed unconditionally, if @a base_merge is @c TRUE, they never result + * in a conflict. + * + * If @a path is not under version control, return the error + * SVN_ERR_UNVERSIONED_RESOURCE and don't touch anyone's properties. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_merge_props2(svn_wc_notify_state_t *state, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_hash_t *baseprops, + const apr_array_header_t *propchanges, + svn_boolean_t base_merge, + svn_boolean_t dry_run, + svn_wc_conflict_resolver_func_t conflict_func, + void *conflict_baton, + apr_pool_t *pool); + + +/** + * Same as svn_wc_merge_props2(), but with a @a conflict_func (and + * baton) of NULL. + * + * @deprecated Provided for backward compatibility with the 1.3 API. + * + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_merge_props(svn_wc_notify_state_t *state, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_hash_t *baseprops, + const apr_array_header_t *propchanges, + svn_boolean_t base_merge, + svn_boolean_t dry_run, + apr_pool_t *pool); + + +/** + * Similar to svn_wc_merge_props(), but no baseprops are given. + * Instead, it's assumed that the incoming propchanges are based + * against the working copy's own baseprops. While this assumption is + * correct for 'svn update', it's incorrect for 'svn merge', and can + * cause flawed behavior. (See issue #2035.) + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_merge_prop_diffs(svn_wc_notify_state_t *state, + const char *path, + svn_wc_adm_access_t *adm_access, + const apr_array_header_t *propchanges, + svn_boolean_t base_merge, + svn_boolean_t dry_run, + apr_pool_t *pool); + + +/** Given a @a path to a wc file, return a stream to the @a contents of + * the pristine copy of the file. This is needed so clients can do + * diffs. If the WC has no text-base, return a @c NULL instead of a + * stream. + * + * @since New in 1.6. + */ +svn_error_t * +svn_wc_get_pristine_contents(svn_stream_t **contents, + const char *path, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + + +/** Returns a path to the pristine copy of @a path. Should use + * svn_wc_get_pristine_contents() instead. + * + * @deprecated Provided for backwards compatibility with the 1.5 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_get_pristine_copy_path(const char *path, + const char **pristine_path, + apr_pool_t *pool); + + +/** + * Recurse from @a path, cleaning up unfinished log business. Perform + * necessary allocations in @a pool. Any working copy locks under @a path + * will be taken over and then cleared by this function. If @a diff3_cmd + * is non-NULL, then use it as the diff3 command for any merging; otherwise, + * use the built-in merge code. + * + * WARNING: there is no mechanism that will protect locks that are still + * being used. + * + * If @a cancel_func is non-NULL, invoke it with @a cancel_baton at + * various points during the operation. If it returns an error + * (typically @c SVN_ERR_CANCELLED), return that error immediately. + * + * @since New in 1.2. + */ +svn_error_t * +svn_wc_cleanup2(const char *path, + const char *diff3_cmd, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_cleanup2(). @a optional_adm_access is an historic + * relic and not used, it may be NULL. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_cleanup(const char *path, + svn_wc_adm_access_t *optional_adm_access, + const char *diff3_cmd, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + + +/** Relocation validation callback typedef. + * + * Called for each relocated file/directory. @a uuid, if non-NULL, contains + * the expected repository UUID, @a url contains the tentative URL. + * + * @a baton is a closure object; it should be provided by the + * implementation, and passed by the caller. + * + * If @a root is TRUE, then the implementation should make sure that @a url + * is the repository root. Else, it can be an URL inside the repository. + * @a pool may be used for temporary allocations. + * + * @since New in 1.5. + */ +typedef svn_error_t *(*svn_wc_relocation_validator3_t)(void *baton, + const char *uuid, + const char *url, + const char *root_url, + apr_pool_t *pool); + +/** Similar to @c svn_wc_relocation_validator3_t, but without + * the @a root_url arguments. + * + * @deprecated Provided for backwards compatibility with the 1.4 API. + */ +typedef svn_error_t *(*svn_wc_relocation_validator2_t)(void *baton, + const char *uuid, + const char *url, + svn_boolean_t root, + apr_pool_t *pool); + +/** Similar to @c svn_wc_relocation_validator2_t, but without + * the @a root and @a pool arguments. @a uuid will not be NULL in this version + * of the function. + * + * @deprecated Provided for backwards compatibility with the 1.3 API. + */ +typedef svn_error_t *(*svn_wc_relocation_validator_t)(void *baton, + const char *uuid, + const char *url); + +/** Change repository references at @a path that begin with @a from + * to begin with @a to instead. Perform necessary allocations in @a pool. + * If @a recurse is TRUE, do so. @a validator (and its baton, + * @a validator_baton), will be called for each newly generated URL. + * + * @a adm_access is an access baton for the directory containing + * @a path. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_relocate3(const char *path, + svn_wc_adm_access_t *adm_access, + const char *from, + const char *to, + svn_boolean_t recurse, + svn_wc_relocation_validator3_t validator, + void *validator_baton, + apr_pool_t *pool); + +/** Similar to svn_wc_relocate3(), but uses @c svn_wc_relocation_validator2_t. + * + * @deprecated Provided for backwards compatibility with the 1.4 API. */ +SVN_DEPRECATED +svn_error_t * +svn_wc_relocate2(const char *path, + svn_wc_adm_access_t *adm_access, + const char *from, + const char *to, + svn_boolean_t recurse, + svn_wc_relocation_validator2_t validator, + void *validator_baton, + apr_pool_t *pool); + +/** Similar to svn_wc_relocate2(), but uses @c svn_wc_relocation_validator_t. + * + * @deprecated Provided for backwards compatibility with the 1.3 API. */ +SVN_DEPRECATED +svn_error_t * +svn_wc_relocate(const char *path, + svn_wc_adm_access_t *adm_access, + const char *from, + const char *to, + svn_boolean_t recurse, + svn_wc_relocation_validator_t validator, + void *validator_baton, + apr_pool_t *pool); + + +/** + * Revert changes to @a path. Perform necessary allocations in @a pool. + * + * @a parent_access is an access baton for the directory containing @a + * path, unless @a path is a working copy root (as determined by @c + * svn_wc_is_wc_root), in which case @a parent_access refers to @a + * path itself. + * + * If @a depth is @c svn_depth_empty, revert just @a path (if a + * directory, then revert just the properties on that directory). + * Else if @c svn_depth_files, revert @a path and any files + * directly under @a path if it is directory. Else if + * @c svn_depth_immediates, revert all of the preceding plus + * properties on immediate subdirectories; else if @c svn_depth_infinity, + * revert path and everything under it fully recursively. + * + * @a changelists is an array of const char * changelist + * names, used as a restrictive filter on items reverted; that is, + * don't revert any item unless it's a member of one of those + * changelists. If @a changelists is empty (or altogether @c NULL), + * no changelist filtering occurs. + * + * If @a cancel_func is non-NULL, call it with @a cancel_baton at + * various points during the reversion process. If it returns an + * error (typically @c SVN_ERR_CANCELLED), return that error + * immediately. + * + * If @a use_commit_times is TRUE, then all reverted working-files + * will have their timestamp set to the last-committed-time. If + * FALSE, the reverted working-files will be touched with the 'now' time. + * + * For each item reverted, @a notify_func will be called with @a notify_baton + * and the path of the reverted item. @a notify_func may be @c NULL if this + * notification is not needed. + * + * If @a path is not under version control, return the error + * SVN_ERR_UNVERSIONED_RESOURCE. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_revert3(const char *path, + svn_wc_adm_access_t *parent_access, + svn_depth_t depth, + svn_boolean_t use_commit_times, + const apr_array_header_t *changelists, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_revert3(), but with @a changelists passed as @c + * NULL, and @a depth set according to @a recursive: if @a recursive + * is TRUE, @a depth is @c svn_depth_infinity; if FALSE, @a depth is + * @c svn_depth_empty. + * + * @note Most APIs map @a recurse==FALSE to @a depth==svn_depth_files; + * revert is deliberately different. + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_revert2(const char *path, + svn_wc_adm_access_t *parent_access, + svn_boolean_t recursive, + svn_boolean_t use_commit_times, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *pool); + +/** + * Similar to svn_wc_revert2(), but takes an @c svn_wc_notify_func_t instead. + * + * @deprecated Provided for backward compatibility with the 1.1 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_revert(const char *path, + svn_wc_adm_access_t *parent_access, + svn_boolean_t recursive, + svn_boolean_t use_commit_times, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func_t notify_func, + void *notify_baton, + apr_pool_t *pool); + + +/* Tmp files */ + +/** Create a unique temporary file in administrative tmp/ area of + * directory @a path. Return a handle in @a *fp and the path + * in @a *new_name. Either @a fp or @a new_name can be NULL. + * + * The flags will be APR_WRITE | APR_CREATE | APR_EXCL and + * optionally @c APR_DELONCLOSE (if the @a delete_when argument is + * set to @c svn_io_file_del_on_close). + * + * This means that as soon as @a fp is closed, the tmp file will vanish. + * + * @since New in 1.4 + */ +svn_error_t * +svn_wc_create_tmp_file2(apr_file_t **fp, + const char **new_name, + const char *path, + svn_io_file_del_t delete_when, + apr_pool_t *pool); + + +/** Same as svn_wc_create_tmp_file2(), but with @a new_name set to @c NULL, + * and without the ability to delete the file on pool cleanup. + * + * @deprecated For compatibility with 1.3 API + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_create_tmp_file(apr_file_t **fp, + const char *path, + svn_boolean_t delete_on_close, + apr_pool_t *pool); + + + +/* EOL conversion and keyword expansion. */ + +/** Set @a xlated_path to a translated copy of @a src + * or to @a src itself if no translation is necessary. + * That is, if @a versioned_file's properties indicate newline conversion or + * keyword expansion, point @a *xlated_path to a copy of @a src + * whose newlines and keywords are converted using the translation + * as requested by @a flags. + * + * When translating to the normal form, inconsistent eol styles will be + * repaired when appropriate for the given setting. When translating + * from normal form, no EOL repair is performed (consistency is assumed). + * This behaviour can be overridden by specifying + * @c SVN_WC_TRANSLATE_FORCE_EOL_REPAIR. + * + * The caller can explicitly request a new file to be returned by setting the + * @c SVN_WC_TRANSLATE_FORCE_COPY flag in @a flags. + * + * This function is generally used to get a file that can be compared + * meaningfully against @a versioned_file's text base, if + * @c SVN_WC_TRANSLATE_TO_NF is specified, against @a versioned_file itself + * if @c SVN_WC_TRANSLATE_FROM_NF is specified. + * + * Output files are created in the temp file area belonging to + * @a versioned_file. By default they will be deleted at pool cleanup. + * + * If @c SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP is specified, the default + * pool cleanup handler to remove @a *xlated_path is not registered. + * + * If an error is returned, the effect on @a *xlated_path is undefined. + * + * @since New in 1.4 + */ +svn_error_t * +svn_wc_translated_file2(const char **xlated_path, + const char *src, + const char *versioned_file, + svn_wc_adm_access_t *adm_access, + apr_uint32_t flags, + apr_pool_t *pool); + + +/** Same as svn_wc_translated_file2, but will never clean up + * temporary files. + * + * @deprecated Provided for compatibility with the 1.3 API + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_translated_file(const char **xlated_p, + const char *vfile, + svn_wc_adm_access_t *adm_access, + svn_boolean_t force_repair, + apr_pool_t *pool); + + +/** Returns a @a stream allocated in @a pool with access to the given + * @a path taking the file properties from @a versioned_file using + * @a adm_access. + * + * When translation from normal form is requested + * (@c SVN_WC_TRANSLATE_FROM_NF is specified in @a flags), @a path + * is used as target path and stream read operations are not supported. + * Conversely, if translation to normal form is requested + * (@c SVN_WC_TRANSLATE_TO_NF is specified in @a flags), @a path is + * used as source path and stream write operations are not supported. + * + * The @a flags are the same constants as those used for + * svn_wc_translated_file(). + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_translated_stream(svn_stream_t **stream, + const char *path, + const char *versioned_file, + svn_wc_adm_access_t *adm_access, + apr_uint32_t flags, + apr_pool_t *pool); + + +/* Text/Prop Deltas Using an Editor */ + + +/** Send the local modifications for versioned file @a path (with + * matching @a file_baton) through @a editor, then close @a file_baton + * afterwards. Use @a pool for any temporary allocation and + * @a adm_access as an access baton for @a path. + * + * This process creates a copy of @a path with keywords and eol + * untranslated. If @a tempfile is non-NULL, set @a *tempfile to the + * path to this copy. Do not clean up the copy; caller can do that. + * If @a digest is non-NULL, put the MD5 checksum of the + * temporary file into @a digest, which must point to @c APR_MD5_DIGESTSIZE + * bytes of storage. (The purpose of handing back the tmp copy is that + * it is usually about to become the new text base anyway, but the + * installation of the new text base is outside the scope of this + * function.) + * + * If @a fulltext, send the untranslated copy of @a path through @a editor + * as full-text; else send it as svndiff against the current text base. + * + * If sending a diff, and the recorded checksum for @a path's text-base + * does not match the current actual checksum, then remove the tmp + * copy (and set @a *tempfile to NULL if appropriate), and return the + * error @c SVN_ERR_WC_CORRUPT_TEXT_BASE. + * + * @note This is intended for use with both infix and postfix + * text-delta styled editor drivers. + * + * @since New in 1.4. + */ +svn_error_t * +svn_wc_transmit_text_deltas2(const char **tempfile, + unsigned char digest[], + const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t fulltext, + const svn_delta_editor_t *editor, + void *file_baton, + apr_pool_t *pool); + +/** Similar to svn_wc_transmit_text_deltas2(), but with @a digest set to NULL. + * + * @deprecated Provided for backwards compatibility with the 1.3 API. + */ +SVN_DEPRECATED +svn_error_t * +svn_wc_transmit_text_deltas(const char *path, + svn_wc_adm_access_t *adm_access, + svn_boolean_t fulltext, + const svn_delta_editor_t *editor, + void *file_baton, + const char **tempfile, + apr_pool_t *pool); + + +/** Given a @a path with its accompanying @a entry, transmit all local + * property modifications using the appropriate @a editor method (in + * conjunction with @a baton). @a adm_access is an access baton set + * that contains @a path. Use @a pool for all allocations. + * + * If a temporary file remains after this function is finished, the + * path to that file is returned in @a *tempfile (so the caller can + * clean this up if it wishes to do so). + * + * @note Starting version 1.5, no tempfile will ever be returned + * anymore. If @a *tempfile is passed, its value is set to @c NULL. + */ +svn_error_t * +svn_wc_transmit_prop_deltas(const char *path, + svn_wc_adm_access_t *adm_access, + const svn_wc_entry_t *entry, + const svn_delta_editor_t *editor, + void *baton, + const char **tempfile, + apr_pool_t *pool); + + +/** Get the run-time configured list of ignore patterns from the + * @c svn_config_t's in the @a config hash, and store them in @a *patterns. + * Allocate @a *patterns and its contents in @a pool. + */ +svn_error_t * +svn_wc_get_default_ignores(apr_array_header_t **patterns, + apr_hash_t *config, + apr_pool_t *pool); + +/** Get the list of ignore patterns from the @c svn_config_t's in the + * @a config hash and the local ignore patterns from the directory + * in @a adm_access, and store them in @a *patterns. + * Allocate @a *patterns and its contents in @a pool. + * + * @since New in 1.3. + */ +svn_error_t * +svn_wc_get_ignores(apr_array_header_t **patterns, + apr_hash_t *config, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + +/** Return TRUE iff @a str matches any of the elements of @a list, a + * list of zero or more ignore patterns. + * + * @since New in 1.5. + */ +svn_boolean_t +svn_wc_match_ignore_list(const char *str, + apr_array_header_t *list, + apr_pool_t *pool); + + +/** Add @a lock to the working copy for @a path. @a adm_access must contain + * a write lock for @a path. If @a path is read-only, due to locking + * properties, make it writable. Perform temporary allocations in @a + * pool. */ +svn_error_t * +svn_wc_add_lock(const char *path, + const svn_lock_t *lock, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + +/** Remove any lock from @a path. @a adm_access must contain a + * write-lock for @a path. If @a path has a lock and the locking + * so specifies, make the file read-only. Don't return an error if @a + * path didn't have a lock. Perform temporary allocations in @a pool. */ +svn_error_t * +svn_wc_remove_lock(const char *path, + svn_wc_adm_access_t *adm_access, + apr_pool_t *pool); + + +/** A structure to report a summary of a working copy, including the + * mix of revisions found within it, whether any parts are switched or + * locally modified, and whether it is a sparse checkout. + * + * @note Fields may be added to the end of this structure in future + * versions. Therefore, to preserve binary compatibility, users + * should not directly allocate structures of this type. + * + * @since New in 1.4 + */ +typedef struct svn_wc_revision_status_t +{ + svn_revnum_t min_rev; /**< Lowest revision found */ + svn_revnum_t max_rev; /**< Highest revision found */ + + svn_boolean_t switched; /**< Is anything switched? */ + svn_boolean_t modified; /**< Is anything modified? */ + + /** Whether any WC paths are at a depth other than @c svn_depth_infinity. + * @since New in 1.5. + */ + svn_boolean_t sparse_checkout; +} svn_wc_revision_status_t; + +/** Set @a *result_p to point to a new @c svn_wc_revision_status_t structure + * containing a summary of the revision range and status of the working copy + * at @a wc_path (not including "externals"). + * + * Set @a (*result_p)->min_rev and @a (*result_p)->max_rev respectively to the + * lowest and highest revision numbers in the working copy. If @a committed + * is TRUE, summarize the last-changed revisions, else the base revisions. + * + * Set @a (*result_p)->switched to indicate whether any item in the WC is + * switched relative to its parent. If @a trail_url is non-NULL, use it to + * determine if @a wc_path itself is switched. It should be any trailing + * portion of @a wc_path's expected URL, long enough to include any parts + * that the caller considers might be changed by a switch. If it does not + * match the end of @a wc_path's actual URL, then report a "switched" + * status. + * + * Set @a (*result_p)->modified to indicate whether any item is locally + * modified. + * + * If @a cancel_func is non-NULL, call it with @a cancel_baton to determine + * if the client has cancelled the operation. + * + * Allocate *result_p in @a pool. + * + * @since New in 1.4 + */ +svn_error_t * +svn_wc_revision_status(svn_wc_revision_status_t **result_p, + const char *wc_path, + const char *trail_url, + svn_boolean_t committed, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + + +/** + * Set @a path's entry's 'changelist' attribute to @a changelist iff + * @a changelist is not @c NULL; otherwise, remove any current + * changelist assignment from @a path. @a changelist may not be the + * empty string. @a adm_access is an access baton set that contains + * @a path. + * + * If @a cancel_func is not @c NULL, call it with @a cancel_baton to + * determine if the client has cancelled the operation. + * + * If @a notify_func is not @c NULL, call it with @a notify_baton to + * report the change (using notification types @c + * svn_wc_notify_changelist_set and @c svn_wc_notify_changelist_clear). + * + * @note For now, directories are NOT allowed to be associated with + * changelists; there is confusion about whether they should behave + * as depth-0 or depth-infinity objects. If @a path is a directory, + * return @c SVN_ERR_UNSUPPORTED_FEATURE. + * + * @note This metadata is purely a client-side "bookkeeping" + * convenience, and is entirely managed by the working copy. + * + * @since New in 1.5. + */ +svn_error_t * +svn_wc_set_changelist(const char *path, + const char *changelist, + svn_wc_adm_access_t *adm_access, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *pool); + +/** Crop @a target according to @a depth. + * + * Remove any item that exceeds the boundary of @a depth (relative to + * @a target) from revision control. Leave modified items behind + * (unversioned), while removing unmodified ones completely. + * + * If @a target starts out with a shallower depth than @a depth, do not + * upgrade it to @a depth (that would not be cropping); however, do + * check children and crop them appropriately according to @a depth. + * + * Returns immediately with no error if @a target is not a directory, + * or if @a depth is not restrictive (e.g., @c svn_depth_infinity). + * + * @a anchor is an access baton, with a tree lock, for the local path to the + * working copy which will be used as the root of this operation. If + * @a target is not empty, it represents an entry in the @a anchor path; + * otherwise, the @a anchor path is the target. @a target may not be + * @c NULL. + * + * If @a cancel_func is not @c NULL, call it with @a cancel_baton at + * various points to determine if the client has cancelled the operation. + * + * If @a notify_func is not @c NULL, call it with @a notify_baton to + * report changes as they are made. + * + * @note: svn_depth_exclude currently does nothing; passing it results + * in immediate success with no side effects. + * + * @since New in 1.6 + */ +svn_error_t * +svn_wc_crop_tree(svn_wc_adm_access_t *anchor, + const char *target, + svn_depth_t depth, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_WC_H */ -- 2.11.0