diff --git a/deps/base64/base64/CMakeLists.txt b/deps/base64/base64/CMakeLists.txt index be1de665a2cd59..ff9f6f21e1ee28 100644 --- a/deps/base64/base64/CMakeLists.txt +++ b/deps/base64/base64/CMakeLists.txt @@ -17,7 +17,7 @@ if (POLICY CMP0127) cmake_policy(SET CMP0127 NEW) endif() -project(base64 LANGUAGES C VERSION 0.5.1) +project(base64 LANGUAGES C VERSION 0.5.2) include(GNUInstallDirs) include(CMakeDependentOption) diff --git a/deps/base64/base64/Makefile b/deps/base64/base64/Makefile index bcb944551ae881..bba3fde4dd05bf 100644 --- a/deps/base64/base64/Makefile +++ b/deps/base64/base64/Makefile @@ -1,4 +1,4 @@ -CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic +CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic -DBASE64_STATIC_DEFINE # Set OBJCOPY if not defined by environment: OBJCOPY ?= objcopy @@ -56,6 +56,7 @@ ifdef OPENMP CFLAGS += -fopenmp endif +TARGET := $(shell $(CC) -dumpmachine) .PHONY: all analyze clean @@ -64,9 +65,17 @@ all: bin/base64 lib/libbase64.o bin/base64: bin/base64.o lib/libbase64.o $(CC) $(CFLAGS) -o $@ $^ -lib/libbase64.o: $(OBJS) - $(LD) -r -o $@ $^ - $(OBJCOPY) --keep-global-symbols=lib/exports.txt $@ +# Workaround: mangle exported function names on MinGW32. +lib/exports.build.txt: lib/exports.txt +ifeq (i686-w64-mingw32, $(TARGET)) + sed -e 's/^/_/' $< > $@ +else + cp -f $< $@ +endif + +lib/libbase64.o: lib/exports.build.txt $(OBJS) + $(LD) -r -o $@ $(OBJS) + $(OBJCOPY) --keep-global-symbols=$< $@ lib/config.h: @echo "#define HAVE_AVX512 $(HAVE_AVX512)" > $@ @@ -97,4 +106,4 @@ analyze: clean scan-build --use-analyzer=`which clang` --status-bugs make clean: - rm -f bin/base64 bin/base64.o lib/libbase64.o lib/config.h $(OBJS) + rm -f bin/base64 bin/base64.o lib/libbase64.o lib/config.h lib/exports.build.txt $(OBJS) diff --git a/deps/base64/base64/bin/base64.c b/deps/base64/base64/bin/base64.c index 98d6b3cbab560c..0e32ed03762df7 100644 --- a/deps/base64/base64/bin/base64.c +++ b/deps/base64/base64/bin/base64.c @@ -1,4 +1,19 @@ -#define _XOPEN_SOURCE // IOV_MAX +// Test for MinGW. +#if defined(__MINGW32__) || defined(__MINGW64__) +# define MINGW +#endif + +// Decide if the writev(2) system call needs to be emulated as a series of +// write(2) calls. At least MinGW does not support writev(2). +#ifdef MINGW +# define EMULATE_WRITEV +#endif + +// Include the necessary system header when using the system's writev(2). +#ifndef EMULATE_WRITEV +# define _XOPEN_SOURCE // Unlock IOV_MAX +# include +#endif #include #include @@ -8,7 +23,7 @@ #include #include #include -#include + #include "../include/libbase64.h" // Size of the buffer for the "raw" (not base64-encoded) data in bytes. @@ -50,6 +65,59 @@ struct buffer { char *enc; }; +// Optionally emulate writev(2) as a series of write calls. +#ifdef EMULATE_WRITEV + +// Quick and dirty definition of IOV_MAX as it is probably not defined. +#ifndef IOV_MAX +# define IOV_MAX 1024 +#endif + +// Quick and dirty definition of this system struct, for local use only. +struct iovec { + + // Opaque data pointer. + void *iov_base; + + // Length of the data in bytes. + size_t iov_len; +}; + +static ssize_t +writev (const int fd, const struct iovec *iov, int iovcnt) +{ + ssize_t r, nwrite = 0; + + // Reset the error marker. + errno = 0; + + while (iovcnt-- > 0) { + + // Write the vector; propagate errors back to the caller. Note + // that this loses information about how much vectors have been + // successfully written, but that also seems to be the case + // with the real function. The API is somewhat flawed. + if ((r = write(fd, iov->iov_base, iov->iov_len)) < 0) { + return r; + } + + // Update the total write count. + nwrite += r; + + // Return early after a partial write; the caller should retry. + if ((size_t) r != iov->iov_len) { + break; + } + + // Move to the next vector. + iov++; + } + + return nwrite; +} + +#endif // EMULATE_WRITEV + static bool buffer_alloc (const struct config *config, struct buffer *buf) { @@ -272,10 +340,23 @@ encode (const struct config *config, struct buffer *buf) return true; } -static int +static inline size_t +find_newline (const char *p, const size_t avail) +{ + // This is very naive and can probably be improved by vectorization. + for (size_t len = 0; len < avail; len++) { + if (p[len] == '\n') { + return len; + } + } + + return avail; +} + +static bool decode (const struct config *config, struct buffer *buf) { - size_t nread, nout; + size_t avail; struct base64_state state; // Initialize the decoder's state structure. @@ -283,18 +364,51 @@ decode (const struct config *config, struct buffer *buf) // Read encoded data into the buffer. Use the smallest buffer size to // be on the safe side: the decoded output will fit the raw buffer. - while ((nread = fread(buf->enc, 1, BUFFER_RAW_SIZE, config->fp)) > 0) { + while ((avail = fread(buf->enc, 1, BUFFER_RAW_SIZE, config->fp)) > 0) { + char *start = buf->enc; + char *outbuf = buf->raw; + size_t ototal = 0; + + // By popular demand, this utility tries to be bug-compatible + // with GNU `base64'. That includes silently ignoring newlines + // in the input. Tokenize the input on newline characters. + while (avail > 0) { + + // Find the offset of the next newline character, which + // is also the length of the next chunk. + size_t outlen, len = find_newline(start, avail); + + // Ignore empty chunks. + if (len == 0) { + start++; + avail--; + continue; + } - // Decode the input into the raw buffer. - if (base64_stream_decode(&state, buf->enc, nread, - buf->raw, &nout) == 0) { - fprintf(stderr, "%s: %s: decoding error\n", - config->name, config->file); - return false; + // Decode the chunk into the raw buffer. + if (base64_stream_decode(&state, start, len, + outbuf, &outlen) == 0) { + fprintf(stderr, "%s: %s: decoding error\n", + config->name, config->file); + return false; + } + + // Update the output buffer pointer and total size. + outbuf += outlen; + ototal += outlen; + + // Bail out if the whole string has been consumed. + if (len == avail) { + break; + } + + // Move the start pointer past the newline. + start += len + 1; + avail -= len + 1; } // Append the raw data to the output stream. - if (write_stdout(config, buf->raw, nout) == false) { + if (write_stdout(config, buf->raw, ototal) == false) { return false; } } diff --git a/deps/base64/base64/lib/env.h b/deps/base64/base64/lib/env.h index d5c2fdb7952735..d489ba54215bbf 100644 --- a/deps/base64/base64/lib/env.h +++ b/deps/base64/base64/lib/env.h @@ -1,6 +1,8 @@ #ifndef BASE64_ENV_H #define BASE64_ENV_H +#include + // This header file contains macro definitions that describe certain aspects of // the compile-time environment. Compatibility and portability macros go here. @@ -46,12 +48,10 @@ #if defined (__x86_64__) // This also works for the x32 ABI, which has a 64-bit word size. # define BASE64_WORDSIZE 64 -#elif defined (_INTEGRAL_MAX_BITS) -# define BASE64_WORDSIZE _INTEGRAL_MAX_BITS -#elif defined (__WORDSIZE) -# define BASE64_WORDSIZE __WORDSIZE -#elif defined (__SIZE_WIDTH__) -# define BASE64_WORDSIZE __SIZE_WIDTH__ +#elif SIZE_MAX == UINT32_MAX +# define BASE64_WORDSIZE 32 +#elif SIZE_MAX == UINT64_MAX +# define BASE64_WORDSIZE 64 #else # error BASE64_WORDSIZE_NOT_DEFINED #endif diff --git a/deps/base64/base64/test/CMakeLists.txt b/deps/base64/base64/test/CMakeLists.txt index ef8787047b2944..f07b65a00c2cb4 100644 --- a/deps/base64/base64/test/CMakeLists.txt +++ b/deps/base64/base64/test/CMakeLists.txt @@ -32,12 +32,10 @@ add_base64_test(test_base64 test_base64.c ) -if (NOT WIN32) - add_base64_test(benchmark - codec_supported.c - benchmark.c - ) -endif() +add_base64_test(benchmark + codec_supported.c + benchmark.c +) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") target_link_libraries(benchmark PRIVATE rt) diff --git a/deps/base64/base64/test/Makefile b/deps/base64/base64/test/Makefile index c896627e0bd8d6..7ecb893a6363b9 100644 --- a/deps/base64/base64/test/Makefile +++ b/deps/base64/base64/test/Makefile @@ -1,4 +1,4 @@ -CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic +CFLAGS += -std=c99 -O3 -Wall -Wextra -pedantic -DBASE64_STATIC_DEFINE ifdef OPENMP CFLAGS += -fopenmp endif @@ -6,6 +6,8 @@ endif TARGET := $(shell $(CC) -dumpmachine) ifneq (, $(findstring darwin, $(TARGET))) BENCH_LDFLAGS= +else ifneq (, $(findstring mingw, $(TARGET))) + BENCH_LDFLAGS= else # default to linux, -lrt needed BENCH_LDFLAGS=-lrt diff --git a/deps/base64/base64/test/benchmark.c b/deps/base64/base64/test/benchmark.c index 80d21a389cb98c..e78b696bedb6b3 100644 --- a/deps/base64/base64/test/benchmark.c +++ b/deps/base64/base64/test/benchmark.c @@ -8,17 +8,25 @@ #define _XOPEN_SOURCE 600 #endif +// Standard cross-platform includes. #include -#include -#include -#include -#include #include #include -#include -#ifdef __MACH__ -#include +// Platform-specific includes. +#if defined(_WIN32) || defined(_WIN64) +# include +# include +#else +# include +# include +# include +# include +# include +#endif + +#if defined(__MACH__) +# include #endif #include "../include/libbase64.h" @@ -60,6 +68,27 @@ bytes_to_mb (size_t bytes) static bool get_random_data (struct buffers *b, char **errmsg) { +#if defined(_WIN32) || defined(_WIN64) + HCRYPTPROV hProvider = 0; + + if (!CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + *errmsg = "Error: CryptAcquireContext"; + return false; + } + + if (!CryptGenRandom(hProvider, b->regsz, b->reg)) { + CryptReleaseContext(hProvider, 0); + *errmsg = "Error: CryptGenRandom"; + return false; + } + + if (!CryptReleaseContext(hProvider, 0)) { + *errmsg = "Error: CryptReleaseContext"; + return false; + } + + return true; +#else int fd; ssize_t nread; size_t total_read = 0; @@ -80,16 +109,19 @@ get_random_data (struct buffers *b, char **errmsg) } total_read += nread; } + close(fd); return true; +#endif } -#ifdef __MACH__ +#if defined(__MACH__) typedef uint64_t base64_timespec; + static void -base64_gettime (base64_timespec * o_time) +base64_gettime (base64_timespec *t) { - *o_time = mach_absolute_time(); + *t = mach_absolute_time(); } static float @@ -101,18 +133,39 @@ timediff_sec (base64_timespec *start, base64_timespec *end) return (float)((diff * tb.numer) / tb.denom) / 1e9f; } +#elif defined(_WIN32) || defined(_WIN64) +typedef ULARGE_INTEGER base64_timespec; + +static void +base64_gettime (base64_timespec *t) +{ + FILETIME current_time_ft; + + GetSystemTimePreciseAsFileTime(¤t_time_ft); + + t->LowPart = current_time_ft.dwLowDateTime; + t->HighPart = current_time_ft.dwHighDateTime; +} + +static float +timediff_sec (base64_timespec *start, base64_timespec *end) +{ + // Timer resolution is 100 nanoseconds (10^-7 sec). + return (end->QuadPart - start->QuadPart) / 1e7f; +} #else typedef struct timespec base64_timespec; + static void -base64_gettime (base64_timespec * o_time) +base64_gettime (base64_timespec *t) { - clock_gettime(CLOCK_REALTIME, o_time); + clock_gettime(CLOCK_REALTIME, t); } static float timediff_sec (base64_timespec *start, base64_timespec *end) { - return (end->tv_sec - start->tv_sec) + ((float)(end->tv_nsec - start->tv_nsec)) / 1e9f; + return (end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec) / 1e9f; } #endif diff --git a/src/base64_version.h b/src/base64_version.h index c3737f4beebfcb..ce3d7c03f8c979 100644 --- a/src/base64_version.h +++ b/src/base64_version.h @@ -2,5 +2,5 @@ // Refer to tools/dep_updaters/update-base64.sh #ifndef SRC_BASE64_VERSION_H_ #define SRC_BASE64_VERSION_H_ -#define BASE64_VERSION "0.5.1" +#define BASE64_VERSION "0.5.2" #endif // SRC_BASE64_VERSION_H_