Imported Upstream version 0.13.2+dsfg1
This commit is contained in:
commit
fb3990e9e5
2036 changed files with 287360 additions and 0 deletions
39
libobs/util/AlignedNew.hpp
Normal file
39
libobs/util/AlignedNew.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bmem.h"
|
||||
|
||||
inline void* operator new(size_t size)
|
||||
{
|
||||
return bmalloc(size);
|
||||
}
|
||||
|
||||
inline void operator delete(void* data)
|
||||
{
|
||||
bfree(data);
|
||||
}
|
||||
|
||||
inline void* operator new[](size_t size)
|
||||
{
|
||||
return bmalloc(size);
|
||||
}
|
||||
|
||||
inline void operator delete[](void* data)
|
||||
{
|
||||
bfree(data);
|
||||
}
|
||||
46
libobs/util/array-serializer.c
Normal file
46
libobs/util/array-serializer.c
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "darray.h"
|
||||
#include "array-serializer.h"
|
||||
|
||||
static size_t array_output_write(void *param, const void *data, size_t size)
|
||||
{
|
||||
struct array_output_data *output = param;
|
||||
da_push_back_array(output->bytes, data, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
static int64_t array_output_get_pos(void *param)
|
||||
{
|
||||
struct array_output_data *data = param;
|
||||
return (int64_t)data->bytes.num;
|
||||
}
|
||||
|
||||
void array_output_serializer_init(struct serializer *s,
|
||||
struct array_output_data *data)
|
||||
{
|
||||
memset(s, 0, sizeof(struct serializer));
|
||||
memset(data, 0, sizeof(struct array_output_data));
|
||||
s->data = data;
|
||||
s->write = array_output_write;
|
||||
s->get_pos = array_output_get_pos;
|
||||
}
|
||||
|
||||
void array_output_serializer_free(struct array_output_data *data)
|
||||
{
|
||||
da_free(data->bytes);
|
||||
}
|
||||
28
libobs/util/array-serializer.h
Normal file
28
libobs/util/array-serializer.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "serializer.h"
|
||||
#include "darray.h"
|
||||
|
||||
struct array_output_data {
|
||||
DARRAY(uint8_t) bytes;
|
||||
};
|
||||
|
||||
EXPORT void array_output_serializer_init(struct serializer *s,
|
||||
struct array_output_data *data);
|
||||
EXPORT void array_output_serializer_free(struct array_output_data *data);
|
||||
135
libobs/util/base.c
Normal file
135
libobs/util/base.c
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "c99defs.h"
|
||||
#include "base.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
static int log_output_level = LOG_DEBUG;
|
||||
#else
|
||||
static int log_output_level = LOG_INFO;
|
||||
#endif
|
||||
|
||||
static int crashing = 0;
|
||||
static void *log_param = NULL;
|
||||
static void *crash_param = NULL;
|
||||
|
||||
static void def_log_handler(int log_level, const char *format,
|
||||
va_list args, void *param)
|
||||
{
|
||||
char out[4096];
|
||||
vsnprintf(out, sizeof(out), format, args);
|
||||
|
||||
if (log_level <= log_output_level) {
|
||||
switch (log_level) {
|
||||
case LOG_DEBUG:
|
||||
fprintf(stdout, "debug: %s\n", out);
|
||||
fflush(stdout);
|
||||
break;
|
||||
|
||||
case LOG_INFO:
|
||||
fprintf(stdout, "info: %s\n", out);
|
||||
fflush(stdout);
|
||||
break;
|
||||
|
||||
case LOG_WARNING:
|
||||
fprintf(stdout, "warning: %s\n", out);
|
||||
fflush(stdout);
|
||||
break;
|
||||
|
||||
case LOG_ERROR:
|
||||
fprintf(stderr, "error: %s\n", out);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(param);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define NORETURN __declspec(noreturn)
|
||||
#else
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#endif
|
||||
|
||||
NORETURN static void def_crash_handler(const char *format, va_list args,
|
||||
void *param)
|
||||
{
|
||||
vfprintf(stderr, format, args);
|
||||
exit(0);
|
||||
|
||||
UNUSED_PARAMETER(param);
|
||||
}
|
||||
|
||||
static log_handler_t log_handler = def_log_handler;
|
||||
static void (*crash_handler)(const char *, va_list, void *) = def_crash_handler;
|
||||
|
||||
void base_get_log_handler(log_handler_t *handler, void **param)
|
||||
{
|
||||
if (handler)
|
||||
*handler = log_handler;
|
||||
if (param)
|
||||
*param = log_param;
|
||||
}
|
||||
|
||||
void base_set_log_handler(log_handler_t handler, void *param)
|
||||
{
|
||||
if (!handler)
|
||||
handler = def_log_handler;
|
||||
|
||||
log_param = param;
|
||||
log_handler = handler;
|
||||
}
|
||||
|
||||
void base_set_crash_handler(
|
||||
void (*handler)(const char *, va_list, void *),
|
||||
void *param)
|
||||
{
|
||||
crash_param = param;
|
||||
crash_handler = handler;
|
||||
}
|
||||
|
||||
void bcrash(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (crashing) {
|
||||
fputs("Crashed in the crash handler", stderr);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
crashing = 1;
|
||||
va_start(args, format);
|
||||
crash_handler(format, args, crash_param);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void blogva(int log_level, const char *format, va_list args)
|
||||
{
|
||||
log_handler(log_level, format, args, log_param);
|
||||
}
|
||||
|
||||
void blog(int log_level, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
blogva(log_level, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
94
libobs/util/base.h
Normal file
94
libobs/util/base.h
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "c99defs.h"
|
||||
|
||||
/*
|
||||
* Just contains logging/crash related stuff
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define STRINGIFY_(x) STRINGIFY(x)
|
||||
#define S__LINE__ STRINGIFY_(__LINE__)
|
||||
|
||||
#define INT_CUR_LINE __LINE__
|
||||
#define FILE_LINE __FILE__ " (" S__LINE__ "): "
|
||||
|
||||
enum {
|
||||
/**
|
||||
* Use if there's a problem that can potentially affect the program,
|
||||
* but isn't enough to require termination of the program.
|
||||
*
|
||||
* Use in creation functions and core subsystem functions. Places that
|
||||
* should definitely not fail.
|
||||
*/
|
||||
LOG_ERROR = 100,
|
||||
|
||||
/**
|
||||
* Use if a problem occurs that doesn't affect the program and is
|
||||
* recoverable.
|
||||
*
|
||||
* Use in places where where failure isn't entirely unexpected, and can
|
||||
* be handled safely.
|
||||
*/
|
||||
LOG_WARNING = 200,
|
||||
|
||||
/**
|
||||
* Informative essage to be displayed in the log.
|
||||
*/
|
||||
LOG_INFO = 300,
|
||||
|
||||
/**
|
||||
* Debug message to be used mostly by developers.
|
||||
*/
|
||||
LOG_DEBUG = 400
|
||||
};
|
||||
|
||||
typedef void (*log_handler_t)(int lvl, const char *msg, va_list args, void *p);
|
||||
|
||||
EXPORT void base_get_log_handler(log_handler_t *handler, void **param);
|
||||
EXPORT void base_set_log_handler(log_handler_t handler, void *param);
|
||||
|
||||
EXPORT void base_set_crash_handler(
|
||||
void (*handler)(const char *, va_list, void *),
|
||||
void *param);
|
||||
|
||||
EXPORT void blogva(int log_level, const char *format, va_list args);
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#define PRINTFATTR(f, a) __attribute__((__format__(__printf__, f, a)))
|
||||
#else
|
||||
#define PRINTFATTR(f, a)
|
||||
#endif
|
||||
|
||||
PRINTFATTR(2, 3)
|
||||
EXPORT void blog(int log_level, const char *format, ...);
|
||||
PRINTFATTR(1, 2)
|
||||
EXPORT void bcrash(const char *format, ...);
|
||||
|
||||
#undef PRINTFATTR
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
154
libobs/util/bmem.c
Normal file
154
libobs/util/bmem.c
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "base.h"
|
||||
#include "bmem.h"
|
||||
#include "platform.h"
|
||||
#include "threading.h"
|
||||
|
||||
/*
|
||||
* NOTE: totally jacked the mem alignment trick from ffmpeg, credit to them:
|
||||
* http://www.ffmpeg.org/
|
||||
*/
|
||||
|
||||
#define ALIGNMENT 32
|
||||
|
||||
/* TODO: use memalign for non-windows systems */
|
||||
#if defined(_WIN32)
|
||||
#define ALIGNED_MALLOC 1
|
||||
#else
|
||||
#define ALIGNMENT_HACK 1
|
||||
#endif
|
||||
|
||||
static void *a_malloc(size_t size)
|
||||
{
|
||||
#ifdef ALIGNED_MALLOC
|
||||
return _aligned_malloc(size, ALIGNMENT);
|
||||
#elif ALIGNMENT_HACK
|
||||
void *ptr = NULL;
|
||||
long diff;
|
||||
|
||||
ptr = malloc(size + ALIGNMENT);
|
||||
if (ptr) {
|
||||
diff = ((~(long)ptr) & (ALIGNMENT - 1)) + 1;
|
||||
ptr = (char *)ptr + diff;
|
||||
((char *)ptr)[-1] = (char)diff;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
#else
|
||||
return malloc(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *a_realloc(void *ptr, size_t size)
|
||||
{
|
||||
#ifdef ALIGNED_MALLOC
|
||||
return _aligned_realloc(ptr, size, ALIGNMENT);
|
||||
#elif ALIGNMENT_HACK
|
||||
long diff;
|
||||
|
||||
if (!ptr)
|
||||
return a_malloc(size);
|
||||
diff = ((char *)ptr)[-1];
|
||||
ptr = realloc((char*)ptr - diff, size + diff);
|
||||
if (ptr)
|
||||
ptr = (char *)ptr + diff;
|
||||
return ptr;
|
||||
#else
|
||||
return realloc(ptr, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void a_free(void *ptr)
|
||||
{
|
||||
#ifdef ALIGNED_MALLOC
|
||||
_aligned_free(ptr);
|
||||
#elif ALIGNMENT_HACK
|
||||
if (ptr)
|
||||
free((char *)ptr - ((char*)ptr)[-1]);
|
||||
#else
|
||||
free(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct base_allocator alloc = {a_malloc, a_realloc, a_free};
|
||||
static long num_allocs = 0;
|
||||
|
||||
void base_set_allocator(struct base_allocator *defs)
|
||||
{
|
||||
memcpy(&alloc, defs, sizeof(struct base_allocator));
|
||||
}
|
||||
|
||||
void *bmalloc(size_t size)
|
||||
{
|
||||
void *ptr = alloc.malloc(size);
|
||||
if (!ptr && !size)
|
||||
ptr = alloc.malloc(1);
|
||||
if (!ptr) {
|
||||
os_breakpoint();
|
||||
bcrash("Out of memory while trying to allocate %lu bytes",
|
||||
(unsigned long)size);
|
||||
}
|
||||
|
||||
os_atomic_inc_long(&num_allocs);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *brealloc(void *ptr, size_t size)
|
||||
{
|
||||
if (!ptr)
|
||||
os_atomic_inc_long(&num_allocs);
|
||||
|
||||
ptr = alloc.realloc(ptr, size);
|
||||
if (!ptr && !size)
|
||||
ptr = alloc.realloc(ptr, 1);
|
||||
if (!ptr) {
|
||||
os_breakpoint();
|
||||
bcrash("Out of memory while trying to allocate %lu bytes",
|
||||
(unsigned long)size);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void bfree(void *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
os_atomic_dec_long(&num_allocs);
|
||||
alloc.free(ptr);
|
||||
}
|
||||
|
||||
long bnum_allocs(void)
|
||||
{
|
||||
return num_allocs;
|
||||
}
|
||||
|
||||
int base_get_alignment(void)
|
||||
{
|
||||
return ALIGNMENT;
|
||||
}
|
||||
|
||||
void *bmemdup(const void *ptr, size_t size)
|
||||
{
|
||||
void *out = bmalloc(size);
|
||||
if (size)
|
||||
memcpy(out, ptr, size);
|
||||
|
||||
return out;
|
||||
}
|
||||
96
libobs/util/bmem.h
Normal file
96
libobs/util/bmem.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "c99defs.h"
|
||||
#include "base.h"
|
||||
#include <wchar.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct base_allocator {
|
||||
void *(*malloc)(size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
};
|
||||
|
||||
EXPORT void base_set_allocator(struct base_allocator *defs);
|
||||
|
||||
EXPORT void *bmalloc(size_t size);
|
||||
EXPORT void *brealloc(void *ptr, size_t size);
|
||||
EXPORT void bfree(void *ptr);
|
||||
|
||||
EXPORT int base_get_alignment(void);
|
||||
|
||||
EXPORT long bnum_allocs(void);
|
||||
|
||||
EXPORT void *bmemdup(const void *ptr, size_t size);
|
||||
|
||||
static inline void *bzalloc(size_t size)
|
||||
{
|
||||
void *mem = bmalloc(size);
|
||||
if (mem)
|
||||
memset(mem, 0, size);
|
||||
return mem;
|
||||
}
|
||||
|
||||
static inline char *bstrdup_n(const char *str, size_t n)
|
||||
{
|
||||
char *dup;
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
dup = (char*)bmemdup(str, n+1);
|
||||
dup[n] = 0;
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
static inline wchar_t *bwstrdup_n(const wchar_t *str, size_t n)
|
||||
{
|
||||
wchar_t *dup;
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
dup = (wchar_t*)bmemdup(str, (n+1) * sizeof(wchar_t));
|
||||
dup[n] = 0;
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
static inline char *bstrdup(const char *str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
return bstrdup_n(str, strlen(str));
|
||||
}
|
||||
|
||||
static inline wchar_t *bwstrdup(const wchar_t *str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
return bwstrdup_n(str, wcslen(str));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
82
libobs/util/c99defs.h
Normal file
82
libobs/util/c99defs.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Contains hacks for getting some C99 stuff working in VC, things like
|
||||
* bool, inline, stdint
|
||||
*/
|
||||
|
||||
#define UNUSED_PARAMETER(param) (void)param
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define DEPRECATED_START __declspec(deprecated)
|
||||
#define DEPRECATED_END
|
||||
#define FORCE_INLINE __forceinline
|
||||
#else
|
||||
#define DEPRECATED_START
|
||||
#define DEPRECATED_END __attribute__ ((deprecated))
|
||||
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#pragma warning (disable : 4996)
|
||||
|
||||
/* Microsoft is one of the most inept companies on the face of the planet.
|
||||
* The fact that even visual studio 2013 doesn't support the standard 'inline'
|
||||
* keyword is so incredibly stupid that I just can't imagine what sort of
|
||||
* incredibly inept moron could possibly be managing the visual C compiler
|
||||
* project. They should be fired, and legally forbidden to have a job in
|
||||
* ANYTHING even REMOTELY related to programming. FOREVER. This should also
|
||||
* apply to the next 10 generations all of their descendents. */
|
||||
#ifndef __cplusplus
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
#if _MSC_VER && _MSC_VER < 0x0708
|
||||
|
||||
#include "vc/vc_stdint.h"
|
||||
#include "vc/vc_stdbool.h"
|
||||
|
||||
#ifndef __off_t_defined
|
||||
#define __off_t_defined
|
||||
#if _FILE_OFFSET_BITS == 64
|
||||
typedef long long off_t;
|
||||
#else
|
||||
typedef long off_t;
|
||||
#endif
|
||||
typedef int64_t off64_t;
|
||||
#endif /* __off_t_defined */
|
||||
|
||||
#define SIZE_T_FORMAT "%u"
|
||||
|
||||
#else
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define SIZE_T_FORMAT "%zu"
|
||||
|
||||
#endif /* _MSC_VER */
|
||||
1309
libobs/util/cf-lexer.c
Normal file
1309
libobs/util/cf-lexer.c
Normal file
File diff suppressed because it is too large
Load diff
206
libobs/util/cf-lexer.h
Normal file
206
libobs/util/cf-lexer.h
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lexer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
EXPORT char *cf_literal_to_str(const char *literal, size_t count);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
* A C-family lexer token is defined as:
|
||||
* 1.) A generic 'name' token. (abc123_def456)
|
||||
* 2.) A numeric sequence (usually starting with a number)
|
||||
* 3.) A sequence of generic whitespace defined as spaces and tabs
|
||||
* 4.) A newline
|
||||
* 5.) A string or character sequence (surrounded by single or double quotes)
|
||||
* 6.) A single character of a type not specified above
|
||||
*/
|
||||
enum cf_token_type {
|
||||
CFTOKEN_NONE,
|
||||
CFTOKEN_NAME,
|
||||
CFTOKEN_NUM,
|
||||
CFTOKEN_SPACETAB,
|
||||
CFTOKEN_NEWLINE,
|
||||
CFTOKEN_STRING,
|
||||
CFTOKEN_OTHER
|
||||
};
|
||||
|
||||
struct cf_token {
|
||||
const struct cf_lexer *lex;
|
||||
struct strref str;
|
||||
struct strref unmerged_str;
|
||||
enum cf_token_type type;
|
||||
};
|
||||
|
||||
static inline void cf_token_clear(struct cf_token *t)
|
||||
{
|
||||
memset(t, 0, sizeof(struct cf_token));
|
||||
}
|
||||
|
||||
static inline void cf_token_copy(struct cf_token *dst,
|
||||
const struct cf_token *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(struct cf_token));
|
||||
}
|
||||
|
||||
static inline void cf_token_add(struct cf_token *dst,
|
||||
const struct cf_token *add)
|
||||
{
|
||||
strref_add(&dst->str, &add->str);
|
||||
strref_add(&dst->unmerged_str, &add->unmerged_str);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
* The c-family lexer is a base lexer for generating a list of string
|
||||
* reference tokens to be used with c-style languages.
|
||||
*
|
||||
* This base lexer is meant to be used as a stepping stone for an actual
|
||||
* language lexer/parser.
|
||||
*
|
||||
* It reformats the text in the two following ways:
|
||||
* 1.) Spliced lines (escaped newlines) are merged
|
||||
* 2.) All comments are converted to a single space
|
||||
*/
|
||||
|
||||
struct cf_lexer {
|
||||
char *file;
|
||||
struct lexer base_lexer;
|
||||
char *reformatted, *write_offset;
|
||||
DARRAY(struct cf_token) tokens;
|
||||
bool unexpected_eof; /* unexpected multi-line comment eof */
|
||||
};
|
||||
|
||||
EXPORT void cf_lexer_init(struct cf_lexer *lex);
|
||||
EXPORT void cf_lexer_free(struct cf_lexer *lex);
|
||||
|
||||
static inline struct cf_token *cf_lexer_get_tokens(struct cf_lexer *lex)
|
||||
{
|
||||
return lex->tokens.array;
|
||||
}
|
||||
|
||||
EXPORT bool cf_lexer_lex(struct cf_lexer *lex, const char *str,
|
||||
const char *file);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* c-family preprocessor definition */
|
||||
|
||||
struct cf_def {
|
||||
struct cf_token name;
|
||||
DARRAY(struct cf_token) params;
|
||||
DARRAY(struct cf_token) tokens;
|
||||
bool macro;
|
||||
};
|
||||
|
||||
static inline void cf_def_init(struct cf_def *cfd)
|
||||
{
|
||||
cf_token_clear(&cfd->name);
|
||||
da_init(cfd->params);
|
||||
da_init(cfd->tokens);
|
||||
cfd->macro = false;
|
||||
}
|
||||
|
||||
static inline void cf_def_addparam(struct cf_def *cfd, struct cf_token *param)
|
||||
{
|
||||
da_push_back(cfd->params, param);
|
||||
}
|
||||
|
||||
static inline void cf_def_addtoken(struct cf_def *cfd, struct cf_token *token)
|
||||
{
|
||||
da_push_back(cfd->tokens, token);
|
||||
}
|
||||
|
||||
static inline struct cf_token *cf_def_getparam(const struct cf_def *cfd,
|
||||
size_t idx)
|
||||
{
|
||||
return cfd->params.array+idx;
|
||||
}
|
||||
|
||||
static inline void cf_def_free(struct cf_def *cfd)
|
||||
{
|
||||
cf_token_clear(&cfd->name);
|
||||
da_free(cfd->params);
|
||||
da_free(cfd->tokens);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
* C-family preprocessor
|
||||
*
|
||||
* This preprocessor allows for standard c-style preprocessor directives
|
||||
* to be applied to source text, such as:
|
||||
*
|
||||
* + #include
|
||||
* + #define/#undef
|
||||
* + #ifdef/#ifndef/#if/#elif/#else/#endif
|
||||
*
|
||||
* Still left to implement (TODO):
|
||||
* + #if/#elif
|
||||
* + "defined" preprocessor keyword
|
||||
* + system includes
|
||||
* + variadic macros
|
||||
* + custom callbacks (for things like pragma)
|
||||
* + option to exclude features such as #import, variadic macros, and other
|
||||
* features for certain language implementations
|
||||
* + macro parameter string operator #
|
||||
* + macro parameter token concactenation operator ##
|
||||
* + predefined macros
|
||||
* + restricted macros
|
||||
*/
|
||||
|
||||
struct cf_preprocessor {
|
||||
struct cf_lexer *lex;
|
||||
struct error_data *ed;
|
||||
DARRAY(struct cf_def) defines;
|
||||
DARRAY(char*) sys_include_dirs;
|
||||
DARRAY(struct cf_lexer) dependencies;
|
||||
DARRAY(struct cf_token) tokens;
|
||||
bool ignore_state;
|
||||
};
|
||||
|
||||
EXPORT void cf_preprocessor_init(struct cf_preprocessor *pp);
|
||||
EXPORT void cf_preprocessor_free(struct cf_preprocessor *pp);
|
||||
|
||||
EXPORT bool cf_preprocess(struct cf_preprocessor *pp, struct cf_lexer *lex,
|
||||
struct error_data *ed);
|
||||
|
||||
static inline void cf_preprocessor_add_sys_include_dir(
|
||||
struct cf_preprocessor *pp, const char *include_dir)
|
||||
{
|
||||
if (include_dir)
|
||||
da_push_back(pp->sys_include_dirs, bstrdup(include_dir));
|
||||
}
|
||||
|
||||
EXPORT void cf_preprocessor_add_def(struct cf_preprocessor *pp,
|
||||
struct cf_def *def);
|
||||
EXPORT void cf_preprocessor_remove_def(struct cf_preprocessor *pp,
|
||||
const char *def_name);
|
||||
|
||||
static inline struct cf_token *cf_preprocessor_get_tokens(
|
||||
struct cf_preprocessor *pp)
|
||||
{
|
||||
return pp->tokens.array;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
65
libobs/util/cf-parser.c
Normal file
65
libobs/util/cf-parser.c
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "cf-parser.h"
|
||||
|
||||
void cf_adderror(struct cf_parser *p, const char *error, int level,
|
||||
const char *val1, const char *val2, const char *val3)
|
||||
{
|
||||
uint32_t row, col;
|
||||
lexer_getstroffset(&p->cur_token->lex->base_lexer,
|
||||
p->cur_token->unmerged_str.array,
|
||||
&row, &col);
|
||||
|
||||
if (!val1 && !val2 && !val3) {
|
||||
error_data_add(&p->error_list, p->cur_token->lex->file,
|
||||
row, col, error, level);
|
||||
} else {
|
||||
struct dstr formatted;
|
||||
dstr_init(&formatted);
|
||||
dstr_safe_printf(&formatted, error, val1, val2, val3, NULL);
|
||||
|
||||
error_data_add(&p->error_list, p->cur_token->lex->file,
|
||||
row, col, formatted.array, level);
|
||||
|
||||
dstr_free(&formatted);
|
||||
}
|
||||
}
|
||||
|
||||
bool cf_pass_pair(struct cf_parser *p, char in, char out)
|
||||
{
|
||||
if (p->cur_token->type != CFTOKEN_OTHER ||
|
||||
*p->cur_token->str.array != in)
|
||||
return p->cur_token->type != CFTOKEN_NONE;
|
||||
|
||||
p->cur_token++;
|
||||
|
||||
while (p->cur_token->type != CFTOKEN_NONE) {
|
||||
if (*p->cur_token->str.array == in) {
|
||||
if (!cf_pass_pair(p, in, out))
|
||||
break;
|
||||
continue;
|
||||
|
||||
} else if(*p->cur_token->str.array == out) {
|
||||
p->cur_token++;
|
||||
return true;
|
||||
}
|
||||
|
||||
p->cur_token++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
291
libobs/util/cf-parser.h
Normal file
291
libobs/util/cf-parser.h
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cf-lexer.h"
|
||||
|
||||
/*
|
||||
* C-family parser
|
||||
*
|
||||
* Handles preprocessing/lexing/errors when parsing a file, and provides a
|
||||
* set of parsing functions to be able to go through all the resulting tokens
|
||||
* more easily.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PARSE_SUCCESS 0
|
||||
#define PARSE_CONTINUE -1
|
||||
#define PARSE_BREAK -2
|
||||
#define PARSE_UNEXPECTED_CONTINUE -3
|
||||
#define PARSE_UNEXPECTED_BREAK -4
|
||||
#define PARSE_EOF -5
|
||||
|
||||
struct cf_parser {
|
||||
struct cf_lexer lex;
|
||||
struct cf_preprocessor pp;
|
||||
struct error_data error_list;
|
||||
|
||||
struct cf_token *cur_token;
|
||||
};
|
||||
|
||||
static inline void cf_parser_init(struct cf_parser *parser)
|
||||
{
|
||||
cf_lexer_init(&parser->lex);
|
||||
cf_preprocessor_init(&parser->pp);
|
||||
error_data_init(&parser->error_list);
|
||||
|
||||
parser->cur_token = NULL;
|
||||
}
|
||||
|
||||
static inline void cf_parser_free(struct cf_parser *parser)
|
||||
{
|
||||
cf_lexer_free(&parser->lex);
|
||||
cf_preprocessor_free(&parser->pp);
|
||||
error_data_free(&parser->error_list);
|
||||
|
||||
parser->cur_token = NULL;
|
||||
}
|
||||
|
||||
static inline bool cf_parser_parse(struct cf_parser *parser,
|
||||
const char *str, const char *file)
|
||||
{
|
||||
if (!cf_lexer_lex(&parser->lex, str, file))
|
||||
return false;
|
||||
|
||||
if (!cf_preprocess(&parser->pp, &parser->lex, &parser->error_list))
|
||||
return false;
|
||||
|
||||
parser->cur_token = cf_preprocessor_get_tokens(&parser->pp);
|
||||
return true;
|
||||
}
|
||||
|
||||
EXPORT void cf_adderror(struct cf_parser *parser, const char *error,
|
||||
int level, const char *val1, const char *val2,
|
||||
const char *val3);
|
||||
|
||||
static inline void cf_adderror_expecting(struct cf_parser *p,
|
||||
const char *expected)
|
||||
{
|
||||
cf_adderror(p, "Expected '$1'", LEX_ERROR, expected, NULL, NULL);
|
||||
}
|
||||
|
||||
static inline void cf_adderror_unexpected_eof(struct cf_parser *p)
|
||||
{
|
||||
cf_adderror(p, "Unexpected EOF", LEX_ERROR,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static inline void cf_adderror_syntax_error(struct cf_parser *p)
|
||||
{
|
||||
cf_adderror(p, "Syntax error", LEX_ERROR,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static inline bool cf_next_token(struct cf_parser *p)
|
||||
{
|
||||
if (p->cur_token->type != CFTOKEN_SPACETAB &&
|
||||
p->cur_token->type != CFTOKEN_NEWLINE &&
|
||||
p->cur_token->type != CFTOKEN_NONE)
|
||||
p->cur_token++;
|
||||
|
||||
while (p->cur_token->type == CFTOKEN_SPACETAB ||
|
||||
p->cur_token->type == CFTOKEN_NEWLINE)
|
||||
p->cur_token++;
|
||||
|
||||
return p->cur_token->type != CFTOKEN_NONE;
|
||||
}
|
||||
|
||||
static inline bool cf_next_valid_token(struct cf_parser *p)
|
||||
{
|
||||
if (!cf_next_token(p)) {
|
||||
cf_adderror_unexpected_eof(p);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
EXPORT bool cf_pass_pair(struct cf_parser *p, char in, char out);
|
||||
|
||||
static inline bool cf_go_to_token(struct cf_parser *p,
|
||||
const char *str1, const char *str2)
|
||||
{
|
||||
while (cf_next_token(p)) {
|
||||
if (strref_cmp(&p->cur_token->str, str1) == 0) {
|
||||
return true;
|
||||
} else if (str2 && strref_cmp(&p->cur_token->str, str2) == 0) {
|
||||
return true;
|
||||
} else if (*p->cur_token->str.array == '{') {
|
||||
if (!cf_pass_pair(p, '{', '}'))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool cf_go_to_valid_token(struct cf_parser *p,
|
||||
const char *str1, const char *str2)
|
||||
{
|
||||
if (!cf_go_to_token(p, str1, str2)) {
|
||||
cf_adderror_unexpected_eof(p);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool cf_go_to_token_type(struct cf_parser *p,
|
||||
enum cf_token_type type)
|
||||
{
|
||||
while (p->cur_token->type != CFTOKEN_NONE &&
|
||||
p->cur_token->type != type)
|
||||
p->cur_token++;
|
||||
|
||||
return p->cur_token->type != CFTOKEN_NONE;
|
||||
}
|
||||
|
||||
static inline int cf_token_should_be(struct cf_parser *p,
|
||||
const char *str, const char *goto1, const char *goto2)
|
||||
{
|
||||
if (strref_cmp(&p->cur_token->str, str) == 0)
|
||||
return PARSE_SUCCESS;
|
||||
|
||||
if (goto1) {
|
||||
if (!cf_go_to_token(p, goto1, goto2))
|
||||
return PARSE_EOF;
|
||||
}
|
||||
|
||||
cf_adderror_expecting(p, str);
|
||||
return PARSE_CONTINUE;
|
||||
}
|
||||
|
||||
static inline int cf_next_token_should_be(struct cf_parser *p,
|
||||
const char *str, const char *goto1, const char *goto2)
|
||||
{
|
||||
if (!cf_next_token(p)) {
|
||||
cf_adderror_unexpected_eof(p);
|
||||
return PARSE_EOF;
|
||||
} else if (strref_cmp(&p->cur_token->str, str) == 0) {
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
if (goto1) {
|
||||
if (!cf_go_to_token(p, goto1, goto2))
|
||||
return PARSE_EOF;
|
||||
}
|
||||
|
||||
cf_adderror_expecting(p, str);
|
||||
return PARSE_CONTINUE;
|
||||
}
|
||||
|
||||
static inline bool cf_peek_token(struct cf_parser *p, struct cf_token *peek)
|
||||
{
|
||||
struct cf_token *cur_token = p->cur_token;
|
||||
bool success = cf_next_token(p);
|
||||
|
||||
*peek = *p->cur_token;
|
||||
p->cur_token = cur_token;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline bool cf_peek_valid_token(struct cf_parser *p,
|
||||
struct cf_token *peek)
|
||||
{
|
||||
bool success = cf_peek_token(p, peek);
|
||||
if (!success)
|
||||
cf_adderror_unexpected_eof(p);
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline bool cf_token_is(struct cf_parser *p, const char *val)
|
||||
{
|
||||
return strref_cmp(&p->cur_token->str, val) == 0;
|
||||
}
|
||||
|
||||
static inline int cf_token_is_type(struct cf_parser *p,
|
||||
enum cf_token_type type, const char *type_expected,
|
||||
const char *goto_token)
|
||||
{
|
||||
if (p->cur_token->type != type) {
|
||||
cf_adderror_expecting(p, type_expected);
|
||||
if (goto_token) {
|
||||
if (!cf_go_to_valid_token(p, goto_token, NULL))
|
||||
return PARSE_EOF;
|
||||
}
|
||||
return PARSE_CONTINUE;
|
||||
}
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static inline void cf_copy_token(struct cf_parser *p, char **dst)
|
||||
{
|
||||
*dst = bstrdup_n(p->cur_token->str.array, p->cur_token->str.len);
|
||||
}
|
||||
|
||||
static inline int cf_get_name(struct cf_parser *p, char **dst,
|
||||
const char *name, const char *goto_token)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
errcode = cf_token_is_type(p, CFTOKEN_NAME, name, goto_token);
|
||||
if (errcode != PARSE_SUCCESS)
|
||||
return errcode;
|
||||
|
||||
*dst = bstrdup_n(p->cur_token->str.array, p->cur_token->str.len);
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static inline int cf_next_name(struct cf_parser *p, char **dst,
|
||||
const char *name, const char *goto_token)
|
||||
{
|
||||
if (!cf_next_valid_token(p))
|
||||
return PARSE_EOF;
|
||||
|
||||
return cf_get_name(p, dst, name, goto_token);
|
||||
}
|
||||
|
||||
static inline int cf_get_name_ref(struct cf_parser *p, struct strref *dst,
|
||||
const char *name, const char *goto_token)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
errcode = cf_token_is_type(p, CFTOKEN_NAME, name, goto_token);
|
||||
if (errcode != PARSE_SUCCESS)
|
||||
return errcode;
|
||||
|
||||
strref_copy(dst, &p->cur_token->str);
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static inline int cf_next_name_ref(struct cf_parser *p, struct strref *dst,
|
||||
const char *name, const char *goto_token)
|
||||
{
|
||||
if (!cf_next_valid_token(p))
|
||||
return PARSE_EOF;
|
||||
|
||||
return cf_get_name_ref(p, dst, name, goto_token);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
259
libobs/util/circlebuf.h
Normal file
259
libobs/util/circlebuf.h
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "c99defs.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "bmem.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Dynamic circular buffer */
|
||||
|
||||
struct circlebuf {
|
||||
void *data;
|
||||
size_t size;
|
||||
|
||||
size_t start_pos;
|
||||
size_t end_pos;
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
static inline void circlebuf_init(struct circlebuf *cb)
|
||||
{
|
||||
memset(cb, 0, sizeof(struct circlebuf));
|
||||
}
|
||||
|
||||
static inline void circlebuf_free(struct circlebuf *cb)
|
||||
{
|
||||
bfree(cb->data);
|
||||
memset(cb, 0, sizeof(struct circlebuf));
|
||||
}
|
||||
|
||||
static inline void circlebuf_reorder_data(struct circlebuf *cb,
|
||||
size_t new_capacity)
|
||||
{
|
||||
size_t difference;
|
||||
uint8_t *data;
|
||||
|
||||
if (!cb->size || !cb->start_pos || cb->end_pos > cb->start_pos)
|
||||
return;
|
||||
|
||||
difference = new_capacity - cb->capacity;
|
||||
data = (uint8_t*)cb->data + cb->start_pos;
|
||||
memmove(data+difference, data, cb->capacity - cb->start_pos);
|
||||
cb->start_pos += difference;
|
||||
}
|
||||
|
||||
static inline void circlebuf_ensure_capacity(struct circlebuf *cb)
|
||||
{
|
||||
size_t new_capacity;
|
||||
if (cb->size <= cb->capacity)
|
||||
return;
|
||||
|
||||
new_capacity = cb->capacity*2;
|
||||
if (cb->size > new_capacity)
|
||||
new_capacity = cb->size;
|
||||
|
||||
cb->data = brealloc(cb->data, new_capacity);
|
||||
circlebuf_reorder_data(cb, new_capacity);
|
||||
cb->capacity = new_capacity;
|
||||
}
|
||||
|
||||
static inline void circlebuf_reserve(struct circlebuf *cb, size_t capacity)
|
||||
{
|
||||
if (capacity <= cb->capacity)
|
||||
return;
|
||||
|
||||
cb->data = brealloc(cb->data, capacity);
|
||||
circlebuf_reorder_data(cb, capacity);
|
||||
cb->capacity = capacity;
|
||||
}
|
||||
|
||||
static inline void circlebuf_upsize(struct circlebuf *cb, size_t size)
|
||||
{
|
||||
size_t add_size = size - cb->size;
|
||||
size_t new_end_pos = cb->end_pos + add_size;
|
||||
|
||||
if (size <= cb->size)
|
||||
return;
|
||||
|
||||
cb->size = size;
|
||||
circlebuf_ensure_capacity(cb);
|
||||
|
||||
if (new_end_pos > cb->capacity) {
|
||||
size_t back_size = cb->capacity - cb->end_pos;
|
||||
size_t loop_size = add_size - back_size;
|
||||
|
||||
if (back_size)
|
||||
memset((uint8_t*)cb->data + cb->end_pos, 0, back_size);
|
||||
|
||||
memset(cb->data, 0, loop_size);
|
||||
new_end_pos -= cb->capacity;
|
||||
} else {
|
||||
memset((uint8_t*)cb->data + cb->end_pos, 0, add_size);
|
||||
}
|
||||
|
||||
cb->end_pos = new_end_pos;
|
||||
}
|
||||
|
||||
/** Overwrites data at a specific point in the buffer (relative). */
|
||||
static inline void circlebuf_place(struct circlebuf *cb, size_t position,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
size_t end_point = position + size;
|
||||
size_t data_end_pos;
|
||||
|
||||
if (end_point > cb->size)
|
||||
circlebuf_upsize(cb, end_point);
|
||||
|
||||
position += cb->start_pos;
|
||||
if (position >= cb->capacity)
|
||||
position -= cb->capacity;
|
||||
|
||||
data_end_pos = position + size;
|
||||
if (data_end_pos > cb->capacity) {
|
||||
size_t back_size = data_end_pos - cb->capacity;
|
||||
size_t loop_size = size - back_size;
|
||||
|
||||
if (back_size)
|
||||
memcpy((uint8_t*)cb->data + position, data, loop_size);
|
||||
memcpy(cb->data, (uint8_t*)data + loop_size, back_size);
|
||||
} else {
|
||||
memcpy((uint8_t*)cb->data + position, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void circlebuf_push_back(struct circlebuf *cb, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
size_t new_end_pos = cb->end_pos + size;
|
||||
|
||||
cb->size += size;
|
||||
circlebuf_ensure_capacity(cb);
|
||||
|
||||
if (new_end_pos > cb->capacity) {
|
||||
size_t back_size = cb->capacity - cb->end_pos;
|
||||
size_t loop_size = size - back_size;
|
||||
|
||||
if (back_size)
|
||||
memcpy((uint8_t*)cb->data + cb->end_pos, data,
|
||||
back_size);
|
||||
memcpy(cb->data, (uint8_t*)data + back_size, loop_size);
|
||||
|
||||
new_end_pos -= cb->capacity;
|
||||
} else {
|
||||
memcpy((uint8_t*)cb->data + cb->end_pos, data, size);
|
||||
}
|
||||
|
||||
cb->end_pos = new_end_pos;
|
||||
}
|
||||
|
||||
static inline void circlebuf_push_front(struct circlebuf *cb, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
cb->size += size;
|
||||
circlebuf_ensure_capacity(cb);
|
||||
|
||||
if (cb->start_pos < size) {
|
||||
size_t back_size = size - cb->start_pos;
|
||||
|
||||
if (cb->start_pos)
|
||||
memcpy(cb->data, (uint8_t*)data + back_size,
|
||||
cb->start_pos);
|
||||
|
||||
cb->start_pos = cb->capacity - back_size;
|
||||
memcpy((uint8_t*)cb->data + cb->start_pos, data, back_size);
|
||||
} else {
|
||||
cb->start_pos -= size;
|
||||
memcpy((uint8_t*)cb->data + cb->start_pos, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void circlebuf_peek_front(struct circlebuf *cb, void *data,
|
||||
size_t size)
|
||||
{
|
||||
assert(size <= cb->size);
|
||||
|
||||
if (data) {
|
||||
size_t start_size = cb->capacity - cb->start_pos;
|
||||
|
||||
if (start_size < size) {
|
||||
memcpy(data, (uint8_t*)cb->data + cb->start_pos,
|
||||
start_size);
|
||||
memcpy((uint8_t*)data + start_size, cb->data,
|
||||
size - start_size);
|
||||
} else {
|
||||
memcpy(data, (uint8_t*)cb->data + cb->start_pos, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void circlebuf_peek_back(struct circlebuf *cb, void *data,
|
||||
size_t size)
|
||||
{
|
||||
assert(size <= cb->size);
|
||||
|
||||
if (data) {
|
||||
size_t back_size = (cb->end_pos ? cb->end_pos : cb->capacity);
|
||||
|
||||
if (back_size < size) {
|
||||
size_t front_size = size - back_size;
|
||||
size_t new_end_pos = cb->capacity - front_size;
|
||||
|
||||
memcpy((uint8_t*)data + (size - back_size), cb->data,
|
||||
back_size);
|
||||
memcpy(data, (uint8_t*)cb->data + new_end_pos,
|
||||
front_size);
|
||||
} else {
|
||||
memcpy(data, (uint8_t*)cb->data + cb->end_pos - size,
|
||||
size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void circlebuf_pop_front(struct circlebuf *cb, void *data,
|
||||
size_t size)
|
||||
{
|
||||
circlebuf_peek_front(cb, data, size);
|
||||
|
||||
cb->size -= size;
|
||||
cb->start_pos += size;
|
||||
if (cb->start_pos >= cb->capacity)
|
||||
cb->start_pos -= cb->capacity;
|
||||
}
|
||||
|
||||
static inline void circlebuf_pop_back(struct circlebuf *cb, void *data,
|
||||
size_t size)
|
||||
{
|
||||
circlebuf_peek_front(cb, data, size);
|
||||
|
||||
cb->size -= size;
|
||||
if (cb->end_pos <= size)
|
||||
cb->end_pos = cb->capacity - (size - cb->end_pos);
|
||||
else
|
||||
cb->end_pos -= size;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
781
libobs/util/config-file.c
Normal file
781
libobs/util/config-file.c
Normal file
|
|
@ -0,0 +1,781 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include "config-file.h"
|
||||
#include "platform.h"
|
||||
#include "base.h"
|
||||
#include "bmem.h"
|
||||
#include "darray.h"
|
||||
#include "lexer.h"
|
||||
#include "dstr.h"
|
||||
|
||||
struct config_item {
|
||||
char *name;
|
||||
char *value;
|
||||
};
|
||||
|
||||
static inline void config_item_free(struct config_item *item)
|
||||
{
|
||||
bfree(item->name);
|
||||
bfree(item->value);
|
||||
}
|
||||
|
||||
struct config_section {
|
||||
char *name;
|
||||
struct darray items; /* struct config_item */
|
||||
};
|
||||
|
||||
static inline void config_section_free(struct config_section *section)
|
||||
{
|
||||
struct config_item *items = section->items.array;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < section->items.num; i++)
|
||||
config_item_free(items+i);
|
||||
|
||||
darray_free(§ion->items);
|
||||
bfree(section->name);
|
||||
}
|
||||
|
||||
struct config_data {
|
||||
char *file;
|
||||
struct darray sections; /* struct config_section */
|
||||
struct darray defaults; /* struct config_section */
|
||||
};
|
||||
|
||||
config_t *config_create(const char *file)
|
||||
{
|
||||
struct config_data *config;
|
||||
FILE *f;
|
||||
|
||||
f = os_fopen(file, "wb");
|
||||
if (!f)
|
||||
return NULL;
|
||||
fclose(f);
|
||||
|
||||
config = bzalloc(sizeof(struct config_data));
|
||||
config->file = bstrdup(file);
|
||||
return config;
|
||||
}
|
||||
|
||||
static inline void remove_ref_whitespace(struct strref *ref)
|
||||
{
|
||||
if (ref->array) {
|
||||
while (is_whitespace(*ref->array)) {
|
||||
ref->array++;
|
||||
ref->len--;
|
||||
}
|
||||
|
||||
while (ref->len && is_whitespace(ref->array[ref->len-1]))
|
||||
ref->len--;
|
||||
}
|
||||
}
|
||||
|
||||
static bool config_parse_string(struct lexer *lex, struct strref *ref,
|
||||
char end)
|
||||
{
|
||||
bool success = end != 0;
|
||||
struct base_token token;
|
||||
base_token_clear(&token);
|
||||
|
||||
while (lexer_getbasetoken(lex, &token, PARSE_WHITESPACE)) {
|
||||
if (end) {
|
||||
if (*token.text.array == end) {
|
||||
success = true;
|
||||
break;
|
||||
} else if (is_newline(*token.text.array)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (is_newline(*token.text.array)) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strref_add(ref, &token.text);
|
||||
}
|
||||
|
||||
remove_ref_whitespace(ref);
|
||||
return success;
|
||||
}
|
||||
|
||||
static void unescape(struct dstr *str)
|
||||
{
|
||||
char *read = str->array;
|
||||
char *write = str->array;
|
||||
|
||||
for (; *read; read++, write++) {
|
||||
char cur = *read;
|
||||
if (cur == '\\') {
|
||||
char next = read[1];
|
||||
if (next == '\\') {
|
||||
read++;
|
||||
} else if (next == 'r') {
|
||||
cur = '\r';
|
||||
read++;
|
||||
} else if (next =='n') {
|
||||
cur = '\n';
|
||||
read++;
|
||||
}
|
||||
}
|
||||
|
||||
if (read != write)
|
||||
*write = cur;
|
||||
}
|
||||
|
||||
if (read != write)
|
||||
*write = '\0';
|
||||
}
|
||||
|
||||
static void config_add_item(struct darray *items, struct strref *name,
|
||||
struct strref *value)
|
||||
{
|
||||
struct config_item item;
|
||||
struct dstr item_value;
|
||||
dstr_init_copy_strref(&item_value, value);
|
||||
|
||||
unescape(&item_value);
|
||||
|
||||
item.name = bstrdup_n(name->array, name->len);
|
||||
item.value = item_value.array;
|
||||
darray_push_back(sizeof(struct config_item), items, &item);
|
||||
}
|
||||
|
||||
static void config_parse_section(struct config_section *section,
|
||||
struct lexer *lex)
|
||||
{
|
||||
struct base_token token;
|
||||
|
||||
while (lexer_getbasetoken(lex, &token, PARSE_WHITESPACE)) {
|
||||
struct strref name, value;
|
||||
|
||||
while (token.type == BASETOKEN_WHITESPACE) {
|
||||
if (!lexer_getbasetoken(lex, &token, PARSE_WHITESPACE))
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.type == BASETOKEN_OTHER) {
|
||||
if (*token.text.array == '#') {
|
||||
do {
|
||||
if (!lexer_getbasetoken(lex, &token,
|
||||
PARSE_WHITESPACE))
|
||||
return;
|
||||
} while (!is_newline(*token.text.array));
|
||||
|
||||
continue;
|
||||
} else if (*token.text.array == '[') {
|
||||
lex->offset--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
strref_copy(&name, &token.text);
|
||||
if (!config_parse_string(lex, &name, '='))
|
||||
continue;
|
||||
|
||||
strref_clear(&value);
|
||||
config_parse_string(lex, &value, 0);
|
||||
|
||||
if (!strref_is_empty(&value))
|
||||
config_add_item(§ion->items, &name, &value);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_config_data(struct darray *sections, struct lexer *lex)
|
||||
{
|
||||
struct strref section_name;
|
||||
struct base_token token;
|
||||
|
||||
base_token_clear(&token);
|
||||
|
||||
while (lexer_getbasetoken(lex, &token, PARSE_WHITESPACE)) {
|
||||
struct config_section *section;
|
||||
|
||||
while (token.type == BASETOKEN_WHITESPACE) {
|
||||
if (!lexer_getbasetoken(lex, &token, PARSE_WHITESPACE))
|
||||
return;
|
||||
}
|
||||
|
||||
if (*token.text.array != '[') {
|
||||
while (!is_newline(*token.text.array)) {
|
||||
if (!lexer_getbasetoken(lex, &token,
|
||||
PARSE_WHITESPACE))
|
||||
return;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
strref_clear(§ion_name);
|
||||
config_parse_string(lex, §ion_name, ']');
|
||||
if (!section_name.len)
|
||||
return;
|
||||
|
||||
section = darray_push_back_new(sizeof(struct config_section),
|
||||
sections);
|
||||
section->name = bstrdup_n(section_name.array,
|
||||
section_name.len);
|
||||
config_parse_section(section, lex);
|
||||
}
|
||||
}
|
||||
|
||||
static int config_parse_file(struct darray *sections, const char *file,
|
||||
bool always_open)
|
||||
{
|
||||
char *file_data;
|
||||
struct lexer lex;
|
||||
FILE *f;
|
||||
|
||||
f = os_fopen(file, "rb");
|
||||
if (always_open && !f)
|
||||
f = os_fopen(file, "w+");
|
||||
if (!f)
|
||||
return CONFIG_FILENOTFOUND;
|
||||
|
||||
os_fread_utf8(f, &file_data);
|
||||
fclose(f);
|
||||
|
||||
if (!file_data)
|
||||
return CONFIG_SUCCESS;
|
||||
|
||||
lexer_init(&lex);
|
||||
lexer_start_move(&lex, file_data);
|
||||
|
||||
parse_config_data(sections, &lex);
|
||||
|
||||
lexer_free(&lex);
|
||||
return CONFIG_SUCCESS;
|
||||
}
|
||||
|
||||
int config_open(config_t **config, const char *file,
|
||||
enum config_open_type open_type)
|
||||
{
|
||||
int errorcode;
|
||||
bool always_open = open_type == CONFIG_OPEN_ALWAYS;
|
||||
|
||||
if (!config)
|
||||
return CONFIG_ERROR;
|
||||
|
||||
*config = bzalloc(sizeof(struct config_data));
|
||||
if (!*config)
|
||||
return CONFIG_ERROR;
|
||||
|
||||
(*config)->file = bstrdup(file);
|
||||
|
||||
errorcode = config_parse_file(&(*config)->sections, file, always_open);
|
||||
|
||||
if (errorcode != CONFIG_SUCCESS) {
|
||||
config_close(*config);
|
||||
*config = NULL;
|
||||
}
|
||||
|
||||
return errorcode;
|
||||
}
|
||||
|
||||
int config_open_string(config_t **config, const char *str)
|
||||
{
|
||||
struct lexer lex;
|
||||
|
||||
if (!config)
|
||||
return CONFIG_ERROR;
|
||||
|
||||
*config = bzalloc(sizeof(struct config_data));
|
||||
if (!*config)
|
||||
return CONFIG_ERROR;
|
||||
|
||||
(*config)->file = NULL;
|
||||
|
||||
lexer_init(&lex);
|
||||
lexer_start(&lex, str);
|
||||
parse_config_data(&(*config)->sections, &lex);
|
||||
lexer_free(&lex);
|
||||
|
||||
return CONFIG_SUCCESS;
|
||||
}
|
||||
|
||||
int config_open_defaults(config_t *config, const char *file)
|
||||
{
|
||||
if (!config)
|
||||
return CONFIG_ERROR;
|
||||
|
||||
return config_parse_file(&config->defaults, file, false);
|
||||
}
|
||||
|
||||
int config_save(config_t *config)
|
||||
{
|
||||
FILE *f;
|
||||
struct dstr str, tmp;
|
||||
size_t i, j;
|
||||
|
||||
if (!config)
|
||||
return CONFIG_ERROR;
|
||||
if (!config->file)
|
||||
return CONFIG_ERROR;
|
||||
|
||||
dstr_init(&str);
|
||||
dstr_init(&tmp);
|
||||
|
||||
f = os_fopen(config->file, "wb");
|
||||
if (!f)
|
||||
return CONFIG_FILENOTFOUND;
|
||||
|
||||
for (i = 0; i < config->sections.num; i++) {
|
||||
struct config_section *section = darray_item(
|
||||
sizeof(struct config_section),
|
||||
&config->sections, i);
|
||||
|
||||
if (i) dstr_cat(&str, "\n");
|
||||
|
||||
dstr_cat(&str, "[");
|
||||
dstr_cat(&str, section->name);
|
||||
dstr_cat(&str, "]\n");
|
||||
|
||||
for (j = 0; j < section->items.num; j++) {
|
||||
struct config_item *item = darray_item(
|
||||
sizeof(struct config_item),
|
||||
§ion->items, j);
|
||||
|
||||
dstr_copy(&tmp, item->value ? item->value : "");
|
||||
dstr_replace(&tmp, "\\", "\\\\");
|
||||
dstr_replace(&tmp, "\r", "\\r");
|
||||
dstr_replace(&tmp, "\n", "\\n");
|
||||
|
||||
dstr_cat(&str, item->name);
|
||||
dstr_cat(&str, "=");
|
||||
dstr_cat(&str, tmp.array);
|
||||
dstr_cat(&str, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
fwrite("\xEF\xBB\xBF", 1, 3, f);
|
||||
#endif
|
||||
fwrite(str.array, 1, str.len, f);
|
||||
fclose(f);
|
||||
|
||||
dstr_free(&tmp);
|
||||
dstr_free(&str);
|
||||
|
||||
return CONFIG_SUCCESS;
|
||||
}
|
||||
|
||||
int config_save_safe(config_t *config, const char *temp_ext,
|
||||
const char *backup_ext)
|
||||
{
|
||||
struct dstr temp_file = {0};
|
||||
struct dstr backup_file = {0};
|
||||
char *file = config->file;
|
||||
int ret;
|
||||
|
||||
if (!temp_ext || !*temp_ext) {
|
||||
blog(LOG_ERROR, "config_save_safe: invalid "
|
||||
"temporary extension specified");
|
||||
return CONFIG_ERROR;
|
||||
}
|
||||
|
||||
dstr_copy(&temp_file, config->file);
|
||||
if (*temp_ext != '.')
|
||||
dstr_cat(&temp_file, ".");
|
||||
dstr_cat(&temp_file, temp_ext);
|
||||
|
||||
config->file = temp_file.array;
|
||||
ret = config_save(config);
|
||||
config->file = file;
|
||||
|
||||
if (ret != CONFIG_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (backup_ext && *backup_ext) {
|
||||
dstr_copy(&backup_file, config->file);
|
||||
if (*backup_ext != '.')
|
||||
dstr_cat(&backup_file, ".");
|
||||
dstr_cat(&backup_file, backup_ext);
|
||||
|
||||
os_unlink(backup_file.array);
|
||||
os_rename(file, backup_file.array);
|
||||
} else {
|
||||
os_unlink(file);
|
||||
}
|
||||
|
||||
os_rename(temp_file.array, file);
|
||||
|
||||
cleanup:
|
||||
dstr_free(&temp_file);
|
||||
dstr_free(&backup_file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void config_close(config_t *config)
|
||||
{
|
||||
struct config_section *defaults, *sections;
|
||||
size_t i;
|
||||
|
||||
if (!config) return;
|
||||
|
||||
defaults = config->defaults.array;
|
||||
sections = config->sections.array;
|
||||
|
||||
for (i = 0; i < config->defaults.num; i++)
|
||||
config_section_free(defaults+i);
|
||||
for (i = 0; i < config->sections.num; i++)
|
||||
config_section_free(sections+i);
|
||||
|
||||
darray_free(&config->defaults);
|
||||
darray_free(&config->sections);
|
||||
bfree(config->file);
|
||||
bfree(config);
|
||||
}
|
||||
|
||||
size_t config_num_sections(config_t *config)
|
||||
{
|
||||
return config->sections.num;
|
||||
}
|
||||
|
||||
const char *config_get_section(config_t *config, size_t idx)
|
||||
{
|
||||
struct config_section *section;
|
||||
|
||||
if (idx >= config->sections.num)
|
||||
return NULL;
|
||||
|
||||
section = darray_item(sizeof(struct config_section), &config->sections,
|
||||
idx);
|
||||
|
||||
return section->name;
|
||||
}
|
||||
|
||||
static const struct config_item *config_find_item(const struct darray *sections,
|
||||
const char *section, const char *name)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < sections->num; i++) {
|
||||
const struct config_section *sec = darray_item(
|
||||
sizeof(struct config_section), sections, i);
|
||||
|
||||
if (astrcmpi(sec->name, section) == 0) {
|
||||
for (j = 0; j < sec->items.num; j++) {
|
||||
struct config_item *item = darray_item(
|
||||
sizeof(struct config_item),
|
||||
&sec->items, j);
|
||||
|
||||
if (astrcmpi(item->name, name) == 0)
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void config_set_item(struct darray *sections, const char *section,
|
||||
const char *name, char *value)
|
||||
{
|
||||
struct config_section *sec = NULL;
|
||||
struct config_section *array = sections->array;
|
||||
struct config_item *item;
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < sections->num; i++) {
|
||||
struct config_section *cur_sec = array+i;
|
||||
struct config_item *items = cur_sec->items.array;
|
||||
|
||||
if (astrcmpi(cur_sec->name, section) == 0) {
|
||||
for (j = 0; j < cur_sec->items.num; j++) {
|
||||
item = items+j;
|
||||
|
||||
if (astrcmpi(item->name, name) == 0) {
|
||||
bfree(item->value);
|
||||
item->value = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sec = cur_sec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sec) {
|
||||
sec = darray_push_back_new(sizeof(struct config_section),
|
||||
sections);
|
||||
sec->name = bstrdup(section);
|
||||
}
|
||||
|
||||
item = darray_push_back_new(sizeof(struct config_item), &sec->items);
|
||||
item->name = bstrdup(name);
|
||||
item->value = value;
|
||||
}
|
||||
|
||||
void config_set_string(config_t *config, const char *section,
|
||||
const char *name, const char *value)
|
||||
{
|
||||
if (!value)
|
||||
value = "";
|
||||
config_set_item(&config->sections, section, name, bstrdup(value));
|
||||
}
|
||||
|
||||
void config_set_int(config_t *config, const char *section,
|
||||
const char *name, int64_t value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%"PRId64, value);
|
||||
config_set_item(&config->sections, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_uint(config_t *config, const char *section,
|
||||
const char *name, uint64_t value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%"PRIu64, value);
|
||||
config_set_item(&config->sections, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_bool(config_t *config, const char *section,
|
||||
const char *name, bool value)
|
||||
{
|
||||
char *str = bstrdup(value ? "true" : "false");
|
||||
config_set_item(&config->sections, section, name, str);
|
||||
}
|
||||
|
||||
void config_set_double(config_t *config, const char *section,
|
||||
const char *name, double value)
|
||||
{
|
||||
char *str = bzalloc(64);
|
||||
os_dtostr(value, str, 64);
|
||||
config_set_item(&config->sections, section, name, str);
|
||||
}
|
||||
|
||||
void config_set_default_string(config_t *config, const char *section,
|
||||
const char *name, const char *value)
|
||||
{
|
||||
if (!value)
|
||||
value = "";
|
||||
config_set_item(&config->defaults, section, name, bstrdup(value));
|
||||
}
|
||||
|
||||
void config_set_default_int(config_t *config, const char *section,
|
||||
const char *name, int64_t value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%"PRId64, value);
|
||||
config_set_item(&config->defaults, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_default_uint(config_t *config, const char *section,
|
||||
const char *name, uint64_t value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%"PRIu64, value);
|
||||
config_set_item(&config->defaults, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_default_bool(config_t *config, const char *section,
|
||||
const char *name, bool value)
|
||||
{
|
||||
char *str = bstrdup(value ? "true" : "false");
|
||||
config_set_item(&config->defaults, section, name, str);
|
||||
}
|
||||
|
||||
void config_set_default_double(config_t *config, const char *section,
|
||||
const char *name, double value)
|
||||
{
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%g", value);
|
||||
config_set_item(&config->defaults, section, name, str.array);
|
||||
}
|
||||
|
||||
const char *config_get_string(const config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const struct config_item *item = config_find_item(&config->sections,
|
||||
section, name);
|
||||
if (!item)
|
||||
item = config_find_item(&config->defaults, section, name);
|
||||
if (!item)
|
||||
return NULL;
|
||||
|
||||
return item->value;
|
||||
}
|
||||
|
||||
static inline int64_t str_to_int64(const char *str)
|
||||
{
|
||||
if (!str || !*str)
|
||||
return 0;
|
||||
|
||||
if (str[0] == '0' && str[1] == 'x')
|
||||
return strtoll(str + 2, NULL, 16);
|
||||
else
|
||||
return strtoll(str, NULL, 10);
|
||||
}
|
||||
|
||||
static inline uint64_t str_to_uint64(const char *str)
|
||||
{
|
||||
if (!str || !*str)
|
||||
return 0;
|
||||
|
||||
if (str[0] == '0' && str[1] == 'x')
|
||||
return strtoull(str + 2, NULL, 16);
|
||||
else
|
||||
return strtoull(str, NULL, 10);
|
||||
}
|
||||
|
||||
int64_t config_get_int(const config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
if (value)
|
||||
return str_to_int64(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t config_get_uint(const config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
if (value)
|
||||
return str_to_uint64(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool config_get_bool(const config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
if (value)
|
||||
return astrcmpi(value, "true") == 0 ||
|
||||
!!str_to_uint64(value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
double config_get_double(const config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
if (value)
|
||||
return os_strtod(value);
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool config_remove_value(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
struct darray *sections = &config->sections;
|
||||
|
||||
for (size_t i = 0; i < sections->num; i++) {
|
||||
struct config_section *sec = darray_item(
|
||||
sizeof(struct config_section), sections, i);
|
||||
|
||||
if (astrcmpi(sec->name, section) != 0)
|
||||
continue;
|
||||
|
||||
for (size_t j = 0; j < sec->items.num; j++) {
|
||||
struct config_item *item = darray_item(
|
||||
sizeof(struct config_item),
|
||||
&sec->items, j);
|
||||
|
||||
if (astrcmpi(item->name, name) == 0) {
|
||||
config_item_free(item);
|
||||
darray_erase(sizeof(struct config_item),
|
||||
&sec->items, j);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *config_get_default_string(const config_t *config,
|
||||
const char *section, const char *name)
|
||||
{
|
||||
const struct config_item *item;
|
||||
|
||||
item = config_find_item(&config->defaults, section, name);
|
||||
if (!item)
|
||||
return NULL;
|
||||
|
||||
return item->value;
|
||||
}
|
||||
|
||||
int64_t config_get_default_int(const config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_default_string(config, section, name);
|
||||
if (value)
|
||||
return str_to_int64(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t config_get_default_uint(const config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_default_string(config, section, name);
|
||||
if (value)
|
||||
return str_to_uint64(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool config_get_default_bool(const config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_default_string(config, section, name);
|
||||
if (value)
|
||||
return astrcmpi(value, "true") == 0 ||
|
||||
!!str_to_uint64(value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
double config_get_default_double(const config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_default_string(config, section, name);
|
||||
if (value)
|
||||
return os_strtod(value);
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool config_has_user_value(const config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
return config_find_item(&config->sections, section, name) != NULL;
|
||||
}
|
||||
|
||||
bool config_has_default_value(const config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
return config_find_item(&config->defaults, section, name) != NULL;
|
||||
}
|
||||
|
||||
128
libobs/util/config-file.h
Normal file
128
libobs/util/config-file.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "c99defs.h"
|
||||
|
||||
/*
|
||||
* Generic ini-style config file functions
|
||||
*
|
||||
* NOTE: It is highly recommended to use the default value functions (bottom of
|
||||
* the file) before reading any variables from config files.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct config_data;
|
||||
typedef struct config_data config_t;
|
||||
|
||||
#define CONFIG_SUCCESS 0
|
||||
#define CONFIG_FILENOTFOUND -1
|
||||
#define CONFIG_ERROR -2
|
||||
|
||||
enum config_open_type {
|
||||
CONFIG_OPEN_EXISTING,
|
||||
CONFIG_OPEN_ALWAYS,
|
||||
};
|
||||
|
||||
EXPORT config_t *config_create(const char *file);
|
||||
EXPORT int config_open(config_t **config, const char *file,
|
||||
enum config_open_type open_type);
|
||||
EXPORT int config_open_string(config_t **config, const char *str);
|
||||
EXPORT int config_save(config_t *config);
|
||||
EXPORT int config_save_safe(config_t *config, const char *temp_ext,
|
||||
const char *backup_ext);
|
||||
EXPORT void config_close(config_t *config);
|
||||
|
||||
EXPORT size_t config_num_sections(config_t *config);
|
||||
EXPORT const char *config_get_section(config_t *config, size_t idx);
|
||||
|
||||
EXPORT void config_set_string(config_t *config, const char *section,
|
||||
const char *name, const char *value);
|
||||
EXPORT void config_set_int(config_t *config, const char *section,
|
||||
const char *name, int64_t value);
|
||||
EXPORT void config_set_uint(config_t *config, const char *section,
|
||||
const char *name, uint64_t value);
|
||||
EXPORT void config_set_bool(config_t *config, const char *section,
|
||||
const char *name, bool value);
|
||||
EXPORT void config_set_double(config_t *config, const char *section,
|
||||
const char *name, double value);
|
||||
|
||||
EXPORT const char *config_get_string(const config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT int64_t config_get_int(const config_t *config, const char *section,
|
||||
const char *name);
|
||||
EXPORT uint64_t config_get_uint(const config_t *config, const char *section,
|
||||
const char *name);
|
||||
EXPORT bool config_get_bool(const config_t *config, const char *section,
|
||||
const char *name);
|
||||
EXPORT double config_get_double(const config_t *config, const char *section,
|
||||
const char *name);
|
||||
|
||||
EXPORT bool config_remove_value(config_t *config, const char *section,
|
||||
const char *name);
|
||||
|
||||
/*
|
||||
* DEFAULT VALUES
|
||||
*
|
||||
* The following functions are used to set what values will return if they do
|
||||
* not exist. Call these functions *once* for each known value before reading
|
||||
* any of them anywhere else.
|
||||
*
|
||||
* These do *not* actually set any values, they only set what values will be
|
||||
* returned for config_get_* if the specified variable does not exist.
|
||||
*
|
||||
* You can initialize the defaults programmitically using config_set_default_*
|
||||
* functions (recommended for most cases), or you can initialize it via a file
|
||||
* with config_open_defaults.
|
||||
*/
|
||||
EXPORT int config_open_defaults(config_t *config, const char *file);
|
||||
|
||||
EXPORT void config_set_default_string(config_t *config, const char *section,
|
||||
const char *name, const char *value);
|
||||
EXPORT void config_set_default_int(config_t *config, const char *section,
|
||||
const char *name, int64_t value);
|
||||
EXPORT void config_set_default_uint(config_t *config, const char *section,
|
||||
const char *name, uint64_t value);
|
||||
EXPORT void config_set_default_bool(config_t *config, const char *section,
|
||||
const char *name, bool value);
|
||||
EXPORT void config_set_default_double(config_t *config, const char *section,
|
||||
const char *name, double value);
|
||||
|
||||
/* These functions allow you to get the current default values rather than get
|
||||
* the actual values. Probably almost never really needed */
|
||||
EXPORT const char *config_get_default_string(const config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT int64_t config_get_default_int(const config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT uint64_t config_get_default_uint(const config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT bool config_get_default_bool(const config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT double config_get_default_double(const config_t *config,
|
||||
const char *section, const char *name);
|
||||
|
||||
EXPORT bool config_has_user_value(const config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT bool config_has_default_value(const config_t *config,
|
||||
const char *section, const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
79
libobs/util/crc32.c
Normal file
79
libobs/util/crc32.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 1986 Gary S. Brown
|
||||
* 2015 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
/* CRC32 code derived from work by Gary S. Brown. */
|
||||
|
||||
static uint32_t crc32_tab[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
uint32_t calc_crc32(uint32_t crc, const void *buf, size_t size)
|
||||
{
|
||||
const uint8_t *p;
|
||||
|
||||
p = buf;
|
||||
crc = crc ^ ~0UL;
|
||||
|
||||
while (size--)
|
||||
crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
|
||||
|
||||
return crc ^ ~0UL;
|
||||
}
|
||||
21
libobs/util/crc32.h
Normal file
21
libobs/util/crc32.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "c99defs.h"
|
||||
|
||||
EXPORT uint32_t calc_crc32(uint32_t crc, const void *buf, size_t size);
|
||||
529
libobs/util/darray.h
Normal file
529
libobs/util/darray.h
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "c99defs.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "bmem.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dynamic array.
|
||||
*
|
||||
* NOTE: Not type-safe when using directly.
|
||||
* Specifying size per call with inline maximizes compiler optimizations
|
||||
*
|
||||
* See DARRAY macro at the bottom of thhe file for slightly safer usage.
|
||||
*/
|
||||
|
||||
#define DARRAY_INVALID ((size_t)-1)
|
||||
|
||||
struct darray {
|
||||
void *array;
|
||||
size_t num;
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
static inline void darray_init(struct darray *dst)
|
||||
{
|
||||
dst->array = NULL;
|
||||
dst->num = 0;
|
||||
dst->capacity = 0;
|
||||
}
|
||||
|
||||
static inline void darray_free(struct darray *dst)
|
||||
{
|
||||
bfree(dst->array);
|
||||
dst->array = NULL;
|
||||
dst->num = 0;
|
||||
dst->capacity = 0;
|
||||
}
|
||||
|
||||
static inline size_t darray_alloc_size(const size_t element_size,
|
||||
const struct darray *da)
|
||||
{
|
||||
return element_size*da->num;
|
||||
}
|
||||
|
||||
static inline void *darray_item(const size_t element_size,
|
||||
const struct darray *da, size_t idx)
|
||||
{
|
||||
return (void*)(((uint8_t*)da->array) + element_size*idx);
|
||||
}
|
||||
|
||||
static inline void *darray_end(const size_t element_size,
|
||||
const struct darray *da)
|
||||
{
|
||||
if (!da->num)
|
||||
return NULL;
|
||||
|
||||
return darray_item(element_size, da, da->num-1);
|
||||
}
|
||||
|
||||
static inline void darray_reserve(const size_t element_size,
|
||||
struct darray *dst, const size_t capacity)
|
||||
{
|
||||
void *ptr;
|
||||
if (capacity == 0 || capacity <= dst->num)
|
||||
return;
|
||||
|
||||
ptr = bmalloc(element_size*capacity);
|
||||
if (dst->num)
|
||||
memcpy(ptr, dst->array, element_size*dst->num);
|
||||
if (dst->array)
|
||||
bfree(dst->array);
|
||||
dst->array = ptr;
|
||||
dst->capacity = capacity;
|
||||
}
|
||||
|
||||
static inline void darray_ensure_capacity(const size_t element_size,
|
||||
struct darray *dst, const size_t new_size)
|
||||
{
|
||||
size_t new_cap;
|
||||
void *ptr;
|
||||
if (new_size <= dst->capacity)
|
||||
return;
|
||||
|
||||
new_cap = (!dst->capacity) ? new_size : dst->capacity*2;
|
||||
if (new_size > new_cap)
|
||||
new_cap = new_size;
|
||||
ptr = bmalloc(element_size*new_cap);
|
||||
if (dst->capacity)
|
||||
memcpy(ptr, dst->array, element_size*dst->capacity);
|
||||
if (dst->array)
|
||||
bfree(dst->array);
|
||||
dst->array = ptr;
|
||||
dst->capacity = new_cap;
|
||||
}
|
||||
|
||||
static inline void darray_resize(const size_t element_size,
|
||||
struct darray *dst, const size_t size)
|
||||
{
|
||||
int b_clear;
|
||||
size_t old_num;
|
||||
|
||||
if (size == dst->num) {
|
||||
return;
|
||||
} else if (size == 0) {
|
||||
dst->num = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
b_clear = size > dst->num;
|
||||
old_num = dst->num;
|
||||
|
||||
darray_ensure_capacity(element_size, dst, size);
|
||||
dst->num = size;
|
||||
|
||||
if (b_clear)
|
||||
memset(darray_item(element_size, dst, old_num), 0,
|
||||
element_size * (dst->num-old_num));
|
||||
}
|
||||
|
||||
static inline void darray_copy(const size_t element_size, struct darray *dst,
|
||||
const struct darray *da)
|
||||
{
|
||||
if (da->num == 0) {
|
||||
darray_free(dst);
|
||||
} else {
|
||||
darray_resize(element_size, dst, da->num);
|
||||
memcpy(dst->array, da->array, element_size*da->num);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void darray_copy_array(const size_t element_size,
|
||||
struct darray *dst, const void *array, const size_t num)
|
||||
{
|
||||
darray_resize(element_size, dst, num);
|
||||
memcpy(dst->array, array, element_size*dst->num);
|
||||
}
|
||||
|
||||
static inline void darray_move(struct darray *dst, struct darray *src)
|
||||
{
|
||||
darray_free(dst);
|
||||
memcpy(dst, src, sizeof(struct darray));
|
||||
src->array = NULL;
|
||||
src->capacity = 0;
|
||||
src->num = 0;
|
||||
}
|
||||
|
||||
static inline size_t darray_find(const size_t element_size,
|
||||
const struct darray *da, const void *item, const size_t idx)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
assert(idx <= da->num);
|
||||
|
||||
for (i = idx; i < da->num; i++) {
|
||||
void *compare = darray_item(element_size, da, i);
|
||||
if (memcmp(compare, item, element_size) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return DARRAY_INVALID;
|
||||
}
|
||||
|
||||
static inline size_t darray_push_back(const size_t element_size,
|
||||
struct darray *dst, const void *item)
|
||||
{
|
||||
darray_ensure_capacity(element_size, dst, ++dst->num);
|
||||
memcpy(darray_end(element_size, dst), item, element_size);
|
||||
|
||||
return dst->num-1;
|
||||
}
|
||||
|
||||
static inline void *darray_push_back_new(const size_t element_size,
|
||||
struct darray *dst)
|
||||
{
|
||||
void *last;
|
||||
|
||||
darray_ensure_capacity(element_size, dst, ++dst->num);
|
||||
|
||||
last = darray_end(element_size, dst);
|
||||
memset(last, 0, element_size);
|
||||
return last;
|
||||
}
|
||||
|
||||
static inline size_t darray_push_back_array(const size_t element_size,
|
||||
struct darray *dst, const void *array, const size_t num)
|
||||
{
|
||||
size_t old_num = dst->num;
|
||||
|
||||
assert(array != NULL);
|
||||
assert(num != 0);
|
||||
|
||||
darray_resize(element_size, dst, dst->num+num);
|
||||
memcpy(darray_item(element_size, dst, old_num), array,
|
||||
element_size*num);
|
||||
|
||||
return old_num;
|
||||
}
|
||||
|
||||
static inline size_t darray_push_back_darray(const size_t element_size,
|
||||
struct darray *dst, const struct darray *da)
|
||||
{
|
||||
return darray_push_back_array(element_size, dst, da->array, da->num);
|
||||
}
|
||||
|
||||
static inline void darray_insert(const size_t element_size, struct darray *dst,
|
||||
const size_t idx, const void *item)
|
||||
{
|
||||
void *new_item;
|
||||
size_t move_count;
|
||||
|
||||
assert(idx <= dst->num);
|
||||
|
||||
if (idx == dst->num) {
|
||||
darray_push_back(element_size, dst, item);
|
||||
return;
|
||||
}
|
||||
|
||||
move_count = dst->num - idx;
|
||||
darray_ensure_capacity(element_size, dst, ++dst->num);
|
||||
|
||||
new_item = darray_item(element_size, dst, idx);
|
||||
|
||||
memmove(darray_item(element_size, dst, idx+1), new_item,
|
||||
move_count*element_size);
|
||||
memcpy(new_item, item, element_size);
|
||||
}
|
||||
|
||||
static inline void *darray_insert_new(const size_t element_size,
|
||||
struct darray *dst, const size_t idx)
|
||||
{
|
||||
void *item;
|
||||
size_t move_count;
|
||||
|
||||
assert(idx <= dst->num);
|
||||
if (idx == dst->num)
|
||||
return darray_push_back_new(element_size, dst);
|
||||
|
||||
item = darray_item(element_size, dst, idx);
|
||||
|
||||
move_count = dst->num - idx;
|
||||
darray_ensure_capacity(element_size, dst, ++dst->num);
|
||||
memmove(darray_item(element_size, dst, idx+1), item,
|
||||
move_count*element_size);
|
||||
|
||||
memset(item, 0, element_size);
|
||||
return item;
|
||||
}
|
||||
|
||||
static inline void darray_insert_array(const size_t element_size,
|
||||
struct darray *dst, const size_t idx,
|
||||
const void *array, const size_t num)
|
||||
{
|
||||
size_t old_num;
|
||||
|
||||
assert(array != NULL);
|
||||
assert(num != 0);
|
||||
assert(idx < dst->num);
|
||||
|
||||
old_num = dst->num;
|
||||
darray_resize(element_size, dst, dst->num+num);
|
||||
|
||||
memmove(darray_item(element_size, dst, idx+num),
|
||||
darray_item(element_size, dst, idx),
|
||||
element_size*(old_num-idx));
|
||||
memcpy(darray_item(element_size, dst, idx), array, element_size*num);
|
||||
}
|
||||
|
||||
static inline void darray_insert_darray(const size_t element_size,
|
||||
struct darray *dst, const size_t idx, const struct darray *da)
|
||||
{
|
||||
darray_insert_array(element_size, dst, idx, da->array, da->num);
|
||||
}
|
||||
|
||||
static inline void darray_erase(const size_t element_size, struct darray *dst,
|
||||
const size_t idx)
|
||||
{
|
||||
assert(idx < dst->num);
|
||||
|
||||
if (idx >= dst->num || !--dst->num)
|
||||
return;
|
||||
|
||||
memmove(darray_item(element_size, dst, idx),
|
||||
darray_item(element_size, dst, idx+1),
|
||||
element_size*(dst->num-idx));
|
||||
}
|
||||
|
||||
static inline void darray_erase_item(const size_t element_size,
|
||||
struct darray *dst, const void *item)
|
||||
{
|
||||
size_t idx = darray_find(element_size, dst, item, 0);
|
||||
if (idx != DARRAY_INVALID)
|
||||
darray_erase(element_size, dst, idx);
|
||||
}
|
||||
|
||||
static inline void darray_erase_range(const size_t element_size,
|
||||
struct darray *dst, const size_t start, const size_t end)
|
||||
{
|
||||
size_t count, move_count;
|
||||
|
||||
assert(start <= dst->num);
|
||||
assert(end <= dst->num);
|
||||
assert(end > start);
|
||||
|
||||
count = end-start;
|
||||
if (count == 1) {
|
||||
darray_erase(element_size, dst, start);
|
||||
return;
|
||||
} else if (count == dst->num) {
|
||||
dst->num = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
move_count = dst->num - end;
|
||||
if (move_count)
|
||||
memmove(darray_item(element_size, dst, start),
|
||||
darray_item(element_size, dst, end),
|
||||
move_count * element_size);
|
||||
|
||||
dst->num -= count;
|
||||
}
|
||||
|
||||
static inline void darray_pop_back(const size_t element_size,
|
||||
struct darray *dst)
|
||||
{
|
||||
assert(dst->num != 0);
|
||||
|
||||
if (dst->num)
|
||||
darray_erase(element_size, dst, dst->num-1);
|
||||
}
|
||||
|
||||
static inline void darray_join(const size_t element_size, struct darray *dst,
|
||||
struct darray *da)
|
||||
{
|
||||
darray_push_back_darray(element_size, dst, da);
|
||||
darray_free(da);
|
||||
}
|
||||
|
||||
static inline void darray_split(const size_t element_size, struct darray *dst1,
|
||||
struct darray *dst2, const struct darray *da, const size_t idx)
|
||||
{
|
||||
struct darray temp;
|
||||
|
||||
assert(da->num >= idx);
|
||||
assert(dst1 != dst2);
|
||||
|
||||
darray_init(&temp);
|
||||
darray_copy(element_size, &temp, da);
|
||||
|
||||
darray_free(dst1);
|
||||
darray_free(dst2);
|
||||
|
||||
if (da->num) {
|
||||
if (idx)
|
||||
darray_copy_array(element_size, dst1, temp.array,
|
||||
temp.num);
|
||||
if (idx < temp.num-1)
|
||||
darray_copy_array(element_size, dst2,
|
||||
darray_item(element_size, &temp, idx),
|
||||
temp.num-idx);
|
||||
}
|
||||
|
||||
darray_free(&temp);
|
||||
}
|
||||
|
||||
static inline void darray_move_item(const size_t element_size,
|
||||
struct darray *dst, const size_t from, const size_t to)
|
||||
{
|
||||
void *temp, *p_from, *p_to;
|
||||
|
||||
if (from == to)
|
||||
return;
|
||||
|
||||
temp = malloc(element_size);
|
||||
p_from = darray_item(element_size, dst, from);
|
||||
p_to = darray_item(element_size, dst, to);
|
||||
|
||||
memcpy(temp, p_from, element_size);
|
||||
|
||||
if (to < from)
|
||||
memmove(darray_item(element_size, dst, to+1), p_to,
|
||||
element_size*(from-to));
|
||||
else
|
||||
memmove(p_from, darray_item(element_size, dst, from+1),
|
||||
element_size*(to-from));
|
||||
|
||||
memcpy(p_to, temp, element_size);
|
||||
free(temp);
|
||||
}
|
||||
|
||||
static inline void darray_swap(const size_t element_size,
|
||||
struct darray *dst, const size_t a, const size_t b)
|
||||
{
|
||||
void *temp, *a_ptr, *b_ptr;
|
||||
|
||||
assert(a < dst->num);
|
||||
assert(b < dst->num);
|
||||
|
||||
if (a == b)
|
||||
return;
|
||||
|
||||
temp = malloc(element_size);
|
||||
a_ptr = darray_item(element_size, dst, a);
|
||||
b_ptr = darray_item(element_size, dst, b);
|
||||
|
||||
memcpy(temp, a_ptr, element_size);
|
||||
memcpy(a_ptr, b_ptr, element_size);
|
||||
memcpy(b_ptr, temp, element_size);
|
||||
|
||||
free(temp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Defines to make dynamic arrays more type-safe.
|
||||
* Note: Still not 100% type-safe but much better than using darray directly
|
||||
* Makes it a little easier to use as well.
|
||||
*
|
||||
* I did -not- want to use a gigantic macro to generate a crapload of
|
||||
* typsafe inline functions per type. It just feels like a mess to me.
|
||||
*/
|
||||
|
||||
#define DARRAY(type) \
|
||||
union { \
|
||||
struct darray da; \
|
||||
struct { \
|
||||
type *array; \
|
||||
size_t num; \
|
||||
size_t capacity; \
|
||||
}; \
|
||||
}
|
||||
|
||||
#define da_init(v) darray_init(&v.da)
|
||||
|
||||
#define da_free(v) darray_free(&v.da)
|
||||
|
||||
#define da_alloc_size(v) (sizeof(*v.array)*v.num)
|
||||
|
||||
#define da_end(v) darray_end(sizeof(*v.array), &v.da)
|
||||
|
||||
#define da_reserve(v, capacity) \
|
||||
darray_reserve(sizeof(*v.array), &v.da, capacity)
|
||||
|
||||
#define da_resize(v, size) darray_resize(sizeof(*v.array), &v.da, size)
|
||||
|
||||
#define da_copy(dst, src) \
|
||||
darray_copy(sizeof(*dst.array), &dst.da, &src.da)
|
||||
|
||||
#define da_copy_array(dst, src_array, n) \
|
||||
darray_copy_array(sizeof(*dst.array), &dst.da, src_array, n)
|
||||
|
||||
#define da_move(dst, src) darray_move(&dst.da, &src.da)
|
||||
|
||||
#define da_find(v, item, idx) \
|
||||
darray_find(sizeof(*v.array), &v.da, item, idx)
|
||||
|
||||
#define da_push_back(v, item) darray_push_back(sizeof(*v.array), &v.da, item)
|
||||
|
||||
#define da_push_back_new(v) darray_push_back_new(sizeof(*v.array), &v.da)
|
||||
|
||||
#define da_push_back_array(dst, src_array, n) \
|
||||
darray_push_back_array(sizeof(*dst.array), &dst.da, src_array, n)
|
||||
|
||||
#define da_push_back_da(dst, src) \
|
||||
darray_push_back_darray(sizeof(*dst.array), &dst.da, &src.da)
|
||||
|
||||
#define da_insert(v, idx, item) \
|
||||
darray_insert(sizeof(*v.array), &v.da, idx, item)
|
||||
|
||||
#define da_insert_new(v, idx) \
|
||||
darray_insert_new(sizeof(*v.array), &v.da, idx)
|
||||
|
||||
#define da_insert_array(dst, idx, src_array, n) \
|
||||
darray_insert_array(sizeof(*dst.array), &dst.da, idx, \
|
||||
src_array, n)
|
||||
|
||||
#define da_insert_da(dst, idx, src) \
|
||||
darray_insert_darray(sizeof(*dst.array), &dst.da, idx, \
|
||||
&src.da)
|
||||
|
||||
#define da_erase(dst, idx) \
|
||||
darray_erase(sizeof(*dst.array), &dst.da, idx)
|
||||
|
||||
#define da_erase_item(dst, item) \
|
||||
darray_erase_item(sizeof(*dst.array), &dst.da, item)
|
||||
|
||||
#define da_erase_range(dst, from, to) \
|
||||
darray_erase_range(sizeof(*dst.array), &dst.da, from, to)
|
||||
|
||||
#define da_pop_back(dst) \
|
||||
darray_pop_back(sizeof(*dst.array), &dst.da);
|
||||
|
||||
#define da_join(dst, src) \
|
||||
darray_join(sizeof(*dst.array), &dst.da, &src.da)
|
||||
|
||||
#define da_split(dst1, dst2, src, idx) \
|
||||
darray_split(sizeof(*src.array), &dst1.da, &dst2.da, \
|
||||
&src.da, idx)
|
||||
|
||||
#define da_move_item(v, from, to) \
|
||||
darray_move_item(sizeof(*v.array), &v.da, from, to)
|
||||
|
||||
#define da_swap(v, idx1, idx2) \
|
||||
darray_swap(sizeof(*v.array), &v.da, idx1, idx2)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
751
libobs/util/dstr.c
Normal file
751
libobs/util/dstr.c
Normal file
|
|
@ -0,0 +1,751 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "c99defs.h"
|
||||
#include "dstr.h"
|
||||
#include "darray.h"
|
||||
#include "bmem.h"
|
||||
#include "utf8.h"
|
||||
#include "lexer.h"
|
||||
#include "platform.h"
|
||||
|
||||
static const char *astrblank = "";
|
||||
static const wchar_t *wstrblank = L"";
|
||||
|
||||
int astrcmpi(const char *str1, const char *str2)
|
||||
{
|
||||
if (!str1)
|
||||
str1 = astrblank;
|
||||
if (!str2)
|
||||
str2 = astrblank;
|
||||
|
||||
do {
|
||||
char ch1 = (char)toupper(*str1);
|
||||
char ch2 = (char)toupper(*str2);
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wstrcmpi(const wchar_t *str1, const wchar_t *str2)
|
||||
{
|
||||
if (!str1)
|
||||
str1 = wstrblank;
|
||||
if (!str2)
|
||||
str2 = wstrblank;
|
||||
|
||||
do {
|
||||
wchar_t ch1 = (wchar_t)towupper(*str1);
|
||||
wchar_t ch2 = (wchar_t)towupper(*str2);
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int astrcmp_n(const char *str1, const char *str2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0;
|
||||
if (!str1)
|
||||
str1 = astrblank;
|
||||
if (!str2)
|
||||
str2 = astrblank;
|
||||
|
||||
do {
|
||||
char ch1 = *str1;
|
||||
char ch2 = *str2;
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++ && --n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wstrcmp_n(const wchar_t *str1, const wchar_t *str2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0;
|
||||
if (!str1)
|
||||
str1 = wstrblank;
|
||||
if (!str2)
|
||||
str2 = wstrblank;
|
||||
|
||||
do {
|
||||
wchar_t ch1 = *str1;
|
||||
wchar_t ch2 = *str2;
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++ && --n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int astrcmpi_n(const char *str1, const char *str2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0;
|
||||
if (!str1)
|
||||
str1 = astrblank;
|
||||
if (!str2)
|
||||
str2 = astrblank;
|
||||
|
||||
do {
|
||||
char ch1 = (char)toupper(*str1);
|
||||
char ch2 = (char)toupper(*str2);
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++ && --n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wstrcmpi_n(const wchar_t *str1, const wchar_t *str2, size_t n)
|
||||
{
|
||||
if (!n)
|
||||
return 0;
|
||||
if (!str1)
|
||||
str1 = wstrblank;
|
||||
if (!str2)
|
||||
str2 = wstrblank;
|
||||
|
||||
do {
|
||||
wchar_t ch1 = (wchar_t)towupper(*str1);
|
||||
wchar_t ch2 = (wchar_t)towupper(*str2);
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (*str1++ && *str2++ && --n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *astrstri(const char *str, const char *find)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (!str || !find)
|
||||
return NULL;
|
||||
|
||||
len = strlen(find);
|
||||
|
||||
do {
|
||||
if (astrcmpi_n(str, find, len) == 0)
|
||||
return (char*)str;
|
||||
} while (*str++);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wchar_t *wstrstri(const wchar_t *str, const wchar_t *find)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (!str || !find)
|
||||
return NULL;
|
||||
|
||||
len = wcslen(find);
|
||||
|
||||
do {
|
||||
if (wstrcmpi_n(str, find, len) == 0)
|
||||
return (wchar_t*)str;
|
||||
} while (*str++);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strdepad(char *str)
|
||||
{
|
||||
char *temp;
|
||||
size_t len;
|
||||
|
||||
if (!str)
|
||||
return str;
|
||||
if (!*str)
|
||||
return str;
|
||||
|
||||
temp = str;
|
||||
|
||||
/* remove preceding spaces/tabs */
|
||||
while (*temp == ' ' || *temp == '\t')
|
||||
++temp;
|
||||
|
||||
len = strlen(str);
|
||||
if (temp != str)
|
||||
memmove(str, temp, len + 1);
|
||||
|
||||
if (len) {
|
||||
temp = str + (len-1);
|
||||
while (*temp == ' ' || *temp == '\t')
|
||||
*(temp--) = 0;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
wchar_t *wcsdepad(wchar_t *str)
|
||||
{
|
||||
wchar_t *temp;
|
||||
size_t len;
|
||||
|
||||
if (!str)
|
||||
return str;
|
||||
if (!*str)
|
||||
return str;
|
||||
|
||||
temp = str;
|
||||
|
||||
/* remove preceding spaces/tabs */
|
||||
while (*temp == ' ' || *temp == '\t')
|
||||
++temp;
|
||||
|
||||
len = wcslen(str);
|
||||
if (temp != str)
|
||||
memmove(str, temp, (len+1) * sizeof(wchar_t));
|
||||
|
||||
if (len) {
|
||||
temp = str + (len-1);
|
||||
while (*temp == ' ' || *temp == '\t')
|
||||
*(temp--) = 0;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
char **strlist_split(const char *str, char split_ch, bool include_empty)
|
||||
{
|
||||
const char *cur_str = str;
|
||||
const char *next_str;
|
||||
const char *new_str;
|
||||
DARRAY(char*) list;
|
||||
|
||||
da_init(list);
|
||||
|
||||
if (str) {
|
||||
next_str = strchr(str, split_ch);
|
||||
|
||||
while (next_str) {
|
||||
size_t size = next_str - cur_str;
|
||||
|
||||
if (size || include_empty) {
|
||||
new_str = bstrdup_n(cur_str, size);
|
||||
da_push_back(list, &new_str);
|
||||
}
|
||||
|
||||
cur_str = next_str+1;
|
||||
next_str = strchr(cur_str, split_ch);
|
||||
}
|
||||
|
||||
if (*cur_str || include_empty) {
|
||||
new_str = bstrdup(cur_str);
|
||||
da_push_back(list, &new_str);
|
||||
}
|
||||
}
|
||||
|
||||
new_str = NULL;
|
||||
da_push_back(list, &new_str);
|
||||
|
||||
return list.array;
|
||||
}
|
||||
|
||||
void strlist_free(char **strlist)
|
||||
{
|
||||
if (strlist) {
|
||||
char **temp = strlist;
|
||||
while (*temp)
|
||||
bfree(*(temp++));
|
||||
|
||||
bfree(strlist);
|
||||
}
|
||||
}
|
||||
|
||||
void dstr_init_copy_strref(struct dstr *dst, const struct strref *src)
|
||||
{
|
||||
dstr_init(dst);
|
||||
dstr_copy_strref(dst, src);
|
||||
}
|
||||
|
||||
void dstr_copy(struct dstr *dst, const char *array)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (!array || !*array) {
|
||||
dstr_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
len = strlen(array);
|
||||
dstr_ensure_capacity(dst, len + 1);
|
||||
memcpy(dst->array, array, len + 1);
|
||||
dst->len = len;
|
||||
}
|
||||
|
||||
void dstr_copy_strref(struct dstr *dst, const struct strref *src)
|
||||
{
|
||||
if (dst->array)
|
||||
dstr_free(dst);
|
||||
|
||||
dstr_ncopy(dst, src->array, src->len);
|
||||
}
|
||||
|
||||
static inline size_t size_min(size_t a, size_t b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
void dstr_ncopy(struct dstr *dst, const char *array, const size_t len)
|
||||
{
|
||||
if (dst->array)
|
||||
dstr_free(dst);
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
dst->array = bmemdup(array, len + 1);
|
||||
dst->len = len;
|
||||
|
||||
dst->array[len] = 0;
|
||||
}
|
||||
|
||||
void dstr_ncopy_dstr(struct dstr *dst, const struct dstr *str, const size_t len)
|
||||
{
|
||||
size_t newlen;
|
||||
|
||||
if (dst->array)
|
||||
dstr_free(dst);
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
newlen = size_min(len, str->len);
|
||||
dst->array = bmemdup(str->array, newlen + 1);
|
||||
dst->len = newlen;
|
||||
|
||||
dst->array[newlen] = 0;
|
||||
}
|
||||
|
||||
void dstr_cat_dstr(struct dstr *dst, const struct dstr *str)
|
||||
{
|
||||
size_t new_len;
|
||||
if (!str->len)
|
||||
return;
|
||||
|
||||
new_len = dst->len + str->len;
|
||||
|
||||
dstr_ensure_capacity(dst, new_len + 1);
|
||||
memcpy(dst->array+dst->len, str->array, str->len + 1);
|
||||
dst->len = new_len;
|
||||
}
|
||||
|
||||
void dstr_cat_strref(struct dstr *dst, const struct strref *str)
|
||||
{
|
||||
dstr_ncat(dst, str->array, str->len);
|
||||
}
|
||||
|
||||
void dstr_ncat(struct dstr *dst, const char *array, const size_t len)
|
||||
{
|
||||
size_t new_len;
|
||||
if (!array || !*array || !len)
|
||||
return;
|
||||
|
||||
new_len = dst->len + len;
|
||||
|
||||
dstr_ensure_capacity(dst, new_len + 1);
|
||||
memcpy(dst->array+dst->len, array, len);
|
||||
|
||||
dst->len = new_len;
|
||||
dst->array[new_len] = 0;
|
||||
}
|
||||
|
||||
void dstr_ncat_dstr(struct dstr *dst, const struct dstr *str, const size_t len)
|
||||
{
|
||||
size_t new_len, in_len;
|
||||
if (!str->array || !*str->array || !len)
|
||||
return;
|
||||
|
||||
in_len = size_min(len, str->len);
|
||||
new_len = dst->len + in_len;
|
||||
|
||||
dstr_ensure_capacity(dst, new_len + 1);
|
||||
memcpy(dst->array+dst->len, str->array, in_len);
|
||||
|
||||
dst->len = new_len;
|
||||
dst->array[new_len] = 0;
|
||||
}
|
||||
|
||||
void dstr_insert(struct dstr *dst, const size_t idx, const char *array)
|
||||
{
|
||||
size_t new_len, len;
|
||||
if (!array || !*array)
|
||||
return;
|
||||
if (idx == dst->len) {
|
||||
dstr_cat(dst, array);
|
||||
return;
|
||||
}
|
||||
|
||||
len = strlen(array);
|
||||
new_len = dst->len + len;
|
||||
|
||||
dstr_ensure_capacity(dst, new_len + 1);
|
||||
dst->len = new_len;
|
||||
|
||||
memmove(dst->array+idx+len, dst->array+idx, dst->len - idx + 1);
|
||||
memcpy(dst->array+idx, array, len);
|
||||
}
|
||||
|
||||
void dstr_insert_dstr(struct dstr *dst, const size_t idx,
|
||||
const struct dstr *str)
|
||||
{
|
||||
size_t new_len;
|
||||
if (!str->len)
|
||||
return;
|
||||
if (idx == dst->len) {
|
||||
dstr_cat_dstr(dst, str);
|
||||
return;
|
||||
}
|
||||
|
||||
new_len = dst->len + str->len;
|
||||
|
||||
dstr_ensure_capacity(dst, (new_len+1));
|
||||
dst->len = new_len;
|
||||
|
||||
memmove(dst->array+idx+str->len, dst->array+idx, dst->len - idx + 1);
|
||||
memcpy(dst->array+idx, str->array, str->len);
|
||||
}
|
||||
|
||||
void dstr_insert_ch(struct dstr *dst, const size_t idx, const char ch)
|
||||
{
|
||||
if (idx == dst->len) {
|
||||
dstr_cat_ch(dst, ch);
|
||||
return;
|
||||
}
|
||||
|
||||
dstr_ensure_capacity(dst, (++dst->len+1));
|
||||
memmove(dst->array+idx+1, dst->array+idx, dst->len - idx + 1);
|
||||
dst->array[idx] = ch;
|
||||
}
|
||||
|
||||
void dstr_remove(struct dstr *dst, const size_t idx, const size_t count)
|
||||
{
|
||||
size_t end;
|
||||
if (!count)
|
||||
return;
|
||||
if (count == dst->len) {
|
||||
dstr_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
end = idx+count;
|
||||
if (end == dst->len)
|
||||
dst->array[idx] = 0;
|
||||
else
|
||||
memmove(dst->array+idx, dst->array+end, dst->len - end + 1);
|
||||
|
||||
dst->len -= count;
|
||||
}
|
||||
|
||||
void dstr_printf(struct dstr *dst, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
dstr_vprintf(dst, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void dstr_catf(struct dstr *dst, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
dstr_vcatf(dst, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void dstr_vprintf(struct dstr *dst, const char *format, va_list args)
|
||||
{
|
||||
va_list args_cp;
|
||||
va_copy(args_cp, args);
|
||||
|
||||
int len = vsnprintf(NULL, 0, format, args_cp);
|
||||
va_end(args_cp);
|
||||
|
||||
if (len < 0) len = 4095;
|
||||
|
||||
dstr_ensure_capacity(dst, ((size_t)len) + 1);
|
||||
len = vsnprintf(dst->array, ((size_t)len) + 1, format, args);
|
||||
|
||||
if (!*dst->array) {
|
||||
dstr_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
dst->len = len < 0 ? strlen(dst->array) : (size_t)len;
|
||||
}
|
||||
|
||||
void dstr_vcatf(struct dstr *dst, const char *format, va_list args)
|
||||
{
|
||||
va_list args_cp;
|
||||
va_copy(args_cp, args);
|
||||
|
||||
int len = vsnprintf(NULL, 0, format, args_cp);
|
||||
va_end(args_cp);
|
||||
|
||||
if (len < 0) len = 4095;
|
||||
|
||||
dstr_ensure_capacity(dst, dst->len + ((size_t)len) + 1);
|
||||
len = vsnprintf(dst->array + dst->len, ((size_t)len) + 1, format, args);
|
||||
|
||||
if (!*dst->array) {
|
||||
dstr_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
dst->len += len < 0 ? strlen(dst->array + dst->len) : (size_t)len;
|
||||
}
|
||||
|
||||
void dstr_safe_printf(struct dstr *dst, const char *format,
|
||||
const char *val1, const char *val2, const char *val3,
|
||||
const char *val4)
|
||||
{
|
||||
dstr_copy(dst, format);
|
||||
if (val1)
|
||||
dstr_replace(dst, "$1", val1);
|
||||
if (val2)
|
||||
dstr_replace(dst, "$2", val2);
|
||||
if (val3)
|
||||
dstr_replace(dst, "$3", val3);
|
||||
if (val4)
|
||||
dstr_replace(dst, "$4", val4);
|
||||
}
|
||||
|
||||
void dstr_replace(struct dstr *str, const char *find,
|
||||
const char *replace)
|
||||
{
|
||||
size_t find_len, replace_len;
|
||||
char *temp;
|
||||
|
||||
if (dstr_is_empty(str))
|
||||
return;
|
||||
|
||||
if (!replace)
|
||||
replace = "";
|
||||
|
||||
find_len = strlen(find);
|
||||
replace_len = strlen(replace);
|
||||
temp = str->array;
|
||||
|
||||
if (replace_len < find_len) {
|
||||
unsigned long count = 0;
|
||||
|
||||
while ((temp = strstr(temp, find)) != NULL) {
|
||||
char *end = temp+find_len;
|
||||
size_t end_len = strlen(end);
|
||||
|
||||
if (end_len) {
|
||||
memmove(temp+replace_len, end, end_len + 1);
|
||||
if (replace_len)
|
||||
memcpy(temp, replace, replace_len);
|
||||
} else {
|
||||
strcpy(temp, replace);
|
||||
}
|
||||
|
||||
temp += replace_len;
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count)
|
||||
str->len += (replace_len-find_len) * count;
|
||||
|
||||
} else if (replace_len > find_len) {
|
||||
unsigned long count = 0;
|
||||
|
||||
while ((temp = strstr(temp, find)) != NULL) {
|
||||
temp += find_len;
|
||||
++count;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
str->len += (replace_len-find_len) * count;
|
||||
dstr_ensure_capacity(str, str->len + 1);
|
||||
temp = str->array;
|
||||
|
||||
while ((temp = strstr(temp, find)) != NULL) {
|
||||
char *end = temp+find_len;
|
||||
size_t end_len = strlen(end);
|
||||
|
||||
if (end_len) {
|
||||
memmove(temp+replace_len, end, end_len + 1);
|
||||
memcpy(temp, replace, replace_len);
|
||||
} else {
|
||||
strcpy(temp, replace);
|
||||
}
|
||||
|
||||
temp += replace_len;
|
||||
}
|
||||
|
||||
} else {
|
||||
while ((temp = strstr(temp, find)) != NULL) {
|
||||
memcpy(temp, replace, replace_len);
|
||||
temp += replace_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dstr_depad(struct dstr *str)
|
||||
{
|
||||
if (str->array) {
|
||||
str->array = strdepad(str->array);
|
||||
if (*str->array)
|
||||
str->len = strlen(str->array);
|
||||
else
|
||||
dstr_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
void dstr_left(struct dstr *dst, const struct dstr *str, const size_t pos)
|
||||
{
|
||||
dstr_resize(dst, pos);
|
||||
if (dst != str)
|
||||
memcpy(dst->array, str->array, pos);
|
||||
}
|
||||
|
||||
void dstr_mid(struct dstr *dst, const struct dstr *str, const size_t start,
|
||||
const size_t count)
|
||||
{
|
||||
struct dstr temp;
|
||||
dstr_init(&temp);
|
||||
dstr_copy_dstr(&temp, str);
|
||||
dstr_ncopy(dst, temp.array+start, count);
|
||||
dstr_free(&temp);
|
||||
}
|
||||
|
||||
void dstr_right(struct dstr *dst, const struct dstr *str, const size_t pos)
|
||||
{
|
||||
struct dstr temp;
|
||||
dstr_init(&temp);
|
||||
dstr_ncopy(&temp, str->array+pos, str->len-pos);
|
||||
dstr_copy_dstr(dst, &temp);
|
||||
dstr_free(&temp);
|
||||
}
|
||||
|
||||
void dstr_from_mbs(struct dstr *dst, const char *mbstr)
|
||||
{
|
||||
dstr_free(dst);
|
||||
dst->len = os_mbs_to_utf8_ptr(mbstr, 0, &dst->array);
|
||||
}
|
||||
|
||||
char *dstr_to_mbs(const struct dstr *str)
|
||||
{
|
||||
char *dst;
|
||||
os_mbs_to_utf8_ptr(str->array, str->len, &dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
wchar_t *dstr_to_wcs(const struct dstr *str)
|
||||
{
|
||||
wchar_t *dst;
|
||||
os_utf8_to_wcs_ptr(str->array, str->len, &dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void dstr_from_wcs(struct dstr *dst, const wchar_t *wstr)
|
||||
{
|
||||
size_t len = wchar_to_utf8(wstr, 0, NULL, 0, 0);
|
||||
|
||||
if (len) {
|
||||
dstr_resize(dst, len);
|
||||
wchar_to_utf8(wstr, 0, dst->array, len+1, 0);
|
||||
} else {
|
||||
dstr_free(dst);
|
||||
}
|
||||
}
|
||||
|
||||
void dstr_to_upper(struct dstr *str)
|
||||
{
|
||||
wchar_t *wstr;
|
||||
wchar_t *temp;
|
||||
|
||||
if (dstr_is_empty(str))
|
||||
return;
|
||||
|
||||
wstr = dstr_to_wcs(str);
|
||||
temp = wstr;
|
||||
|
||||
if (!wstr)
|
||||
return;
|
||||
|
||||
while (*temp) {
|
||||
*temp = (wchar_t)towupper(*temp);
|
||||
temp++;
|
||||
}
|
||||
|
||||
dstr_from_wcs(str, wstr);
|
||||
bfree(wstr);
|
||||
}
|
||||
|
||||
void dstr_to_lower(struct dstr *str)
|
||||
{
|
||||
wchar_t *wstr;
|
||||
wchar_t *temp;
|
||||
|
||||
if (dstr_is_empty(str))
|
||||
return;
|
||||
|
||||
wstr = dstr_to_wcs(str);
|
||||
temp = wstr;
|
||||
|
||||
if (!wstr)
|
||||
return;
|
||||
|
||||
while (*temp) {
|
||||
*temp = (wchar_t)towlower(*temp);
|
||||
temp++;
|
||||
}
|
||||
|
||||
dstr_from_wcs(str, wstr);
|
||||
bfree(wstr);
|
||||
}
|
||||
335
libobs/util/dstr.h
Normal file
335
libobs/util/dstr.h
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "c99defs.h"
|
||||
#include "bmem.h"
|
||||
|
||||
/*
|
||||
* Dynamic string
|
||||
*
|
||||
* Helper struct/functions for dynamically sizing string buffers.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct strref;
|
||||
|
||||
struct dstr {
|
||||
char *array;
|
||||
size_t len; /* number of characters, excluding null terminator */
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#define PRINTFATTR(f, a) __attribute__((__format__(__printf__, f, a)))
|
||||
#else
|
||||
#define PRINTFATTR(f, a)
|
||||
#endif
|
||||
|
||||
EXPORT int astrcmpi(const char *str1, const char *str2);
|
||||
EXPORT int wstrcmpi(const wchar_t *str1, const wchar_t *str2);
|
||||
EXPORT int astrcmp_n(const char *str1, const char *str2, size_t n);
|
||||
EXPORT int wstrcmp_n(const wchar_t *str1, const wchar_t *str2, size_t n);
|
||||
EXPORT int astrcmpi_n(const char *str1, const char *str2, size_t n);
|
||||
EXPORT int wstrcmpi_n(const wchar_t *str1, const wchar_t *str2, size_t n);
|
||||
|
||||
EXPORT char *astrstri(const char *str, const char *find);
|
||||
EXPORT wchar_t *wstrstri(const wchar_t *str, const wchar_t *find);
|
||||
|
||||
EXPORT char *strdepad(char *str);
|
||||
EXPORT wchar_t *wcsdepad(wchar_t *str);
|
||||
|
||||
EXPORT char **strlist_split(const char *str, char split_ch, bool include_empty);
|
||||
EXPORT void strlist_free(char **strlist);
|
||||
|
||||
static inline void dstr_init(struct dstr *dst);
|
||||
static inline void dstr_init_move(struct dstr *dst, struct dstr *src);
|
||||
static inline void dstr_init_move_array(struct dstr *dst, char *str);
|
||||
static inline void dstr_init_copy(struct dstr *dst, const char *src);
|
||||
static inline void dstr_init_copy_dstr(struct dstr *dst,
|
||||
const struct dstr *src);
|
||||
EXPORT void dstr_init_copy_strref(struct dstr *dst, const struct strref *src);
|
||||
|
||||
static inline void dstr_free(struct dstr *dst);
|
||||
static inline void dstr_array_free(struct dstr *array, const size_t count);
|
||||
|
||||
static inline void dstr_move(struct dstr *dst, struct dstr *src);
|
||||
static inline void dstr_move_array(struct dstr *dst, char *str);
|
||||
|
||||
EXPORT void dstr_copy(struct dstr *dst, const char *array);
|
||||
static inline void dstr_copy_dstr(struct dstr *dst, const struct dstr *src);
|
||||
EXPORT void dstr_copy_strref(struct dstr *dst, const struct strref *src);
|
||||
|
||||
EXPORT void dstr_ncopy(struct dstr *dst, const char *array,
|
||||
const size_t len);
|
||||
EXPORT void dstr_ncopy_dstr(struct dstr *dst, const struct dstr *src,
|
||||
const size_t len);
|
||||
|
||||
static inline void dstr_resize(struct dstr *dst, const size_t num);
|
||||
static inline void dstr_reserve(struct dstr *dst, const size_t num);
|
||||
|
||||
static inline bool dstr_is_empty(const struct dstr *str);
|
||||
|
||||
static inline void dstr_cat(struct dstr *dst, const char *array);
|
||||
EXPORT void dstr_cat_dstr(struct dstr *dst, const struct dstr *str);
|
||||
EXPORT void dstr_cat_strref(struct dstr *dst, const struct strref *str);
|
||||
|
||||
static inline void dstr_cat_ch(struct dstr *dst, char ch);
|
||||
|
||||
EXPORT void dstr_ncat(struct dstr *dst, const char *array, const size_t len);
|
||||
EXPORT void dstr_ncat_dstr(struct dstr *dst, const struct dstr *str,
|
||||
const size_t len);
|
||||
|
||||
EXPORT void dstr_insert(struct dstr *dst, const size_t idx,
|
||||
const char *array);
|
||||
EXPORT void dstr_insert_dstr(struct dstr *dst, const size_t idx,
|
||||
const struct dstr *str);
|
||||
EXPORT void dstr_insert_ch(struct dstr *dst, const size_t idx,
|
||||
const char ch);
|
||||
|
||||
EXPORT void dstr_remove(struct dstr *dst, const size_t idx, const size_t count);
|
||||
|
||||
PRINTFATTR(2, 3)
|
||||
EXPORT void dstr_printf(struct dstr *dst, const char *format, ...);
|
||||
PRINTFATTR(2, 3)
|
||||
EXPORT void dstr_catf(struct dstr *dst, const char *format, ...);
|
||||
|
||||
EXPORT void dstr_vprintf(struct dstr *dst, const char *format, va_list args);
|
||||
EXPORT void dstr_vcatf(struct dstr *dst, const char *format, va_list args);
|
||||
|
||||
EXPORT void dstr_safe_printf(struct dstr *dst, const char *format,
|
||||
const char *val1, const char *val2, const char *val3,
|
||||
const char *val4);
|
||||
|
||||
static inline const char *dstr_find_i(const struct dstr *str,
|
||||
const char *find);
|
||||
static inline const char *dstr_find(const struct dstr *str,
|
||||
const char *find);
|
||||
|
||||
EXPORT void dstr_replace(struct dstr *str, const char *find,
|
||||
const char *replace);
|
||||
|
||||
static inline int dstr_cmp(const struct dstr *str1, const char *str2);
|
||||
static inline int dstr_cmpi(const struct dstr *str1, const char *str2);
|
||||
static inline int dstr_ncmp(const struct dstr *str1, const char *str2,
|
||||
const size_t n);
|
||||
static inline int dstr_ncmpi(const struct dstr *str1, const char *str2,
|
||||
const size_t n);
|
||||
|
||||
EXPORT void dstr_depad(struct dstr *dst);
|
||||
|
||||
EXPORT void dstr_left(struct dstr *dst, const struct dstr *str,
|
||||
const size_t pos);
|
||||
EXPORT void dstr_mid(struct dstr *dst, const struct dstr *str,
|
||||
const size_t start, const size_t count);
|
||||
EXPORT void dstr_right(struct dstr *dst, const struct dstr *str,
|
||||
const size_t pos);
|
||||
|
||||
static inline char dstr_end(const struct dstr *str);
|
||||
|
||||
EXPORT void dstr_from_mbs(struct dstr *dst, const char *mbstr);
|
||||
EXPORT char *dstr_to_mbs(const struct dstr *str);
|
||||
EXPORT void dstr_from_wcs(struct dstr *dst, const wchar_t *wstr);
|
||||
EXPORT wchar_t *dstr_to_wcs(const struct dstr *str);
|
||||
|
||||
EXPORT void dstr_to_upper(struct dstr *str);
|
||||
EXPORT void dstr_to_lower(struct dstr *str);
|
||||
|
||||
#undef PRINTFATTR
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static inline void dstr_init(struct dstr *dst)
|
||||
{
|
||||
dst->array = NULL;
|
||||
dst->len = 0;
|
||||
dst->capacity = 0;
|
||||
}
|
||||
|
||||
static inline void dstr_init_move_array(struct dstr *dst, char *str)
|
||||
{
|
||||
dst->array = str;
|
||||
dst->len = (!str) ? 0 : strlen(str);
|
||||
dst->capacity = dst->len + 1;
|
||||
}
|
||||
|
||||
static inline void dstr_init_move(struct dstr *dst, struct dstr *src)
|
||||
{
|
||||
*dst = *src;
|
||||
dstr_init(src);
|
||||
}
|
||||
|
||||
static inline void dstr_init_copy(struct dstr *dst, const char *str)
|
||||
{
|
||||
dstr_init(dst);
|
||||
dstr_copy(dst, str);
|
||||
}
|
||||
|
||||
static inline void dstr_init_copy_dstr(struct dstr *dst, const struct dstr *src)
|
||||
{
|
||||
dstr_init(dst);
|
||||
dstr_copy_dstr(dst, src);
|
||||
}
|
||||
|
||||
static inline void dstr_free(struct dstr *dst)
|
||||
{
|
||||
bfree(dst->array);
|
||||
dst->array = NULL;
|
||||
dst->len = 0;
|
||||
dst->capacity = 0;
|
||||
}
|
||||
|
||||
static inline void dstr_array_free(struct dstr *array, const size_t count)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++)
|
||||
dstr_free(array+i);
|
||||
}
|
||||
|
||||
static inline void dstr_move_array(struct dstr *dst, char *str)
|
||||
{
|
||||
dstr_free(dst);
|
||||
dst->array = str;
|
||||
dst->len = (!str) ? 0 : strlen(str);
|
||||
dst->capacity = dst->len + 1;
|
||||
}
|
||||
|
||||
static inline void dstr_move(struct dstr *dst, struct dstr *src)
|
||||
{
|
||||
dstr_free(dst);
|
||||
dstr_init_move(dst, src);
|
||||
}
|
||||
|
||||
static inline void dstr_ensure_capacity(struct dstr *dst, const size_t new_size)
|
||||
{
|
||||
size_t new_cap;
|
||||
if (new_size <= dst->capacity)
|
||||
return;
|
||||
|
||||
new_cap = (!dst->capacity) ? new_size : dst->capacity*2;
|
||||
if (new_size > new_cap)
|
||||
new_cap = new_size;
|
||||
dst->array = (char*)brealloc(dst->array, new_cap);
|
||||
dst->capacity = new_cap;
|
||||
}
|
||||
|
||||
static inline void dstr_copy_dstr(struct dstr *dst, const struct dstr *src)
|
||||
{
|
||||
if (dst->array)
|
||||
dstr_free(dst);
|
||||
|
||||
dstr_ensure_capacity(dst, src->len + 1);
|
||||
memcpy(dst->array, src->array, src->len + 1);
|
||||
dst->len = src->len;
|
||||
}
|
||||
|
||||
static inline void dstr_reserve(struct dstr *dst, const size_t capacity)
|
||||
{
|
||||
if (capacity == 0 || capacity <= dst->len)
|
||||
return;
|
||||
|
||||
dst->array = (char*)brealloc(dst->array, capacity);
|
||||
dst->capacity = capacity;
|
||||
}
|
||||
|
||||
static inline void dstr_resize(struct dstr *dst, const size_t num)
|
||||
{
|
||||
if (!num) {
|
||||
dstr_free(dst);
|
||||
return;
|
||||
}
|
||||
|
||||
dstr_ensure_capacity(dst, num + 1);
|
||||
dst->array[num] = 0;
|
||||
dst->len = num;
|
||||
}
|
||||
|
||||
static inline bool dstr_is_empty(const struct dstr *str)
|
||||
{
|
||||
if (!str->array || !str->len)
|
||||
return true;
|
||||
if (!*str->array)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void dstr_cat(struct dstr *dst, const char *array)
|
||||
{
|
||||
size_t len;
|
||||
if (!array || !*array)
|
||||
return;
|
||||
|
||||
len = strlen(array);
|
||||
dstr_ncat(dst, array, len);
|
||||
}
|
||||
|
||||
static inline void dstr_cat_ch(struct dstr *dst, char ch)
|
||||
{
|
||||
dstr_ensure_capacity(dst, ++dst->len + 1);
|
||||
dst->array[dst->len-1] = ch;
|
||||
dst->array[dst->len] = 0;
|
||||
}
|
||||
|
||||
static inline const char *dstr_find_i(const struct dstr *str, const char *find)
|
||||
{
|
||||
return astrstri(str->array, find);
|
||||
}
|
||||
|
||||
static inline const char *dstr_find(const struct dstr *str, const char *find)
|
||||
{
|
||||
return strstr(str->array, find);
|
||||
}
|
||||
|
||||
static inline int dstr_cmp(const struct dstr *str1, const char *str2)
|
||||
{
|
||||
return strcmp(str1->array, str2);
|
||||
}
|
||||
|
||||
static inline int dstr_cmpi(const struct dstr *str1, const char *str2)
|
||||
{
|
||||
return astrcmpi(str1->array, str2);
|
||||
}
|
||||
|
||||
static inline int dstr_ncmp(const struct dstr *str1, const char *str2,
|
||||
const size_t n)
|
||||
{
|
||||
return astrcmp_n(str1->array, str2, n);
|
||||
}
|
||||
|
||||
static inline int dstr_ncmpi(const struct dstr *str1, const char *str2,
|
||||
const size_t n)
|
||||
{
|
||||
return astrcmpi_n(str1->array, str2, n);
|
||||
}
|
||||
|
||||
static inline char dstr_end(const struct dstr *str)
|
||||
{
|
||||
if (dstr_is_empty(str))
|
||||
return 0;
|
||||
|
||||
return str->array[str->len - 1];
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
49
libobs/util/dstr.hpp
Normal file
49
libobs/util/dstr.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dstr.h"
|
||||
|
||||
class DStr {
|
||||
dstr str;
|
||||
|
||||
DStr(DStr const&) = delete;
|
||||
DStr &operator=(DStr const&) = delete;
|
||||
|
||||
public:
|
||||
inline DStr() {dstr_init(&str);}
|
||||
inline DStr(DStr &&other) : DStr()
|
||||
{
|
||||
dstr_move(&str, &other.str);
|
||||
}
|
||||
|
||||
inline DStr &operator=(DStr &&other)
|
||||
{
|
||||
dstr_move(&str, &other.str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline ~DStr() {dstr_free(&str);}
|
||||
|
||||
inline operator dstr*() {return &str;}
|
||||
inline operator const dstr*() const {return &str;}
|
||||
|
||||
inline operator char*() {return str.array;}
|
||||
inline operator const char*() const {return str.array;}
|
||||
|
||||
inline dstr *operator->() {return &str;}
|
||||
};
|
||||
174
libobs/util/file-serializer.c
Normal file
174
libobs/util/file-serializer.c
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dstr.h"
|
||||
#include "file-serializer.h"
|
||||
#include "platform.h"
|
||||
|
||||
static size_t file_input_read(void *file, void *data, size_t size)
|
||||
{
|
||||
return fread(data, 1, size, file);
|
||||
}
|
||||
|
||||
static int64_t file_input_seek(void *file, int64_t offset,
|
||||
enum serialize_seek_type seek_type)
|
||||
{
|
||||
int origin = SEEK_SET;
|
||||
|
||||
switch (seek_type) {
|
||||
case SERIALIZE_SEEK_START: origin = SEEK_SET; break;
|
||||
case SERIALIZE_SEEK_CURRENT: origin = SEEK_CUR; break;
|
||||
case SERIALIZE_SEEK_END: origin = SEEK_END; break;
|
||||
}
|
||||
|
||||
if (os_fseeki64(file, offset, origin) == -1)
|
||||
return -1;
|
||||
|
||||
return os_ftelli64(file);
|
||||
}
|
||||
|
||||
static int64_t file_input_get_pos(void *file)
|
||||
{
|
||||
return os_ftelli64(file);
|
||||
}
|
||||
|
||||
bool file_input_serializer_init(struct serializer *s, const char *path)
|
||||
{
|
||||
s->data = os_fopen(path, "rb");
|
||||
if (!s->data)
|
||||
return false;
|
||||
|
||||
s->read = file_input_read;
|
||||
s->write = NULL;
|
||||
s->seek = file_input_seek;
|
||||
s->get_pos = file_input_get_pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
void file_input_serializer_free(struct serializer *s)
|
||||
{
|
||||
if (s->data)
|
||||
fclose(s->data);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct file_output_data {
|
||||
FILE *file;
|
||||
char *temp_name;
|
||||
char *file_name;
|
||||
};
|
||||
|
||||
static size_t file_output_write(void *sdata, const void *data, size_t size)
|
||||
{
|
||||
struct file_output_data *out = sdata;
|
||||
return fwrite(data, 1, size, out->file);
|
||||
}
|
||||
|
||||
static int64_t file_output_seek(void *sdata, int64_t offset,
|
||||
enum serialize_seek_type seek_type)
|
||||
{
|
||||
struct file_output_data *out = sdata;
|
||||
int origin = SEEK_SET;
|
||||
|
||||
switch (seek_type) {
|
||||
case SERIALIZE_SEEK_START: origin = SEEK_SET; break;
|
||||
case SERIALIZE_SEEK_CURRENT: origin = SEEK_CUR; break;
|
||||
case SERIALIZE_SEEK_END: origin = SEEK_END; break;
|
||||
}
|
||||
|
||||
if (os_fseeki64(out->file, offset, origin) == -1)
|
||||
return -1;
|
||||
|
||||
return os_ftelli64(out->file);
|
||||
}
|
||||
|
||||
static int64_t file_output_get_pos(void *sdata)
|
||||
{
|
||||
struct file_output_data *out = sdata;
|
||||
return os_ftelli64(out->file);
|
||||
}
|
||||
|
||||
bool file_output_serializer_init(struct serializer *s, const char *path)
|
||||
{
|
||||
FILE *file = os_fopen(path, "wb");
|
||||
struct file_output_data *out;
|
||||
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
out = bzalloc(sizeof(*out));
|
||||
out->file = file;
|
||||
|
||||
s->data = out;
|
||||
s->read = NULL;
|
||||
s->write = file_output_write;
|
||||
s->seek = file_output_seek;
|
||||
s->get_pos = file_output_get_pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool file_output_serializer_init_safe(struct serializer *s,
|
||||
const char *path, const char *temp_ext)
|
||||
{
|
||||
struct dstr temp_name = {0};
|
||||
struct file_output_data *out;
|
||||
FILE *file;
|
||||
|
||||
if (!temp_ext || !*temp_ext)
|
||||
return false;
|
||||
|
||||
dstr_copy(&temp_name, path);
|
||||
if (*temp_ext != '.')
|
||||
dstr_cat_ch(&temp_name, '.');
|
||||
dstr_cat(&temp_name, temp_ext);
|
||||
|
||||
file = os_fopen(temp_name.array, "wb");
|
||||
if (!file) {
|
||||
dstr_free(&temp_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
out = bzalloc(sizeof(*out));
|
||||
out->file_name = bstrdup(path);
|
||||
out->temp_name = temp_name.array;
|
||||
out->file = file;
|
||||
|
||||
s->data = out;
|
||||
s->read = NULL;
|
||||
s->write = file_output_write;
|
||||
s->seek = file_output_seek;
|
||||
s->get_pos = file_output_get_pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
void file_output_serializer_free(struct serializer *s)
|
||||
{
|
||||
struct file_output_data *out = s->data;
|
||||
|
||||
if (out) {
|
||||
fclose(out->file);
|
||||
|
||||
if (out->temp_name) {
|
||||
os_unlink(out->file_name);
|
||||
os_rename(out->temp_name, out->file_name);
|
||||
}
|
||||
|
||||
bfree(out->file_name);
|
||||
bfree(out->temp_name);
|
||||
bfree(out);
|
||||
}
|
||||
}
|
||||
27
libobs/util/file-serializer.h
Normal file
27
libobs/util/file-serializer.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "serializer.h"
|
||||
|
||||
EXPORT bool file_input_serializer_init(struct serializer *s, const char *path);
|
||||
EXPORT void file_input_serializer_free(struct serializer *s);
|
||||
|
||||
EXPORT bool file_output_serializer_init(struct serializer *s, const char *path);
|
||||
EXPORT bool file_output_serializer_init_safe(struct serializer *s,
|
||||
const char *path, const char *temp_ext);
|
||||
EXPORT void file_output_serializer_free(struct serializer *s);
|
||||
311
libobs/util/lexer.c
Normal file
311
libobs/util/lexer.c
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "lexer.h"
|
||||
|
||||
static const char *astrblank = "";
|
||||
|
||||
int strref_cmp(const struct strref *str1, const char *str2)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (strref_is_empty(str1))
|
||||
return (!str2 || !*str2) ? 0 : -1;
|
||||
if (!str2)
|
||||
str2 = astrblank;
|
||||
|
||||
do {
|
||||
char ch1, ch2;
|
||||
|
||||
ch1 = (i < str1->len) ? str1->array[i] : 0;
|
||||
ch2 = *str2;
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (i++ < str1->len && *str2++);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strref_cmpi(const struct strref *str1, const char *str2)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (strref_is_empty(str1))
|
||||
return (!str2 || !*str2) ? 0 : -1;
|
||||
if (!str2)
|
||||
str2 = astrblank;
|
||||
|
||||
do {
|
||||
char ch1, ch2;
|
||||
|
||||
ch1 = (i < str1->len) ? (char)toupper(str1->array[i]) : 0;
|
||||
ch2 = (char)toupper(*str2);
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
} while (i++ < str1->len && *str2++);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strref_cmp_strref(const struct strref *str1, const struct strref *str2)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (strref_is_empty(str1))
|
||||
return strref_is_empty(str2) ? 0 : -1;
|
||||
if (strref_is_empty(str2))
|
||||
return -1;
|
||||
|
||||
do {
|
||||
char ch1, ch2;
|
||||
|
||||
ch1 = (i < str1->len) ? str1->array[i] : 0;
|
||||
ch2 = (i < str2->len) ? str2->array[i] : 0;
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
|
||||
i++;
|
||||
} while (i <= str1->len && i <= str2->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strref_cmpi_strref(const struct strref *str1, const struct strref *str2)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (strref_is_empty(str1))
|
||||
return strref_is_empty(str2) ? 0 : -1;
|
||||
if (strref_is_empty(str2))
|
||||
return -1;
|
||||
|
||||
do {
|
||||
char ch1, ch2;
|
||||
|
||||
ch1 = (i < str1->len) ? (char)toupper(str1->array[i]) : 0;
|
||||
ch2 = (i < str2->len) ? (char)toupper(str2->array[i]) : 0;
|
||||
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
|
||||
i++;
|
||||
} while (i <= str1->len && i <= str2->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
bool valid_int_str(const char *str, size_t n)
|
||||
{
|
||||
bool found_num = false;
|
||||
|
||||
if (!str)
|
||||
return false;
|
||||
if (!*str)
|
||||
return false;
|
||||
|
||||
if (!n)
|
||||
n = strlen(str);
|
||||
if (*str == '-' || *str == '+')
|
||||
++str;
|
||||
|
||||
do {
|
||||
if (*str > '9' || *str < '0')
|
||||
return false;
|
||||
|
||||
found_num = true;
|
||||
} while(*++str && --n);
|
||||
|
||||
return found_num;
|
||||
}
|
||||
|
||||
bool valid_float_str(const char *str, size_t n)
|
||||
{
|
||||
bool found_num = false;
|
||||
bool found_exp = false;
|
||||
bool found_dec = false;
|
||||
|
||||
if (!str)
|
||||
return false;
|
||||
if (!*str)
|
||||
return false;
|
||||
|
||||
if (!n)
|
||||
n = strlen(str);
|
||||
if (*str == '-' || *str == '+')
|
||||
++str;
|
||||
|
||||
do {
|
||||
if (*str == '.') {
|
||||
if (found_dec || found_exp || !found_num)
|
||||
return false;
|
||||
|
||||
found_dec = true;
|
||||
|
||||
} else if (*str == 'e') {
|
||||
if (found_exp || !found_num)
|
||||
return false;
|
||||
|
||||
found_exp = true;
|
||||
found_num = false;
|
||||
|
||||
} else if (*str == '-' || *str == '+') {
|
||||
if (!found_exp || !found_num)
|
||||
return false;
|
||||
|
||||
} else if (*str > '9' || *str < '0') {
|
||||
return false;
|
||||
} else {
|
||||
found_num = true;
|
||||
}
|
||||
} while(*++str && --n);
|
||||
|
||||
return found_num;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void error_data_add(struct error_data *data, const char *file,
|
||||
uint32_t row, uint32_t column, const char *msg, int level)
|
||||
{
|
||||
struct error_item item;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
item.file = file;
|
||||
item.row = row;
|
||||
item.column = column;
|
||||
item.level = level;
|
||||
item.error = bstrdup(msg);
|
||||
|
||||
da_push_back(data->errors, &item);
|
||||
}
|
||||
|
||||
char *error_data_buildstring(struct error_data *ed)
|
||||
{
|
||||
struct dstr str;
|
||||
struct error_item *items = ed->errors.array;
|
||||
size_t i;
|
||||
|
||||
dstr_init(&str);
|
||||
for (i = 0; i < ed->errors.num; i++) {
|
||||
struct error_item *item = items+i;
|
||||
dstr_catf(&str, "%s (%u, %u): %s\n", item->file, item->row,
|
||||
item->column, item->error);
|
||||
}
|
||||
|
||||
return str.array;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static inline enum base_token_type get_char_token_type(const char ch)
|
||||
{
|
||||
if (is_whitespace(ch))
|
||||
return BASETOKEN_WHITESPACE;
|
||||
else if (ch >= '0' && ch <= '9')
|
||||
return BASETOKEN_DIGIT;
|
||||
else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
|
||||
return BASETOKEN_ALPHA;
|
||||
|
||||
return BASETOKEN_OTHER;
|
||||
}
|
||||
|
||||
bool lexer_getbasetoken(struct lexer *lex, struct base_token *token,
|
||||
enum ignore_whitespace iws)
|
||||
{
|
||||
const char *offset = lex->offset;
|
||||
const char *token_start = NULL;
|
||||
enum base_token_type type = BASETOKEN_NONE;
|
||||
bool ignore_whitespace = (iws == IGNORE_WHITESPACE);
|
||||
|
||||
if (!offset)
|
||||
return false;
|
||||
|
||||
while (*offset != 0) {
|
||||
char ch = *(offset++);
|
||||
enum base_token_type new_type = get_char_token_type(ch);
|
||||
|
||||
if (type == BASETOKEN_NONE) {
|
||||
if (new_type == BASETOKEN_WHITESPACE &&
|
||||
ignore_whitespace)
|
||||
continue;
|
||||
|
||||
token_start = offset-1;
|
||||
type = new_type;
|
||||
|
||||
if (type != BASETOKEN_DIGIT &&
|
||||
type != BASETOKEN_ALPHA) {
|
||||
if (is_newline(ch) &&
|
||||
is_newline_pair(ch, *offset)) {
|
||||
offset++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (type != new_type) {
|
||||
offset--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lex->offset = offset;
|
||||
|
||||
if (token_start && offset > token_start) {
|
||||
strref_set(&token->text, token_start, offset-token_start);
|
||||
token->type = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void lexer_getstroffset(const struct lexer *lex, const char *str,
|
||||
uint32_t *row, uint32_t *col)
|
||||
{
|
||||
uint32_t cur_col = 1, cur_row = 1;
|
||||
const char *text = lex->text;
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
|
||||
while (text < str) {
|
||||
if (is_newline(*text)) {
|
||||
text += newline_size(text)-1;
|
||||
cur_col = 1;
|
||||
cur_row++;
|
||||
} else {
|
||||
cur_col++;
|
||||
}
|
||||
|
||||
text++;
|
||||
}
|
||||
|
||||
*row = cur_row;
|
||||
*col = cur_col;
|
||||
}
|
||||
284
libobs/util/lexer.h
Normal file
284
libobs/util/lexer.h
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "c99defs.h"
|
||||
#include "dstr.h"
|
||||
#include "darray.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* string reference (string segment within an already existing array) */
|
||||
|
||||
struct strref {
|
||||
const char *array;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static inline void strref_clear(struct strref *dst)
|
||||
{
|
||||
dst->array = NULL;
|
||||
dst->len = 0;
|
||||
}
|
||||
|
||||
static inline void strref_set(struct strref *dst, const char *array, size_t len)
|
||||
{
|
||||
dst->array = array;
|
||||
dst->len = len;
|
||||
}
|
||||
|
||||
static inline void strref_copy(struct strref *dst, const struct strref *src)
|
||||
{
|
||||
dst->array = src->array;
|
||||
dst->len = src->len;
|
||||
}
|
||||
|
||||
static inline void strref_add(struct strref *dst, const struct strref *t)
|
||||
{
|
||||
if (!dst->array)
|
||||
strref_copy(dst, t);
|
||||
else
|
||||
dst->len += t->len;
|
||||
}
|
||||
|
||||
static inline bool strref_is_empty(const struct strref *str)
|
||||
{
|
||||
return !str || !str->array || !str->len || !*str->array;
|
||||
}
|
||||
|
||||
EXPORT int strref_cmp(const struct strref *str1, const char *str2);
|
||||
EXPORT int strref_cmpi(const struct strref *str1, const char *str2);
|
||||
EXPORT int strref_cmp_strref(const struct strref *str1,
|
||||
const struct strref *str2);
|
||||
EXPORT int strref_cmpi_strref(const struct strref *str1,
|
||||
const struct strref *str2);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
EXPORT bool valid_int_str(const char *str, size_t n);
|
||||
EXPORT bool valid_float_str(const char *str, size_t n);
|
||||
|
||||
static inline bool valid_int_strref(const struct strref *str)
|
||||
{
|
||||
return valid_int_str(str->array, str->len);
|
||||
}
|
||||
|
||||
static inline bool valid_float_strref(const struct strref *str)
|
||||
{
|
||||
return valid_float_str(str->array, str->len);
|
||||
}
|
||||
|
||||
static inline bool is_whitespace(char ch)
|
||||
{
|
||||
return ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n';
|
||||
}
|
||||
|
||||
static inline bool is_newline(char ch)
|
||||
{
|
||||
return ch == '\r' || ch == '\n';
|
||||
}
|
||||
|
||||
static inline bool is_space_or_tab(const char ch)
|
||||
{
|
||||
return ch == ' ' || ch == '\t';
|
||||
}
|
||||
|
||||
static inline bool is_newline_pair(char ch1, char ch2)
|
||||
{
|
||||
return (ch1 == '\r' && ch2 == '\n') ||
|
||||
(ch1 == '\n' && ch2 == '\r');
|
||||
}
|
||||
|
||||
static inline int newline_size(const char *array)
|
||||
{
|
||||
if (strncmp(array, "\r\n", 2) == 0 || strncmp(array, "\n\r", 2) == 0)
|
||||
return 2;
|
||||
else if (*array == '\r' || *array == '\n')
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* A "base" token is one of four things:
|
||||
* 1.) A sequence of alpha characters
|
||||
* 2.) A sequence of numeric characters
|
||||
* 3.) A single whitespace character if whitespace is not ignored
|
||||
* 4.) A single character that does not fall into the above 3 categories
|
||||
*/
|
||||
|
||||
enum base_token_type {
|
||||
BASETOKEN_NONE,
|
||||
BASETOKEN_ALPHA,
|
||||
BASETOKEN_DIGIT,
|
||||
BASETOKEN_WHITESPACE,
|
||||
BASETOKEN_OTHER,
|
||||
};
|
||||
|
||||
struct base_token {
|
||||
struct strref text;
|
||||
enum base_token_type type;
|
||||
bool passed_whitespace;
|
||||
};
|
||||
|
||||
static inline void base_token_clear(struct base_token *t)
|
||||
{
|
||||
memset(t, 0, sizeof(struct base_token));
|
||||
}
|
||||
|
||||
static inline void base_token_copy(struct base_token *dst,
|
||||
struct base_token *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(struct base_token));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define LEX_ERROR 0
|
||||
#define LEX_WARNING 1
|
||||
|
||||
struct error_item {
|
||||
char *error;
|
||||
const char *file;
|
||||
uint32_t row, column;
|
||||
int level;
|
||||
};
|
||||
|
||||
static inline void error_item_init(struct error_item *ei)
|
||||
{
|
||||
memset(ei, 0, sizeof(struct error_item));
|
||||
}
|
||||
|
||||
static inline void error_item_free(struct error_item *ei)
|
||||
{
|
||||
bfree(ei->error);
|
||||
error_item_init(ei);
|
||||
}
|
||||
|
||||
static inline void error_item_array_free(struct error_item *array, size_t num)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < num; i++)
|
||||
error_item_free(array+i);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct error_data {
|
||||
DARRAY(struct error_item) errors;
|
||||
};
|
||||
|
||||
static inline void error_data_init(struct error_data *data)
|
||||
{
|
||||
da_init(data->errors);
|
||||
}
|
||||
|
||||
static inline void error_data_free(struct error_data *data)
|
||||
{
|
||||
error_item_array_free(data->errors.array, data->errors.num);
|
||||
da_free(data->errors);
|
||||
}
|
||||
|
||||
static inline const struct error_item *error_data_item(struct error_data *ed,
|
||||
size_t idx)
|
||||
{
|
||||
return ed->errors.array+idx;
|
||||
}
|
||||
|
||||
EXPORT char *error_data_buildstring(struct error_data *ed);
|
||||
|
||||
EXPORT void error_data_add(struct error_data *ed, const char *file,
|
||||
uint32_t row, uint32_t column, const char *msg, int level);
|
||||
|
||||
static inline size_t error_data_type_count(struct error_data *ed,
|
||||
int type)
|
||||
{
|
||||
size_t count = 0, i;
|
||||
for (i = 0; i < ed->errors.num; i++) {
|
||||
if (ed->errors.array[i].level == type)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline bool error_data_has_errors(struct error_data *ed)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < ed->errors.num; i++)
|
||||
if (ed->errors.array[i].level == LEX_ERROR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct lexer {
|
||||
char *text;
|
||||
const char *offset;
|
||||
};
|
||||
|
||||
static inline void lexer_init(struct lexer *lex)
|
||||
{
|
||||
memset(lex, 0, sizeof(struct lexer));
|
||||
}
|
||||
|
||||
static inline void lexer_free(struct lexer *lex)
|
||||
{
|
||||
bfree(lex->text);
|
||||
lexer_init(lex);
|
||||
}
|
||||
|
||||
static inline void lexer_start(struct lexer *lex, const char *text)
|
||||
{
|
||||
lexer_free(lex);
|
||||
lex->text = bstrdup(text);
|
||||
lex->offset = lex->text;
|
||||
}
|
||||
|
||||
static inline void lexer_start_move(struct lexer *lex, char *text)
|
||||
{
|
||||
lexer_free(lex);
|
||||
lex->text = text;
|
||||
lex->offset = lex->text;
|
||||
}
|
||||
|
||||
static inline void lexer_reset(struct lexer *lex)
|
||||
{
|
||||
lex->offset = lex->text;
|
||||
}
|
||||
|
||||
enum ignore_whitespace {
|
||||
PARSE_WHITESPACE,
|
||||
IGNORE_WHITESPACE
|
||||
};
|
||||
|
||||
EXPORT bool lexer_getbasetoken(struct lexer *lex, struct base_token *t,
|
||||
enum ignore_whitespace iws);
|
||||
|
||||
EXPORT void lexer_getstroffset(const struct lexer *lex, const char *str,
|
||||
uint32_t *row, uint32_t *col);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
87
libobs/util/pipe-posix.c
Normal file
87
libobs/util/pipe-posix.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "bmem.h"
|
||||
#include "pipe.h"
|
||||
|
||||
struct os_process_pipe {
|
||||
bool read_pipe;
|
||||
FILE *file;
|
||||
};
|
||||
|
||||
os_process_pipe_t *os_process_pipe_create(const char *cmd_line,
|
||||
const char *type)
|
||||
{
|
||||
struct os_process_pipe pipe = {0};
|
||||
struct os_process_pipe *out;
|
||||
|
||||
if (!cmd_line || !type) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pipe.file = popen(cmd_line, type);
|
||||
pipe.read_pipe = *type == 'r';
|
||||
|
||||
if (pipe.file == (FILE*)-1 || pipe.file == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out = bmalloc(sizeof(pipe));
|
||||
*out = pipe;
|
||||
return out;
|
||||
}
|
||||
|
||||
int os_process_pipe_destroy(os_process_pipe_t *pp)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (pp) {
|
||||
int status = pclose(pp->file);
|
||||
if (WIFEXITED(status))
|
||||
ret = (int)(char)WEXITSTATUS(status);
|
||||
bfree(pp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t os_process_pipe_read(os_process_pipe_t *pp, uint8_t *data, size_t len)
|
||||
{
|
||||
if (!pp) {
|
||||
return 0;
|
||||
}
|
||||
if (!pp->read_pipe) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fread(data, 1, len, pp->file);
|
||||
}
|
||||
|
||||
size_t os_process_pipe_write(os_process_pipe_t *pp, const uint8_t *data,
|
||||
size_t len)
|
||||
{
|
||||
if (!pp) {
|
||||
return 0;
|
||||
}
|
||||
if (pp->read_pipe) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fwrite(data, 1, len, pp->file);
|
||||
}
|
||||
181
libobs/util/pipe-windows.c
Normal file
181
libobs/util/pipe-windows.c
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include "platform.h"
|
||||
#include "bmem.h"
|
||||
#include "pipe.h"
|
||||
|
||||
struct os_process_pipe {
|
||||
bool read_pipe;
|
||||
HANDLE handle;
|
||||
HANDLE process;
|
||||
};
|
||||
|
||||
static bool create_pipe(HANDLE *input, HANDLE *output)
|
||||
{
|
||||
SECURITY_ATTRIBUTES sa = {0};
|
||||
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.bInheritHandle = true;
|
||||
|
||||
if (!CreatePipe(input, output, &sa, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool create_process(const char *cmd_line, HANDLE stdin_handle,
|
||||
HANDLE stdout_handle, HANDLE *process)
|
||||
{
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
wchar_t *cmd_line_w = NULL;
|
||||
STARTUPINFOW si = {0};
|
||||
bool success = false;
|
||||
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.hStdInput = stdin_handle;
|
||||
si.hStdOutput = stdout_handle;
|
||||
|
||||
os_utf8_to_wcs_ptr(cmd_line, 0, &cmd_line_w);
|
||||
if (cmd_line_w) {
|
||||
success = !!CreateProcessW(NULL, cmd_line_w, NULL, NULL, true,
|
||||
CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
|
||||
|
||||
if (success) {
|
||||
*process = pi.hProcess;
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
bfree(cmd_line_w);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
os_process_pipe_t *os_process_pipe_create(const char *cmd_line,
|
||||
const char *type)
|
||||
{
|
||||
os_process_pipe_t *pp = NULL;
|
||||
bool read_pipe;
|
||||
HANDLE process;
|
||||
HANDLE output;
|
||||
HANDLE input;
|
||||
bool success;
|
||||
|
||||
if (!cmd_line || !type) {
|
||||
return NULL;
|
||||
}
|
||||
if (*type != 'r' && *type != 'w') {
|
||||
return NULL;
|
||||
}
|
||||
if (!create_pipe(&input, &output)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
read_pipe = *type == 'r';
|
||||
|
||||
success = !!SetHandleInformation(read_pipe ? input : output,
|
||||
HANDLE_FLAG_INHERIT, false);
|
||||
if (!success) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
success = create_process(cmd_line, read_pipe ? NULL : input,
|
||||
read_pipe ? output : NULL, &process);
|
||||
if (!success) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
pp = bmalloc(sizeof(*pp));
|
||||
pp->handle = read_pipe ? input : output;
|
||||
pp->read_pipe = read_pipe;
|
||||
pp->process = process;
|
||||
|
||||
CloseHandle(read_pipe ? output : input);
|
||||
return pp;
|
||||
|
||||
error:
|
||||
CloseHandle(output);
|
||||
CloseHandle(input);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int os_process_pipe_destroy(os_process_pipe_t *pp)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (pp) {
|
||||
DWORD code;
|
||||
|
||||
CloseHandle(pp->handle);
|
||||
|
||||
WaitForSingleObject(pp->process, INFINITE);
|
||||
if (GetExitCodeProcess(pp->process, &code))
|
||||
ret = (int)code;
|
||||
|
||||
CloseHandle(pp->process);
|
||||
bfree(pp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t os_process_pipe_read(os_process_pipe_t *pp, uint8_t *data, size_t len)
|
||||
{
|
||||
DWORD bytes_read;
|
||||
bool success;
|
||||
|
||||
if (!pp) {
|
||||
return 0;
|
||||
}
|
||||
if (!pp->read_pipe) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
success = !!ReadFile(pp->handle, data, (DWORD)len, &bytes_read, NULL);
|
||||
if (success && bytes_read) {
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t os_process_pipe_write(os_process_pipe_t *pp, const uint8_t *data,
|
||||
size_t len)
|
||||
{
|
||||
DWORD bytes_written;
|
||||
bool success;
|
||||
|
||||
if (!pp) {
|
||||
return 0;
|
||||
}
|
||||
if (pp->read_pipe) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
success = !!WriteFile(pp->handle, data, (DWORD)len, &bytes_written,
|
||||
NULL);
|
||||
if (success && bytes_written) {
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
31
libobs/util/pipe.h
Normal file
31
libobs/util/pipe.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "c99defs.h"
|
||||
|
||||
struct os_process_pipe;
|
||||
typedef struct os_process_pipe os_process_pipe_t;
|
||||
|
||||
EXPORT os_process_pipe_t *os_process_pipe_create(const char *cmd_line,
|
||||
const char *type);
|
||||
EXPORT int os_process_pipe_destroy(os_process_pipe_t *pp);
|
||||
|
||||
EXPORT size_t os_process_pipe_read(os_process_pipe_t *pp, uint8_t *data,
|
||||
size_t len);
|
||||
EXPORT size_t os_process_pipe_write(os_process_pipe_t *pp, const uint8_t *data,
|
||||
size_t len);
|
||||
292
libobs/util/platform-cocoa.m
Normal file
292
libobs/util/platform-cocoa.m
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014 Ruwen Hahn <palana@stunned.de>
|
||||
* Hugh "Jim" Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "base.h"
|
||||
#include "platform.h"
|
||||
#include "dstr.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
/* clock function selection taken from libc++ */
|
||||
static uint64_t ns_time_simple()
|
||||
{
|
||||
return mach_absolute_time();
|
||||
}
|
||||
|
||||
static double ns_time_compute_factor()
|
||||
{
|
||||
mach_timebase_info_data_t info = {1, 1};
|
||||
mach_timebase_info(&info);
|
||||
return ((double)info.numer) / info.denom;
|
||||
}
|
||||
|
||||
static uint64_t ns_time_full()
|
||||
{
|
||||
static double factor = 0.;
|
||||
if (factor == 0.) factor = ns_time_compute_factor();
|
||||
return (uint64_t)(mach_absolute_time() * factor);
|
||||
}
|
||||
|
||||
typedef uint64_t (*time_func)();
|
||||
|
||||
static time_func ns_time_select_func()
|
||||
{
|
||||
mach_timebase_info_data_t info = {1, 1};
|
||||
mach_timebase_info(&info);
|
||||
if (info.denom == info.numer)
|
||||
return ns_time_simple;
|
||||
return ns_time_full;
|
||||
}
|
||||
|
||||
uint64_t os_gettime_ns(void)
|
||||
{
|
||||
static time_func f = NULL;
|
||||
if (!f) f = ns_time_select_func();
|
||||
return f();
|
||||
}
|
||||
|
||||
/* gets the location ~/Library/Application Support/[name] */
|
||||
int os_get_config_path(char *dst, size_t size, const char *name)
|
||||
{
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(
|
||||
NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
|
||||
if([paths count] == 0)
|
||||
bcrash("Could not get home directory (platform-cocoa)");
|
||||
|
||||
NSString *application_support = paths[0];
|
||||
const char *base_path = [application_support UTF8String];
|
||||
|
||||
if (!name || !*name)
|
||||
return snprintf(dst, size, "%s", base_path);
|
||||
else
|
||||
return snprintf(dst, size, "%s/%s", base_path, name);
|
||||
}
|
||||
|
||||
char *os_get_config_path_ptr(const char *name)
|
||||
{
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(
|
||||
NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
|
||||
if([paths count] == 0)
|
||||
bcrash("Could not get home directory (platform-cocoa)");
|
||||
|
||||
NSString *application_support = paths[0];
|
||||
|
||||
NSUInteger len = [application_support
|
||||
lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
char *path_ptr = bmalloc(len+1);
|
||||
|
||||
path_ptr[len] = 0;
|
||||
|
||||
memcpy(path_ptr, [application_support UTF8String], len);
|
||||
|
||||
struct dstr path;
|
||||
dstr_init_move_array(&path, path_ptr);
|
||||
dstr_cat(&path, "/");
|
||||
dstr_cat(&path, name);
|
||||
return path.array;
|
||||
}
|
||||
|
||||
struct os_cpu_usage_info {
|
||||
int64_t last_cpu_time;
|
||||
int64_t last_sys_time;
|
||||
int core_count;
|
||||
};
|
||||
|
||||
static inline void add_time_value(time_value_t *dst, time_value_t *a,
|
||||
time_value_t *b)
|
||||
{
|
||||
dst->microseconds = a->microseconds + b->microseconds;
|
||||
dst->seconds = a->seconds + b->seconds;
|
||||
|
||||
if (dst->microseconds >= 1000000) {
|
||||
dst->seconds += dst->microseconds / 1000000;
|
||||
dst->microseconds %= 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_time_info(int64_t *cpu_time, int64_t *sys_time)
|
||||
{
|
||||
mach_port_t task = mach_task_self();
|
||||
struct task_thread_times_info thread_data;
|
||||
struct task_basic_info_64 task_data;
|
||||
mach_msg_type_number_t count;
|
||||
kern_return_t kern_ret;
|
||||
time_value_t cur_time;
|
||||
|
||||
*cpu_time = 0;
|
||||
*sys_time = 0;
|
||||
|
||||
count = TASK_THREAD_TIMES_INFO_COUNT;
|
||||
kern_ret = task_info(task, TASK_THREAD_TIMES_INFO,
|
||||
(task_info_t)&thread_data, &count);
|
||||
if (kern_ret != KERN_SUCCESS)
|
||||
return false;
|
||||
|
||||
count = TASK_BASIC_INFO_64_COUNT;
|
||||
kern_ret = task_info(task, TASK_BASIC_INFO_64,
|
||||
(task_info_t)&task_data, &count);
|
||||
if (kern_ret != KERN_SUCCESS)
|
||||
return false;
|
||||
|
||||
add_time_value(&cur_time, &thread_data.user_time,
|
||||
&thread_data.system_time);
|
||||
add_time_value(&cur_time, &cur_time, &task_data.user_time);
|
||||
add_time_value(&cur_time, &cur_time, &task_data.system_time);
|
||||
|
||||
*cpu_time = os_gettime_ns() / 1000;
|
||||
*sys_time = cur_time.seconds * 1000000 + cur_time.microseconds;
|
||||
return true;
|
||||
}
|
||||
|
||||
os_cpu_usage_info_t *os_cpu_usage_info_start(void)
|
||||
{
|
||||
struct os_cpu_usage_info *info = bmalloc(sizeof(*info));
|
||||
|
||||
if (!get_time_info(&info->last_cpu_time, &info->last_sys_time)) {
|
||||
bfree(info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info->core_count = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return info;
|
||||
}
|
||||
|
||||
double os_cpu_usage_info_query(os_cpu_usage_info_t *info)
|
||||
{
|
||||
int64_t sys_time, cpu_time;
|
||||
int64_t sys_time_delta, cpu_time_delta;
|
||||
|
||||
if (!info || !get_time_info(&cpu_time, &sys_time))
|
||||
return 0.0;
|
||||
|
||||
sys_time_delta = sys_time - info->last_sys_time;
|
||||
cpu_time_delta = cpu_time - info->last_cpu_time;
|
||||
|
||||
if (cpu_time_delta == 0)
|
||||
return 0.0;
|
||||
|
||||
info->last_sys_time = sys_time;
|
||||
info->last_cpu_time = cpu_time;
|
||||
|
||||
return (double)sys_time_delta * 100.0 / (double)cpu_time_delta /
|
||||
(double)info->core_count;
|
||||
}
|
||||
|
||||
void os_cpu_usage_info_destroy(os_cpu_usage_info_t *info)
|
||||
{
|
||||
if (info)
|
||||
bfree(info);
|
||||
}
|
||||
|
||||
os_performance_token_t *os_request_high_performance(const char *reason)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSProcessInfo *pi = [NSProcessInfo processInfo];
|
||||
SEL sel = @selector(beginActivityWithOptions:reason:);
|
||||
if (![pi respondsToSelector:sel])
|
||||
return nil;
|
||||
|
||||
//taken from http://stackoverflow.com/a/20100906
|
||||
id activity = [pi beginActivityWithOptions:0x00FFFFFF
|
||||
reason:@(reason)];
|
||||
|
||||
return CFBridgingRetain(activity);
|
||||
}
|
||||
}
|
||||
|
||||
void os_end_high_performance(os_performance_token_t *token)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSProcessInfo *pi = [NSProcessInfo processInfo];
|
||||
SEL sel = @selector(beginActivityWithOptions:reason:);
|
||||
if (![pi respondsToSelector:sel])
|
||||
return;
|
||||
|
||||
[pi endActivity:CFBridgingRelease(token)];
|
||||
}
|
||||
}
|
||||
|
||||
struct os_inhibit_info {
|
||||
CFStringRef reason;
|
||||
IOPMAssertionID sleep_id;
|
||||
IOPMAssertionID user_id;
|
||||
bool active;
|
||||
};
|
||||
|
||||
os_inhibit_t *os_inhibit_sleep_create(const char *reason)
|
||||
{
|
||||
struct os_inhibit_info *info = bzalloc(sizeof(*info));
|
||||
if (!reason)
|
||||
info->reason = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
reason, kCFStringEncodingUTF8);
|
||||
else
|
||||
info->reason = CFStringCreateCopy(kCFAllocatorDefault,
|
||||
CFSTR(""));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
bool os_inhibit_sleep_set_active(os_inhibit_t *info, bool active)
|
||||
{
|
||||
IOReturn success;
|
||||
|
||||
if (!info)
|
||||
return false;
|
||||
if (info->active == active)
|
||||
return false;
|
||||
|
||||
if (active) {
|
||||
IOPMAssertionDeclareUserActivity(info->reason,
|
||||
kIOPMUserActiveLocal, &info->user_id);
|
||||
success = IOPMAssertionCreateWithName(
|
||||
kIOPMAssertionTypeNoDisplaySleep,
|
||||
kIOPMAssertionLevelOn, info->reason,
|
||||
&info->sleep_id);
|
||||
|
||||
if (success != kIOReturnSuccess) {
|
||||
blog(LOG_WARNING, "Failed to disable sleep");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
IOPMAssertionRelease(info->sleep_id);
|
||||
}
|
||||
|
||||
info->active = active;
|
||||
return true;
|
||||
}
|
||||
|
||||
void os_inhibit_sleep_destroy(os_inhibit_t *info)
|
||||
{
|
||||
if (info) {
|
||||
os_inhibit_sleep_set_active(info, false);
|
||||
CFRelease(info->reason);
|
||||
bfree(info);
|
||||
}
|
||||
}
|
||||
198
libobs/util/platform-nix-dbus.c
Normal file
198
libobs/util/platform-nix-dbus.c
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <dbus/dbus.h>
|
||||
#include "bmem.h"
|
||||
|
||||
/* NOTE: This is basically just the VLC implementation from its d-bus power
|
||||
* management inhibition code. Credit is theirs for this. */
|
||||
|
||||
enum service_type {
|
||||
FREEDESKTOP_SS, /* freedesktop screensaver (KDE >= 4, GNOME >= 3.10) */
|
||||
FREEDESKTOP_PM, /* freedesktop power management (KDE, gnome <= 2.26) */
|
||||
MATE_SM, /* MATE (>= 1.0) session manager */
|
||||
GNOME_SM, /* GNOME 2.26 - 3.4 sessopm mamager */
|
||||
};
|
||||
|
||||
struct service_info {
|
||||
const char *name;
|
||||
const char *path;
|
||||
const char *uninhibit;
|
||||
};
|
||||
|
||||
static const struct service_info services[] = {
|
||||
[FREEDESKTOP_SS] = {
|
||||
.name = "org.freedesktop.ScreenSaver",
|
||||
.path = "/ScreenSaver",
|
||||
.uninhibit = "UnInhibit",
|
||||
},
|
||||
[FREEDESKTOP_PM] = {
|
||||
.name = "org.freedesktop.PowerManagement.Inhibit",
|
||||
.path = "/org/freedesktop/PowerManagement",
|
||||
.uninhibit = "UnInhibit",
|
||||
},
|
||||
[MATE_SM] = {
|
||||
.name = "org.mate.SessionManager",
|
||||
.path = "/org/mate/SessionManager",
|
||||
.uninhibit = "Uninhibit",
|
||||
},
|
||||
[GNOME_SM] = {
|
||||
.name = "org.gnome.SessionManager",
|
||||
.path = "/org/gnome/SessionManager",
|
||||
.uninhibit = "Uninhibit",
|
||||
},
|
||||
};
|
||||
|
||||
static const size_t num_services =
|
||||
(sizeof(services) / sizeof(struct service_info));
|
||||
|
||||
struct dbus_sleep_info {
|
||||
const struct service_info *service;
|
||||
DBusPendingCall *pending;
|
||||
DBusConnection *c;
|
||||
dbus_uint32_t id;
|
||||
enum service_type type;
|
||||
};
|
||||
|
||||
void dbus_sleep_info_destroy(struct dbus_sleep_info *info)
|
||||
{
|
||||
if (info) {
|
||||
if (info->pending) {
|
||||
dbus_pending_call_cancel(info->pending);
|
||||
dbus_pending_call_unref(info->pending);
|
||||
}
|
||||
|
||||
dbus_connection_close(info->c);
|
||||
dbus_connection_unref(info->c);
|
||||
bfree(info);
|
||||
}
|
||||
}
|
||||
|
||||
struct dbus_sleep_info *dbus_sleep_info_create(void)
|
||||
{
|
||||
struct dbus_sleep_info *info = bzalloc(sizeof(*info));
|
||||
DBusError err;
|
||||
|
||||
dbus_error_init(&err);
|
||||
|
||||
info->c = dbus_bus_get_private(DBUS_BUS_SESSION, &err);
|
||||
if (!info->c) {
|
||||
blog(LOG_ERROR, "Could not create dbus connection: %s",
|
||||
err.message);
|
||||
bfree(info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_services; i++) {
|
||||
const struct service_info *service = &services[i];
|
||||
|
||||
if (!service->name)
|
||||
continue;
|
||||
|
||||
if (dbus_bus_name_has_owner(info->c, service->name, NULL)) {
|
||||
blog(LOG_DEBUG, "Found dbus service: %s",
|
||||
service->name);
|
||||
info->service = service;
|
||||
info->type = (enum service_type)i;
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
dbus_sleep_info_destroy(info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dbus_inhibit_sleep(struct dbus_sleep_info *info, const char *reason,
|
||||
bool active)
|
||||
{
|
||||
DBusMessage *reply;
|
||||
const char *method;
|
||||
dbus_bool_t success;
|
||||
|
||||
if (info->pending) {
|
||||
|
||||
dbus_pending_call_block(info->pending);
|
||||
reply = dbus_pending_call_steal_reply(info->pending);
|
||||
dbus_pending_call_unref(info->pending);
|
||||
info->pending = NULL;
|
||||
|
||||
if (reply) {
|
||||
success = dbus_message_get_args(reply, NULL,
|
||||
DBUS_TYPE_UINT32, &info->id,
|
||||
DBUS_TYPE_INVALID);
|
||||
if (!success)
|
||||
info->id = 0;
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
}
|
||||
|
||||
if (active == !!info->id)
|
||||
return;
|
||||
|
||||
method = active ? "Inhibit" : info->service->uninhibit;
|
||||
|
||||
reply = dbus_message_new_method_call(info->service->name,
|
||||
info->service->path, info->service->name, method);
|
||||
if (reply == NULL) {
|
||||
blog(LOG_ERROR, "dbus_message_new_method_call failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
const char *program = "libobs";
|
||||
dbus_uint32_t flags = 0xC;
|
||||
dbus_uint32_t xid = 0;
|
||||
|
||||
assert(info->id == 0);
|
||||
|
||||
switch (info->type) {
|
||||
case MATE_SM:
|
||||
case GNOME_SM:
|
||||
success = dbus_message_append_args(reply,
|
||||
DBUS_TYPE_STRING, &program,
|
||||
DBUS_TYPE_UINT32, &xid,
|
||||
DBUS_TYPE_STRING, &reason,
|
||||
DBUS_TYPE_UINT32, &flags,
|
||||
DBUS_TYPE_INVALID);
|
||||
break;
|
||||
default:
|
||||
success = dbus_message_append_args(reply,
|
||||
DBUS_TYPE_STRING, &program,
|
||||
DBUS_TYPE_STRING, &reason,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
success = dbus_connection_send_with_reply(info->c,
|
||||
reply, &info->pending, -1);
|
||||
if (!success)
|
||||
info->pending = NULL;
|
||||
}
|
||||
} else {
|
||||
assert(info->id != 0);
|
||||
success = dbus_message_append_args(reply,
|
||||
DBUS_TYPE_UINT32, &info->id,
|
||||
DBUS_TYPE_INVALID);
|
||||
if (success)
|
||||
success = dbus_connection_send(info->c, reply, NULL);
|
||||
if (!success)
|
||||
info->id = 0;
|
||||
}
|
||||
|
||||
dbus_connection_flush(info->c);
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
598
libobs/util/platform-nix.c
Normal file
598
libobs/util/platform-nix.c
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <glob.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "obsconfig.h"
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
#include <sys/times.h>
|
||||
#include <sys/wait.h>
|
||||
#include <spawn.h>
|
||||
#endif
|
||||
|
||||
#include "darray.h"
|
||||
#include "dstr.h"
|
||||
#include "platform.h"
|
||||
#include "threading.h"
|
||||
|
||||
void *os_dlopen(const char *path)
|
||||
{
|
||||
struct dstr dylib_name;
|
||||
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
dstr_init_copy(&dylib_name, path);
|
||||
if (!dstr_find(&dylib_name, ".so"))
|
||||
dstr_cat(&dylib_name, ".so");
|
||||
|
||||
void *res = dlopen(dylib_name.array, RTLD_LAZY);
|
||||
if (!res)
|
||||
blog(LOG_ERROR, "os_dlopen(%s->%s): %s\n",
|
||||
path, dylib_name.array, dlerror());
|
||||
|
||||
dstr_free(&dylib_name);
|
||||
return res;
|
||||
}
|
||||
|
||||
void *os_dlsym(void *module, const char *func)
|
||||
{
|
||||
return dlsym(module, func);
|
||||
}
|
||||
|
||||
void os_dlclose(void *module)
|
||||
{
|
||||
dlclose(module);
|
||||
}
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
|
||||
struct os_cpu_usage_info {
|
||||
clock_t last_cpu_time, last_sys_time, last_user_time;
|
||||
int core_count;
|
||||
};
|
||||
|
||||
os_cpu_usage_info_t *os_cpu_usage_info_start(void)
|
||||
{
|
||||
struct os_cpu_usage_info *info = bmalloc(sizeof(*info));
|
||||
struct tms time_sample;
|
||||
|
||||
info->last_cpu_time = times(&time_sample);
|
||||
info->last_sys_time = time_sample.tms_stime;
|
||||
info->last_user_time = time_sample.tms_utime;
|
||||
info->core_count = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return info;
|
||||
}
|
||||
|
||||
double os_cpu_usage_info_query(os_cpu_usage_info_t *info)
|
||||
{
|
||||
struct tms time_sample;
|
||||
clock_t cur_cpu_time;
|
||||
double percent;
|
||||
|
||||
if (!info)
|
||||
return 0.0;
|
||||
|
||||
cur_cpu_time = times(&time_sample);
|
||||
if (cur_cpu_time <= info->last_cpu_time ||
|
||||
time_sample.tms_stime < info->last_sys_time ||
|
||||
time_sample.tms_utime < info->last_user_time)
|
||||
return 0.0;
|
||||
|
||||
percent = (double)(time_sample.tms_stime - info->last_sys_time +
|
||||
(time_sample.tms_utime - info->last_user_time));
|
||||
percent /= (double)(cur_cpu_time - info->last_cpu_time);
|
||||
percent /= (double)info->core_count;
|
||||
|
||||
info->last_cpu_time = cur_cpu_time;
|
||||
info->last_sys_time = time_sample.tms_stime;
|
||||
info->last_user_time = time_sample.tms_utime;
|
||||
|
||||
return percent * 100.0;
|
||||
}
|
||||
|
||||
void os_cpu_usage_info_destroy(os_cpu_usage_info_t *info)
|
||||
{
|
||||
if (info)
|
||||
bfree(info);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool os_sleepto_ns(uint64_t time_target)
|
||||
{
|
||||
uint64_t current = os_gettime_ns();
|
||||
if (time_target < current)
|
||||
return false;
|
||||
|
||||
time_target -= current;
|
||||
|
||||
struct timespec req, remain;
|
||||
memset(&req, 0, sizeof(req));
|
||||
memset(&remain, 0, sizeof(remain));
|
||||
req.tv_sec = time_target/1000000000;
|
||||
req.tv_nsec = time_target%1000000000;
|
||||
|
||||
while (nanosleep(&req, &remain)) {
|
||||
req = remain;
|
||||
memset(&remain, 0, sizeof(remain));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void os_sleep_ms(uint32_t duration)
|
||||
{
|
||||
usleep(duration*1000);
|
||||
}
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
|
||||
uint64_t os_gettime_ns(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return ((uint64_t) ts.tv_sec * 1000000000ULL + (uint64_t) ts.tv_nsec);
|
||||
}
|
||||
|
||||
/* should return $HOME/.[name], or when using XDG,
|
||||
* should return $HOME/.config/[name] as default */
|
||||
int os_get_config_path(char *dst, size_t size, const char *name)
|
||||
{
|
||||
#ifdef USE_XDG
|
||||
char *xdg_ptr = getenv("XDG_CONFIG_HOME");
|
||||
|
||||
// If XDG_CONFIG_HOME is unset,
|
||||
// we use the default $HOME/.config/[name] instead
|
||||
if (xdg_ptr == NULL) {
|
||||
char *home_ptr = getenv("HOME");
|
||||
if (home_ptr == NULL)
|
||||
bcrash("Could not get $HOME\n");
|
||||
|
||||
if (!name || !*name) {
|
||||
return snprintf(dst, size, "%s/.config", home_ptr);
|
||||
} else {
|
||||
return snprintf(dst, size, "%s/.config/%s", home_ptr,
|
||||
name);
|
||||
}
|
||||
} else {
|
||||
if (!name || !*name)
|
||||
return snprintf(dst, size, "%s", xdg_ptr);
|
||||
else
|
||||
return snprintf(dst, size, "%s/%s", xdg_ptr, name);
|
||||
}
|
||||
#else
|
||||
char *path_ptr = getenv("HOME");
|
||||
if (path_ptr == NULL)
|
||||
bcrash("Could not get $HOME\n");
|
||||
|
||||
if (!name || !*name)
|
||||
return snprintf(dst, size, "%s", path_ptr);
|
||||
else
|
||||
return snprintf(dst, size, "%s/.%s", path_ptr, name);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* should return $HOME/.[name], or when using XDG,
|
||||
* should return $HOME/.config/[name] as default */
|
||||
char *os_get_config_path_ptr(const char *name)
|
||||
{
|
||||
#ifdef USE_XDG
|
||||
struct dstr path;
|
||||
char *xdg_ptr = getenv("XDG_CONFIG_HOME");
|
||||
|
||||
/* If XDG_CONFIG_HOME is unset,
|
||||
* we use the default $HOME/.config/[name] instead */
|
||||
if (xdg_ptr == NULL) {
|
||||
char *home_ptr = getenv("HOME");
|
||||
if (home_ptr == NULL)
|
||||
bcrash("Could not get $HOME\n");
|
||||
|
||||
dstr_init_copy(&path, home_ptr);
|
||||
dstr_cat(&path, "/.config/");
|
||||
dstr_cat(&path, name);
|
||||
} else {
|
||||
dstr_init_copy(&path, xdg_ptr);
|
||||
dstr_cat(&path, "/");
|
||||
dstr_cat(&path, name);
|
||||
}
|
||||
return path.array;
|
||||
#else
|
||||
char *path_ptr = getenv("HOME");
|
||||
if (path_ptr == NULL)
|
||||
bcrash("Could not get $HOME\n");
|
||||
|
||||
struct dstr path;
|
||||
dstr_init_copy(&path, path_ptr);
|
||||
dstr_cat(&path, "/.");
|
||||
dstr_cat(&path, name);
|
||||
return path.array;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool os_file_exists(const char *path)
|
||||
{
|
||||
return access(path, F_OK) == 0;
|
||||
}
|
||||
|
||||
size_t os_get_abs_path(const char *path, char *abspath, size_t size)
|
||||
{
|
||||
size_t min_size = size < PATH_MAX ? size : PATH_MAX;
|
||||
char newpath[PATH_MAX];
|
||||
int ret;
|
||||
|
||||
if (!abspath)
|
||||
return 0;
|
||||
|
||||
if (!realpath(path, newpath))
|
||||
return 0;
|
||||
|
||||
ret = snprintf(abspath, min_size, "%s", newpath);
|
||||
return ret >= 0 ? ret : 0;
|
||||
}
|
||||
|
||||
char *os_get_abs_path_ptr(const char *path)
|
||||
{
|
||||
char *ptr = bmalloc(512);
|
||||
|
||||
if (!os_get_abs_path(path, ptr, 512)) {
|
||||
bfree(ptr);
|
||||
ptr = NULL;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
struct os_dir {
|
||||
const char *path;
|
||||
DIR *dir;
|
||||
struct dirent *cur_dirent;
|
||||
struct os_dirent out;
|
||||
};
|
||||
|
||||
os_dir_t *os_opendir(const char *path)
|
||||
{
|
||||
struct os_dir *dir;
|
||||
DIR *dir_val;
|
||||
|
||||
dir_val = opendir(path);
|
||||
if (!dir_val)
|
||||
return NULL;
|
||||
|
||||
dir = bzalloc(sizeof(struct os_dir));
|
||||
dir->dir = dir_val;
|
||||
dir->path = path;
|
||||
return dir;
|
||||
}
|
||||
|
||||
static inline bool is_dir(const char *path)
|
||||
{
|
||||
struct stat stat_info;
|
||||
if (stat(path, &stat_info) == 0)
|
||||
return !!S_ISDIR(stat_info.st_mode);
|
||||
|
||||
blog(LOG_DEBUG, "is_dir: stat for %s failed, errno: %d", path, errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct os_dirent *os_readdir(os_dir_t *dir)
|
||||
{
|
||||
struct dstr file_path = {0};
|
||||
|
||||
if (!dir) return NULL;
|
||||
|
||||
dir->cur_dirent = readdir(dir->dir);
|
||||
if (!dir->cur_dirent)
|
||||
return NULL;
|
||||
|
||||
strncpy(dir->out.d_name, dir->cur_dirent->d_name, 255);
|
||||
|
||||
dstr_copy(&file_path, dir->path);
|
||||
dstr_cat(&file_path, "/");
|
||||
dstr_cat(&file_path, dir->out.d_name);
|
||||
|
||||
dir->out.directory = is_dir(file_path.array);
|
||||
|
||||
dstr_free(&file_path);
|
||||
|
||||
return &dir->out;
|
||||
}
|
||||
|
||||
void os_closedir(os_dir_t *dir)
|
||||
{
|
||||
if (dir) {
|
||||
closedir(dir->dir);
|
||||
bfree(dir);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t os_get_free_space(const char *path)
|
||||
{
|
||||
struct statvfs info;
|
||||
int64_t ret = (int64_t)statvfs(path, &info);
|
||||
|
||||
if (ret == 0)
|
||||
ret = (int64_t)info.f_bsize * (int64_t)info.f_bfree;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct posix_glob_info {
|
||||
struct os_glob_info base;
|
||||
glob_t gl;
|
||||
};
|
||||
|
||||
int os_glob(const char *pattern, int flags, os_glob_t **pglob)
|
||||
{
|
||||
struct posix_glob_info pgi;
|
||||
int ret = glob(pattern, 0, NULL, &pgi.gl);
|
||||
|
||||
if (ret == 0) {
|
||||
DARRAY(struct os_globent) list;
|
||||
da_init(list);
|
||||
|
||||
for (size_t i = 0; i < pgi.gl.gl_pathc; i++) {
|
||||
struct os_globent ent = {0};
|
||||
|
||||
ent.path = pgi.gl.gl_pathv[i];
|
||||
ent.directory = is_dir(ent.path);
|
||||
da_push_back(list, &ent);
|
||||
}
|
||||
|
||||
pgi.base.gl_pathc = list.num;
|
||||
pgi.base.gl_pathv = list.array;
|
||||
|
||||
*pglob = bmemdup(&pgi, sizeof(pgi));
|
||||
} else {
|
||||
*pglob = NULL;
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void os_globfree(os_glob_t *pglob)
|
||||
{
|
||||
if (pglob) {
|
||||
struct posix_glob_info *pgi = (struct posix_glob_info*)pglob;
|
||||
globfree(&pgi->gl);
|
||||
|
||||
bfree(pgi->base.gl_pathv);
|
||||
bfree(pgi);
|
||||
}
|
||||
}
|
||||
|
||||
int os_unlink(const char *path)
|
||||
{
|
||||
return unlink(path);
|
||||
}
|
||||
|
||||
int os_rmdir(const char *path)
|
||||
{
|
||||
return rmdir(path);
|
||||
}
|
||||
|
||||
int os_mkdir(const char *path)
|
||||
{
|
||||
if (mkdir(path, 0755) == 0)
|
||||
return MKDIR_SUCCESS;
|
||||
|
||||
return (errno == EEXIST) ? MKDIR_EXISTS : MKDIR_ERROR;
|
||||
}
|
||||
|
||||
int os_rename(const char *old_path, const char *new_path)
|
||||
{
|
||||
return rename(old_path, new_path);
|
||||
}
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
os_performance_token_t *os_request_high_performance(const char *reason)
|
||||
{
|
||||
UNUSED_PARAMETER(reason);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void os_end_high_performance(os_performance_token_t *token)
|
||||
{
|
||||
UNUSED_PARAMETER(token);
|
||||
}
|
||||
#endif
|
||||
|
||||
int os_copyfile(const char *file_path_in, const char *file_path_out)
|
||||
{
|
||||
FILE *file_out = NULL;
|
||||
FILE *file_in = NULL;
|
||||
uint8_t data[4096];
|
||||
int ret = -1;
|
||||
size_t size;
|
||||
|
||||
if (os_file_exists(file_path_out))
|
||||
return -1;
|
||||
|
||||
file_in = fopen(file_path_in, "rb");
|
||||
if (!file_in)
|
||||
return -1;
|
||||
|
||||
file_out = fopen(file_path_out, "ab+");
|
||||
if (!file_out)
|
||||
goto error;
|
||||
|
||||
do {
|
||||
size = fread(data, 1, sizeof(data), file_in);
|
||||
if (size)
|
||||
size = fwrite(data, 1, size, file_out);
|
||||
} while (size == sizeof(data));
|
||||
|
||||
ret = feof(file_in) ? 0 : -1;
|
||||
|
||||
error:
|
||||
if (file_out)
|
||||
fclose(file_out);
|
||||
fclose(file_in);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *os_getcwd(char *path, size_t size)
|
||||
{
|
||||
return getcwd(path, size);
|
||||
}
|
||||
|
||||
int os_chdir(const char *path)
|
||||
{
|
||||
return chdir(path);
|
||||
}
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
|
||||
#if HAVE_DBUS
|
||||
struct dbus_sleep_info;
|
||||
|
||||
extern struct dbus_sleep_info *dbus_sleep_info_create(void);
|
||||
extern void dbus_inhibit_sleep(struct dbus_sleep_info *dbus, const char *sleep,
|
||||
bool active);
|
||||
extern void dbus_sleep_info_destroy(struct dbus_sleep_info *dbus);
|
||||
#endif
|
||||
|
||||
struct os_inhibit_info {
|
||||
#if HAVE_DBUS
|
||||
struct dbus_sleep_info *dbus;
|
||||
#endif
|
||||
pthread_t screensaver_thread;
|
||||
os_event_t *stop_event;
|
||||
char *reason;
|
||||
posix_spawnattr_t attr;
|
||||
bool active;
|
||||
};
|
||||
|
||||
os_inhibit_t *os_inhibit_sleep_create(const char *reason)
|
||||
{
|
||||
struct os_inhibit_info *info = bzalloc(sizeof(*info));
|
||||
sigset_t set;
|
||||
|
||||
#if HAVE_DBUS
|
||||
info->dbus = dbus_sleep_info_create();
|
||||
#endif
|
||||
|
||||
os_event_init(&info->stop_event, OS_EVENT_TYPE_AUTO);
|
||||
posix_spawnattr_init(&info->attr);
|
||||
|
||||
sigemptyset(&set);
|
||||
posix_spawnattr_setsigmask(&info->attr, &set);
|
||||
sigaddset(&set, SIGPIPE);
|
||||
posix_spawnattr_setsigdefault(&info->attr, &set);
|
||||
posix_spawnattr_setflags(&info->attr,
|
||||
POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK);
|
||||
|
||||
info->reason = bstrdup(reason);
|
||||
return info;
|
||||
}
|
||||
|
||||
extern char **environ;
|
||||
|
||||
static void reset_screensaver(os_inhibit_t *info)
|
||||
{
|
||||
char *argv[3] = {(char*)"xdg-screensaver", (char*)"reset", NULL};
|
||||
pid_t pid;
|
||||
|
||||
int err = posix_spawnp(&pid, "xdg-screensaver", NULL, &info->attr,
|
||||
argv, environ);
|
||||
if (err == 0) {
|
||||
int status;
|
||||
while (waitpid(pid, &status, 0) == -1);
|
||||
} else {
|
||||
blog(LOG_WARNING, "Failed to create xdg-screensaver: %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
static void *screensaver_thread(void *param)
|
||||
{
|
||||
os_inhibit_t *info = param;
|
||||
|
||||
while (os_event_timedwait(info->stop_event, 30000) == ETIMEDOUT)
|
||||
reset_screensaver(info);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool os_inhibit_sleep_set_active(os_inhibit_t *info, bool active)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!info)
|
||||
return false;
|
||||
if (info->active == active)
|
||||
return false;
|
||||
|
||||
#if HAVE_DBUS
|
||||
if (info->dbus)
|
||||
dbus_inhibit_sleep(info->dbus, info->reason, active);
|
||||
#endif
|
||||
|
||||
if (!info->stop_event)
|
||||
return true;
|
||||
|
||||
if (active) {
|
||||
ret = pthread_create(&info->screensaver_thread, NULL,
|
||||
&screensaver_thread, info);
|
||||
if (ret < 0) {
|
||||
blog(LOG_ERROR, "Failed to create screensaver "
|
||||
"inhibitor thread");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
os_event_signal(info->stop_event);
|
||||
pthread_join(info->screensaver_thread, NULL);
|
||||
}
|
||||
|
||||
info->active = active;
|
||||
return true;
|
||||
}
|
||||
|
||||
void os_inhibit_sleep_destroy(os_inhibit_t *info)
|
||||
{
|
||||
if (info) {
|
||||
os_inhibit_sleep_set_active(info, false);
|
||||
#if HAVE_DBUS
|
||||
dbus_sleep_info_destroy(info->dbus);
|
||||
#endif
|
||||
os_event_destroy(info->stop_event);
|
||||
posix_spawnattr_destroy(&info->attr);
|
||||
bfree(info->reason);
|
||||
bfree(info);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void os_breakpoint()
|
||||
{
|
||||
raise(SIGTRAP);
|
||||
}
|
||||
779
libobs/util/platform-windows.c
Normal file
779
libobs/util/platform-windows.c
Normal file
|
|
@ -0,0 +1,779 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
#include <intrin.h>
|
||||
|
||||
#include "base.h"
|
||||
#include "platform.h"
|
||||
#include "darray.h"
|
||||
#include "dstr.h"
|
||||
#include "windows/win-version.h"
|
||||
|
||||
#include "../../deps/w32-pthreads/pthread.h"
|
||||
|
||||
static bool have_clockfreq = false;
|
||||
static LARGE_INTEGER clock_freq;
|
||||
static uint32_t winver = 0;
|
||||
|
||||
static inline uint64_t get_clockfreq(void)
|
||||
{
|
||||
if (!have_clockfreq)
|
||||
QueryPerformanceFrequency(&clock_freq);
|
||||
return clock_freq.QuadPart;
|
||||
}
|
||||
|
||||
static inline uint32_t get_winver(void)
|
||||
{
|
||||
if (!winver) {
|
||||
struct win_version_info ver;
|
||||
get_win_ver(&ver);
|
||||
winver = (ver.major << 16) | ver.minor;
|
||||
}
|
||||
|
||||
return winver;
|
||||
}
|
||||
|
||||
void *os_dlopen(const char *path)
|
||||
{
|
||||
struct dstr dll_name;
|
||||
wchar_t *wpath;
|
||||
wchar_t *wpath_slash;
|
||||
HMODULE h_library = NULL;
|
||||
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
dstr_init_copy(&dll_name, path);
|
||||
dstr_replace(&dll_name, "\\", "/");
|
||||
if (!dstr_find(&dll_name, ".dll"))
|
||||
dstr_cat(&dll_name, ".dll");
|
||||
|
||||
os_utf8_to_wcs_ptr(dll_name.array, 0, &wpath);
|
||||
|
||||
/* to make module dependency issues easier to deal with, allow
|
||||
* dynamically loaded libraries on windows to search for dependent
|
||||
* libraries that are within the library's own directory */
|
||||
wpath_slash = wcsrchr(wpath, L'/');
|
||||
if (wpath_slash) {
|
||||
*wpath_slash = 0;
|
||||
SetDllDirectoryW(wpath);
|
||||
*wpath_slash = L'/';
|
||||
}
|
||||
|
||||
h_library = LoadLibraryW(wpath);
|
||||
bfree(wpath);
|
||||
dstr_free(&dll_name);
|
||||
|
||||
if (wpath_slash)
|
||||
SetDllDirectoryW(NULL);
|
||||
|
||||
if (!h_library)
|
||||
blog(LOG_INFO, "LoadLibrary failed for '%s', error: %ld",
|
||||
path, GetLastError());
|
||||
|
||||
return h_library;
|
||||
}
|
||||
|
||||
void *os_dlsym(void *module, const char *func)
|
||||
{
|
||||
void *handle;
|
||||
|
||||
handle = (void*)GetProcAddress(module, func);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void os_dlclose(void *module)
|
||||
{
|
||||
FreeLibrary(module);
|
||||
}
|
||||
|
||||
union time_data {
|
||||
FILETIME ft;
|
||||
unsigned long long val;
|
||||
};
|
||||
|
||||
struct os_cpu_usage_info {
|
||||
union time_data last_time, last_sys_time, last_user_time;
|
||||
DWORD core_count;
|
||||
};
|
||||
|
||||
os_cpu_usage_info_t *os_cpu_usage_info_start(void)
|
||||
{
|
||||
struct os_cpu_usage_info *info = bzalloc(sizeof(*info));
|
||||
SYSTEM_INFO si;
|
||||
FILETIME dummy;
|
||||
|
||||
GetSystemInfo(&si);
|
||||
GetSystemTimeAsFileTime(&info->last_time.ft);
|
||||
GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
|
||||
&info->last_sys_time.ft, &info->last_user_time.ft);
|
||||
info->core_count = si.dwNumberOfProcessors;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
double os_cpu_usage_info_query(os_cpu_usage_info_t *info)
|
||||
{
|
||||
union time_data cur_time, cur_sys_time, cur_user_time;
|
||||
FILETIME dummy;
|
||||
double percent;
|
||||
|
||||
if (!info)
|
||||
return 0.0;
|
||||
|
||||
GetSystemTimeAsFileTime(&cur_time.ft);
|
||||
GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
|
||||
&cur_sys_time.ft, &cur_user_time.ft);
|
||||
|
||||
percent = (double)(cur_sys_time.val - info->last_sys_time.val +
|
||||
(cur_user_time.val - info->last_user_time.val));
|
||||
percent /= (double)(cur_time.val - info->last_time.val);
|
||||
percent /= (double)info->core_count;
|
||||
|
||||
info->last_time.val = cur_time.val;
|
||||
info->last_sys_time.val = cur_sys_time.val;
|
||||
info->last_user_time.val = cur_user_time.val;
|
||||
|
||||
return percent * 100.0;
|
||||
}
|
||||
|
||||
void os_cpu_usage_info_destroy(os_cpu_usage_info_t *info)
|
||||
{
|
||||
if (info)
|
||||
bfree(info);
|
||||
}
|
||||
|
||||
bool os_sleepto_ns(uint64_t time_target)
|
||||
{
|
||||
uint64_t t = os_gettime_ns();
|
||||
uint32_t milliseconds;
|
||||
|
||||
if (t >= time_target)
|
||||
return false;
|
||||
|
||||
milliseconds = (uint32_t)((time_target - t)/1000000);
|
||||
if (milliseconds > 1)
|
||||
Sleep(milliseconds-1);
|
||||
|
||||
for (;;) {
|
||||
t = os_gettime_ns();
|
||||
if (t >= time_target)
|
||||
return true;
|
||||
|
||||
#if 0
|
||||
Sleep(1);
|
||||
#else
|
||||
Sleep(0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void os_sleep_ms(uint32_t duration)
|
||||
{
|
||||
/* windows 8+ appears to have decreased sleep precision */
|
||||
if (get_winver() >= 0x0602 && duration > 0)
|
||||
duration--;
|
||||
|
||||
Sleep(duration);
|
||||
}
|
||||
|
||||
uint64_t os_gettime_ns(void)
|
||||
{
|
||||
LARGE_INTEGER current_time;
|
||||
double time_val;
|
||||
|
||||
QueryPerformanceCounter(¤t_time);
|
||||
time_val = (double)current_time.QuadPart;
|
||||
time_val *= 1000000000.0;
|
||||
time_val /= (double)get_clockfreq();
|
||||
|
||||
return (uint64_t)time_val;
|
||||
}
|
||||
|
||||
/* returns %appdata%\[name] on windows */
|
||||
int os_get_config_path(char *dst, size_t size, const char *name)
|
||||
{
|
||||
wchar_t path_utf16[MAX_PATH];
|
||||
|
||||
SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
|
||||
path_utf16);
|
||||
|
||||
if (os_wcs_to_utf8(path_utf16, 0, dst, size) != 0) {
|
||||
if (!name || !*name) {
|
||||
return (int)strlen(dst);
|
||||
}
|
||||
|
||||
if (strcat_s(dst, size, "\\") == 0) {
|
||||
if (strcat_s(dst, size, name) == 0) {
|
||||
return (int)strlen(dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *os_get_config_path_ptr(const char *name)
|
||||
{
|
||||
char *ptr;
|
||||
wchar_t path_utf16[MAX_PATH];
|
||||
struct dstr path;
|
||||
|
||||
SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
|
||||
path_utf16);
|
||||
|
||||
os_wcs_to_utf8_ptr(path_utf16, 0, &ptr);
|
||||
dstr_init_move_array(&path, ptr);
|
||||
dstr_cat(&path, "\\");
|
||||
dstr_cat(&path, name);
|
||||
return path.array;
|
||||
}
|
||||
|
||||
bool os_file_exists(const char *path)
|
||||
{
|
||||
WIN32_FIND_DATAW wfd;
|
||||
HANDLE hFind;
|
||||
wchar_t *path_utf16;
|
||||
|
||||
if (!os_utf8_to_wcs_ptr(path, 0, &path_utf16))
|
||||
return false;
|
||||
|
||||
hFind = FindFirstFileW(path_utf16, &wfd);
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
FindClose(hFind);
|
||||
|
||||
bfree(path_utf16);
|
||||
return hFind != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
size_t os_get_abs_path(const char *path, char *abspath, size_t size)
|
||||
{
|
||||
wchar_t wpath[512];
|
||||
wchar_t wabspath[512];
|
||||
size_t out_len = 0;
|
||||
size_t len;
|
||||
|
||||
if (!abspath)
|
||||
return 0;
|
||||
|
||||
len = os_utf8_to_wcs(path, 0, wpath, 512);
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
if (_wfullpath(wabspath, wpath, 512) != NULL)
|
||||
out_len = os_wcs_to_utf8(wabspath, 0, abspath, size);
|
||||
return out_len;
|
||||
}
|
||||
|
||||
char *os_get_abs_path_ptr(const char *path)
|
||||
{
|
||||
char *ptr = bmalloc(512);
|
||||
|
||||
if (!os_get_abs_path(path, ptr, 512)) {
|
||||
bfree(ptr);
|
||||
ptr = NULL;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
struct os_dir {
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATA wfd;
|
||||
bool first;
|
||||
struct os_dirent out;
|
||||
};
|
||||
|
||||
os_dir_t *os_opendir(const char *path)
|
||||
{
|
||||
struct dstr path_str = {0};
|
||||
struct os_dir *dir = NULL;
|
||||
WIN32_FIND_DATA wfd;
|
||||
HANDLE handle;
|
||||
wchar_t *w_path;
|
||||
|
||||
dstr_copy(&path_str, path);
|
||||
dstr_cat(&path_str, "/*.*");
|
||||
|
||||
if (os_utf8_to_wcs_ptr(path_str.array, path_str.len, &w_path) > 0) {
|
||||
handle = FindFirstFileW(w_path, &wfd);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
dir = bzalloc(sizeof(struct os_dir));
|
||||
dir->handle = handle;
|
||||
dir->first = true;
|
||||
dir->wfd = wfd;
|
||||
}
|
||||
|
||||
bfree(w_path);
|
||||
}
|
||||
|
||||
dstr_free(&path_str);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
static inline bool is_dir(WIN32_FIND_DATA *wfd)
|
||||
{
|
||||
return !!(wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
struct os_dirent *os_readdir(os_dir_t *dir)
|
||||
{
|
||||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
if (dir->first) {
|
||||
dir->first = false;
|
||||
} else {
|
||||
if (!FindNextFileW(dir->handle, &dir->wfd))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_wcs_to_utf8(dir->wfd.cFileName, 0, dir->out.d_name,
|
||||
sizeof(dir->out.d_name));
|
||||
|
||||
dir->out.directory = is_dir(&dir->wfd);
|
||||
|
||||
return &dir->out;
|
||||
}
|
||||
|
||||
void os_closedir(os_dir_t *dir)
|
||||
{
|
||||
if (dir) {
|
||||
FindClose(dir->handle);
|
||||
bfree(dir);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t os_get_free_space(const char *path)
|
||||
{
|
||||
ULARGE_INTEGER remainingSpace;
|
||||
char abs_path[512];
|
||||
wchar_t w_abs_path[512];
|
||||
|
||||
if (os_get_abs_path(path, abs_path, 512) > 0) {
|
||||
if (os_utf8_to_wcs(abs_path, 0, w_abs_path, 512) > 0) {
|
||||
BOOL success = GetDiskFreeSpaceExW(w_abs_path,
|
||||
(PULARGE_INTEGER)&remainingSpace,
|
||||
NULL, NULL);
|
||||
if (success)
|
||||
return (int64_t)remainingSpace.QuadPart;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void make_globent(struct os_globent *ent, WIN32_FIND_DATA *wfd,
|
||||
const char *pattern)
|
||||
{
|
||||
struct dstr name = {0};
|
||||
struct dstr path = {0};
|
||||
char *slash;
|
||||
|
||||
dstr_from_wcs(&name, wfd->cFileName);
|
||||
dstr_copy(&path, pattern);
|
||||
slash = strrchr(path.array, '/');
|
||||
if (slash)
|
||||
dstr_resize(&path, slash + 1 - path.array);
|
||||
else
|
||||
dstr_free(&path);
|
||||
|
||||
dstr_cat_dstr(&path, &name);
|
||||
ent->path = path.array;
|
||||
ent->directory = is_dir(wfd);
|
||||
|
||||
dstr_free(&name);
|
||||
}
|
||||
|
||||
int os_glob(const char *pattern, int flags, os_glob_t **pglob)
|
||||
{
|
||||
DARRAY(struct os_globent) files;
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATA wfd;
|
||||
int ret = -1;
|
||||
wchar_t *w_path;
|
||||
|
||||
da_init(files);
|
||||
|
||||
if (os_utf8_to_wcs_ptr(pattern, 0, &w_path) > 0) {
|
||||
handle = FindFirstFileW(w_path, &wfd);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
struct os_globent ent = {0};
|
||||
make_globent(&ent, &wfd, pattern);
|
||||
if (ent.path)
|
||||
da_push_back(files, &ent);
|
||||
} while (FindNextFile(handle, &wfd));
|
||||
FindClose(handle);
|
||||
|
||||
*pglob = bmalloc(sizeof(**pglob));
|
||||
(*pglob)->gl_pathc = files.num;
|
||||
(*pglob)->gl_pathv = files.array;
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
bfree(w_path);
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
*pglob = NULL;
|
||||
|
||||
UNUSED_PARAMETER(flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void os_globfree(os_glob_t *pglob)
|
||||
{
|
||||
if (pglob) {
|
||||
for (size_t i = 0; i < pglob->gl_pathc; i++)
|
||||
bfree(pglob->gl_pathv[i].path);
|
||||
bfree(pglob->gl_pathv);
|
||||
bfree(pglob);
|
||||
}
|
||||
}
|
||||
|
||||
int os_unlink(const char *path)
|
||||
{
|
||||
wchar_t *w_path;
|
||||
bool success;
|
||||
|
||||
os_utf8_to_wcs_ptr(path, 0, &w_path);
|
||||
if (!w_path)
|
||||
return -1;
|
||||
|
||||
success = !!DeleteFileW(w_path);
|
||||
bfree(w_path);
|
||||
|
||||
return success ? 0 : -1;
|
||||
}
|
||||
|
||||
int os_rmdir(const char *path)
|
||||
{
|
||||
wchar_t *w_path;
|
||||
bool success;
|
||||
|
||||
os_utf8_to_wcs_ptr(path, 0, &w_path);
|
||||
if (!w_path)
|
||||
return -1;
|
||||
|
||||
success = !!RemoveDirectoryW(w_path);
|
||||
bfree(w_path);
|
||||
|
||||
return success ? 0 : -1;
|
||||
}
|
||||
|
||||
int os_mkdir(const char *path)
|
||||
{
|
||||
wchar_t *path_utf16;
|
||||
BOOL success;
|
||||
|
||||
if (!os_utf8_to_wcs_ptr(path, 0, &path_utf16))
|
||||
return MKDIR_ERROR;
|
||||
|
||||
success = CreateDirectory(path_utf16, NULL);
|
||||
bfree(path_utf16);
|
||||
|
||||
if (!success)
|
||||
return (GetLastError() == ERROR_ALREADY_EXISTS) ?
|
||||
MKDIR_EXISTS : MKDIR_ERROR;
|
||||
|
||||
return MKDIR_SUCCESS;
|
||||
}
|
||||
|
||||
int os_rename(const char *old_path, const char *new_path)
|
||||
{
|
||||
wchar_t *old_path_utf16 = NULL;
|
||||
wchar_t *new_path_utf16 = NULL;
|
||||
int code = -1;
|
||||
|
||||
if (!os_utf8_to_wcs_ptr(old_path, 0, &old_path_utf16)) {
|
||||
return -1;
|
||||
}
|
||||
if (!os_utf8_to_wcs_ptr(new_path, 0, &new_path_utf16)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
code = MoveFileW(old_path_utf16, new_path_utf16) ? 0 : -1;
|
||||
|
||||
error:
|
||||
bfree(old_path_utf16);
|
||||
bfree(new_path_utf16);
|
||||
return code;
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinst_dll, DWORD reason, LPVOID reserved)
|
||||
{
|
||||
switch (reason) {
|
||||
|
||||
case DLL_PROCESS_ATTACH:
|
||||
timeBeginPeriod(1);
|
||||
#ifdef PTW32_STATIC_LIB
|
||||
pthread_win32_process_attach_np();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
timeEndPeriod(1);
|
||||
#ifdef PTW32_STATIC_LIB
|
||||
pthread_win32_process_detach_np();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
#ifdef PTW32_STATIC_LIB
|
||||
pthread_win32_thread_attach_np();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
#ifdef PTW32_STATIC_LIB
|
||||
pthread_win32_thread_detach_np();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(hinst_dll);
|
||||
UNUSED_PARAMETER(reserved);
|
||||
return true;
|
||||
}
|
||||
|
||||
os_performance_token_t *os_request_high_performance(const char *reason)
|
||||
{
|
||||
UNUSED_PARAMETER(reason);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void os_end_high_performance(os_performance_token_t *token)
|
||||
{
|
||||
UNUSED_PARAMETER(token);
|
||||
}
|
||||
|
||||
int os_copyfile(const char *file_in, const char *file_out)
|
||||
{
|
||||
wchar_t *file_in_utf16 = NULL;
|
||||
wchar_t *file_out_utf16 = NULL;
|
||||
int code = -1;
|
||||
|
||||
if (!os_utf8_to_wcs_ptr(file_in, 0, &file_in_utf16)) {
|
||||
return -1;
|
||||
}
|
||||
if (!os_utf8_to_wcs_ptr(file_out, 0, &file_out_utf16)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
code = CopyFileW(file_in_utf16, file_out_utf16, true) ? 0 : -1;
|
||||
|
||||
error:
|
||||
bfree(file_in_utf16);
|
||||
bfree(file_out_utf16);
|
||||
return code;
|
||||
}
|
||||
|
||||
char *os_getcwd(char *path, size_t size)
|
||||
{
|
||||
wchar_t *path_w;
|
||||
DWORD len;
|
||||
|
||||
len = GetCurrentDirectoryW(0, NULL);
|
||||
if (!len)
|
||||
return NULL;
|
||||
|
||||
path_w = bmalloc((len + 1) * sizeof(wchar_t));
|
||||
GetCurrentDirectoryW(len + 1, path_w);
|
||||
os_wcs_to_utf8(path_w, (size_t)len, path, size);
|
||||
bfree(path_w);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
int os_chdir(const char *path)
|
||||
{
|
||||
wchar_t *path_w = NULL;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
size = os_utf8_to_wcs_ptr(path, 0, &path_w);
|
||||
if (!path_w)
|
||||
return -1;
|
||||
|
||||
ret = SetCurrentDirectoryW(path_w) ? 0 : -1;
|
||||
bfree(path_w);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef DWORD (WINAPI *get_file_version_info_size_w_t)(
|
||||
LPCWSTR module,
|
||||
LPDWORD unused);
|
||||
typedef BOOL (WINAPI *get_file_version_info_w_t)(
|
||||
LPCWSTR module,
|
||||
DWORD unused,
|
||||
DWORD len,
|
||||
LPVOID data);
|
||||
typedef BOOL (WINAPI *ver_query_value_w_t)(
|
||||
LPVOID data,
|
||||
LPCWSTR subblock,
|
||||
LPVOID *buf,
|
||||
PUINT sizeout);
|
||||
|
||||
static get_file_version_info_size_w_t get_file_version_info_size = NULL;
|
||||
static get_file_version_info_w_t get_file_version_info = NULL;
|
||||
static ver_query_value_w_t ver_query_value = NULL;
|
||||
static bool ver_initialized = false;
|
||||
static bool ver_initialize_success = false;
|
||||
|
||||
static bool initialize_version_functions(void)
|
||||
{
|
||||
HMODULE ver = GetModuleHandleW(L"version");
|
||||
|
||||
ver_initialized = true;
|
||||
|
||||
if (!ver) {
|
||||
ver = LoadLibraryW(L"version");
|
||||
if (!ver) {
|
||||
blog(LOG_ERROR, "Failed to load windows "
|
||||
"version library");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
get_file_version_info_size = (get_file_version_info_size_w_t)
|
||||
GetProcAddress(ver, "GetFileVersionInfoSizeW");
|
||||
get_file_version_info = (get_file_version_info_w_t)
|
||||
GetProcAddress(ver, "GetFileVersionInfoW");
|
||||
ver_query_value = (ver_query_value_w_t)
|
||||
GetProcAddress(ver, "VerQueryValueW");
|
||||
|
||||
if (!get_file_version_info_size ||
|
||||
!get_file_version_info ||
|
||||
!ver_query_value) {
|
||||
blog(LOG_ERROR, "Failed to load windows version "
|
||||
"functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
ver_initialize_success = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_dll_ver(const wchar_t *lib, struct win_version_info *ver_info)
|
||||
{
|
||||
VS_FIXEDFILEINFO *info = NULL;
|
||||
UINT len = 0;
|
||||
BOOL success;
|
||||
LPVOID data;
|
||||
DWORD size;
|
||||
|
||||
if (!ver_initialized && !initialize_version_functions())
|
||||
return false;
|
||||
if (!ver_initialize_success)
|
||||
return false;
|
||||
|
||||
size = get_file_version_info_size(lib, NULL);
|
||||
if (!size) {
|
||||
blog(LOG_ERROR, "Failed to get windows version info size");
|
||||
return false;
|
||||
}
|
||||
|
||||
data = bmalloc(size);
|
||||
if (!get_file_version_info(L"kernel32", 0, size, data)) {
|
||||
blog(LOG_ERROR, "Failed to get windows version info");
|
||||
bfree(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
success = ver_query_value(data, L"\\", (LPVOID*)&info, &len);
|
||||
if (!success || !info || !len) {
|
||||
blog(LOG_ERROR, "Failed to get windows version info value");
|
||||
bfree(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
ver_info->major = (int)HIWORD(info->dwFileVersionMS);
|
||||
ver_info->minor = (int)LOWORD(info->dwFileVersionMS);
|
||||
ver_info->build = (int)HIWORD(info->dwFileVersionLS);
|
||||
ver_info->revis = (int)LOWORD(info->dwFileVersionLS);
|
||||
|
||||
bfree(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
void get_win_ver(struct win_version_info *info)
|
||||
{
|
||||
static struct win_version_info ver = {0};
|
||||
static bool got_version = false;
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if (!got_version) {
|
||||
get_dll_ver(L"kernel32", &ver);
|
||||
got_version = true;
|
||||
}
|
||||
|
||||
*info = ver;
|
||||
}
|
||||
|
||||
struct os_inhibit_info {
|
||||
bool active;
|
||||
};
|
||||
|
||||
os_inhibit_t *os_inhibit_sleep_create(const char *reason)
|
||||
{
|
||||
UNUSED_PARAMETER(reason);
|
||||
return bzalloc(sizeof(struct os_inhibit_info));
|
||||
}
|
||||
|
||||
bool os_inhibit_sleep_set_active(os_inhibit_t *info, bool active)
|
||||
{
|
||||
if (!info)
|
||||
return false;
|
||||
if (info->active == active)
|
||||
return false;
|
||||
|
||||
if (active) {
|
||||
SetThreadExecutionState(
|
||||
ES_CONTINUOUS |
|
||||
ES_SYSTEM_REQUIRED |
|
||||
ES_AWAYMODE_REQUIRED |
|
||||
ES_DISPLAY_REQUIRED);
|
||||
} else {
|
||||
SetThreadExecutionState(ES_CONTINUOUS);
|
||||
}
|
||||
|
||||
info->active = active;
|
||||
return true;
|
||||
}
|
||||
|
||||
void os_inhibit_sleep_destroy(os_inhibit_t *info)
|
||||
{
|
||||
if (info) {
|
||||
os_inhibit_sleep_set_active(info, false);
|
||||
bfree(info);
|
||||
}
|
||||
}
|
||||
|
||||
void os_breakpoint(void)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
604
libobs/util/platform.c
Normal file
604
libobs/util/platform.c
Normal file
|
|
@ -0,0 +1,604 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <locale.h>
|
||||
#include "c99defs.h"
|
||||
#include "platform.h"
|
||||
#include "bmem.h"
|
||||
#include "utf8.h"
|
||||
#include "dstr.h"
|
||||
|
||||
FILE *os_wfopen(const wchar_t *path, const char *mode)
|
||||
{
|
||||
FILE *file = NULL;
|
||||
|
||||
if (path) {
|
||||
#ifdef _MSC_VER
|
||||
wchar_t *wcs_mode;
|
||||
|
||||
os_utf8_to_wcs_ptr(mode, 0, &wcs_mode);
|
||||
file = _wfopen(path, wcs_mode);
|
||||
bfree(wcs_mode);
|
||||
#else
|
||||
char *mbs_path;
|
||||
|
||||
os_wcs_to_utf8_ptr(path, 0, &mbs_path);
|
||||
file = fopen(mbs_path, mode);
|
||||
bfree(mbs_path);
|
||||
#endif
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
FILE *os_fopen(const char *path, const char *mode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
wchar_t *wpath = NULL;
|
||||
FILE *file = NULL;
|
||||
|
||||
if (path) {
|
||||
os_utf8_to_wcs_ptr(path, 0, &wpath);
|
||||
file = os_wfopen(wpath, mode);
|
||||
bfree(wpath);
|
||||
}
|
||||
|
||||
return file;
|
||||
#else
|
||||
return path ? fopen(path, mode) : NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t os_fgetsize(FILE *file)
|
||||
{
|
||||
int64_t cur_offset = os_ftelli64(file);
|
||||
int64_t size;
|
||||
int errval = 0;
|
||||
|
||||
if (fseek(file, 0, SEEK_END) == -1)
|
||||
return -1;
|
||||
|
||||
size = os_ftelli64(file);
|
||||
if (size == -1)
|
||||
errval = errno;
|
||||
|
||||
if (os_fseeki64(file, cur_offset, SEEK_SET) != 0 && errval != 0)
|
||||
errno = errval;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int os_fseeki64(FILE *file, int64_t offset, int origin)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _fseeki64(file, offset, origin);
|
||||
#else
|
||||
return fseeko(file, offset, origin);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t os_ftelli64(FILE *file)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _ftelli64(file);
|
||||
#else
|
||||
return ftello(file);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t os_fread_mbs(FILE *file, char **pstr)
|
||||
{
|
||||
size_t size = 0;
|
||||
size_t len = 0;
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
size = (size_t)os_ftelli64(file);
|
||||
*pstr = NULL;
|
||||
|
||||
if (size > 0) {
|
||||
char *mbstr = bmalloc(size+1);
|
||||
|
||||
fseek(file, 0, SEEK_SET);
|
||||
size = fread(mbstr, 1, size, file);
|
||||
if (size == 0) {
|
||||
bfree(mbstr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mbstr[size] = 0;
|
||||
len = os_mbs_to_utf8_ptr(mbstr, size, pstr);
|
||||
bfree(mbstr);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t os_fread_utf8(FILE *file, char **pstr)
|
||||
{
|
||||
size_t size = 0;
|
||||
size_t size_read;
|
||||
size_t len = 0;
|
||||
|
||||
*pstr = NULL;
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
size = (size_t)os_ftelli64(file);
|
||||
|
||||
if (size > 0) {
|
||||
char bom[3];
|
||||
char *utf8str;
|
||||
off_t offset;
|
||||
|
||||
/* remove the ghastly BOM if present */
|
||||
fseek(file, 0, SEEK_SET);
|
||||
size_read = fread(bom, 1, 3, file);
|
||||
if (size_read != 3)
|
||||
return 0;
|
||||
|
||||
offset = (astrcmp_n(bom, "\xEF\xBB\xBF", 3) == 0) ? 3 : 0;
|
||||
|
||||
size -= offset;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
utf8str = bmalloc(size+1);
|
||||
fseek(file, offset, SEEK_SET);
|
||||
|
||||
size = fread(utf8str, 1, size, file);
|
||||
if (size == 0) {
|
||||
bfree(utf8str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
utf8str[size] = 0;
|
||||
|
||||
*pstr = utf8str;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
char *os_quick_read_mbs_file(const char *path)
|
||||
{
|
||||
FILE *f = os_fopen(path, "rb");
|
||||
char *file_string = NULL;
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
os_fread_mbs(f, &file_string);
|
||||
fclose(f);
|
||||
|
||||
return file_string;
|
||||
}
|
||||
|
||||
char *os_quick_read_utf8_file(const char *path)
|
||||
{
|
||||
FILE *f = os_fopen(path, "rb");
|
||||
char *file_string = NULL;
|
||||
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
os_fread_utf8(f, &file_string);
|
||||
fclose(f);
|
||||
|
||||
return file_string;
|
||||
}
|
||||
|
||||
bool os_quick_write_mbs_file(const char *path, const char *str, size_t len)
|
||||
{
|
||||
FILE *f = os_fopen(path, "wb");
|
||||
char *mbs = NULL;
|
||||
size_t mbs_len = 0;
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
mbs_len = os_utf8_to_mbs_ptr(str, len, &mbs);
|
||||
if (mbs_len)
|
||||
fwrite(mbs, 1, mbs_len, f);
|
||||
bfree(mbs);
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool os_quick_write_utf8_file(const char *path, const char *str, size_t len,
|
||||
bool marker)
|
||||
{
|
||||
FILE *f = os_fopen(path, "wb");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
if (marker)
|
||||
fwrite("\xEF\xBB\xBF", 1, 3, f);
|
||||
if (len)
|
||||
fwrite(str, 1, len, f);
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool os_quick_write_utf8_file_safe(const char *path, const char *str,
|
||||
size_t len, bool marker, const char *temp_ext,
|
||||
const char *backup_ext)
|
||||
{
|
||||
struct dstr backup_path = {0};
|
||||
struct dstr temp_path = {0};
|
||||
bool success = false;
|
||||
|
||||
if (!temp_ext || !*temp_ext) {
|
||||
blog(LOG_ERROR, "os_quick_write_utf8_file_safe: invalid "
|
||||
"temporary extension specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
dstr_copy(&temp_path, path);
|
||||
if (*temp_ext != '.')
|
||||
dstr_cat(&temp_path, ".");
|
||||
dstr_cat(&temp_path, temp_ext);
|
||||
|
||||
if (!os_quick_write_utf8_file(temp_path.array, str, len, marker)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (backup_ext && *backup_ext) {
|
||||
dstr_copy(&backup_path, path);
|
||||
if (*backup_ext != '.')
|
||||
dstr_cat(&backup_path, ".");
|
||||
dstr_cat(&backup_path, backup_ext);
|
||||
|
||||
os_unlink(backup_path.array);
|
||||
os_rename(path, backup_path.array);
|
||||
|
||||
dstr_free(&backup_path);
|
||||
} else {
|
||||
os_unlink(path);
|
||||
}
|
||||
|
||||
os_rename(temp_path.array, path);
|
||||
success = true;
|
||||
|
||||
cleanup:
|
||||
dstr_free(&backup_path);
|
||||
dstr_free(&temp_path);
|
||||
return success;
|
||||
}
|
||||
|
||||
int64_t os_get_file_size(const char *path)
|
||||
{
|
||||
FILE* f = os_fopen(path, "rb");
|
||||
if (!f)
|
||||
return -1;
|
||||
|
||||
int64_t sz = os_fgetsize(f);
|
||||
fclose(f);
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
size_t os_mbs_to_wcs(const char *str, size_t len, wchar_t *dst, size_t dst_size)
|
||||
{
|
||||
size_t out_len;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
out_len = dst ? (dst_size - 1) : mbstowcs(NULL, str, len);
|
||||
|
||||
if (dst) {
|
||||
if (!dst_size)
|
||||
return 0;
|
||||
|
||||
if (out_len)
|
||||
out_len = mbstowcs(dst, str, out_len + 1);
|
||||
|
||||
dst[out_len] = 0;
|
||||
}
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
size_t os_utf8_to_wcs(const char *str, size_t len, wchar_t *dst,
|
||||
size_t dst_size)
|
||||
{
|
||||
size_t in_len;
|
||||
size_t out_len;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
in_len = len ? len : strlen(str);
|
||||
out_len = dst ? (dst_size - 1) : utf8_to_wchar(str, in_len, NULL, 0, 0);
|
||||
|
||||
if (dst) {
|
||||
if (!dst_size)
|
||||
return 0;
|
||||
|
||||
if (out_len)
|
||||
out_len = utf8_to_wchar(str, in_len,
|
||||
dst, out_len + 1, 0);
|
||||
|
||||
dst[out_len] = 0;
|
||||
}
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
size_t os_wcs_to_mbs(const wchar_t *str, size_t len, char *dst, size_t dst_size)
|
||||
{
|
||||
size_t out_len;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
out_len = dst ? (dst_size - 1) : wcstombs(NULL, str, len);
|
||||
|
||||
if (dst) {
|
||||
if (!dst_size)
|
||||
return 0;
|
||||
|
||||
if (out_len)
|
||||
out_len = wcstombs(dst, str, out_len + 1);
|
||||
|
||||
dst[out_len] = 0;
|
||||
}
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
size_t os_wcs_to_utf8(const wchar_t *str, size_t len, char *dst,
|
||||
size_t dst_size)
|
||||
{
|
||||
size_t in_len;
|
||||
size_t out_len;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
in_len = (len != 0) ? len : wcslen(str);
|
||||
out_len = dst ? (dst_size - 1) : wchar_to_utf8(str, in_len, NULL, 0, 0);
|
||||
|
||||
if (dst) {
|
||||
if (!dst_size)
|
||||
return 0;
|
||||
|
||||
if (out_len)
|
||||
out_len = wchar_to_utf8(str, in_len,
|
||||
dst, out_len + 1, 0);
|
||||
|
||||
dst[out_len] = 0;
|
||||
}
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
size_t os_mbs_to_wcs_ptr(const char *str, size_t len, wchar_t **pstr)
|
||||
{
|
||||
if (str) {
|
||||
size_t out_len = os_mbs_to_wcs(str, len, NULL, 0);
|
||||
|
||||
*pstr = bmalloc((out_len + 1) * sizeof(wchar_t));
|
||||
return os_mbs_to_wcs(str, len, *pstr, out_len + 1);
|
||||
} else {
|
||||
*pstr = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t os_utf8_to_wcs_ptr(const char *str, size_t len, wchar_t **pstr)
|
||||
{
|
||||
if (str) {
|
||||
size_t out_len = os_utf8_to_wcs(str, len, NULL, 0);
|
||||
|
||||
*pstr = bmalloc((out_len + 1) * sizeof(wchar_t));
|
||||
return os_utf8_to_wcs(str, len, *pstr, out_len + 1);
|
||||
} else {
|
||||
*pstr = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t os_wcs_to_mbs_ptr(const wchar_t *str, size_t len, char **pstr)
|
||||
{
|
||||
if (str) {
|
||||
size_t out_len = os_wcs_to_mbs(str, len, NULL, 0);
|
||||
|
||||
*pstr = bmalloc((out_len + 1) * sizeof(char));
|
||||
return os_wcs_to_mbs(str, len, *pstr, out_len + 1);
|
||||
} else {
|
||||
*pstr = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t os_wcs_to_utf8_ptr(const wchar_t *str, size_t len, char **pstr)
|
||||
{
|
||||
if (str) {
|
||||
size_t out_len = os_wcs_to_utf8(str, len, NULL, 0);
|
||||
|
||||
*pstr = bmalloc((out_len + 1) * sizeof(char));
|
||||
return os_wcs_to_utf8(str, len, *pstr, out_len + 1);
|
||||
} else {
|
||||
*pstr = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t os_utf8_to_mbs_ptr(const char *str, size_t len, char **pstr)
|
||||
{
|
||||
char *dst = NULL;
|
||||
size_t out_len = 0;
|
||||
|
||||
if (str) {
|
||||
wchar_t *wstr = NULL;
|
||||
size_t wlen = os_utf8_to_wcs_ptr(str, len, &wstr);
|
||||
out_len = os_wcs_to_mbs_ptr(wstr, wlen, &dst);
|
||||
bfree(wstr);
|
||||
}
|
||||
*pstr = dst;
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
size_t os_mbs_to_utf8_ptr(const char *str, size_t len, char **pstr)
|
||||
{
|
||||
char *dst = NULL;
|
||||
size_t out_len = 0;
|
||||
|
||||
if (str) {
|
||||
wchar_t *wstr = NULL;
|
||||
size_t wlen = os_mbs_to_wcs_ptr(str, len, &wstr);
|
||||
out_len = os_wcs_to_utf8_ptr(wstr, wlen, &dst);
|
||||
bfree(wstr);
|
||||
}
|
||||
|
||||
*pstr = dst;
|
||||
return out_len;
|
||||
}
|
||||
|
||||
/* locale independent double conversion from jansson, credit goes to them */
|
||||
|
||||
static inline void to_locale(char *str)
|
||||
{
|
||||
const char *point;
|
||||
char *pos;
|
||||
|
||||
point = localeconv()->decimal_point;
|
||||
if(*point == '.') {
|
||||
/* No conversion needed */
|
||||
return;
|
||||
}
|
||||
|
||||
pos = strchr(str, '.');
|
||||
if(pos)
|
||||
*pos = *point;
|
||||
}
|
||||
|
||||
static inline void from_locale(char *buffer)
|
||||
{
|
||||
const char *point;
|
||||
char *pos;
|
||||
|
||||
point = localeconv()->decimal_point;
|
||||
if(*point == '.') {
|
||||
/* No conversion needed */
|
||||
return;
|
||||
}
|
||||
|
||||
pos = strchr(buffer, *point);
|
||||
if(pos)
|
||||
*pos = '.';
|
||||
}
|
||||
|
||||
double os_strtod(const char *str)
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, 64, "%s", str);
|
||||
to_locale(buf);
|
||||
return strtod(buf, NULL);
|
||||
}
|
||||
|
||||
int os_dtostr(double value, char *dst, size_t size)
|
||||
{
|
||||
int ret;
|
||||
char *start, *end;
|
||||
size_t length;
|
||||
|
||||
ret = snprintf(dst, size, "%.17g", value);
|
||||
if(ret < 0)
|
||||
return -1;
|
||||
|
||||
length = (size_t)ret;
|
||||
if(length >= size)
|
||||
return -1;
|
||||
|
||||
from_locale(dst);
|
||||
|
||||
/* Make sure there's a dot or 'e' in the output. Otherwise
|
||||
a real is converted to an integer when decoding */
|
||||
if(strchr(dst, '.') == NULL && strchr(dst, 'e') == NULL) {
|
||||
if(length + 3 >= size) {
|
||||
/* No space to append ".0" */
|
||||
return -1;
|
||||
}
|
||||
dst[length] = '.';
|
||||
dst[length + 1] = '0';
|
||||
dst[length + 2] = '\0';
|
||||
length += 2;
|
||||
}
|
||||
|
||||
/* Remove leading '+' from positive exponent. Also remove leading
|
||||
zeros from exponents (added by some printf() implementations) */
|
||||
start = strchr(dst, 'e');
|
||||
if(start) {
|
||||
start++;
|
||||
end = start + 1;
|
||||
|
||||
if(*start == '-')
|
||||
start++;
|
||||
|
||||
while(*end == '0')
|
||||
end++;
|
||||
|
||||
if(end != start) {
|
||||
memmove(start, end, length - (size_t)(end - dst));
|
||||
length -= (size_t)(end - start);
|
||||
}
|
||||
}
|
||||
|
||||
return (int)length;
|
||||
}
|
||||
|
||||
static int recursive_mkdir(char *path)
|
||||
{
|
||||
char *last_slash;
|
||||
int ret;
|
||||
|
||||
ret = os_mkdir(path);
|
||||
if (ret != MKDIR_ERROR)
|
||||
return ret;
|
||||
|
||||
last_slash = strrchr(path, '/');
|
||||
if (!last_slash)
|
||||
return MKDIR_ERROR;
|
||||
|
||||
*last_slash = 0;
|
||||
ret = recursive_mkdir(path);
|
||||
*last_slash = '/';
|
||||
|
||||
if (ret == MKDIR_ERROR)
|
||||
return MKDIR_ERROR;
|
||||
|
||||
ret = os_mkdir(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int os_mkdirs(const char *dir)
|
||||
{
|
||||
struct dstr dir_str;
|
||||
int ret;
|
||||
|
||||
dstr_init_copy(&dir_str, dir);
|
||||
dstr_replace(&dir_str, "\\", "/");
|
||||
ret = recursive_mkdir(dir_str.array);
|
||||
dstr_free(&dir_str);
|
||||
return ret;
|
||||
}
|
||||
190
libobs/util/platform.h
Normal file
190
libobs/util/platform.h
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <sys/types.h>
|
||||
#include "c99defs.h"
|
||||
|
||||
/*
|
||||
* Platform-independent functions for Accessing files, encoding, DLLs,
|
||||
* sleep, timer, and timing.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
EXPORT FILE *os_wfopen(const wchar_t *path, const char *mode);
|
||||
EXPORT FILE *os_fopen(const char *path, const char *mode);
|
||||
EXPORT int64_t os_fgetsize(FILE *file);
|
||||
|
||||
EXPORT int os_fseeki64(FILE *file, int64_t offset, int origin);
|
||||
EXPORT int64_t os_ftelli64(FILE *file);
|
||||
|
||||
EXPORT size_t os_fread_mbs(FILE *file, char **pstr);
|
||||
EXPORT size_t os_fread_utf8(FILE *file, char **pstr);
|
||||
|
||||
/* functions purely for convenience */
|
||||
EXPORT char *os_quick_read_utf8_file(const char *path);
|
||||
EXPORT bool os_quick_write_utf8_file(const char *path, const char *str,
|
||||
size_t len, bool marker);
|
||||
EXPORT bool os_quick_write_utf8_file_safe(const char *path, const char *str,
|
||||
size_t len, bool marker, const char *temp_ext,
|
||||
const char *backup_ext);
|
||||
EXPORT char *os_quick_read_mbs_file(const char *path);
|
||||
EXPORT bool os_quick_write_mbs_file(const char *path, const char *str,
|
||||
size_t len);
|
||||
|
||||
EXPORT int64_t os_get_file_size(const char *path);
|
||||
EXPORT int64_t os_get_free_space(const char *path);
|
||||
|
||||
EXPORT size_t os_mbs_to_wcs(const char *str, size_t str_len, wchar_t *dst,
|
||||
size_t dst_size);
|
||||
EXPORT size_t os_utf8_to_wcs(const char *str, size_t len, wchar_t *dst,
|
||||
size_t dst_size);
|
||||
EXPORT size_t os_wcs_to_mbs(const wchar_t *str, size_t len, char *dst,
|
||||
size_t dst_size);
|
||||
EXPORT size_t os_wcs_to_utf8(const wchar_t *str, size_t len, char *dst,
|
||||
size_t dst_size);
|
||||
|
||||
EXPORT size_t os_mbs_to_wcs_ptr(const char *str, size_t len, wchar_t **pstr);
|
||||
EXPORT size_t os_utf8_to_wcs_ptr(const char *str, size_t len, wchar_t **pstr);
|
||||
EXPORT size_t os_wcs_to_mbs_ptr(const wchar_t *str, size_t len, char **pstr);
|
||||
EXPORT size_t os_wcs_to_utf8_ptr(const wchar_t *str, size_t len, char **pstr);
|
||||
|
||||
EXPORT size_t os_utf8_to_mbs_ptr(const char *str, size_t len, char **pstr);
|
||||
EXPORT size_t os_mbs_to_utf8_ptr(const char *str, size_t len, char **pstr);
|
||||
|
||||
EXPORT double os_strtod(const char *str);
|
||||
EXPORT int os_dtostr(double value, char *dst, size_t size);
|
||||
|
||||
EXPORT void *os_dlopen(const char *path);
|
||||
EXPORT void *os_dlsym(void *module, const char *func);
|
||||
EXPORT void os_dlclose(void *module);
|
||||
|
||||
struct os_cpu_usage_info;
|
||||
typedef struct os_cpu_usage_info os_cpu_usage_info_t;
|
||||
|
||||
EXPORT os_cpu_usage_info_t *os_cpu_usage_info_start(void);
|
||||
EXPORT double os_cpu_usage_info_query(os_cpu_usage_info_t *info);
|
||||
EXPORT void os_cpu_usage_info_destroy(os_cpu_usage_info_t *info);
|
||||
|
||||
typedef const void os_performance_token_t;
|
||||
EXPORT os_performance_token_t *os_request_high_performance(const char *reason);
|
||||
EXPORT void os_end_high_performance(os_performance_token_t *);
|
||||
|
||||
/**
|
||||
* Sleeps to a specific time (in nanoseconds). Doesn't have to be super
|
||||
* accurate in terms of actual slept time because the target time is ensured.
|
||||
* Returns false if already at or past target time.
|
||||
*/
|
||||
EXPORT bool os_sleepto_ns(uint64_t time_target);
|
||||
EXPORT void os_sleep_ms(uint32_t duration);
|
||||
|
||||
EXPORT uint64_t os_gettime_ns(void);
|
||||
|
||||
EXPORT int os_get_config_path(char *dst, size_t size, const char *name);
|
||||
EXPORT char *os_get_config_path_ptr(const char *name);
|
||||
|
||||
EXPORT bool os_file_exists(const char *path);
|
||||
|
||||
EXPORT size_t os_get_abs_path(const char *path, char *abspath, size_t size);
|
||||
EXPORT char *os_get_abs_path_ptr(const char *path);
|
||||
|
||||
struct os_dir;
|
||||
typedef struct os_dir os_dir_t;
|
||||
|
||||
struct os_dirent {
|
||||
char d_name[256];
|
||||
bool directory;
|
||||
};
|
||||
|
||||
EXPORT os_dir_t *os_opendir(const char *path);
|
||||
EXPORT struct os_dirent *os_readdir(os_dir_t *dir);
|
||||
EXPORT void os_closedir(os_dir_t *dir);
|
||||
|
||||
struct os_globent {
|
||||
char *path;
|
||||
bool directory;
|
||||
};
|
||||
|
||||
struct os_glob_info {
|
||||
size_t gl_pathc;
|
||||
struct os_globent *gl_pathv;
|
||||
};
|
||||
|
||||
typedef struct os_glob_info os_glob_t;
|
||||
|
||||
/* currently no flags available */
|
||||
|
||||
EXPORT int os_glob(const char *pattern, int flags, os_glob_t **pglob);
|
||||
EXPORT void os_globfree(os_glob_t *pglob);
|
||||
|
||||
EXPORT int os_unlink(const char *path);
|
||||
EXPORT int os_rmdir(const char *path);
|
||||
|
||||
EXPORT char *os_getcwd(char *path, size_t size);
|
||||
EXPORT int os_chdir(const char *path);
|
||||
|
||||
#define MKDIR_EXISTS 1
|
||||
#define MKDIR_SUCCESS 0
|
||||
#define MKDIR_ERROR -1
|
||||
|
||||
EXPORT int os_mkdir(const char *path);
|
||||
EXPORT int os_mkdirs(const char *path);
|
||||
EXPORT int os_rename(const char *old_path, const char *new_path);
|
||||
EXPORT int os_copyfile(const char *file_in, const char *file_out);
|
||||
|
||||
struct os_inhibit_info;
|
||||
typedef struct os_inhibit_info os_inhibit_t;
|
||||
|
||||
EXPORT os_inhibit_t *os_inhibit_sleep_create(const char *reason);
|
||||
EXPORT bool os_inhibit_sleep_set_active(os_inhibit_t *info, bool active);
|
||||
EXPORT void os_inhibit_sleep_destroy(os_inhibit_t *info);
|
||||
|
||||
EXPORT void os_breakpoint(void);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strtoll _strtoi64
|
||||
#if _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
# define ARCH_BITS 64
|
||||
#else
|
||||
# ifdef _WIN32
|
||||
# ifdef _WIN64
|
||||
# define ARCH_BITS 64
|
||||
# else
|
||||
# define ARCH_BITS 32
|
||||
# endif
|
||||
# else
|
||||
# ifdef __LP64__
|
||||
# define ARCH_BITS 64
|
||||
# else
|
||||
# define ARCH_BITS 32
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
1177
libobs/util/profiler.c
Normal file
1177
libobs/util/profiler.c
Normal file
File diff suppressed because it is too large
Load diff
116
libobs/util/profiler.h
Normal file
116
libobs/util/profiler.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include "darray.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct profiler_snapshot profiler_snapshot_t;
|
||||
typedef struct profiler_snapshot_entry profiler_snapshot_entry_t;
|
||||
typedef struct profiler_time_entry profiler_time_entry_t;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Profiling */
|
||||
|
||||
EXPORT void profile_register_root(const char *name,
|
||||
uint64_t expected_time_between_calls);
|
||||
|
||||
EXPORT void profile_start(const char *name);
|
||||
EXPORT void profile_end(const char *name);
|
||||
|
||||
EXPORT void profile_reenable_thread(void);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Profiler control */
|
||||
|
||||
EXPORT void profiler_start(void);
|
||||
EXPORT void profiler_stop(void);
|
||||
|
||||
EXPORT void profiler_print(profiler_snapshot_t *snap);
|
||||
EXPORT void profiler_print_time_between_calls(profiler_snapshot_t *snap);
|
||||
|
||||
EXPORT void profiler_free(void);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Profiler name storage */
|
||||
|
||||
typedef struct profiler_name_store profiler_name_store_t;
|
||||
|
||||
EXPORT profiler_name_store_t *profiler_name_store_create(void);
|
||||
EXPORT void profiler_name_store_free(profiler_name_store_t *store);
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#define PRINTFATTR(f, a) __attribute__((__format__(__printf__, f, a)))
|
||||
#else
|
||||
#define PRINTFATTR(f, a)
|
||||
#endif
|
||||
|
||||
PRINTFATTR(2, 3)
|
||||
EXPORT const char *profile_store_name(profiler_name_store_t *store,
|
||||
const char *format, ...);
|
||||
|
||||
#undef PRINTFATTR
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Profiler data access */
|
||||
|
||||
struct profiler_time_entry {
|
||||
uint64_t time_delta;
|
||||
uint64_t count;
|
||||
};
|
||||
|
||||
typedef DARRAY(profiler_time_entry_t) profiler_time_entries_t;
|
||||
|
||||
typedef bool (*profiler_entry_enum_func)(void *context,
|
||||
profiler_snapshot_entry_t *entry);
|
||||
|
||||
EXPORT profiler_snapshot_t *profile_snapshot_create(void);
|
||||
EXPORT void profile_snapshot_free(profiler_snapshot_t *snap);
|
||||
|
||||
EXPORT bool profiler_snapshot_dump_csv(const profiler_snapshot_t *snap,
|
||||
const char *filename);
|
||||
EXPORT bool profiler_snapshot_dump_csv_gz(const profiler_snapshot_t *snap,
|
||||
const char *filename);
|
||||
|
||||
EXPORT size_t profiler_snapshot_num_roots(profiler_snapshot_t *snap);
|
||||
EXPORT void profiler_snapshot_enumerate_roots(profiler_snapshot_t *snap,
|
||||
profiler_entry_enum_func func, void *context);
|
||||
|
||||
typedef bool (*profiler_name_filter_func)(void *data, const char *name,
|
||||
bool *remove);
|
||||
EXPORT void profiler_snapshot_filter_roots(profiler_snapshot_t *snap,
|
||||
profiler_name_filter_func func, void *data);
|
||||
|
||||
EXPORT size_t profiler_snapshot_num_children(profiler_snapshot_entry_t *entry);
|
||||
EXPORT void profiler_snapshot_enumerate_children(
|
||||
profiler_snapshot_entry_t *entry,
|
||||
profiler_entry_enum_func func, void *context);
|
||||
|
||||
EXPORT const char *profiler_snapshot_entry_name(
|
||||
profiler_snapshot_entry_t *entry);
|
||||
|
||||
EXPORT profiler_time_entries_t *profiler_snapshot_entry_times(
|
||||
profiler_snapshot_entry_t *entry);
|
||||
EXPORT uint64_t profiler_snapshot_entry_min_time(
|
||||
profiler_snapshot_entry_t *entry);
|
||||
EXPORT uint64_t profiler_snapshot_entry_max_time(
|
||||
profiler_snapshot_entry_t *entry);
|
||||
EXPORT uint64_t profiler_snapshot_entry_overall_count(
|
||||
profiler_snapshot_entry_t *entry);
|
||||
|
||||
EXPORT profiler_time_entries_t *profiler_snapshot_entry_times_between_calls(
|
||||
profiler_snapshot_entry_t *entry);
|
||||
EXPORT uint64_t profiler_snapshot_entry_expected_time_between_calls(
|
||||
profiler_snapshot_entry_t *entry);
|
||||
EXPORT uint64_t profiler_snapshot_entry_min_time_between_calls(
|
||||
profiler_snapshot_entry_t *entry);
|
||||
EXPORT uint64_t profiler_snapshot_entry_max_time_between_calls(
|
||||
profiler_snapshot_entry_t *entry);
|
||||
EXPORT uint64_t profiler_snapshot_entry_overall_between_calls_count(
|
||||
profiler_snapshot_entry_t *entry);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
52
libobs/util/profiler.hpp
Normal file
52
libobs/util/profiler.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include "profiler.h"
|
||||
|
||||
struct ScopeProfiler {
|
||||
const char *name;
|
||||
bool enabled = true;
|
||||
|
||||
ScopeProfiler(const char *name)
|
||||
: name(name)
|
||||
{
|
||||
profile_start(name);
|
||||
}
|
||||
|
||||
~ScopeProfiler() { Stop(); }
|
||||
|
||||
ScopeProfiler(const ScopeProfiler &) = delete;
|
||||
ScopeProfiler(ScopeProfiler &&other)
|
||||
: name(other.name),
|
||||
enabled(other.enabled)
|
||||
{
|
||||
other.enabled = false;
|
||||
}
|
||||
|
||||
ScopeProfiler &operator=(const ScopeProfiler &) = delete;
|
||||
ScopeProfiler &operator=(ScopeProfiler &&other) = delete;
|
||||
|
||||
void Stop()
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
profile_end(name);
|
||||
enabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef NO_PROFILER_MACROS
|
||||
|
||||
#define ScopeProfiler_NameConcatImpl(x, y) x ## y
|
||||
#define ScopeProfiler_NameConcat(x, y) ScopeProfiler_NameConcatImpl(x, y)
|
||||
|
||||
#ifdef __COUNTER__
|
||||
#define ScopeProfiler_Name(x) ScopeProfiler_NameConcat(x, __COUNTER__)
|
||||
#else
|
||||
#define ScopeProfiler_Name(x) ScopeProfiler_NameConcat(x, __LINE__)
|
||||
#endif
|
||||
|
||||
#define ProfileScope(x) ScopeProfiler \
|
||||
ScopeProfiler_Name(SCOPE_PROFILE){x}
|
||||
|
||||
#endif
|
||||
164
libobs/util/serializer.h
Normal file
164
libobs/util/serializer.h
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "c99defs.h"
|
||||
|
||||
/*
|
||||
* General programmable serialization functions. (A shared interface to
|
||||
* various reading/writing to/from different inputs/outputs)
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum serialize_seek_type {
|
||||
SERIALIZE_SEEK_START,
|
||||
SERIALIZE_SEEK_CURRENT,
|
||||
SERIALIZE_SEEK_END
|
||||
};
|
||||
|
||||
struct serializer {
|
||||
void *data;
|
||||
|
||||
size_t (*read)(void *, void *, size_t);
|
||||
size_t (*write)(void *, const void *, size_t);
|
||||
int64_t (*seek)(void *, int64_t, enum serialize_seek_type);
|
||||
int64_t (*get_pos)(void *);
|
||||
};
|
||||
|
||||
static inline size_t s_read(struct serializer *s, void *data, size_t size)
|
||||
{
|
||||
if (s && s->read && data && size)
|
||||
return s->read(s->data, (void*)data, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t s_write(struct serializer *s, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
if (s && s->write && data && size)
|
||||
return s->write(s->data, (void*)data, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t serialize(struct serializer *s, void *data, size_t len)
|
||||
{
|
||||
if (s) {
|
||||
if (s->write)
|
||||
return s->write(s->data, data, len);
|
||||
else if (s->read)
|
||||
return s->read(s->data, data, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int64_t serializer_seek(struct serializer *s, int64_t offset,
|
||||
enum serialize_seek_type seek_type)
|
||||
{
|
||||
if (s && s->seek)
|
||||
return s->seek(s->data, offset, seek_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int64_t serializer_get_pos(struct serializer *s)
|
||||
{
|
||||
if (s && s->get_pos)
|
||||
return s->get_pos(s->data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* formatted this to be similar to the AVIO layout that ffmpeg uses */
|
||||
|
||||
static inline void s_w8(struct serializer *s, uint8_t u8)
|
||||
{
|
||||
s_write(s, &u8, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
static inline void s_wl16(struct serializer *s, uint16_t u16)
|
||||
{
|
||||
s_w8(s, (uint8_t)u16);
|
||||
s_w8(s, u16 >> 8);
|
||||
}
|
||||
|
||||
static inline void s_wl24(struct serializer *s, uint32_t u24)
|
||||
{
|
||||
s_w8 (s, (uint8_t)u24);
|
||||
s_wl16(s, (uint16_t)(u24 >> 8));
|
||||
}
|
||||
|
||||
static inline void s_wl32(struct serializer *s, uint32_t u32)
|
||||
{
|
||||
s_wl16(s, (uint16_t)u32);
|
||||
s_wl16(s, (uint16_t)(u32 >> 16));
|
||||
}
|
||||
|
||||
static inline void s_wl64(struct serializer *s, uint64_t u64)
|
||||
{
|
||||
s_wl32(s, (uint32_t)u64);
|
||||
s_wl32(s, (uint32_t)(u64 >> 32));
|
||||
}
|
||||
|
||||
static inline void s_wlf(struct serializer *s, float f)
|
||||
{
|
||||
s_wl32(s, *(uint32_t*)&f);
|
||||
}
|
||||
|
||||
static inline void s_wld(struct serializer *s, double d)
|
||||
{
|
||||
s_wl64(s, *(uint64_t*)&d);
|
||||
}
|
||||
|
||||
static inline void s_wb16(struct serializer *s, uint16_t u16)
|
||||
{
|
||||
s_w8(s, u16 >> 8);
|
||||
s_w8(s, (uint8_t)u16);
|
||||
}
|
||||
|
||||
static inline void s_wb24(struct serializer *s, uint32_t u24)
|
||||
{
|
||||
s_wb16(s, (uint16_t)(u24 >> 8));
|
||||
s_w8 (s, (uint8_t)u24);
|
||||
}
|
||||
|
||||
static inline void s_wb32(struct serializer *s, uint32_t u32)
|
||||
{
|
||||
s_wb16(s, (uint16_t)(u32 >> 16));
|
||||
s_wb16(s, (uint16_t)u32);
|
||||
}
|
||||
|
||||
static inline void s_wb64(struct serializer *s, uint64_t u64)
|
||||
{
|
||||
s_wb32(s, (uint32_t)(u64 >> 32));
|
||||
s_wb32(s, (uint32_t)u64);
|
||||
}
|
||||
|
||||
static inline void s_wbf(struct serializer *s, float f)
|
||||
{
|
||||
s_wb32(s, *(uint32_t*)&f);
|
||||
}
|
||||
|
||||
static inline void s_wbd(struct serializer *s, double d)
|
||||
{
|
||||
s_wb64(s, *(uint64_t*)&d);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
416
libobs/util/text-lookup.c
Normal file
416
libobs/util/text-lookup.c
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dstr.h"
|
||||
#include "text-lookup.h"
|
||||
#include "lexer.h"
|
||||
#include "platform.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct text_leaf {
|
||||
char *lookup, *value;
|
||||
};
|
||||
|
||||
static inline void text_leaf_destroy(struct text_leaf *leaf)
|
||||
{
|
||||
if (leaf) {
|
||||
bfree(leaf->lookup);
|
||||
bfree(leaf->value);
|
||||
bfree(leaf);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct text_node {
|
||||
struct dstr str;
|
||||
struct text_node *first_subnode;
|
||||
struct text_leaf *leaf;
|
||||
|
||||
struct text_node *next;
|
||||
};
|
||||
|
||||
static void text_node_destroy(struct text_node *node)
|
||||
{
|
||||
struct text_node *subnode;
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
subnode = node->first_subnode;
|
||||
while (subnode) {
|
||||
struct text_node *destroy_node = subnode;
|
||||
|
||||
subnode = subnode->next;
|
||||
text_node_destroy(destroy_node);
|
||||
}
|
||||
|
||||
dstr_free(&node->str);
|
||||
if (node->leaf)
|
||||
text_leaf_destroy(node->leaf);
|
||||
bfree(node);
|
||||
}
|
||||
|
||||
static struct text_node *text_node_bychar(struct text_node *node, char ch)
|
||||
{
|
||||
struct text_node *subnode = node->first_subnode;
|
||||
|
||||
while (subnode) {
|
||||
if (!dstr_is_empty(&subnode->str) &&
|
||||
subnode->str.array[0] == ch)
|
||||
return subnode;
|
||||
|
||||
subnode = subnode->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct text_node *text_node_byname(struct text_node *node,
|
||||
const char *name)
|
||||
{
|
||||
struct text_node *subnode = node->first_subnode;
|
||||
|
||||
while (subnode) {
|
||||
if (astrcmpi_n(subnode->str.array, name, subnode->str.len) == 0)
|
||||
return subnode;
|
||||
|
||||
subnode = subnode->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
struct text_lookup {
|
||||
struct dstr language;
|
||||
struct text_node *top;
|
||||
};
|
||||
|
||||
static void lookup_createsubnode(const char *lookup_val,
|
||||
struct text_leaf *leaf, struct text_node *node)
|
||||
{
|
||||
struct text_node *new = bzalloc(sizeof(struct text_node));
|
||||
new->leaf = leaf;
|
||||
new->next = node->first_subnode;
|
||||
dstr_copy(&new->str, lookup_val);
|
||||
|
||||
node->first_subnode = new;
|
||||
}
|
||||
|
||||
static void lookup_splitnode(const char *lookup_val, size_t len,
|
||||
struct text_leaf *leaf, struct text_node *node)
|
||||
{
|
||||
struct text_node *split = bzalloc(sizeof(struct text_node));
|
||||
|
||||
dstr_copy(&split->str, node->str.array+len);
|
||||
split->leaf = node->leaf;
|
||||
split->first_subnode = node->first_subnode;
|
||||
node->first_subnode = split;
|
||||
|
||||
dstr_resize(&node->str, len);
|
||||
|
||||
if (lookup_val[len] != 0) {
|
||||
node->leaf = NULL;
|
||||
lookup_createsubnode(lookup_val+len, leaf, node);
|
||||
} else {
|
||||
node->leaf = leaf;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void lookup_replaceleaf(struct text_node *node,
|
||||
struct text_leaf *leaf)
|
||||
{
|
||||
text_leaf_destroy(node->leaf);
|
||||
node->leaf = leaf;
|
||||
}
|
||||
|
||||
static void lookup_addstring(const char *lookup_val, struct text_leaf *leaf,
|
||||
struct text_node *node)
|
||||
{
|
||||
struct text_node *child;
|
||||
|
||||
/* value already exists, so replace */
|
||||
if (!lookup_val || !*lookup_val) {
|
||||
lookup_replaceleaf(node, leaf);
|
||||
return;
|
||||
}
|
||||
|
||||
child = text_node_bychar(node, *lookup_val);
|
||||
if (child) {
|
||||
size_t len;
|
||||
|
||||
for (len = 0; len < child->str.len; len++) {
|
||||
char val1 = child->str.array[len],
|
||||
val2 = lookup_val[len];
|
||||
|
||||
if (val1 >= 'A' && val1 <= 'Z')
|
||||
val1 += 0x20;
|
||||
if (val2 >= 'A' && val2 <= 'Z')
|
||||
val2 += 0x20;
|
||||
|
||||
if (val1 != val2)
|
||||
break;
|
||||
}
|
||||
|
||||
if (len == child->str.len) {
|
||||
lookup_addstring(lookup_val+len, leaf, child);
|
||||
return;
|
||||
} else {
|
||||
lookup_splitnode(lookup_val, len, leaf, child);
|
||||
}
|
||||
} else {
|
||||
lookup_createsubnode(lookup_val, leaf, node);
|
||||
}
|
||||
}
|
||||
|
||||
static void lookup_getstringtoken(struct lexer *lex, struct strref *token)
|
||||
{
|
||||
const char *temp = lex->offset;
|
||||
bool was_backslash = false;
|
||||
|
||||
while (*temp != 0 && *temp != '\n') {
|
||||
if (!was_backslash) {
|
||||
if (*temp == '\\') {
|
||||
was_backslash = true;
|
||||
} else if (*temp == '"') {
|
||||
temp++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
was_backslash = false;
|
||||
}
|
||||
|
||||
++temp;
|
||||
}
|
||||
|
||||
token->len += (size_t)(temp - lex->offset);
|
||||
|
||||
if (*token->array == '"') {
|
||||
token->array++;
|
||||
token->len--;
|
||||
|
||||
if (*(temp-1) == '"')
|
||||
token->len--;
|
||||
}
|
||||
|
||||
lex->offset = temp;
|
||||
}
|
||||
|
||||
static bool lookup_gettoken(struct lexer *lex, struct strref *str)
|
||||
{
|
||||
struct base_token temp;
|
||||
|
||||
base_token_clear(&temp);
|
||||
strref_clear(str);
|
||||
|
||||
while (lexer_getbasetoken(lex, &temp, PARSE_WHITESPACE)) {
|
||||
char ch = *temp.text.array;
|
||||
|
||||
if (!str->array) {
|
||||
/* comments are designated with a #, and end at LF */
|
||||
if (ch == '#') {
|
||||
while(ch != '\n' && ch != 0)
|
||||
ch = *(++lex->offset);
|
||||
} else if (temp.type == BASETOKEN_WHITESPACE) {
|
||||
strref_copy(str, &temp.text);
|
||||
break;
|
||||
} else {
|
||||
strref_copy(str, &temp.text);
|
||||
if (ch == '"') {
|
||||
lookup_getstringtoken(lex, str);
|
||||
break;
|
||||
} else if (ch == '=') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (temp.type == BASETOKEN_WHITESPACE ||
|
||||
*temp.text.array == '=') {
|
||||
lex->offset -= temp.text.len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch == '#') {
|
||||
lex->offset--;
|
||||
break;
|
||||
}
|
||||
|
||||
str->len += temp.text.len;
|
||||
}
|
||||
}
|
||||
|
||||
return (str->len != 0);
|
||||
}
|
||||
|
||||
static inline bool lookup_goto_nextline(struct lexer *p)
|
||||
{
|
||||
struct strref val;
|
||||
bool success = true;
|
||||
|
||||
strref_clear(&val);
|
||||
|
||||
while (true) {
|
||||
if (!lookup_gettoken(p, &val)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if (*val.array == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static char *convert_string(const char *str, size_t len)
|
||||
{
|
||||
struct dstr out;
|
||||
out.array = bstrdup_n(str, len);
|
||||
out.capacity = len+1;
|
||||
out.len = len;
|
||||
|
||||
dstr_replace(&out, "\\n", "\n");
|
||||
dstr_replace(&out, "\\t", "\t");
|
||||
dstr_replace(&out, "\\r", "\r");
|
||||
|
||||
return out.array;
|
||||
}
|
||||
|
||||
static void lookup_addfiledata(struct text_lookup *lookup,
|
||||
const char *file_data)
|
||||
{
|
||||
struct lexer lex;
|
||||
struct strref name, value;
|
||||
|
||||
lexer_init(&lex);
|
||||
lexer_start(&lex, file_data);
|
||||
strref_clear(&name);
|
||||
strref_clear(&value);
|
||||
|
||||
while (lookup_gettoken(&lex, &name)) {
|
||||
struct text_leaf *leaf;
|
||||
bool got_eq = false;
|
||||
|
||||
if (*name.array == '\n')
|
||||
continue;
|
||||
getval:
|
||||
if (!lookup_gettoken(&lex, &value))
|
||||
break;
|
||||
if (*value.array == '\n')
|
||||
continue;
|
||||
else if (!got_eq && *value.array == '=') {
|
||||
got_eq = true;
|
||||
goto getval;
|
||||
}
|
||||
|
||||
leaf = bmalloc(sizeof(struct text_leaf));
|
||||
leaf->lookup = bstrdup_n(name.array, name.len);
|
||||
leaf->value = convert_string(value.array, value.len);
|
||||
|
||||
lookup_addstring(leaf->lookup, leaf, lookup->top);
|
||||
|
||||
if (!lookup_goto_nextline(&lex))
|
||||
break;
|
||||
}
|
||||
|
||||
lexer_free(&lex);
|
||||
}
|
||||
|
||||
static inline bool lookup_getstring(const char *lookup_val,
|
||||
const char **out, struct text_node *node)
|
||||
{
|
||||
struct text_node *child;
|
||||
char ch;
|
||||
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
child = text_node_byname(node, lookup_val);
|
||||
if (!child)
|
||||
return false;
|
||||
|
||||
lookup_val += child->str.len;
|
||||
ch = *lookup_val;
|
||||
if (ch)
|
||||
return lookup_getstring(lookup_val, out, child);
|
||||
|
||||
if (!child->leaf)
|
||||
return false;
|
||||
|
||||
*out = child->leaf->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
lookup_t *text_lookup_create(const char *path)
|
||||
{
|
||||
struct text_lookup *lookup = bzalloc(sizeof(struct text_lookup));
|
||||
|
||||
if (!text_lookup_add(lookup, path)) {
|
||||
bfree(lookup);
|
||||
lookup = NULL;
|
||||
}
|
||||
|
||||
return lookup;
|
||||
}
|
||||
|
||||
bool text_lookup_add(lookup_t *lookup, const char *path)
|
||||
{
|
||||
struct dstr file_str;
|
||||
char *temp = NULL;
|
||||
FILE *file;
|
||||
|
||||
file = os_fopen(path, "rb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
os_fread_utf8(file, &temp);
|
||||
dstr_init_move_array(&file_str, temp);
|
||||
fclose(file);
|
||||
|
||||
if (!file_str.array)
|
||||
return false;
|
||||
|
||||
if (!lookup->top)
|
||||
lookup->top = bzalloc(sizeof(struct text_node));
|
||||
|
||||
dstr_replace(&file_str, "\r", " ");
|
||||
lookup_addfiledata(lookup, file_str.array);
|
||||
dstr_free(&file_str);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void text_lookup_destroy(lookup_t *lookup)
|
||||
{
|
||||
if (lookup) {
|
||||
dstr_free(&lookup->language);
|
||||
text_node_destroy(lookup->top);
|
||||
|
||||
bfree(lookup);
|
||||
}
|
||||
}
|
||||
|
||||
bool text_lookup_getstr(lookup_t *lookup, const char *lookup_val,
|
||||
const char **out)
|
||||
{
|
||||
if (lookup)
|
||||
return lookup_getstring(lookup_val, out, lookup->top);
|
||||
return false;
|
||||
}
|
||||
46
libobs/util/text-lookup.h
Normal file
46
libobs/util/text-lookup.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Text Lookup interface
|
||||
*
|
||||
* Used for storing and looking up localized strings. Stores locazation
|
||||
* strings in a radix/trie tree to efficiently look up associated strings via a
|
||||
* unique string identifier name.
|
||||
*/
|
||||
|
||||
#include "c99defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* opaque typdef */
|
||||
struct text_lookup;
|
||||
typedef struct text_lookup lookup_t;
|
||||
|
||||
/* functions */
|
||||
EXPORT lookup_t *text_lookup_create(const char *path);
|
||||
EXPORT bool text_lookup_add(lookup_t *lookup, const char *path);
|
||||
EXPORT void text_lookup_destroy(lookup_t *lookup);
|
||||
EXPORT bool text_lookup_getstr(lookup_t *lookup, const char *lookup_val,
|
||||
const char **out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
258
libobs/util/threading-posix.c
Normal file
258
libobs/util/threading-posix.c
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined(__APPLE__) || defined(__MINGW32__)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#include <mach/semaphore.h>
|
||||
#include <mach/task.h>
|
||||
#include <mach/mach_init.h>
|
||||
#else
|
||||
#define _GNU_SOURCE
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
#include "bmem.h"
|
||||
#include "threading.h"
|
||||
|
||||
struct os_event_data {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
volatile bool signalled;
|
||||
bool manual;
|
||||
};
|
||||
|
||||
int os_event_init(os_event_t **event, enum os_event_type type)
|
||||
{
|
||||
int code = 0;
|
||||
|
||||
struct os_event_data *data = bzalloc(sizeof(struct os_event_data));
|
||||
|
||||
if ((code = pthread_mutex_init(&data->mutex, NULL)) < 0) {
|
||||
bfree(data);
|
||||
return code;
|
||||
}
|
||||
|
||||
if ((code = pthread_cond_init(&data->cond, NULL)) < 0) {
|
||||
pthread_mutex_destroy(&data->mutex);
|
||||
bfree(data);
|
||||
return code;
|
||||
}
|
||||
|
||||
data->manual = (type == OS_EVENT_TYPE_MANUAL);
|
||||
data->signalled = false;
|
||||
*event = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os_event_destroy(os_event_t *event)
|
||||
{
|
||||
if (event) {
|
||||
pthread_mutex_destroy(&event->mutex);
|
||||
pthread_cond_destroy(&event->cond);
|
||||
bfree(event);
|
||||
}
|
||||
}
|
||||
|
||||
int os_event_wait(os_event_t *event)
|
||||
{
|
||||
int code = 0;
|
||||
pthread_mutex_lock(&event->mutex);
|
||||
if (!event->signalled)
|
||||
code = pthread_cond_wait(&event->cond, &event->mutex);
|
||||
|
||||
if (code == 0) {
|
||||
if (!event->manual)
|
||||
event->signalled = false;
|
||||
pthread_mutex_unlock(&event->mutex);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static inline void add_ms_to_ts(struct timespec *ts,
|
||||
unsigned long milliseconds)
|
||||
{
|
||||
ts->tv_sec += milliseconds/1000;
|
||||
ts->tv_nsec += (milliseconds%1000)*1000000;
|
||||
if (ts->tv_nsec > 1000000000) {
|
||||
ts->tv_sec += 1;
|
||||
ts->tv_nsec -= 1000000000;
|
||||
}
|
||||
}
|
||||
|
||||
int os_event_timedwait(os_event_t *event, unsigned long milliseconds)
|
||||
{
|
||||
int code = 0;
|
||||
pthread_mutex_lock(&event->mutex);
|
||||
if (!event->signalled) {
|
||||
struct timespec ts;
|
||||
#if defined(__APPLE__) || defined(__MINGW32__)
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
#endif
|
||||
add_ms_to_ts(&ts, milliseconds);
|
||||
code = pthread_cond_timedwait(&event->cond, &event->mutex, &ts);
|
||||
}
|
||||
|
||||
if (code == 0) {
|
||||
if (!event->manual)
|
||||
event->signalled = false;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&event->mutex);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
int os_event_try(os_event_t *event)
|
||||
{
|
||||
int ret = EAGAIN;
|
||||
|
||||
pthread_mutex_lock(&event->mutex);
|
||||
if (event->signalled) {
|
||||
if (!event->manual)
|
||||
event->signalled = false;
|
||||
ret = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&event->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int os_event_signal(os_event_t *event)
|
||||
{
|
||||
int code = 0;
|
||||
|
||||
pthread_mutex_lock(&event->mutex);
|
||||
code = pthread_cond_signal(&event->cond);
|
||||
event->signalled = true;
|
||||
pthread_mutex_unlock(&event->mutex);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
void os_event_reset(os_event_t *event)
|
||||
{
|
||||
pthread_mutex_lock(&event->mutex);
|
||||
event->signalled = false;
|
||||
pthread_mutex_unlock(&event->mutex);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
struct os_sem_data {
|
||||
semaphore_t sem;
|
||||
task_t task;
|
||||
};
|
||||
|
||||
int os_sem_init(os_sem_t **sem, int value)
|
||||
{
|
||||
semaphore_t new_sem;
|
||||
task_t task = mach_task_self();
|
||||
|
||||
if (semaphore_create(task, &new_sem, 0, value) != KERN_SUCCESS)
|
||||
return -1;
|
||||
|
||||
*sem = bzalloc(sizeof(struct os_sem_data));
|
||||
if (!*sem)
|
||||
return -2;
|
||||
|
||||
(*sem)->sem = new_sem;
|
||||
(*sem)->task = task;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os_sem_destroy(os_sem_t *sem)
|
||||
{
|
||||
if (sem) {
|
||||
semaphore_destroy(sem->task, sem->sem);
|
||||
bfree(sem);
|
||||
}
|
||||
}
|
||||
|
||||
int os_sem_post(os_sem_t *sem)
|
||||
{
|
||||
if (!sem) return -1;
|
||||
return (semaphore_signal(sem->sem) == KERN_SUCCESS) ? 0 : -1;
|
||||
}
|
||||
|
||||
int os_sem_wait(os_sem_t *sem)
|
||||
{
|
||||
if (!sem) return -1;
|
||||
return (semaphore_wait(sem->sem) == KERN_SUCCESS) ? 0 : -1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct os_sem_data {
|
||||
sem_t sem;
|
||||
};
|
||||
|
||||
int os_sem_init(os_sem_t **sem, int value)
|
||||
{
|
||||
sem_t new_sem;
|
||||
int ret = sem_init(&new_sem, 0, value);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
*sem = bzalloc(sizeof(struct os_sem_data));
|
||||
(*sem)->sem = new_sem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os_sem_destroy(os_sem_t *sem)
|
||||
{
|
||||
if (sem) {
|
||||
sem_destroy(&sem->sem);
|
||||
bfree(sem);
|
||||
}
|
||||
}
|
||||
|
||||
int os_sem_post(os_sem_t *sem)
|
||||
{
|
||||
if (!sem) return -1;
|
||||
return sem_post(&sem->sem);
|
||||
}
|
||||
|
||||
int os_sem_wait(os_sem_t *sem)
|
||||
{
|
||||
if (!sem) return -1;
|
||||
return sem_wait(&sem->sem);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void os_set_thread_name(const char *name)
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
pthread_setname_np(name);
|
||||
#elif defined(__FreeBSD__)
|
||||
pthread_set_name_np(pthread_self(), name);
|
||||
#elif defined(__GLIBC__) && !defined(__MINGW32__)
|
||||
pthread_setname_np(pthread_self(), name);
|
||||
#endif
|
||||
}
|
||||
53
libobs/util/threading-posix.h
Normal file
53
libobs/util/threading-posix.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
static inline long os_atomic_inc_long(volatile long *val)
|
||||
{
|
||||
return __sync_add_and_fetch(val, 1);
|
||||
}
|
||||
|
||||
static inline long os_atomic_dec_long(volatile long *val)
|
||||
{
|
||||
return __sync_sub_and_fetch(val, 1);
|
||||
}
|
||||
|
||||
static inline long os_atomic_set_long(volatile long *ptr, long val)
|
||||
{
|
||||
return __sync_lock_test_and_set(ptr, val);
|
||||
}
|
||||
|
||||
static inline long os_atomic_load_long(const volatile long *ptr)
|
||||
{
|
||||
return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
static inline bool os_atomic_compare_swap_long(volatile long *val,
|
||||
long old_val, long new_val)
|
||||
{
|
||||
return __sync_bool_compare_and_swap(val, old_val, new_val);
|
||||
}
|
||||
|
||||
static inline bool os_atomic_set_bool(volatile bool *ptr, bool val)
|
||||
{
|
||||
return __sync_lock_test_and_set(ptr, val);
|
||||
}
|
||||
|
||||
static inline bool os_atomic_load_bool(const volatile bool *ptr)
|
||||
{
|
||||
return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
191
libobs/util/threading-windows.c
Normal file
191
libobs/util/threading-windows.c
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "bmem.h"
|
||||
#include "threading.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <excpt.h>
|
||||
#ifndef TRYLEVEL_NONE
|
||||
#ifndef __MINGW64__
|
||||
#define NO_SEH_MINGW
|
||||
#endif
|
||||
#ifndef __try
|
||||
#define __try
|
||||
#endif
|
||||
#ifndef __except
|
||||
#define __except(x) if (0)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int os_event_init(os_event_t **event, enum os_event_type type)
|
||||
{
|
||||
HANDLE handle;
|
||||
|
||||
handle = CreateEvent(NULL, (type == OS_EVENT_TYPE_MANUAL), FALSE, NULL);
|
||||
if (!handle)
|
||||
return -1;
|
||||
|
||||
*event = (os_event_t*)handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os_event_destroy(os_event_t *event)
|
||||
{
|
||||
if (event)
|
||||
CloseHandle((HANDLE)event);
|
||||
}
|
||||
|
||||
int os_event_wait(os_event_t *event)
|
||||
{
|
||||
DWORD code;
|
||||
|
||||
if (!event)
|
||||
return EINVAL;
|
||||
|
||||
code = WaitForSingleObject((HANDLE)event, INFINITE);
|
||||
if (code != WAIT_OBJECT_0)
|
||||
return EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_event_timedwait(os_event_t *event, unsigned long milliseconds)
|
||||
{
|
||||
DWORD code;
|
||||
|
||||
if (!event)
|
||||
return EINVAL;
|
||||
|
||||
code = WaitForSingleObject((HANDLE)event, milliseconds);
|
||||
if (code == WAIT_TIMEOUT)
|
||||
return ETIMEDOUT;
|
||||
else if (code != WAIT_OBJECT_0)
|
||||
return EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_event_try(os_event_t *event)
|
||||
{
|
||||
DWORD code;
|
||||
|
||||
if (!event)
|
||||
return EINVAL;
|
||||
|
||||
code = WaitForSingleObject((HANDLE)event, 0);
|
||||
if (code == WAIT_TIMEOUT)
|
||||
return EAGAIN;
|
||||
else if (code != WAIT_OBJECT_0)
|
||||
return EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_event_signal(os_event_t *event)
|
||||
{
|
||||
if (!event)
|
||||
return EINVAL;
|
||||
|
||||
if (!SetEvent((HANDLE)event))
|
||||
return EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os_event_reset(os_event_t *event)
|
||||
{
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
ResetEvent((HANDLE)event);
|
||||
}
|
||||
|
||||
int os_sem_init(os_sem_t **sem, int value)
|
||||
{
|
||||
HANDLE handle = CreateSemaphore(NULL, (LONG)value, 0x7FFFFFFF, NULL);
|
||||
if (!handle)
|
||||
return -1;
|
||||
|
||||
*sem = (os_sem_t*)handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os_sem_destroy(os_sem_t *sem)
|
||||
{
|
||||
if (sem)
|
||||
CloseHandle((HANDLE)sem);
|
||||
}
|
||||
|
||||
int os_sem_post(os_sem_t *sem)
|
||||
{
|
||||
if (!sem) return -1;
|
||||
return ReleaseSemaphore((HANDLE)sem, 1, NULL) ? 0 : -1;
|
||||
}
|
||||
|
||||
int os_sem_wait(os_sem_t *sem)
|
||||
{
|
||||
DWORD ret;
|
||||
|
||||
if (!sem) return -1;
|
||||
ret = WaitForSingleObject((HANDLE)sem, INFINITE);
|
||||
return (ret == WAIT_OBJECT_0) ? 0 : -1;
|
||||
}
|
||||
|
||||
#define VC_EXCEPTION 0x406D1388
|
||||
|
||||
#pragma pack(push,8)
|
||||
struct vs_threadname_info {
|
||||
DWORD type; /* 0x1000 */
|
||||
const char *name;
|
||||
DWORD thread_id;
|
||||
DWORD flags;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#define THREADNAME_INFO_SIZE \
|
||||
(sizeof(struct vs_threadname_info) / sizeof(ULONG_PTR))
|
||||
|
||||
void os_set_thread_name(const char *name)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
UNUSED_PARAMETER(name);
|
||||
#else
|
||||
struct vs_threadname_info info;
|
||||
info.type = 0x1000;
|
||||
info.name = name;
|
||||
info.thread_id = GetCurrentThreadId();
|
||||
info.flags = 0;
|
||||
|
||||
#ifdef NO_SEH_MINGW
|
||||
__try1(EXCEPTION_EXECUTE_HANDLER) {
|
||||
#else
|
||||
__try {
|
||||
#endif
|
||||
RaiseException(VC_EXCEPTION, 0, THREADNAME_INFO_SIZE,
|
||||
(ULONG_PTR*)&info);
|
||||
#ifdef NO_SEH_MINGW
|
||||
} __except1 {
|
||||
#else
|
||||
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
55
libobs/util/threading-windows.h
Normal file
55
libobs/util/threading-windows.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
static inline long os_atomic_inc_long(volatile long *val)
|
||||
{
|
||||
return _InterlockedIncrement(val);
|
||||
}
|
||||
|
||||
static inline long os_atomic_dec_long(volatile long *val)
|
||||
{
|
||||
return _InterlockedDecrement(val);
|
||||
}
|
||||
|
||||
static inline long os_atomic_set_long(volatile long *ptr, long val)
|
||||
{
|
||||
return (long)_InterlockedExchange((volatile long*)ptr, (long)val);
|
||||
}
|
||||
|
||||
static inline long os_atomic_load_long(const volatile long *ptr)
|
||||
{
|
||||
return (long)_InterlockedOr((volatile long*)ptr, 0);
|
||||
}
|
||||
|
||||
static inline bool os_atomic_compare_swap_long(volatile long *val,
|
||||
long old_val, long new_val)
|
||||
{
|
||||
return _InterlockedCompareExchange(val, new_val, old_val) == old_val;
|
||||
}
|
||||
|
||||
static inline bool os_atomic_set_bool(volatile bool *ptr, bool val)
|
||||
{
|
||||
return !!_InterlockedExchange8((volatile char*)ptr, (char)val);
|
||||
}
|
||||
|
||||
static inline bool os_atomic_load_bool(const volatile bool *ptr)
|
||||
{
|
||||
return !!_InterlockedOr8((volatile char*)ptr, 0);
|
||||
}
|
||||
84
libobs/util/threading.h
Normal file
84
libobs/util/threading.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Allows posix thread usage on windows as well as other operating systems.
|
||||
* Use this header if you want to make your code more platform independent.
|
||||
*
|
||||
* Also provides a custom platform-independent "event" handler via
|
||||
* pthread conditional waits.
|
||||
*/
|
||||
|
||||
#include "c99defs.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "../../deps/w32-pthreads/pthread.h"
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "threading-windows.h"
|
||||
#else
|
||||
#include "threading-posix.h"
|
||||
#endif
|
||||
|
||||
/* this may seem strange, but you can't use it unless it's an initializer */
|
||||
static inline void pthread_mutex_init_value(pthread_mutex_t *mutex)
|
||||
{
|
||||
pthread_mutex_t init_val = PTHREAD_MUTEX_INITIALIZER;
|
||||
if (!mutex)
|
||||
return;
|
||||
|
||||
*mutex = init_val;
|
||||
}
|
||||
|
||||
enum os_event_type {
|
||||
OS_EVENT_TYPE_AUTO,
|
||||
OS_EVENT_TYPE_MANUAL
|
||||
};
|
||||
|
||||
struct os_event_data;
|
||||
struct os_sem_data;
|
||||
typedef struct os_event_data os_event_t;
|
||||
typedef struct os_sem_data os_sem_t;
|
||||
|
||||
EXPORT int os_event_init(os_event_t **event, enum os_event_type type);
|
||||
EXPORT void os_event_destroy(os_event_t *event);
|
||||
EXPORT int os_event_wait(os_event_t *event);
|
||||
EXPORT int os_event_timedwait(os_event_t *event, unsigned long milliseconds);
|
||||
EXPORT int os_event_try(os_event_t *event);
|
||||
EXPORT int os_event_signal(os_event_t *event);
|
||||
EXPORT void os_event_reset(os_event_t *event);
|
||||
|
||||
EXPORT int os_sem_init(os_sem_t **sem, int value);
|
||||
EXPORT void os_sem_destroy(os_sem_t *sem);
|
||||
EXPORT int os_sem_post(os_sem_t *sem);
|
||||
EXPORT int os_sem_wait(os_sem_t *sem);
|
||||
|
||||
EXPORT void os_set_thread_name(const char *name);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
374
libobs/util/utf8.c
Normal file
374
libobs/util/utf8.c
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Alexey Vatchenko <av@bsdua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <wchar.h>
|
||||
|
||||
#include "utf8.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
#include "c99defs.h"
|
||||
|
||||
static inline bool has_utf8_bom(const char *in_char)
|
||||
{
|
||||
uint8_t *in = (uint8_t*)in_char;
|
||||
return (in && in[0] == 0xef && in[1] == 0xbb && in[2] == 0xbf);
|
||||
}
|
||||
|
||||
size_t utf8_to_wchar(const char *in, size_t insize, wchar_t *out,
|
||||
size_t outsize, int flags)
|
||||
{
|
||||
int i_insize = (int)insize;
|
||||
int ret;
|
||||
|
||||
if (i_insize == 0)
|
||||
i_insize = (int)strlen(in);
|
||||
|
||||
/* prevent bom from being used in the string */
|
||||
if (has_utf8_bom(in)) {
|
||||
if (i_insize >= 3) {
|
||||
in += 3;
|
||||
insize -= 3;
|
||||
}
|
||||
}
|
||||
|
||||
ret = MultiByteToWideChar(CP_UTF8, 0, in, i_insize, out, (int)outsize);
|
||||
|
||||
UNUSED_PARAMETER(flags);
|
||||
return (ret > 0) ? (size_t)ret : 0;
|
||||
}
|
||||
|
||||
size_t wchar_to_utf8(const wchar_t *in, size_t insize, char *out,
|
||||
size_t outsize, int flags)
|
||||
{
|
||||
int i_insize = (int)insize;
|
||||
int ret;
|
||||
|
||||
if (i_insize == 0)
|
||||
i_insize = (int)wcslen(in);
|
||||
|
||||
ret = WideCharToMultiByte(CP_UTF8, 0, in, i_insize, out, (int)outsize,
|
||||
NULL, NULL);
|
||||
|
||||
UNUSED_PARAMETER(flags);
|
||||
return (ret > 0) ? (size_t)ret : 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define _NXT 0x80
|
||||
#define _SEQ2 0xc0
|
||||
#define _SEQ3 0xe0
|
||||
#define _SEQ4 0xf0
|
||||
#define _SEQ5 0xf8
|
||||
#define _SEQ6 0xfc
|
||||
|
||||
#define _BOM 0xfeff
|
||||
|
||||
static int wchar_forbidden(wchar_t sym);
|
||||
static int utf8_forbidden(unsigned char octet);
|
||||
|
||||
static int wchar_forbidden(wchar_t sym)
|
||||
{
|
||||
/* Surrogate pairs */
|
||||
if (sym >= 0xd800 && sym <= 0xdfff)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int utf8_forbidden(unsigned char octet)
|
||||
{
|
||||
switch (octet) {
|
||||
case 0xc0:
|
||||
case 0xc1:
|
||||
case 0xf5:
|
||||
case 0xff:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DESCRIPTION
|
||||
* This function translates UTF-8 string into UCS-4 string (all symbols
|
||||
* will be in local machine byte order).
|
||||
*
|
||||
* It takes the following arguments:
|
||||
* in - input UTF-8 string. It can be null-terminated.
|
||||
* insize - size of input string in bytes. If insize is 0,
|
||||
* function continues until a null terminator is reached.
|
||||
* out - result buffer for UCS-4 string. If out is NULL,
|
||||
* function returns size of result buffer.
|
||||
* outsize - size of out buffer in wide characters.
|
||||
*
|
||||
* RETURN VALUES
|
||||
* The function returns size of result buffer (in wide characters).
|
||||
* Zero is returned in case of error.
|
||||
*
|
||||
* CAVEATS
|
||||
* 1. If UTF-8 string contains zero symbols, they will be translated
|
||||
* as regular symbols.
|
||||
* 2. If UTF8_IGNORE_ERROR or UTF8_SKIP_BOM flag is set, sizes may vary
|
||||
* when `out' is NULL and not NULL. It's because of special UTF-8
|
||||
* sequences which may result in forbidden (by RFC3629) UNICODE
|
||||
* characters. So, the caller must check return value every time and
|
||||
* not prepare buffer in advance (\0 terminate) but after calling this
|
||||
* function.
|
||||
*/
|
||||
size_t utf8_to_wchar(const char *in, size_t insize, wchar_t *out,
|
||||
size_t outsize, int flags)
|
||||
{
|
||||
unsigned char *p, *lim;
|
||||
wchar_t *wlim, high;
|
||||
size_t n, total, i, n_bits;
|
||||
|
||||
if (in == NULL || (outsize == 0 && out != NULL))
|
||||
return 0;
|
||||
|
||||
total = 0;
|
||||
p = (unsigned char *)in;
|
||||
lim = (insize != 0) ? (p + insize) : (unsigned char*)-1;
|
||||
wlim = out + outsize;
|
||||
|
||||
for (; p < lim; p += n) {
|
||||
if (!*p)
|
||||
break;
|
||||
|
||||
if (utf8_forbidden(*p) != 0 &&
|
||||
(flags & UTF8_IGNORE_ERROR) == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Get number of bytes for one wide character.
|
||||
*/
|
||||
n = 1; /* default: 1 byte. Used when skipping bytes. */
|
||||
if ((*p & 0x80) == 0)
|
||||
high = (wchar_t)*p;
|
||||
else if ((*p & 0xe0) == _SEQ2) {
|
||||
n = 2;
|
||||
high = (wchar_t)(*p & 0x1f);
|
||||
} else if ((*p & 0xf0) == _SEQ3) {
|
||||
n = 3;
|
||||
high = (wchar_t)(*p & 0x0f);
|
||||
} else if ((*p & 0xf8) == _SEQ4) {
|
||||
n = 4;
|
||||
high = (wchar_t)(*p & 0x07);
|
||||
} else if ((*p & 0xfc) == _SEQ5) {
|
||||
n = 5;
|
||||
high = (wchar_t)(*p & 0x03);
|
||||
} else if ((*p & 0xfe) == _SEQ6) {
|
||||
n = 6;
|
||||
high = (wchar_t)(*p & 0x01);
|
||||
} else {
|
||||
if ((flags & UTF8_IGNORE_ERROR) == 0)
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* does the sequence header tell us truth about length? */
|
||||
if ((size_t)(lim - p) <= n - 1) {
|
||||
if ((flags & UTF8_IGNORE_ERROR) == 0)
|
||||
return 0;
|
||||
n = 1;
|
||||
continue; /* skip */
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate sequence.
|
||||
* All symbols must have higher bits set to 10xxxxxx
|
||||
*/
|
||||
if (n > 1) {
|
||||
for (i = 1; i < n; i++) {
|
||||
if ((p[i] & 0xc0) != _NXT)
|
||||
break;
|
||||
}
|
||||
if (i != n) {
|
||||
if ((flags & UTF8_IGNORE_ERROR) == 0)
|
||||
return 0;
|
||||
n = 1;
|
||||
continue; /* skip */
|
||||
}
|
||||
}
|
||||
|
||||
total++;
|
||||
|
||||
if (out == NULL)
|
||||
continue;
|
||||
|
||||
if (out >= wlim)
|
||||
return 0; /* no space left */
|
||||
|
||||
*out = 0;
|
||||
n_bits = 0;
|
||||
for (i = 1; i < n; i++) {
|
||||
*out |= (wchar_t)(p[n - i] & 0x3f) << n_bits;
|
||||
n_bits += 6; /* 6 low bits in every byte */
|
||||
}
|
||||
*out |= high << n_bits;
|
||||
|
||||
if (wchar_forbidden(*out) != 0) {
|
||||
if ((flags & UTF8_IGNORE_ERROR) == 0)
|
||||
return 0; /* forbidden character */
|
||||
else {
|
||||
total--;
|
||||
out--;
|
||||
}
|
||||
} else if (*out == _BOM && (flags & UTF8_SKIP_BOM) != 0) {
|
||||
total--;
|
||||
out--;
|
||||
}
|
||||
|
||||
out++;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/*
|
||||
* DESCRIPTION
|
||||
* This function translates UCS-4 symbols (given in local machine
|
||||
* byte order) into UTF-8 string.
|
||||
*
|
||||
* It takes the following arguments:
|
||||
* in - input unicode string. It can be null-terminated.
|
||||
* insize - size of input string in wide characters. If insize is 0,
|
||||
* function continues until a null terminator is reaches.
|
||||
* out - result buffer for utf8 string. If out is NULL,
|
||||
* function returns size of result buffer.
|
||||
* outsize - size of result buffer.
|
||||
*
|
||||
* RETURN VALUES
|
||||
* The function returns size of result buffer (in bytes). Zero is returned
|
||||
* in case of error.
|
||||
*
|
||||
* CAVEATS
|
||||
* If UCS-4 string contains zero symbols, they will be translated
|
||||
* as regular symbols.
|
||||
*/
|
||||
size_t wchar_to_utf8(const wchar_t *in, size_t insize, char *out,
|
||||
size_t outsize, int flags)
|
||||
{
|
||||
wchar_t *w, *wlim, ch = 0;
|
||||
unsigned char *p, *lim, *oc;
|
||||
size_t total, n;
|
||||
|
||||
if (in == NULL || (outsize == 0 && out != NULL))
|
||||
return 0;
|
||||
|
||||
w = (wchar_t *)in;
|
||||
wlim = (insize != 0) ? (w + insize) : (wchar_t*)-1;
|
||||
p = (unsigned char *)out;
|
||||
lim = p + outsize;
|
||||
total = 0;
|
||||
|
||||
for (; w < wlim; w++) {
|
||||
if (!*w)
|
||||
break;
|
||||
|
||||
if (wchar_forbidden(*w) != 0) {
|
||||
if ((flags & UTF8_IGNORE_ERROR) == 0)
|
||||
return 0;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*w == _BOM && (flags & UTF8_SKIP_BOM) != 0)
|
||||
continue;
|
||||
|
||||
if (*w < 0) {
|
||||
if ((flags & UTF8_IGNORE_ERROR) == 0)
|
||||
return 0;
|
||||
continue;
|
||||
} else if (*w <= 0x0000007f)
|
||||
n = 1;
|
||||
else if (*w <= 0x000007ff)
|
||||
n = 2;
|
||||
else if (*w <= 0x0000ffff)
|
||||
n = 3;
|
||||
else if (*w <= 0x001fffff)
|
||||
n = 4;
|
||||
else if (*w <= 0x03ffffff)
|
||||
n = 5;
|
||||
else /* if (*w <= 0x7fffffff) */
|
||||
n = 6;
|
||||
|
||||
total += n;
|
||||
|
||||
if (out == NULL)
|
||||
continue;
|
||||
|
||||
if ((size_t)(lim - p) <= n - 1)
|
||||
return 0; /* no space left */
|
||||
|
||||
ch = *w;
|
||||
oc = (unsigned char *)&ch;
|
||||
switch (n) {
|
||||
case 1:
|
||||
*p = oc[0];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
p[1] = _NXT | (oc[0] & 0x3f);
|
||||
p[0] = _SEQ2 | (oc[0] >> 6) | ((oc[1] & 0x07) << 2);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
p[2] = _NXT | (oc[0] & 0x3f);
|
||||
p[1] = _NXT | (oc[0] >> 6) | ((oc[1] & 0x0f) << 2);
|
||||
p[0] = _SEQ3 | ((oc[1] & 0xf0) >> 4);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
p[3] = _NXT | (oc[0] & 0x3f);
|
||||
p[2] = _NXT | (oc[0] >> 6) | ((oc[1] & 0x0f) << 2);
|
||||
p[1] = _NXT | ((oc[1] & 0xf0) >> 4) |
|
||||
((oc[2] & 0x03) << 4);
|
||||
p[0] = _SEQ4 | ((oc[2] & 0x1f) >> 2);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
p[4] = _NXT | (oc[0] & 0x3f);
|
||||
p[3] = _NXT | (oc[0] >> 6) | ((oc[1] & 0x0f) << 2);
|
||||
p[2] = _NXT | ((oc[1] & 0xf0) >> 4) |
|
||||
((oc[2] & 0x03) << 4);
|
||||
p[1] = _NXT | (oc[2] >> 2);
|
||||
p[0] = _SEQ5 | (oc[3] & 0x03);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
p[5] = _NXT | (oc[0] & 0x3f);
|
||||
p[4] = _NXT | (oc[0] >> 6) | ((oc[1] & 0x0f) << 2);
|
||||
p[3] = _NXT | (oc[1] >> 4) | ((oc[2] & 0x03) << 4);
|
||||
p[2] = _NXT | (oc[2] >> 2);
|
||||
p[1] = _NXT | (oc[3] & 0x3f);
|
||||
p[0] = _SEQ6 | ((oc[3] & 0x40) >> 6);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: do not check here for forbidden UTF-8 characters.
|
||||
* They cannot appear here because we do proper convertion.
|
||||
*/
|
||||
|
||||
p += n;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
#endif
|
||||
37
libobs/util/utf8.h
Normal file
37
libobs/util/utf8.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Alexey Vatchenko <av@bsdua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* utf8: implementation of UTF-8 charset encoding (RFC3629).
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define UTF8_IGNORE_ERROR 0x01
|
||||
#define UTF8_SKIP_BOM 0x02
|
||||
|
||||
size_t utf8_to_wchar(const char *in, size_t insize, wchar_t *out,
|
||||
size_t outsize, int flags);
|
||||
size_t wchar_to_utf8(const wchar_t *in, size_t insize, char *out,
|
||||
size_t outsize, int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
140
libobs/util/util.hpp
Normal file
140
libobs/util/util.hpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Useful C++ classes/bindings for util data and pointers */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "bmem.h"
|
||||
#include "config-file.h"
|
||||
#include "text-lookup.h"
|
||||
|
||||
/* RAII wrappers */
|
||||
|
||||
template<typename T> class BPtr {
|
||||
T *ptr;
|
||||
|
||||
BPtr(BPtr const&) = delete;
|
||||
|
||||
BPtr &operator=(BPtr const&) = delete;
|
||||
|
||||
public:
|
||||
inline BPtr(T *p=nullptr) : ptr(p) {}
|
||||
inline BPtr(BPtr &&other) : ptr(other.ptr) {other.ptr = nullptr;}
|
||||
inline ~BPtr() {bfree(ptr);}
|
||||
|
||||
inline T *operator=(T *p) {bfree(ptr); ptr = p; return p;}
|
||||
inline operator T*() {return ptr;}
|
||||
inline T **operator&() {bfree(ptr); ptr = nullptr; return &ptr;}
|
||||
|
||||
inline bool operator!() {return ptr == NULL;}
|
||||
inline bool operator==(T p) {return ptr == p;}
|
||||
inline bool operator!=(T p) {return ptr != p;}
|
||||
};
|
||||
|
||||
class ConfigFile {
|
||||
config_t *config;
|
||||
|
||||
ConfigFile(ConfigFile const&) = delete;
|
||||
ConfigFile &operator=(ConfigFile const&) = delete;
|
||||
|
||||
public:
|
||||
inline ConfigFile() : config(NULL) {}
|
||||
inline ConfigFile(ConfigFile &&other) : config(other.config)
|
||||
{
|
||||
other.config = nullptr;
|
||||
}
|
||||
inline ~ConfigFile()
|
||||
{
|
||||
config_close(config);
|
||||
}
|
||||
|
||||
inline bool Create(const char *file)
|
||||
{
|
||||
Close();
|
||||
config = config_create(file);
|
||||
return config != NULL;
|
||||
}
|
||||
|
||||
inline void Swap(ConfigFile &other)
|
||||
{
|
||||
config_t *newConfig = other.config;
|
||||
other.config = config;
|
||||
config = newConfig;
|
||||
}
|
||||
|
||||
inline int Open(const char *file, config_open_type openType)
|
||||
{
|
||||
Close();
|
||||
return config_open(&config, file, openType);
|
||||
}
|
||||
|
||||
inline int Save()
|
||||
{
|
||||
return config_save(config);
|
||||
}
|
||||
|
||||
inline int SaveSafe(const char *temp_ext,
|
||||
const char *backup_ext = nullptr)
|
||||
{
|
||||
return config_save_safe(config, temp_ext, backup_ext);
|
||||
}
|
||||
|
||||
inline void Close()
|
||||
{
|
||||
config_close(config);
|
||||
config = NULL;
|
||||
}
|
||||
|
||||
inline operator config_t*() const {return config;}
|
||||
};
|
||||
|
||||
class TextLookup {
|
||||
lookup_t *lookup;
|
||||
|
||||
TextLookup(TextLookup const&) = delete;
|
||||
|
||||
TextLookup &operator=(TextLookup const&) = delete;
|
||||
|
||||
public:
|
||||
inline TextLookup(lookup_t *lookup=nullptr) : lookup(lookup) {}
|
||||
inline TextLookup(TextLookup &&other) : lookup(other.lookup)
|
||||
{
|
||||
other.lookup = nullptr;
|
||||
}
|
||||
inline ~TextLookup() {text_lookup_destroy(lookup);}
|
||||
|
||||
inline TextLookup& operator=(lookup_t *val)
|
||||
{
|
||||
text_lookup_destroy(lookup);
|
||||
lookup = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator lookup_t*() const {return lookup;}
|
||||
|
||||
inline const char *GetString(const char *lookupVal) const
|
||||
{
|
||||
const char *out;
|
||||
if (!text_lookup_getstr(lookup, lookupVal, &out))
|
||||
return lookupVal;
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
100
libobs/util/util_uint128.h
Normal file
100
libobs/util/util_uint128.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct util_uint128 {
|
||||
union {
|
||||
uint32_t i32[4];
|
||||
struct {
|
||||
uint64_t low;
|
||||
uint64_t high;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct util_uint128 util_uint128_t;
|
||||
|
||||
static inline util_uint128_t util_add128(util_uint128_t a, util_uint128_t b)
|
||||
{
|
||||
util_uint128_t out;
|
||||
uint64_t val;
|
||||
|
||||
val = (a.low & 0xFFFFFFFFULL) + (b.low & 0xFFFFFFFFULL);
|
||||
out.i32[0] = (uint32_t)(val & 0xFFFFFFFFULL);
|
||||
val >>= 32;
|
||||
|
||||
val += (a.low >> 32) + (b.low >> 32);
|
||||
out.i32[1] = (uint32_t)val;
|
||||
val >>= 32;
|
||||
|
||||
val += (a.high & 0xFFFFFFFFULL) + (b.high & 0xFFFFFFFFULL);
|
||||
out.i32[2] = (uint32_t)(val & 0xFFFFFFFFULL);
|
||||
val >>= 32;
|
||||
|
||||
val += (a.high >> 32) + (b.high >> 32);
|
||||
out.i32[3] = (uint32_t)val;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline util_uint128_t util_lshift64(uint64_t a, int num)
|
||||
{
|
||||
util_uint128_t val;
|
||||
val.low = a << num;
|
||||
val.high = a >> (64 - num);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline util_uint128_t util_mul64_64(uint64_t a, uint64_t b)
|
||||
{
|
||||
util_uint128_t out;
|
||||
uint64_t m;
|
||||
|
||||
m = (a & 0xFFFFFFFFULL) * (b & 0xFFFFFFFFULL);
|
||||
out.low = m;
|
||||
out.high = 0;
|
||||
|
||||
m = (a >> 32) * (b & 0xFFFFFFFFULL);
|
||||
out = util_add128(out, util_lshift64(m, 32));
|
||||
|
||||
m = (a & 0xFFFFFFFFULL) * (b >> 32);
|
||||
out = util_add128(out, util_lshift64(m, 32));
|
||||
|
||||
m = (a >> 32) * (b >> 32);
|
||||
out = util_add128(out, util_lshift64(m, 64));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline util_uint128_t util_div128_32(util_uint128_t a, uint32_t b)
|
||||
{
|
||||
util_uint128_t out;
|
||||
uint64_t val = 0;
|
||||
|
||||
for (int i = 3; i >= 0; i--) {
|
||||
val = (val << 32) | a.i32[i];
|
||||
if (val < b) {
|
||||
out.i32[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
out.i32[i] = (uint32_t)(val / b);
|
||||
val = val % b;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
285
libobs/util/vc/vc_inttypes.h
Normal file
285
libobs/util/vc/vc_inttypes.h
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The name of the author may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_INTTYPES_H_ // [
|
||||
#define _MSC_INTTYPES_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
// 7.8 Format conversion of integer types
|
||||
|
||||
typedef struct {
|
||||
intmax_t quot;
|
||||
intmax_t rem;
|
||||
} imaxdiv_t;
|
||||
|
||||
// 7.8.1 Macros for format specifiers
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
|
||||
|
||||
// The fprintf macros for signed integers are:
|
||||
#define PRId8 "d"
|
||||
#define PRIi8 "i"
|
||||
#define PRIdLEAST8 "d"
|
||||
#define PRIiLEAST8 "i"
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIiFAST8 "i"
|
||||
|
||||
#define PRId16 "hd"
|
||||
#define PRIi16 "hi"
|
||||
#define PRIdLEAST16 "hd"
|
||||
#define PRIiLEAST16 "hi"
|
||||
#define PRIdFAST16 "hd"
|
||||
#define PRIiFAST16 "hi"
|
||||
|
||||
#define PRId32 "I32d"
|
||||
#define PRIi32 "I32i"
|
||||
#define PRIdLEAST32 "I32d"
|
||||
#define PRIiLEAST32 "I32i"
|
||||
#define PRIdFAST32 "I32d"
|
||||
#define PRIiFAST32 "I32i"
|
||||
|
||||
#define PRId64 "I64d"
|
||||
#define PRIi64 "I64i"
|
||||
#define PRIdLEAST64 "I64d"
|
||||
#define PRIiLEAST64 "I64i"
|
||||
#define PRIdFAST64 "I64d"
|
||||
#define PRIiFAST64 "I64i"
|
||||
|
||||
#define PRIdMAX "I64d"
|
||||
#define PRIiMAX "I64i"
|
||||
|
||||
#define PRIdPTR "Id"
|
||||
#define PRIiPTR "Ii"
|
||||
|
||||
// The fprintf macros for unsigned integers are:
|
||||
#define PRIo8 "o"
|
||||
#define PRIu8 "u"
|
||||
#define PRIx8 "x"
|
||||
#define PRIX8 "X"
|
||||
#define PRIoLEAST8 "o"
|
||||
#define PRIuLEAST8 "u"
|
||||
#define PRIxLEAST8 "x"
|
||||
#define PRIXLEAST8 "X"
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIXFAST8 "X"
|
||||
|
||||
#define PRIo16 "ho"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
#define PRIoLEAST16 "ho"
|
||||
#define PRIuLEAST16 "hu"
|
||||
#define PRIxLEAST16 "hx"
|
||||
#define PRIXLEAST16 "hX"
|
||||
#define PRIoFAST16 "ho"
|
||||
#define PRIuFAST16 "hu"
|
||||
#define PRIxFAST16 "hx"
|
||||
#define PRIXFAST16 "hX"
|
||||
|
||||
#define PRIo32 "I32o"
|
||||
#define PRIu32 "I32u"
|
||||
#define PRIx32 "I32x"
|
||||
#define PRIX32 "I32X"
|
||||
#define PRIoLEAST32 "I32o"
|
||||
#define PRIuLEAST32 "I32u"
|
||||
#define PRIxLEAST32 "I32x"
|
||||
#define PRIXLEAST32 "I32X"
|
||||
#define PRIoFAST32 "I32o"
|
||||
#define PRIuFAST32 "I32u"
|
||||
#define PRIxFAST32 "I32x"
|
||||
#define PRIXFAST32 "I32X"
|
||||
|
||||
#define PRIo64 "I64o"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIx64 "I64x"
|
||||
#define PRIX64 "I64X"
|
||||
#define PRIoLEAST64 "I64o"
|
||||
#define PRIuLEAST64 "I64u"
|
||||
#define PRIxLEAST64 "I64x"
|
||||
#define PRIXLEAST64 "I64X"
|
||||
#define PRIoFAST64 "I64o"
|
||||
#define PRIuFAST64 "I64u"
|
||||
#define PRIxFAST64 "I64x"
|
||||
#define PRIXFAST64 "I64X"
|
||||
|
||||
#define PRIoMAX "I64o"
|
||||
#define PRIuMAX "I64u"
|
||||
#define PRIxMAX "I64x"
|
||||
#define PRIXMAX "I64X"
|
||||
|
||||
#define PRIoPTR "Io"
|
||||
#define PRIuPTR "Iu"
|
||||
#define PRIxPTR "Ix"
|
||||
#define PRIXPTR "IX"
|
||||
|
||||
// The fscanf macros for signed integers are:
|
||||
#define SCNd16 "hd"
|
||||
#define SCNi16 "hi"
|
||||
#define SCNdLEAST16 "hd"
|
||||
#define SCNiLEAST16 "hi"
|
||||
#define SCNdFAST16 "hd"
|
||||
#define SCNiFAST16 "hi"
|
||||
|
||||
#define SCNd32 "ld"
|
||||
#define SCNi32 "li"
|
||||
#define SCNdLEAST32 "ld"
|
||||
#define SCNiLEAST32 "li"
|
||||
#define SCNdFAST32 "ld"
|
||||
#define SCNiFAST32 "li"
|
||||
|
||||
#define SCNd64 "I64d"
|
||||
#define SCNi64 "I64i"
|
||||
#define SCNdLEAST64 "I64d"
|
||||
#define SCNiLEAST64 "I64i"
|
||||
#define SCNdFAST64 "I64d"
|
||||
#define SCNiFAST64 "I64i"
|
||||
|
||||
#define SCNdMAX "I64d"
|
||||
#define SCNiMAX "I64i"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNdPTR "I64d"
|
||||
# define SCNiPTR "I64i"
|
||||
#else // _WIN64 ][
|
||||
# define SCNdPTR "ld"
|
||||
# define SCNiPTR "li"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// The fscanf macros for unsigned integers are:
|
||||
#define SCNo16 "ho"
|
||||
#define SCNu16 "hu"
|
||||
#define SCNx16 "hx"
|
||||
#define SCNX16 "hX"
|
||||
#define SCNoLEAST16 "ho"
|
||||
#define SCNuLEAST16 "hu"
|
||||
#define SCNxLEAST16 "hx"
|
||||
#define SCNXLEAST16 "hX"
|
||||
#define SCNoFAST16 "ho"
|
||||
#define SCNuFAST16 "hu"
|
||||
#define SCNxFAST16 "hx"
|
||||
#define SCNXFAST16 "hX"
|
||||
|
||||
#define SCNo32 "lo"
|
||||
#define SCNu32 "lu"
|
||||
#define SCNx32 "lx"
|
||||
#define SCNX32 "lX"
|
||||
#define SCNoLEAST32 "lo"
|
||||
#define SCNuLEAST32 "lu"
|
||||
#define SCNxLEAST32 "lx"
|
||||
#define SCNXLEAST32 "lX"
|
||||
#define SCNoFAST32 "lo"
|
||||
#define SCNuFAST32 "lu"
|
||||
#define SCNxFAST32 "lx"
|
||||
#define SCNXFAST32 "lX"
|
||||
|
||||
#define SCNo64 "I64o"
|
||||
#define SCNu64 "I64u"
|
||||
#define SCNx64 "I64x"
|
||||
#define SCNX64 "I64X"
|
||||
#define SCNoLEAST64 "I64o"
|
||||
#define SCNuLEAST64 "I64u"
|
||||
#define SCNxLEAST64 "I64x"
|
||||
#define SCNXLEAST64 "I64X"
|
||||
#define SCNoFAST64 "I64o"
|
||||
#define SCNuFAST64 "I64u"
|
||||
#define SCNxFAST64 "I64x"
|
||||
#define SCNXFAST64 "I64X"
|
||||
|
||||
#define SCNoMAX "I64o"
|
||||
#define SCNuMAX "I64u"
|
||||
#define SCNxMAX "I64x"
|
||||
#define SCNXMAX "I64X"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNoPTR "I64o"
|
||||
# define SCNuPTR "I64u"
|
||||
# define SCNxPTR "I64x"
|
||||
# define SCNXPTR "I64X"
|
||||
#else // _WIN64 ][
|
||||
# define SCNoPTR "lo"
|
||||
# define SCNuPTR "lu"
|
||||
# define SCNxPTR "lx"
|
||||
# define SCNXPTR "lX"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#endif // __STDC_FORMAT_MACROS ]
|
||||
|
||||
// 7.8.2 Functions for greatest-width integer types
|
||||
|
||||
// 7.8.2.1 The imaxabs function
|
||||
#define imaxabs _abs64
|
||||
|
||||
// 7.8.2.2 The imaxdiv function
|
||||
|
||||
// This is modified version of div() function from Microsoft's div.c found
|
||||
// in %MSVC.NET%\crt\src\div.c
|
||||
#ifdef STATIC_IMAXDIV // [
|
||||
static
|
||||
#else // STATIC_IMAXDIV ][
|
||||
_inline
|
||||
#endif // STATIC_IMAXDIV ]
|
||||
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
|
||||
{
|
||||
imaxdiv_t result;
|
||||
|
||||
result.quot = numer / denom;
|
||||
result.rem = numer % denom;
|
||||
|
||||
if (numer < 0 && result.rem > 0) {
|
||||
// did division wrong; must fix up
|
||||
++result.quot;
|
||||
result.rem -= denom;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 7.8.2.3 The strtoimax and strtoumax functions
|
||||
#define strtoimax _strtoi64
|
||||
#define strtoumax _strtoui64
|
||||
|
||||
// 7.8.2.4 The wcstoimax and wcstoumax functions
|
||||
#define wcstoimax _wcstoi64
|
||||
#define wcstoumax _wcstoui64
|
||||
|
||||
|
||||
#endif // _MSC_INTTYPES_H_ ]
|
||||
9
libobs/util/vc/vc_stdbool.h
Normal file
9
libobs/util/vc/vc_stdbool.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
typedef int8_t _Bool;
|
||||
#define bool _Bool
|
||||
#define true 1
|
||||
#define false 0
|
||||
#define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
204
libobs/util/vc/vc_stdint.h
Normal file
204
libobs/util/vc/vc_stdint.h
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/* ISO C9x 7.18 Integer types <stdint.h>
|
||||
* Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794)
|
||||
*
|
||||
* THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
*
|
||||
* Contributor: Danny Smith <danny_r_smith_2001@yahoo.co.nz>
|
||||
*
|
||||
* This source code is offered for use in the public domain. You may
|
||||
* use, modify or distribute it freely.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but
|
||||
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
|
||||
* DISCLAIMED. This includes but is not limited to warranties of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Date: 2000-12-02
|
||||
*/
|
||||
|
||||
#ifndef _STDINT_H
|
||||
#define _STDINT_H
|
||||
#define __need_wint_t
|
||||
#define __need_wchar_t
|
||||
#include <stddef.h>
|
||||
|
||||
/* 7.18.1.1 Exact-width integer types */
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef int int32_t;
|
||||
typedef unsigned uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
/* 7.18.1.2 Minimum-width integer types */
|
||||
typedef signed char int_least8_t;
|
||||
typedef unsigned char uint_least8_t;
|
||||
typedef short int_least16_t;
|
||||
typedef unsigned short uint_least16_t;
|
||||
typedef int int_least32_t;
|
||||
typedef unsigned uint_least32_t;
|
||||
typedef __int64 int_least64_t;
|
||||
typedef unsigned __int64 uint_least64_t;
|
||||
|
||||
/* 7.18.1.3 Fastest minimum-width integer types
|
||||
* Not actually guaranteed to be fastest for all purposes
|
||||
* Here we use the exact-width types for 8 and 16-bit ints.
|
||||
*/
|
||||
typedef char int_fast8_t;
|
||||
typedef unsigned char uint_fast8_t;
|
||||
typedef short int_fast16_t;
|
||||
typedef unsigned short uint_fast16_t;
|
||||
typedef int int_fast32_t;
|
||||
typedef unsigned int uint_fast32_t;
|
||||
typedef __int64 int_fast64_t;
|
||||
typedef unsigned __int64 uint_fast64_t;
|
||||
|
||||
/* 7.18.1.4 Integer types capable of holding object pointers */
|
||||
/*typedef int intptr_t;
|
||||
typedef unsigned uintptr_t;*/
|
||||
|
||||
/* 7.18.1.5 Greatest-width integer types */
|
||||
typedef __int64 intmax_t;
|
||||
typedef unsigned __int64 uintmax_t;
|
||||
|
||||
/* 7.18.2 Limits of specified-width integer types */
|
||||
#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS)
|
||||
|
||||
/* 7.18.2.1 Limits of exact-width integer types */
|
||||
#define INT8_MIN (-128)
|
||||
#define INT16_MIN (-32768)
|
||||
#define INT32_MIN (-2147483647 - 1)
|
||||
#define INT64_MIN (-9223372036854775807LL - 1)
|
||||
|
||||
#define INT8_MAX 127
|
||||
#define INT16_MAX 32767
|
||||
#define INT32_MAX 2147483647
|
||||
#define INT64_MAX 9223372036854775807LL
|
||||
|
||||
#define UINT8_MAX 0xff /* 255U */
|
||||
#define UINT16_MAX 0xffff /* 65535U */
|
||||
#define UINT32_MAX 0xffffffff /* 4294967295U */
|
||||
#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
|
||||
|
||||
/* 7.18.2.2 Limits of minimum-width integer types */
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
/* 7.18.2.3 Limits of fastest minimum-width integer types */
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
/* 7.18.2.4 Limits of integer types capable of holding
|
||||
object pointers */
|
||||
#if defined(_WIN64) || defined(__LP64__)
|
||||
#define INTPTR_MIN INT64_MIN
|
||||
#define INTPTR_MAX INT64_MAX
|
||||
#define UINTPTR_MAX UINT64_MAX
|
||||
#else
|
||||
#define INTPTR_MIN INT32_MIN
|
||||
#define INTPTR_MAX INT32_MAX
|
||||
#define UINTPTR_MAX UINT32_MAX
|
||||
#endif
|
||||
|
||||
/* 7.18.2.5 Limits of greatest-width integer types */
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
/* 7.18.3 Limits of other integer types */
|
||||
#if defined(_WIN64) || defined(__LP64__)
|
||||
#define PTRDIFF_MIN INT64_MIN
|
||||
#define PTRDIFF_MAX INT64_MAX
|
||||
#else
|
||||
#define PTRDIFF_MIN INT32_MIN
|
||||
#define PTRDIFF_MAX INT32_MAX
|
||||
#endif
|
||||
|
||||
#define SIG_ATOMIC_MIN INT32_MIN
|
||||
#define SIG_ATOMIC_MAX INT32_MAX
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#if defined(_WIN64) || defined(__LP64__)
|
||||
#define SIZE_MAX UINT64_MAX
|
||||
#else
|
||||
#define SIZE_MAX UINT32_MAX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifndef WCHAR_MIN /* also in wchar.h */
|
||||
#define WCHAR_MIN 0
|
||||
#define WCHAR_MAX ((wchar_t)-1) /* UINT16_MAX */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* wint_t is unsigned short for compatibility with MS runtime
|
||||
*/
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX ((wint_t)-1) /* UINT16_MAX */
|
||||
|
||||
#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */
|
||||
|
||||
|
||||
/* 7.18.4 Macros for integer constants */
|
||||
#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS)
|
||||
|
||||
/* 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
Accoding to Douglas Gwyn <gwyn@arl.mil>:
|
||||
"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
|
||||
9899:1999 as initially published, the expansion was required
|
||||
to be an integer constant of precisely matching type, which
|
||||
is impossible to accomplish for the shorter types on most
|
||||
platforms, because C99 provides no standard way to designate
|
||||
an integer constant with width less than that of type int.
|
||||
TC1 changed this to require just an integer constant
|
||||
*expression* with *promoted* type."
|
||||
|
||||
The trick used here is from Clive D W Feather.
|
||||
*/
|
||||
|
||||
#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val))
|
||||
#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val))
|
||||
#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val))
|
||||
#define INT64_C(val) (INT_LEAST64_MAX-INT_LEAST64_MAX+(val))
|
||||
|
||||
#define UINT8_C(val) (UINT_LEAST8_MAX-UINT_LEAST8_MAX+(val))
|
||||
#define UINT16_C(val) (UINT_LEAST16_MAX-UINT_LEAST16_MAX+(val))
|
||||
#define UINT32_C(val) (UINT_LEAST32_MAX-UINT_LEAST32_MAX+(val))
|
||||
#define UINT64_C(val) (UINT_LEAST64_MAX-UINT_LEAST64_MAX+(val))
|
||||
|
||||
/* 7.18.4.2 Macros for greatest-width integer constants */
|
||||
#define INTMAX_C(val) (INTMAX_MAX-INTMAX_MAX+(val))
|
||||
#define UINTMAX_C(val) (UINTMAX_MAX-UINTMAX_MAX+(val))
|
||||
|
||||
#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */
|
||||
|
||||
#endif
|
||||
44
libobs/util/windows/CoTaskMemPtr.hpp
Normal file
44
libobs/util/windows/CoTaskMemPtr.hpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
template<typename T> class CoTaskMemPtr {
|
||||
T *ptr;
|
||||
|
||||
inline void Clear() {if (ptr) CoTaskMemFree(ptr);}
|
||||
|
||||
public:
|
||||
inline CoTaskMemPtr() : ptr(NULL) {}
|
||||
inline CoTaskMemPtr(T *ptr_) : ptr(ptr_) {}
|
||||
inline ~CoTaskMemPtr() {Clear();}
|
||||
|
||||
inline operator T*() const {return ptr;}
|
||||
inline T *operator->() const {return ptr;}
|
||||
|
||||
inline CoTaskMemPtr& operator=(T* val)
|
||||
{
|
||||
Clear();
|
||||
ptr = val;
|
||||
}
|
||||
|
||||
inline T** operator&()
|
||||
{
|
||||
Clear();
|
||||
ptr = NULL;
|
||||
return &ptr;
|
||||
}
|
||||
};
|
||||
140
libobs/util/windows/ComPtr.hpp
Normal file
140
libobs/util/windows/ComPtr.hpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Oh no I have my own com pointer class, the world is ending, how dare you
|
||||
* write your own! */
|
||||
|
||||
template<class T> class ComPtr {
|
||||
|
||||
protected:
|
||||
T *ptr;
|
||||
|
||||
inline void Kill()
|
||||
{
|
||||
if (ptr)
|
||||
ptr->Release();
|
||||
}
|
||||
|
||||
inline void Replace(T *p)
|
||||
{
|
||||
if (ptr != p) {
|
||||
if (p) p->AddRef();
|
||||
if (ptr) ptr->Release();
|
||||
ptr = p;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
inline ComPtr() : ptr(nullptr) {}
|
||||
inline ComPtr(T *p) : ptr(p) {if (ptr) ptr->AddRef();}
|
||||
inline ComPtr(const ComPtr<T> &c) : ptr(c.ptr) {if (ptr) ptr->AddRef();}
|
||||
inline ComPtr(ComPtr<T> &&c) : ptr(c.ptr) {c.ptr = nullptr;}
|
||||
inline ~ComPtr() {Kill();}
|
||||
|
||||
inline void Clear()
|
||||
{
|
||||
if (ptr) {
|
||||
ptr->Release();
|
||||
ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline ComPtr<T> &operator=(T *p)
|
||||
{
|
||||
Replace(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline ComPtr<T> &operator=(const ComPtr<T> &c)
|
||||
{
|
||||
Replace(c.ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline ComPtr<T> &operator=(ComPtr<T> &&c)
|
||||
{
|
||||
if (this != &c) {
|
||||
Kill();
|
||||
ptr = c.ptr;
|
||||
c.ptr = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline T *Detach()
|
||||
{
|
||||
T *out = ptr;
|
||||
ptr = nullptr;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline void CopyTo(T **out)
|
||||
{
|
||||
if (out) {
|
||||
if (ptr) ptr->AddRef();
|
||||
*out = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline ULONG Release()
|
||||
{
|
||||
ULONG ref;
|
||||
|
||||
if (!ptr) return 0;
|
||||
ref = ptr->Release();
|
||||
ptr = nullptr;
|
||||
return ref;
|
||||
}
|
||||
|
||||
inline T **Assign() {Clear(); return &ptr;}
|
||||
inline void Set(T *p) {Kill(); ptr = p;}
|
||||
|
||||
inline T *Get() const {return ptr;}
|
||||
|
||||
inline T **operator&() {return Assign();}
|
||||
|
||||
inline operator T*() const {return ptr;}
|
||||
inline T *operator->() const {return ptr;}
|
||||
|
||||
inline bool operator==(T *p) const {return ptr == p;}
|
||||
inline bool operator!=(T *p) const {return ptr != p;}
|
||||
|
||||
inline bool operator!() const {return !ptr;}
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
template<class T> class ComQIPtr : public ComPtr<T> {
|
||||
|
||||
public:
|
||||
inline ComQIPtr(IUnknown *unk)
|
||||
{
|
||||
this->ptr = nullptr;
|
||||
unk->QueryInterface(__uuidof(T), (void**)&this->ptr);
|
||||
}
|
||||
|
||||
inline ComPtr<T> &operator=(IUnknown *unk)
|
||||
{
|
||||
ComPtr<T>::Clear();
|
||||
unk->QueryInterface(__uuidof(T), (void**)&this->ptr);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
27
libobs/util/windows/HRError.hpp
Normal file
27
libobs/util/windows/HRError.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct HRError {
|
||||
const char *str;
|
||||
HRESULT hr;
|
||||
|
||||
inline HRError(const char *str, HRESULT hr)
|
||||
: str(str), hr (hr)
|
||||
{
|
||||
}
|
||||
};
|
||||
54
libobs/util/windows/WinHandle.hpp
Normal file
54
libobs/util/windows/WinHandle.hpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class WinHandle {
|
||||
HANDLE handle;
|
||||
|
||||
inline void Clear()
|
||||
{
|
||||
if (handle && handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
public:
|
||||
inline WinHandle() : handle(NULL) {}
|
||||
inline WinHandle(HANDLE handle_) : handle(handle_) {}
|
||||
inline ~WinHandle() {Clear();}
|
||||
|
||||
inline operator HANDLE() const {return handle;}
|
||||
|
||||
inline WinHandle& operator=(HANDLE handle_)
|
||||
{
|
||||
if (handle_ != handle) {
|
||||
Clear();
|
||||
handle = handle_;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline HANDLE* operator&()
|
||||
{
|
||||
return &handle;
|
||||
}
|
||||
|
||||
inline bool Valid() const
|
||||
{
|
||||
return handle && handle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
};
|
||||
37
libobs/util/windows/win-version.h
Normal file
37
libobs/util/windows/win-version.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Hugh Bailey <obs.jim@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../c99defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct win_version_info {
|
||||
int major;
|
||||
int minor;
|
||||
int build;
|
||||
int revis;
|
||||
};
|
||||
|
||||
EXPORT bool get_dll_ver(const wchar_t *lib, struct win_version_info *info);
|
||||
EXPORT void get_win_ver(struct win_version_info *info);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue