summaryrefslogtreecommitdiffstats
path: root/src/VBox/Runtime/common/vfs/vfsiosmisc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/common/vfs/vfsiosmisc.cpp')
-rw-r--r--src/VBox/Runtime/common/vfs/vfsiosmisc.cpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/vfs/vfsiosmisc.cpp b/src/VBox/Runtime/common/vfs/vfsiosmisc.cpp
new file mode 100644
index 00000000..87cbf72f
--- /dev/null
+++ b/src/VBox/Runtime/common/vfs/vfsiosmisc.cpp
@@ -0,0 +1,228 @@
+/* $Id: vfsiosmisc.cpp $ */
+/** @file
+ * IPRT - Virtual File System, Misc I/O Stream Operations.
+ */
+
+/*
+ * Copyright (C) 2010-2020 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 <iprt/vfs.h>
+#include <iprt/vfslowlevel.h>
+
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+
+
+
+RTDECL(int) RTVfsIoStrmValidateUtf8Encoding(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, PRTFOFF poffError)
+{
+ /*
+ * Validate input.
+ */
+ if (poffError)
+ {
+ AssertPtrReturn(poffError, VINF_SUCCESS);
+ *poffError = 0;
+ }
+ AssertReturn(!(fFlags & ~RTVFS_VALIDATE_UTF8_VALID_MASK), VERR_INVALID_PARAMETER);
+
+ /*
+ * The loop.
+ */
+ char achBuf[1024 + 1];
+ size_t cbUsed = 0;
+ int rc;
+ for (;;)
+ {
+ /*
+ * Fill the buffer
+ */
+ size_t cbRead = 0;
+ rc = RTVfsIoStrmRead(hVfsIos, &achBuf[cbUsed], sizeof(achBuf) - cbUsed - 1, true /*fBlocking*/, &cbRead);
+ if (RT_FAILURE(rc))
+ break;
+ cbUsed += cbRead;
+ if (!cbUsed)
+ {
+ Assert(rc == VINF_EOF);
+ break;
+ }
+ achBuf[sizeof(achBuf) - 1] = '\0';
+
+ /*
+ * Process the data in the buffer, maybe leaving the final chars till
+ * the next round.
+ */
+ const char *pszCur = achBuf;
+ size_t offEnd = rc == VINF_EOF
+ ? cbUsed
+ : cbUsed >= 7
+ ? cbUsed - 7
+ : 0;
+ size_t off;
+ while ((off = (pszCur - &achBuf[0])) < offEnd)
+ {
+ RTUNICP uc;
+ rc = RTStrGetCpEx(&pszCur, &uc);
+ if (RT_FAILURE(rc))
+ break;
+ if (!uc)
+ {
+ if (fFlags & RTVFS_VALIDATE_UTF8_NO_NULL)
+ {
+ rc = VERR_INVALID_UTF8_ENCODING;
+ break;
+ }
+ }
+ else if (uc > 0x10ffff)
+ {
+ if (fFlags & RTVFS_VALIDATE_UTF8_BY_RTC_3629)
+ {
+ rc = VERR_INVALID_UTF8_ENCODING;
+ break;
+ }
+ }
+ }
+
+ if (off < cbUsed)
+ {
+ cbUsed -= off;
+ memmove(achBuf, pszCur, cbUsed);
+ }
+ }
+
+ /*
+ * Set the offset on failure.
+ */
+ if (poffError && RT_FAILURE(rc))
+ {
+ }
+
+ return rc == VINF_EOF ? VINF_SUCCESS : rc;
+}
+
+
+/** Header size. */
+#define READ_ALL_HEADER_SIZE 0x20
+/** The header magic. It's followed by the size (both size_t). */
+#define READ_ALL_HEADER_MAGIC UINT32_C(0x11223355)
+
+RTDECL(int) RTVfsIoStrmReadAll(RTVFSIOSTREAM hVfsIos, void **ppvBuf, size_t *pcbBuf)
+{
+ /*
+ * Try query the object information and in case the stream has a known
+ * size we could use for guidance.
+ */
+ RTFSOBJINFO ObjInfo;
+ int rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_NOTHING);
+ size_t cbAllocated = RT_SUCCESS(rc) && ObjInfo.cbObject > 0 && ObjInfo.cbObject < _1G
+ ? (size_t)ObjInfo.cbObject + 1 : _16K;
+ cbAllocated += READ_ALL_HEADER_SIZE;
+ void *pvBuf = RTMemAlloc(cbAllocated);
+ if (pvBuf)
+ {
+ memset(pvBuf, 0xfe, READ_ALL_HEADER_SIZE);
+ size_t off = 0;
+ for (;;)
+ {
+ /*
+ * Handle buffer growing and detecting the end of it all.
+ */
+ size_t cbToRead = cbAllocated - off - READ_ALL_HEADER_SIZE - 1;
+ if (!cbToRead)
+ {
+ /* The end? */
+ uint8_t bIgn;
+ size_t cbIgn;
+ rc = RTVfsIoStrmRead(hVfsIos, &bIgn, 0, true /*fBlocking*/, &cbIgn);
+ if (rc == VINF_EOF)
+ break;
+
+ /* Grow the buffer. */
+ cbAllocated -= READ_ALL_HEADER_SIZE - 1;
+ cbAllocated = RT_MAX(RT_MIN(cbAllocated, _32M), _1K);
+ cbAllocated = RT_ALIGN_Z(cbAllocated, _4K);
+ cbAllocated += READ_ALL_HEADER_SIZE + 1;
+
+ void *pvNew = RTMemRealloc(pvBuf, cbAllocated);
+ AssertBreakStmt(pvNew, rc = VERR_NO_MEMORY);
+ pvBuf = pvNew;
+
+ cbToRead = cbAllocated - off - READ_ALL_HEADER_SIZE - 1;
+ }
+ Assert(cbToRead < cbAllocated);
+
+ /*
+ * Read.
+ */
+ size_t cbActual;
+ rc = RTVfsIoStrmRead(hVfsIos, (uint8_t *)pvBuf + READ_ALL_HEADER_SIZE + off, cbToRead,
+ true /*fBlocking*/, &cbActual);
+ if (RT_FAILURE(rc))
+ break;
+ Assert(cbActual > 0);
+ Assert(cbActual <= cbToRead);
+ off += cbActual;
+ if (rc == VINF_EOF)
+ break;
+ }
+ Assert(rc != VERR_EOF);
+ if (RT_SUCCESS(rc))
+ {
+ ((size_t *)pvBuf)[0] = READ_ALL_HEADER_MAGIC;
+ ((size_t *)pvBuf)[1] = off;
+ ((uint8_t *)pvBuf)[READ_ALL_HEADER_SIZE + off] = 0;
+
+ *ppvBuf = (uint8_t *)pvBuf + READ_ALL_HEADER_SIZE;
+ *pcbBuf = off;
+ return VINF_SUCCESS;
+ }
+
+ RTMemFree(pvBuf);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ *ppvBuf = NULL;
+ *pcbBuf = 0;
+ return rc;
+}
+
+
+RTDECL(void) RTVfsIoStrmReadAllFree(void *pvBuf, size_t cbBuf)
+{
+ AssertPtrReturnVoid(pvBuf);
+
+ /* Spool back to the start of the header. */
+ pvBuf = (uint8_t *)pvBuf - READ_ALL_HEADER_SIZE;
+
+ /* Make sure the caller isn't messing with us. Hardcoded, but works. */
+ Assert(((size_t *)pvBuf)[0] == READ_ALL_HEADER_MAGIC);
+ Assert(((size_t *)pvBuf)[1] == cbBuf); RT_NOREF_PV(cbBuf);
+
+ /* Free it. */
+ RTMemFree(pvBuf);
+}
+