Imported Upstream version 0.13.2+dsfg1

This commit is contained in:
Sebastian Ramacher 2016-02-24 00:16:51 +01:00
commit fb3990e9e5
2036 changed files with 287360 additions and 0 deletions

View 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);
}

View 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);
}

View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

206
libobs/util/cf-lexer.h Normal file
View 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
View 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
View 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
View 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
View 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(&section->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(&section->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(&section_name);
config_parse_string(lex, &section_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),
&section->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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;}
};

View 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);
}
}

View 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
View 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
View 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
View 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
View 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
View 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);

View 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);
}
}

View 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
View 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);
}

View 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(&current_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
View 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
View 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

File diff suppressed because it is too large Load diff

116
libobs/util/profiler.h Normal file
View 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
View 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
View 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
View 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
View 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

View 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
}

View 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);
}

View 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
}

View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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_ ]

View 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
View 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

View 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;
}
};

View 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

View 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)
{
}
};

View 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;
}
};

View 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