Files
core/include/tools/UnixWrappers.h
Tor Lillqvist b28a46aa50 Make sure that <tools/UnixWrappers.h> stays compilable as C
We don't use it yet from any C source file, but the plan is to do
that. Mainly from freetype, fontconfig, and cairo, when these are
built for Windows when the --enable-headless options is used (for the
new Collabora Office).

Also some cleanups, sorting #include lines, avoiding warnings, etc.

Change-Id: Ifef3588d06fdcceaeaeb3482399737faaf558d7d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195602
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Tested-by: Jenkins
2025-12-15 07:31:21 +01:00

337 lines
8.5 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/* Wrappers to use Unix-style file APIs on Windows.
*
* Of course, LibreOffice has tons of APIs from before whose whole point is to hide system
* dependencies behind a cross-platform API. All the "sal" and "osl" stuff, for starters. The
* wrappers in this file is not intended to replace those. The point with these wrappers is to
* quickly port code that was written for Unix *only* to Windows, with minimal changes to the source
* code. Basically you just need to prefix calls to functions like open() and stat() with wrap_.
*
* In Windows, "file descriptors" are a thing in the C library, not the operating system. But the C
* library does provide the same core set of functionality as Unix-like systems do. The functions
* use almost the same names, except that for some reason, to avoid compilation warnings, you need
* to call variants with names preceded by an underscore, like _close().
* Another Windows complication is that the file system is based on UTF-16 names. You can't just
* pass file names as eight-bit characters to _open() and expect it to work for all file
* names. Instead, you need to call a function with a "w" prefix, like _wopen(), that takes a wide
* character string (UTF-16).
* This header is in C, not C++, because we want it to be usable from some external libraries
* written in C that we compile as part of LibreOffice in some circumstances, particularly for
* Windows.
*
* All functions behave like the wrapped ones, set errno on errors.
*/
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <wchar.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#include <io.h>
#include <string.h>
#include <assert.h>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
/* Undo the mapping in <Windows.h> of CreateFont => CreateFontW etc, as vcl also uses these
* identifiers.
*/
#undef CreateFont
#undef GetGlyphOutline
#else
#include <unistd.h>
#include <sys/mman.h>
#endif
#ifdef _WIN32
#define MAP_FAILED ((void*)-1)
#define S_ISDIR(m) (((m)&_S_IFMT) == _S_IFDIR)
#define F_OK 00
#define W_OK 02
#define R_OK 04
#define X_OK R_OK
#define PATH_MAX MAX_PATH
#endif
#ifdef __cplusplus
#define UNIXWRAPPERS_H_MAYBE_UNUSED [[maybe_unused]]
#else
#define UNIXWRAPPERS_H_MAYBE_UNUSED
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#ifdef _WIN32
static wchar_t* string_to_wide_string(const char* string)
{
const size_t len = strlen(string);
if (len == 0)
{
return _wcsdup(L"");
}
if (len > INT_MAX)
{
/* Trying to be funny, eh? */
return _wcsdup(L"");
}
const int wlen = MultiByteToWideChar(CP_UTF8, 0, string, (int)len, NULL, 0);
if (wlen <= 0)
{
return NULL;
}
wchar_t* result = (wchar_t*)malloc(wlen * 2 + 2);
assert(result);
MultiByteToWideChar(CP_UTF8, 0, string, (int)len, result, wlen);
result[wlen] = L'\0';
return result;
}
#endif
/* Pass in UTF-8 filename */
UNIXWRAPPERS_H_MAYBE_UNUSED static int wrap_open(const char* path, int flags, int mode)
{
#ifdef _WIN32
wchar_t* wpath = string_to_wide_string(path);
int result = _wopen(wpath, flags, mode);
free(wpath);
return result;
#else
return open(path, flags, mode);
#endif
}
#if 0
/* Pass in UTF-16 filename */
UNIXWRAPPERS_H_MAYBE_UNUSED static int wrap_wopen(const wchar_t* path, int flags, int mode)
{
#ifdef _WIN32
return _wopen(path, flags, mode);
#else
rtl_String* str;
int len = wcslen(path);
bool success = rtl_convertUStringToString(&str, path, len, RTL_TEXTENCODING_UTF8,
RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
| RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR);
int result;
if (success)
{
char* spath = malloc(len + 1);
strcat(spath, str, len);
spath[len] = 0;
result = open(str->buffer, flags, path);
free(spath);
}
else
{
result = -1;
errno = EIO;
}
rtl_string_release(str);
return result;
#endif
}
#endif
UNIXWRAPPERS_H_MAYBE_UNUSED static int wrap_read(int fd, void* buf, int nbytes)
{
#ifdef _WIN32
return _read(fd, buf, nbytes);
#else
return read(fd, buf, nbytes);
#endif
}
UNIXWRAPPERS_H_MAYBE_UNUSED static int wrap_write(int fd, const void* buf, int nbytes)
{
#ifdef _WIN32
return _write(fd, buf, nbytes);
#else
return write(fd, buf, nbytes);
#endif
}
UNIXWRAPPERS_H_MAYBE_UNUSED static int wrap_fstat(int fd, struct stat* st)
{
#ifdef _WIN32
/* Sadly just "struct stat" in the Microsoft C library means a legacy one with 32-bit size,
* 32-bit time one. But it is a *different* type than struct _stat32, even if identical.
*/
struct _stat32 st32;
int result = _fstat32(fd, &st32);
if (result != -1)
{
st->st_dev = st32.st_dev;
st->st_ino = st32.st_ino;
st->st_mode = st32.st_mode;
st->st_nlink = st32.st_nlink;
st->st_uid = st32.st_uid;
st->st_gid = st32.st_gid;
st->st_rdev = st32.st_rdev;
st->st_size = st32.st_size;
st->st_atime = st32.st_atime;
st->st_mtime = st32.st_mtime;
st->st_ctime = st32.st_ctime;
}
return result;
#else
return fstat(fd, st);
#endif
}
UNIXWRAPPERS_H_MAYBE_UNUSED static void* wrap_mmap(int64_t size, int fd, intptr_t* handle)
{
#ifdef _WIN32
*handle = (intptr_t)CreateFileMappingW((HANDLE)_get_osfhandle(fd), NULL,
SEC_COMMIT | PAGE_READONLY, 0, 0, NULL);
return MapViewOfFile((HANDLE)*handle, FILE_MAP_READ, 0, 0, size);
#else
/* No handle needs to be stored */
(void)handle;
return mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
#endif
}
UNIXWRAPPERS_H_MAYBE_UNUSED static int wrap_munmap(void* pointer, int64_t size, intptr_t handle)
{
#ifdef _WIN32
(void)size;
CloseHandle((HANDLE)handle);
if (!UnmapViewOfFile(pointer))
{
errno = EIO;
return -1;
}
return 0;
#else
(void)handle;
return munmap(pointer, size);
#endif
}
UNIXWRAPPERS_H_MAYBE_UNUSED static int wrap_dup(int fd)
{
#ifdef _WIN32
return _dup(fd);
#else
return dup(fd);
#endif
}
UNIXWRAPPERS_H_MAYBE_UNUSED static int wrap_close(int fd)
{
#ifdef _WIN32
return _close(fd);
#else
return close(fd);
#endif
}
/* This doesn't usea file descriptor but is related to the above functionality so keep here
* anyway.
*/
UNIXWRAPPERS_H_MAYBE_UNUSED static FILE* wrap_fopen(const char* path, const char* mode)
{
#ifdef _WIN32
wchar_t* wpath = string_to_wide_string(path);
wchar_t* wmode = string_to_wide_string(mode);
FILE* result = _wfopen(wpath, wmode);
free(wpath);
free(wmode);
return result;
#else
return fopen(path, mode);
#endif
}
UNIXWRAPPERS_H_MAYBE_UNUSED static int wrap_stat(const char* path, struct stat* st)
{
#ifdef _WIN32
struct _stat32 st32;
wchar_t* wpath = string_to_wide_string(path);
int result = _wstat32(wpath, &st32);
free(wpath);
if (result != -1)
{
st->st_dev = st32.st_dev;
st->st_ino = st32.st_ino;
st->st_mode = st32.st_mode;
st->st_nlink = st32.st_nlink;
st->st_uid = st32.st_uid;
st->st_gid = st32.st_gid;
st->st_rdev = st32.st_rdev;
st->st_size = st32.st_size;
st->st_atime = st32.st_atime;
st->st_mtime = st32.st_mtime;
st->st_ctime = st32.st_ctime;
}
return result;
#else
return stat(path, st);
#endif
}
UNIXWRAPPERS_H_MAYBE_UNUSED static int wrap_access(const char* path, int mode)
{
#ifdef _WIN32
wchar_t* wpath = string_to_wide_string(path);
int result = _waccess(wpath, mode);
free(wpath);
return result;
#else
return access(path, mode);
#endif
}
UNIXWRAPPERS_H_MAYBE_UNUSED static const char* wrap_realpath(const char* path, char* resolved_path)
{
#ifdef _WIN32
strcpy(resolved_path, path);
return resolved_path;
#else
return realpath(path, resolved_path);
#endif
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#ifdef __cplusplus
}
#endif
#undef UNIXWRAPPERS_H_MAYBE_UNUSED
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */