summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/common/path/RTPathCalcRelative.cpp')
-rw-r--r--src/VBox/Runtime/common/path/RTPathCalcRelative.cpp130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp b/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp
new file mode 100644
index 00000000..fbb6b64c
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp
@@ -0,0 +1,130 @@
+/* $Id: RTPathCalcRelative.cpp $ */
+/** @file
+ * IPRT - RTPathCreateRelative.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+
+
+
+RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst,
+ const char *pszPathFrom,
+ const char *pszPathTo)
+{
+ int rc = VINF_SUCCESS;
+
+ AssertPtrReturn(pszPathDst, VERR_INVALID_POINTER);
+ AssertReturn(cbPathDst, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszPathFrom, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszPathTo, VERR_INVALID_POINTER);
+ AssertReturn(RTPathStartsWithRoot(pszPathFrom), VERR_INVALID_PARAMETER);
+ AssertReturn(RTPathStartsWithRoot(pszPathTo), VERR_INVALID_PARAMETER);
+ AssertReturn(RTStrCmp(pszPathFrom, pszPathTo), VERR_INVALID_PARAMETER);
+
+ /*
+ * Check for different root specifiers (drive letters), creating a relative path doesn't work here.
+ * @todo: How to handle case insensitive root specifiers correctly?
+ */
+ size_t offRootFrom = rtPathRootSpecLen(pszPathFrom);
+ size_t offRootTo = rtPathRootSpecLen(pszPathTo);
+
+ if ( offRootFrom != offRootTo
+ || RTStrNCmp(pszPathFrom, pszPathTo, offRootFrom))
+ return VERR_NOT_SUPPORTED;
+
+ /* Filter out the parent path which is equal to both paths. */
+ while ( *pszPathFrom == *pszPathTo
+ && *pszPathFrom != '\0'
+ && *pszPathTo != '\0')
+ {
+ pszPathFrom++;
+ pszPathTo++;
+ }
+
+ /*
+ * Because path components can start with an equal string but differ afterwards we
+ * need to go back to the beginning of the current component.
+ */
+ while (!RTPATH_IS_SEP(*pszPathFrom))
+ pszPathFrom--;
+
+ pszPathFrom++; /* Skip path separator. */
+
+ while (!RTPATH_IS_SEP(*pszPathTo))
+ pszPathTo--;
+
+ pszPathTo++; /* Skip path separator. */
+
+ /* Paths point to the first non equal component now. */
+ char aszPathTmp[RTPATH_MAX + 1];
+ unsigned offPathTmp = 0;
+
+ /* Create the part to go up from pszPathFrom. */
+ while (*pszPathFrom != '\0')
+ {
+ while ( !RTPATH_IS_SEP(*pszPathFrom)
+ && *pszPathFrom != '\0')
+ pszPathFrom++;
+
+ if (RTPATH_IS_SEP(*pszPathFrom))
+ {
+ if (offPathTmp + 3 >= sizeof(aszPathTmp) - 1)
+ return VERR_FILENAME_TOO_LONG;
+ aszPathTmp[offPathTmp++] = '.';
+ aszPathTmp[offPathTmp++] = '.';
+ aszPathTmp[offPathTmp++] = RTPATH_SLASH;
+ pszPathFrom++;
+ }
+ }
+
+ aszPathTmp[offPathTmp] = '\0';
+
+ /* Now append the rest of pszPathTo to the final path. */
+ char *pszPathTmp = &aszPathTmp[offPathTmp];
+ size_t cbPathTmp = sizeof(aszPathTmp) - offPathTmp - 1;
+ rc = RTStrCatP(&pszPathTmp, &cbPathTmp, pszPathTo);
+ if (RT_SUCCESS(rc))
+ {
+ *pszPathTmp = '\0';
+
+ size_t cchPathTmp = strlen(aszPathTmp);
+ if (cchPathTmp >= cbPathDst)
+ return VERR_BUFFER_OVERFLOW;
+ memcpy(pszPathDst, aszPathTmp, cchPathTmp + 1);
+ }
+ else
+ rc = VERR_FILENAME_TOO_LONG;
+
+ return rc;
+}
+