diff options
Diffstat (limited to 'sal/rtl')
38 files changed, 19003 insertions, 0 deletions
diff --git a/sal/rtl/source/alloc.c b/sal/rtl/source/alloc.c new file mode 100644 index 000000000000..44b37c255004 --- /dev/null +++ b/sal/rtl/source/alloc.c @@ -0,0 +1,1541 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifdef PROFILE +#undef OSL_DEBUG_LEVEL +#define OSL_DEBUG_LEVEL 0 +#endif /* PROFILE */ + +#include <sal/types.h> +#include <osl/diagnose.h> +#include <rtl/alloc.h> + +#ifndef INCLUDED_STDDEF_H +#include <stddef.h> +#define INCLUDED_STDDEF_H +#endif + +#ifndef INCLUDED_STDLIB_H +#include <stdlib.h> +#define INCLUDED_STDLIB_H +#endif + +#ifndef INCLUDED_STRING_H +#include <string.h> +#define INCLUDED_STRING_H +#endif + +#ifndef FORCE_SYSALLOC + +/*=========================================================================== + * + * rtl_memory (UNX) internals. + * + *=========================================================================*/ +#ifdef SAL_UNX + +#include <unistd.h> +#include <pthread.h> +#include <sys/mman.h> +#include <fcntl.h> + +typedef pthread_mutex_t mutex_type; + +#define RTL_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define RTL_MUTEX_ACQUIRE(a) pthread_mutex_lock((a)) +#define RTL_MUTEX_RELEASE(a) pthread_mutex_unlock((a)) + +#if defined(FREEBSD) || defined(NETBSD) || defined(MACOSX) +static sal_Size __rtl_memory_vmpagesize (void) +{ + /* xBSD */ + return (sal_Size)(getpagesize()); +} +#elif defined(LINUX) || defined(SOLARIS) +static sal_Size __rtl_memory_vmpagesize (void) +{ + /* POSIX */ + return (sal_Size)(sysconf(_SC_PAGESIZE)); +} +#else +static sal_Size __rtl_memory_vmpagesize (void) +{ + /* other */ + return (sal_Size)(0x2000); +} +#endif /* FREEBSD || NETBSD || MACOSX || LINUX || SOLARIS */ + +#ifndef PROT_HEAP +#define PROT_HEAP (PROT_READ | PROT_WRITE | PROT_EXEC) +#endif + +/* #95880# building on Solaris 8 provides MAP_ANON, but it + is not available on Solaris 7 */ +#if defined (SOLARIS) +#ifdef MAP_ANON +#undef MAP_ANON +#endif +#endif + +#ifndef MAP_ANON +static void* __rtl_memory_vmalloc (sal_Size n) +{ + /* SYSV */ + int fd = open("/dev/zero", O_RDWR); + if (!(fd < 0)) + { + void * p = mmap(NULL, n, PROT_HEAP, MAP_PRIVATE, fd, 0); + close(fd); + return ((p == MAP_FAILED) ? NULL : p); + } + return (NULL); +} +#else /* MAP_ANON */ +static void* __rtl_memory_vmalloc (sal_Size n) +{ + /* xBSD */ + void * p = mmap(NULL, n, PROT_HEAP, MAP_PRIVATE | MAP_ANON, -1, 0); + return ((p == MAP_FAILED) ? NULL : p); +} +#endif /* MAP_ANON */ + +#define RTL_MEMORY_ALLOC(n) __rtl_memory_vmalloc((sal_Size)(n)) +#define RTL_MEMORY_FREE(p, n) munmap((void*)(p), (sal_Size)(n)) + +#endif /* SAL_UNX */ + +/*=========================================================================== + * + * rtl_memory (W32) internals. + * + *=========================================================================*/ +#ifdef SAL_W32 + +#define WIN32_LEAN_AND_MEAN +#ifdef _MSC_VER +#pragma warning(push,1) /* disable warnings within system headers */ +#endif +#include <windows.h> +#include <wchar.h> + +typedef CRITICAL_SECTION mutex_type; + +/* Static initializer (struct declared in WINNT.H). */ +#define RTL_MUTEX_INITIALIZER { NULL, -1, 0, NULL, NULL, 0 } + +/* + * __rtl_mutex_init (dynamic initialization). + * + * Static initialization (with DebugInfo == NULL) + * leads to Access Violation upon first contention. + */ +static void __rtl_mutex_init (LPCRITICAL_SECTION lpCriticalSection) +{ + static LONG g_spinlock = 0; + + while (InterlockedExchange (&g_spinlock, 1) == 1) + { + /* Already locked, spin */ + Sleep (0); + } + if (!(lpCriticalSection->DebugInfo)) + { + /* Dynamic initialization */ + InitializeCriticalSection (lpCriticalSection); + } + InterlockedExchange (&g_spinlock, 0); +} + +#define RTL_MUTEX_INIT(a) __rtl_mutex_init((LPCRITICAL_SECTION)(a)) +#define RTL_MUTEX_ACQUIRE(a) EnterCriticalSection((a)) +#define RTL_MUTEX_RELEASE(a) LeaveCriticalSection((a)) + +static sal_Size __rtl_memory_vmpagesize (void) +{ + SYSTEM_INFO info; + GetSystemInfo (&info); + return ((sal_Size)(info.dwPageSize)); +} + +#define RTL_MEMORY_ALLOC(n) \ +(void*)(VirtualAlloc (NULL, (SIZE_T)(n), MEM_COMMIT, PAGE_READWRITE)) + +#define RTL_MEMORY_FREE(p, n) \ +(void)(VirtualFree ((LPVOID)(p), (SIZE_T)(0), MEM_RELEASE)) + +#endif /* SAL_W32 */ + +/*=========================================================================== + * + * rtl_memory (OS2) internals. + * + *=========================================================================*/ +#ifdef SAL_OS2 + +#define INCL_DOS +#include <os2.h> + +typedef HMTX mutex_type; + +/* Static initializer */ +#define RTL_MUTEX_INITIALIZER -1 + +/* + * __rtl_mutex_init (dynamic initialization). + * + * Static initialization (with DebugInfo == NULL) + * leads to Access Violation upon first contention. + */ +static void __rtl_mutex_init (mutex_type* mutex) +{ + APIRET rc = 0; + + rc = DosCreateMutexSem(NULL,mutex,0,0); + +} + +static int __rtl_mutex_destroy (mutex_type* mutex) +{ + APIRET rc = 0; + + + do { + rc = DosCloseMutexSem(*mutex); + if (rc == 301) DosReleaseMutexSem(*mutex); + } while (rc == 301); + + *mutex = 0; + + /* Return the completion status: */ + return (0); +} + + +static int __rtl_mutex_acquire(mutex_type* mutex) +{ + int ret = 0; + int status = 0; + APIRET rc = 0; + + // initialize static semaphores created with PTHREAD_MUTEX_INITIALIZER state. + if (*mutex == -1) + __rtl_mutex_init( mutex); + + rc = DosRequestMutexSem(*mutex,SEM_INDEFINITE_WAIT); + if (rc) + return(1); + + /* Return the completion status: */ + return (0); +} + +static int __rtl_mutex_release(mutex_type* mutex) +{ + int ret = 0; + APIRET rc = 0; + int status; + + + // initialize static semaphores created with PTHREAD_MUTEX_INITIALIZER state. + if (*mutex == -1) + __rtl_mutex_init( mutex); + + rc = DosReleaseMutexSem(*mutex); + + /* Return the completion status: */ + return (0); +} + +#define RTL_MUTEX_INIT(a) __rtl_mutex_init((mutex_type*)(a)) +#define RTL_MUTEX_ACQUIRE(a) __rtl_mutex_acquire((mutex_type*)(a)) +#define RTL_MUTEX_RELEASE(a) __rtl_mutex_release((mutex_type*)(a)) + +static sal_Size __rtl_memory_vmpagesize (void) +{ + return (sal_Size)(getpagesize()); +} + +#define RTL_MEMORY_ALLOC(n) (void*)(malloc(n)) + +#define RTL_MEMORY_FREE(p, n) (void)(free(p)) + +#endif /* SAL_OS2 */ + +/*=========================================================================== + * + * rtl_memory (global) internals. + * + *=========================================================================*/ +#define __L__ 32 +#define __P__ 24 +#define __N__ ((__L__) + (__P__)) +#define __M__ 0x10000 + +static const sal_Size __T__ = (__M__) * 2 / 3; + +typedef struct __rtl_memory_desc_st memory_type; +struct __rtl_memory_desc_st +{ + sal_Size m_length; + sal_Size m_offset; + memory_type *m_flink; + memory_type *m_blink; +}; + +static const int __C__ = 2 * sizeof(sal_Size); +static const int __Q__ = 2 * sizeof(memory_type*); + +typedef struct __rtl_memory_stat_st memory_stat; +struct __rtl_memory_stat_st +{ + sal_uInt64 m_dequeue; + sal_uInt64 m_enqueue; + sal_Int32 m_delta_q; + + sal_uInt64 m_deqsize; + sal_uInt64 m_enqsize; + sal_Int32 m_delta_n; +}; + +#define RTL_MEMORY_ALIGN(n, m) (((n) + ((m) - 1)) & ~((m) - 1)) +#define RTL_MEMORY_SIZEOF(a) RTL_MEMORY_ALIGN(sizeof(a), sizeof(memory_type)) + +struct __rtl_memory_global_st +{ + sal_Size m_magic; + sal_Size m_align; + + union { + mutex_type m_lock; + char m_data[RTL_MEMORY_SIZEOF(mutex_type)]; + } m_mutex; + + memory_type m_alloc_head; + memory_type m_spare_head; + memory_type m_queue_head[__N__]; + +#if OSL_DEBUG_LEVEL > 0 + memory_stat m_queue_stat[__N__]; +#endif /* OSL_DEBUG_LEVEL */ +}; + +static struct __rtl_memory_global_st g_memory = +{ + 0, 0, { RTL_MUTEX_INITIALIZER }, + { 0, 0, NULL, NULL }, { 0, 0, NULL, NULL }, { { 0, 0, NULL, NULL } }, +#if OSL_DEBUG_LEVEL > 0 + { { 0, 0, 0, 0, 0, 0 } } +#endif /* OSL_DEBUG_LEVEL */ +}; + +void SAL_CALL ___rtl_memory_init (void); +void SAL_CALL ___rtl_memory_fini (void); + +#define RTL_MEMORY_ENTER() \ +{ \ + if (!(g_memory.m_align)) ___rtl_memory_init(); \ + RTL_MUTEX_ACQUIRE(&(g_memory.m_mutex.m_lock)); \ +} + +#define RTL_MEMORY_LEAVE() \ +{ \ + RTL_MUTEX_RELEASE(&(g_memory.m_mutex.m_lock)); \ +} + +/*=========================================================================== + * + * rtl_memory (queue) internals. + * + *=========================================================================*/ +#if defined(PROFILE) || (OSL_DEBUG_LEVEL > 0) +static sal_Size queue (sal_Size n) +{ + /* k = n div __C__ */ + register sal_Size k = n / __C__, m = __L__; + + OSL_PRECOND((__L__ == 32), + "__rtl_memory_queue(): internal logic error"); + if (k > m) + { + /* k = k div __L__ = k div 32 */ + k >>= 5; + while ((k >>= 1) > 0) m++; + k = m; + } + + OSL_POSTCOND((0 < k) && (k < __N__), + "__rtl_memory_queue(): " + "internal error: index out of bounds"); + return (k); +} +#else /* PRODUCT */ +#define queue(k, n) \ +{ \ + (k) = ((n) / __C__); \ + if ((k) > __L__) \ + { \ + register sal_Size m = __L__; \ + (k) >>= 5; \ + while (((k) >>= 1) > 0) m++; \ + (k) = m; \ + } \ +} +#endif /* OSL_DEBUG_LEVEL || PRODUCT */ + +#define queue_start(entry) \ +{ \ + (entry)->m_flink = (entry); \ + (entry)->m_blink = (entry); \ +} + +#define queue_remove(entry) \ +{ \ + (entry)->m_blink->m_flink = (entry)->m_flink; \ + (entry)->m_flink->m_blink = (entry)->m_blink; \ + queue_start(entry); \ +} + +#define queue_insert_head(head, entry) \ +{ \ + (entry)->m_blink = (head); \ + (entry)->m_flink = (head)->m_flink; \ + (head)->m_flink = (entry); \ + (entry)->m_flink->m_blink = (entry); \ +} + +#define queue_insert_tail(head, entry) \ +{ \ + (entry)->m_flink = (head); \ + (entry)->m_blink = (head)->m_blink; \ + (head)->m_blink = (entry); \ + (entry)->m_blink->m_flink = (entry); \ +} + +/*=========================================================================== + * + * rtl_memory (debug) internals. + * + *=========================================================================*/ +#if OSL_DEBUG_LEVEL > 0 + +#define __dbg_memory_succ(entry, length) \ +(memory_type*)((char*)((entry)) + ((length) & ~0x1)) + +#define __dbg_memory_pred(entry, offset) \ +(memory_type*)((char*)((entry)) - ((offset) & ~0x1)) + +#define __dbg_memory_ensure(entry) (!((sal_Size)(entry) & 0x7)) + +/* + * __dbg_memory_dequeue. + */ +static void __dbg_memory_dequeue (sal_Size n) +{ + register sal_Size k = queue(n); + + g_memory.m_queue_stat[k].m_dequeue += 1; + g_memory.m_queue_stat[k].m_delta_q += 1; + + g_memory.m_queue_stat[k].m_deqsize += n; + g_memory.m_queue_stat[k].m_delta_n += n; +} + +/* + * __dbg_memory_enqueue. + */ +static void __dbg_memory_enqueue (sal_Size n) +{ + register sal_Size k = queue(n); + + g_memory.m_queue_stat[k].m_enqueue += 1; + g_memory.m_queue_stat[k].m_delta_q -= 1; + + g_memory.m_queue_stat[k].m_enqsize += n; + g_memory.m_queue_stat[k].m_delta_n -= n; +} + +/* + * __dbg_memory_insert. + */ +static void __dbg_memory_insert (memory_type **ppMemory) +{ + register memory_type * succ; + succ = __dbg_memory_succ (*ppMemory, sizeof(memory_type)); + + succ->m_length = (*ppMemory)->m_length - sizeof(memory_type); + succ->m_offset = (*ppMemory)->m_offset; + + queue_insert_tail (&(g_memory.m_alloc_head), (*ppMemory)); + (*ppMemory) = succ; +} + +/* + * __dbg_memory_remove. + */ +static void __dbg_memory_remove (memory_type **ppMemory) +{ + (*ppMemory) = __dbg_memory_pred (*ppMemory, sizeof(memory_type)); + queue_remove (*ppMemory); +} + +/* + * __dbg_memory_verify_chain. + */ +static int __dbg_memory_verify_chain (memory_type * x) +{ + if (!__dbg_memory_ensure(x)) + { + OSL_ENSURE(0, "__rtl_memory_verify(): invalid pointer alignment."); + return (0); + } + if (!__dbg_memory_ensure(x->m_length & ~0x1)) + { + OSL_ENSURE(0, "__rtl_memory_verify(): dynamic memory corruption"); + return (0); + } + if (!__dbg_memory_ensure(x->m_offset & ~0x1)) + { + OSL_ENSURE(0, "__rtl_memory_verify(): dynamic memory corruption"); + return (0); + } + if (!(x->m_length & ~0x1)) + { + OSL_ENSURE(0, "__rtl_memory_verify(): dynamic memory corruption"); + return (0); + } + return (1); +} + +/* + * __dbg_memory_verify_queue. + */ +static int __dbg_memory_verify_queue (memory_type * x) +{ + if (!__dbg_memory_ensure(x)) + { + OSL_ENSURE(0, "__rtl_memory_verify(): invalid pointer alignment."); + return (0); + } + if (!__dbg_memory_ensure(x->m_flink)) + { + OSL_ENSURE(0, "__rtl_memory_verify(): free memory corruption"); + return (0); + } + if (!__dbg_memory_ensure(x->m_blink)) + { + OSL_ENSURE(0, "__rtl_memory_verify(): free memory corruption"); + return (0); + } + if ((x == x->m_flink) || (x == x->m_blink)) + { + OSL_ENSURE(0, "__rtl_memory_verify(): internal logic error"); + return (0); + } + return (1); +} + +/* + * __dbg_memory_verify_alloc. + */ +static int __dbg_memory_verify_alloc (memory_type * x) +{ + register memory_type *head, *entry; + head = entry = &(g_memory.m_alloc_head); + + if (!__dbg_memory_ensure(x)) + { + OSL_ENSURE(0, "__rtl_memory_verify(): invalid pointer alignment."); + return (0); + } + while (!((entry = entry->m_flink) == head)) + { + if ((entry < x) && (x < __dbg_memory_succ(entry, entry->m_length))) + { + head = entry = __dbg_memory_succ(entry, sizeof(memory_type)); + while (!((x == entry) || (entry->m_offset & 0x1))) + { + /* no match, not last */ + if (!__dbg_memory_verify_chain (entry)) + return (0); + entry = __dbg_memory_succ(entry, entry->m_length); + } + + /* match, or last */ + if (!__dbg_memory_verify_chain (entry)) + return (0); + break; + } + } + if (!(x == entry)) + { + OSL_ENSURE(0, "__rtl_memory_verify(): memory not allocated."); + return (0); + } + return (1); +} + +/* + * __dbg_memory_verify. + */ +static int __dbg_memory_verify (memory_type * x, int debug) +{ + /* dispatch upon 'debug' level */ + if (debug) + { + /* verify allocation */ + if (!__dbg_memory_verify_alloc (x)) + return (0); + } + else + { + /* verify 'chain' fields */ + if (!__dbg_memory_verify_chain (x)) + return (0); + } + + /* verify 'used' bit */ + if (!(x->m_length & 0x1)) + { + OSL_ENSURE(0, "__rtl_memory_verify(): memory not used."); + return (0); + } + return (1); +} + +#if OSL_DEBUG_LEVEL > 1 +/* + * __dbg_memory_usage_update. + */ +static sal_Size __dbg_memory_usage_update (memory_stat * stat, sal_Size length) +{ + register sal_Size n = (length & ~0x1), k = queue(n); + + stat[k].m_dequeue += 1; + stat[k].m_deqsize += n; + + if (!(length & 0x1)) + { + /* not used */ + stat[k].m_enqueue += 1; + stat[k].m_enqsize += n; + return (n); + } + else + { + /* used */ + stat[k].m_delta_q += 1; + stat[k].m_delta_n += n; + return (0); + } +} + +/* + * __dbg_memory_usage. + */ +static void __dbg_memory_usage (memory_stat * total) +{ + register memory_type *head, *entry, *memory; + memory_stat stat[__N__]; + + memset (stat, 0, __N__ * sizeof(memory_stat)); + + head = entry = &(g_memory.m_alloc_head); + while (!((entry = entry->m_flink) == head)) + { + register sal_Size k = 0, n = entry->m_length - sizeof(memory_type); + + memory = __dbg_memory_succ(entry, sizeof(memory_type)); + while (!(memory->m_offset & 0x1)) + { + /* not last */ + k += __dbg_memory_usage_update (stat, memory->m_length); + memory = __dbg_memory_succ(memory, memory->m_length); + } + + k += __dbg_memory_usage_update (stat, memory->m_length); + OSL_TRACE("%x %10d %10d", (sal_Size)(entry), n, k); + } + + if (total) + { + sal_Size i; + + memset (total, 0, sizeof(memory_stat)); + for (i = 0; i < __N__; i++) + { + total->m_dequeue += stat[i].m_dequeue; + total->m_enqueue += stat[i].m_enqueue; + total->m_delta_q += stat[i].m_delta_q; + + total->m_deqsize += stat[i].m_deqsize; + total->m_enqsize += stat[i].m_enqsize; + total->m_delta_n += stat[i].m_delta_n; + } + } +} +#endif /* OSL_DEBUG_LEVEL */ + +#endif /* OSL_DEBUG_LEVEL */ +#if OSL_DEBUG_LEVEL > 0 + +#define DBG_MEMORY_DEQUEUE(n) __dbg_memory_dequeue((sal_Size)(n) & ~0x1) +#define DBG_MEMORY_ENQUEUE(n) __dbg_memory_enqueue((sal_Size)(n) & ~0x1) + +#define DBG_MEMORY_DEQFILL(entry, offset, length) \ + memset(((char*)(entry) + (offset)), 0x77777777, (length)) +#define DBG_MEMORY_ENQFILL(entry, offset, length) \ + memset(((char*)(entry) + (offset)), 0x33333333, (length)) + +#define DBG_MEMORY_INSERT(entry) __dbg_memory_insert((entry)) +#define DBG_MEMORY_REMOVE(entry) __dbg_memory_remove((entry)) + +#if OSL_DEBUG_LEVEL > 1 +#define DBG_MEMORY_VERIFY(entry) __dbg_memory_verify((entry), 1) +#else /* OSL_DEBUG_LEVEL > 0 */ +#define DBG_MEMORY_VERIFY(entry) __dbg_memory_verify((entry), 0) +#endif /* OSL_DEBUG_LEVEL */ + +#define DBG_MEMORY_VERIFY_CHAIN(entry) __dbg_memory_verify_chain((entry)) +#define DBG_MEMORY_VERIFY_QUEUE(entry) __dbg_memory_verify_queue((entry)) + +#else /* PRODUCT */ + +#define DBG_MEMORY_DEQUEUE(n) +#define DBG_MEMORY_ENQUEUE(n) + +#define DBG_MEMORY_DEQFILL(entry, offset, length) +#define DBG_MEMORY_ENQFILL(entry, offset, length) + +#define DBG_MEMORY_INSERT(entry) +#define DBG_MEMORY_REMOVE(entry) + +#define DBG_MEMORY_VERIFY(entry) +#define DBG_MEMORY_VERIFY_CHAIN(entry) +#define DBG_MEMORY_VERIFY_QUEUE(entry) + +#endif /* OSL_DEBUG_LEVEL || PRODUCT */ + +/*=========================================================================== + * + * rtl_memory (manager) internals. + * + *=========================================================================*/ +#define queue_cast(entry, offset) \ +((memory_type*)((char*)(entry) + (ptrdiff_t)(offset))) + +#define __rtl_memory_used(entry) ((entry)->m_length & 0x1) +#define __rtl_memory_last(entry) ((entry)->m_offset & 0x1) +#define __rtl_memory_offset(entry) \ + ((ptrdiff_t)((entry)->m_offset & ~0x1)) + +/* + * ___rtl_memory_init. + */ +void SAL_CALL ___rtl_memory_init (void) +{ +#if defined(RTL_MUTEX_INIT) + RTL_MUTEX_INIT (&(g_memory.m_mutex.m_lock)); +#endif /* RTL_MUTEX_INIT */ + + RTL_MUTEX_ACQUIRE(&(g_memory.m_mutex.m_lock)); + if (!(g_memory.m_align)) + { + sal_Size pagesize; + int i; + + queue_start (&(g_memory.m_alloc_head)); + queue_start (&(g_memory.m_spare_head)); + + for (i = 0; i < __N__; i++) + queue_start (&(g_memory.m_queue_head[i])); + for (i = 1; i <= __L__; i++) + g_memory.m_queue_head[i].m_length = i * __C__; + for (i = __L__ + 1; i < __N__; i++) + g_memory.m_queue_head[i].m_length = + 2 * g_memory.m_queue_head[i - 1].m_length; + + pagesize = __rtl_memory_vmpagesize(); + g_memory.m_align = RTL_MEMORY_ALIGN(__M__, pagesize); + } + RTL_MUTEX_RELEASE(&(g_memory.m_mutex.m_lock)); +} + +/* + * ___rtl_memory_fini. + */ +void SAL_CALL ___rtl_memory_fini (void) +{ +#if OSL_DEBUG_LEVEL > 1 + + memory_stat total; + + __dbg_memory_usage (&total); + if (total.m_delta_n > 0) + { + OSL_TRACE("___rtl_memory_fini(): " + "Leak: %10d (Alloc: %10d, Free: %10d)", + total.m_delta_n, + (sal_uInt32)(total.m_deqsize & 0xffffffff), + (sal_uInt32)(total.m_enqsize & 0xffffffff)); + } + +#endif /* OSL_DEBUG_LEVEL */ +} + +/* + * __rtl_memory_merge. + */ +#if defined(PROFILE) || (OSL_DEBUG_LEVEL > 0) +static void __rtl_memory_merge (memory_type * prev, memory_type * next) +{ + /* adjust length */ + prev->m_length += next->m_length; + if (!__rtl_memory_last(next)) + { + /* not last, adjust offset */ + register memory_type * succ = queue_cast(prev, prev->m_length); + DBG_MEMORY_VERIFY_CHAIN (succ); + succ->m_offset = prev->m_length | __rtl_memory_last(succ); + } + + /* propagate 'last' bit */ + prev->m_offset |= __rtl_memory_last(next); +} +#else /* PRODUCT */ +#define __rtl_memory_merge(prev, next) \ +{ \ + (prev)->m_length += (next)->m_length; \ + if (!__rtl_memory_last((next))) \ + { \ + register memory_type * succ = queue_cast((prev), (prev)->m_length); \ + succ->m_offset = (prev)->m_length | __rtl_memory_last(succ); \ + } \ + (prev)->m_offset |= __rtl_memory_last((next)); \ +} +#endif /* OSL_DEBUG_LEVEL || PRODUCT */ + +/* + * __rtl_memory_split. + */ +#if defined(PROFILE) || (OSL_DEBUG_LEVEL > 0) +static void __rtl_memory_split (memory_type * prev, memory_type * next) +{ + /* adjust length */ + prev->m_length -= next->m_length; + if (!__rtl_memory_last(prev)) + { + /* not last, adjust offset */ + register memory_type * succ = queue_cast(next, next->m_length); + DBG_MEMORY_VERIFY_CHAIN (succ); + succ->m_offset = next->m_length | __rtl_memory_last(succ); + } + + /* propagate 'last' bit */ + next->m_offset |= __rtl_memory_last(prev); + prev->m_offset &= ~0x1; +} +#else /* PRODUCT */ +#define __rtl_memory_split(prev, next) \ +{ \ + (prev)->m_length -= (next)->m_length; \ + if (!__rtl_memory_last((prev))) \ + { \ + register memory_type * succ = queue_cast((next), (next)->m_length); \ + succ->m_offset = (next)->m_length | __rtl_memory_last(succ); \ + } \ +\ + (next)->m_offset |= __rtl_memory_last((prev)); \ + (prev)->m_offset &= ~0x1; \ +} +#endif /* OSL_DEBUG_LEVEL || PRODUCT */ + +/* + * __rtl_memory_insert. + */ +#if defined(PROFILE) || (OSL_DEBUG_LEVEL > 0) +static void __rtl_memory_insert (memory_type * memory, sal_Size n) +{ + /* obtain queue head */ + register memory_type *head; + + head = &(g_memory.m_queue_head[queue(n)]); + DBG_MEMORY_VERIFY_CHAIN (head); + + /* insert at queue tail (first-in first-out) */ + queue_insert_tail (head, memory); +} +#else /* PRODUCT */ +#define __rtl_memory_insert(memory, n) \ +{ \ + register sal_Size h; \ +\ + queue(h, (n)); \ + queue_insert_tail (&(g_memory.m_queue_head[h]), (memory)); \ +} +#endif /* OSL_DEBUG_LEVEL || PRODUCT */ + +/* + * __rtl_memory_resize. + */ +#if defined(PROFILE) || (OSL_DEBUG_LEVEL > 0) +static void __rtl_memory_resize (memory_type * memory, sal_Size n) +{ + register sal_Size k = (memory->m_length - n); + + OSL_ENSURE(!(memory->m_length & 0x1), + "__rtl_memory_resize(): " + "internal logic error."); + + if ((k >= sizeof(memory_type)) && (n <= __T__)) + { + /* split */ + register memory_type * remain = queue_cast(memory, n); + + remain->m_length = k; remain->m_offset = n; + __rtl_memory_split (memory, remain); + + /* check postcond */ + if (!__rtl_memory_last(remain)) + { + /* not last, verify used next entry */ + register memory_type *next; + + next = queue_cast(remain, remain->m_length); + DBG_MEMORY_VERIFY_CHAIN (next); + + OSL_POSTCOND(__rtl_memory_used(next), + "__rtl_memory_resize(): " + "internal logic error."); + } + + /* enqueue */ + __rtl_memory_insert (remain, k); + DBG_MEMORY_VERIFY_QUEUE (remain); + } + + DBG_MEMORY_DEQUEUE(memory->m_length); +} +#else /* PRODUCT */ +#define __rtl_memory_resize(memory, n) \ +{ \ + register sal_Size kn = ((memory)->m_length - (n)); \ + if ((kn >= sizeof(memory_type)) && (n <= __T__)) \ + { \ + register memory_type * remain = queue_cast((memory), (n)); \ +\ + remain->m_length = kn; remain->m_offset = (n); \ + __rtl_memory_split ((memory), remain); \ +\ + __rtl_memory_insert (remain, kn); \ + } \ +} +#endif /* OSL_DEBUG_LEVEL || PRODUCT */ + +/* + * __rtl_memory_dequeue. + */ +#if defined(PROFILE) || (OSL_DEBUG_LEVEL > 0) +static void __rtl_memory_dequeue (memory_type **ppMemory, sal_Size n) +{ + register memory_type *head, *entry; + register sal_Size k, m = n; + + OSL_PRECOND(!*ppMemory, "__rtl_memory_dequeue(): internal logic error."); + for (k = queue(m); k < __N__; k++) + { + /* first fit (equals best fit w/ ascending insert) */ + head = &(g_memory.m_queue_head[k]); + for (entry = head->m_flink; entry != head; entry = entry->m_flink) + { + /* queue not empty */ + DBG_MEMORY_VERIFY_CHAIN (entry); + if (entry->m_length >= m) + { + /* remove entry */ + DBG_MEMORY_VERIFY_QUEUE (entry); + queue_remove (entry); + + /* assign result */ + *ppMemory = entry; + goto dequeue_leave; + } + } + } + + head = &(g_memory.m_spare_head); + for (entry = head->m_flink; entry != head; entry = entry->m_flink) + { + /* queue not empty */ + DBG_MEMORY_VERIFY_CHAIN (entry); + if (entry->m_length >= m) + { + /* remove entry */ + DBG_MEMORY_VERIFY_QUEUE (entry); + queue_remove (entry); + + /* assign result */ + *ppMemory = entry; + goto dequeue_leave; + } + } + +#if OSL_DEBUG_LEVEL > 0 + /* adjust for DBG_MEMORY_INSERT() overhead */ + m += sizeof(memory_type); +#endif /* OSL_DEBUG_LEVEL */ + + k = RTL_MEMORY_ALIGN((m > __M__) ? m : __M__, g_memory.m_align); + if (!((entry = RTL_MEMORY_ALLOC(k)) == 0)) + { + entry->m_length = k; + entry->m_offset = 0x1; /* set 'last' bit */ + + *ppMemory = entry; + DBG_MEMORY_INSERT(ppMemory); + } + +dequeue_leave: + OSL_POSTCOND(*ppMemory, "__rtl_memory_dequeue(): out of memory."); + if ((entry = *ppMemory) != 0) + { + /* adjust length */ + __rtl_memory_resize (entry, n); + + /* fill w/ 'uninitialized' pattern */ + DBG_MEMORY_DEQFILL (entry, __C__, entry->m_length - __C__); + } +#if OSL_DEBUG_LEVEL > 1 + if (!entry) + { + memory_stat total; + __dbg_memory_usage (&total); + } +#endif /* OSL_DEBUG_LEVEL */ +} +#else /* PRODUCT */ +#define __rtl_memory_dequeue(ppMemory, n, label) \ +{ \ + register memory_type *head, *entry; \ + register sal_Size h, m = (n); \ +\ + queue (h, m); \ + for (; h < __N__; h++) \ + { \ + head = &(g_memory.m_queue_head[h]); \ + for (entry = head->m_flink; entry != head; entry = entry->m_flink) \ + { \ + if (entry->m_length >= m) \ + { \ + queue_remove (entry); \ + goto label; \ + } \ + } \ + } \ +\ + head = &(g_memory.m_spare_head); \ + for (entry = head->m_flink; entry != head; entry = entry->m_flink) \ + { \ + if (entry->m_length >= m) \ + { \ + queue_remove (entry); \ + goto label; \ + } \ + } \ +\ + h = RTL_MEMORY_ALIGN((m > __M__) ? m : __M__, g_memory.m_align); \ + if (!((entry = RTL_MEMORY_ALLOC(h)) == 0)) \ + { \ + entry->m_length = h; \ + entry->m_offset = 0x1; \ + } \ +\ +label: \ + if (entry) \ + { \ + __rtl_memory_resize (entry, (n)); \ + *(ppMemory) = entry; \ + } \ +} +#endif /* OSL_DEBUG_LEVEL || PRODUCT */ + +#if defined(PROFILE) || (OSL_DEBUG_LEVEL > 0) +#define RTL_MEMORY_DEQUEUE(m, n, l) __rtl_memory_dequeue((m), (n)) +#else /* PRODUCT */ +#define RTL_MEMORY_DEQUEUE(m, n, l) __rtl_memory_dequeue(m, n, l) +#endif /* OSL_DEBUG_LEVEL || PRODUCT */ + +/* + * __rtl_memory_enqueue. + */ +#if defined(PROFILE) || (OSL_DEBUG_LEVEL > 0) +static void __rtl_memory_enqueue (memory_type **ppMemory) +{ + register memory_type *head = *ppMemory; + + OSL_ENSURE(!__rtl_memory_used(head), + "__rtl_memory_enqueue(): " + "internal logic error."); + DBG_MEMORY_ENQUEUE (head->m_length); + + /* fill w/ 'deinitialized' pattern */ + DBG_MEMORY_ENQFILL (head, __C__, head->m_length - __C__); + + /* try merge w/ next entry */ + if (!__rtl_memory_last(head)) + { + /* not last, check next in chain */ + register memory_type * next; + + next = queue_cast(head, head->m_length); + DBG_MEMORY_VERIFY_CHAIN (next); + + if (!__rtl_memory_used(next)) + { + /* next not used */ + DBG_MEMORY_VERIFY_QUEUE (next); + queue_remove (next); + + /* merge w/ next */ + __rtl_memory_merge (head, next); + DBG_MEMORY_ENQFILL (next, 0, sizeof(memory_type)); + } + } + + /* try merge w/ prev entry */ + if (__rtl_memory_offset(head) > 0) + { + /* not first, check prev in chain */ + register memory_type * prev; + + prev = queue_cast(head, -(__rtl_memory_offset(head))); + DBG_MEMORY_VERIFY_CHAIN (prev); + + if (!__rtl_memory_used(prev)) + { + /* prev not used */ + DBG_MEMORY_VERIFY_QUEUE (prev); + queue_remove (prev); + + /* merge w/ prev */ + __rtl_memory_merge (prev, head); + DBG_MEMORY_ENQFILL (head, 0, sizeof(memory_type)); + head = prev; + } + } + + if (!(head->m_offset == 0x1)) + { + /* page still used, enqueue */ + __rtl_memory_insert (head, head->m_length); + head = 0; + } + else if (head->m_length <= g_memory.m_align) + { + /* small page unused, check spare page */ + register memory_type * spare; + + spare = &(g_memory.m_spare_head); + if (spare->m_flink == spare) + { + /* keep as spare page */ + queue_insert_tail (spare, head); + head = 0; + } + } + if ((*ppMemory = head) != 0) + { + /* page unused, remove */ + DBG_MEMORY_REMOVE(ppMemory); + } +} +#else /* PRODUCT */ +#define __rtl_memory_enqueue(ppMemory) \ +{ \ + register memory_type *head = *(ppMemory); \ +\ + if (!__rtl_memory_last(head)) \ + { \ + register memory_type * next; \ + next = queue_cast(head, head->m_length); \ + if (!__rtl_memory_used(next)) \ + { \ + queue_remove (next); \ + __rtl_memory_merge (head, next); \ + } \ + } \ +\ + if (__rtl_memory_offset(head) > 0) \ + { \ + register memory_type * prev; \ + prev = queue_cast(head, -(__rtl_memory_offset(head))); \ + if (!__rtl_memory_used(prev)) \ + { \ + queue_remove (prev); \ + __rtl_memory_merge (prev, head); \ + head = prev; \ + } \ + } \ +\ + if (!(head->m_offset == 0x1)) \ + { \ + register memory_type * used = head; \ + __rtl_memory_insert (used, used->m_length); \ + head = 0; \ + } \ + else if (head->m_length <= g_memory.m_align) \ + { \ + register memory_type * spare; \ + spare = &(g_memory.m_spare_head); \ + if (spare->m_flink == spare) \ + { \ + queue_insert_tail (spare, head); \ + head = 0; \ + } \ + } \ +\ + *(ppMemory) = head; \ +} +#endif /* OSL_DEBUG_LEVEL || PRODUCT */ + +#define RTL_MEMORY_ENQUEUE(m) __rtl_memory_enqueue((m)) + +#endif /* FORCE_SYSALLOC */ + +/*=========================================================================== + * + * rtl_memory (manager) implementation. + * + *=========================================================================*/ +/* + * rtl_reallocateMemory. + */ +#ifndef FORCE_SYSALLOC +void* SAL_CALL rtl_reallocateMemory (void * p, sal_Size n) SAL_THROW_EXTERN_C() +{ + memory_type * memory; + if (!(!p || !n)) + { + /* reallocate */ + register sal_Size datlen; + + memory = queue_cast(p, -(__C__)); p = 0; + n = RTL_MEMORY_ALIGN(n, __Q__) + __C__; + + RTL_MEMORY_ENTER(); + DBG_MEMORY_VERIFY(memory); + + /* clear 'used' bit */ + DBG_MEMORY_ENQUEUE (memory->m_length); + memory->m_length &= ~0x1; + + /* amount of data to be moved or copied */ + datlen = ((memory->m_length < n) ? memory->m_length : n); + + /* try merge w/ next entry */ + if (!__rtl_memory_last(memory)) + { + /* not last, check next in chain */ + register memory_type * next; + + next = queue_cast(memory, memory->m_length); + DBG_MEMORY_VERIFY_CHAIN(next); + + if (!__rtl_memory_used(next)) + { + /* next not used */ + DBG_MEMORY_VERIFY_QUEUE(next); + queue_remove (next); + + /* merge w/ next */ + __rtl_memory_merge (memory, next); + } + } + + /* try merge w/ prev entry */ + if (__rtl_memory_offset(memory) > 0) + { + /* not first, check prev in chain */ + register memory_type * prev; + + prev = queue_cast(memory, -(__rtl_memory_offset(memory))); + DBG_MEMORY_VERIFY_CHAIN (prev); + + if (!__rtl_memory_used(prev)) + { + /* prev not used, try merge, move */ + if ((memory->m_length + prev->m_length) >= n) + { + /* prev does fit */ + DBG_MEMORY_VERIFY_QUEUE (prev); + queue_remove (prev); + + /* merge w/ prev */ + __rtl_memory_merge (prev, memory); + + /* move to prev */ + memmove ( + queue_cast(prev, __C__), + queue_cast(memory, __C__), + datlen - __C__); + memory = prev; + } + } + } + + if (memory->m_length >= n) + { + /* adjust, set 'used' bit */ + __rtl_memory_resize (memory, n); + memory->m_length |= 0x1; + + /* assign result */ + p = queue_cast(memory, __C__); + } + else + { + /* allocate */ + memory_type * result = 0; + + /* restore 'used' bit */ + DBG_MEMORY_DEQUEUE (memory->m_length); + memory->m_length |= 0x80000000; + + RTL_MEMORY_DEQUEUE (&result, n, realloc_label_1); + if (result) + { + /* set 'used' bit */ + result->m_length |= 0x1; + + /* copy */ + memcpy ( + queue_cast(result, __C__), + queue_cast(memory, __C__), + datlen - __C__); + + /* clear 'used' bit, enqueue */ + memory->m_length &= 0x7fffffff; + RTL_MEMORY_ENQUEUE (&memory); + if (memory) + { + /* free memory page */ + RTL_MEMORY_FREE(memory, memory->m_length); + } + + /* assign result */ + p = queue_cast(result, __C__); + } + } + RTL_MEMORY_LEAVE(); + } + else if (!p) + { + /* allocate */ + memory = 0; + n = RTL_MEMORY_ALIGN(n, __Q__) + __C__; + + RTL_MEMORY_ENTER(); + RTL_MEMORY_DEQUEUE (&memory, n, realloc_label_2); + if (memory) + { + /* set 'used' bit */ + memory->m_length |= 0x1; + + /* assign result */ + p = queue_cast(memory, __C__); + } + RTL_MEMORY_LEAVE(); + } + else if (!n) + { + /* free */ + memory = queue_cast(p, -(__C__)); p = 0; + + RTL_MEMORY_ENTER(); + DBG_MEMORY_VERIFY(memory); + + /* clear 'used' bit, enqueue */ + memory->m_length &= ~0x1; + + RTL_MEMORY_ENQUEUE (&memory); + if (memory) + { + /* free memory page */ + RTL_MEMORY_FREE(memory, memory->m_length); + } + RTL_MEMORY_LEAVE(); + } + return (p); +} +#else /* FORCE_SYSALLOC */ +void* SAL_CALL rtl_reallocateMemory (void * p, sal_Size n) SAL_THROW_EXTERN_C() +{ + return realloc(p, (sal_Size)(n)); +} +#endif /* FORCE_SYSALLOC */ + +/* + * rtl_allocateMemory. + */ +#ifndef FORCE_SYSALLOC +void* SAL_CALL rtl_allocateMemory (sal_Size n) SAL_THROW_EXTERN_C() +{ + void * p = 0; + if (n > 0) + { + memory_type * memory = 0; + n = RTL_MEMORY_ALIGN(n, __Q__) + __C__; + + RTL_MEMORY_ENTER(); + RTL_MEMORY_DEQUEUE (&memory, n, alloc_label); + if (memory) + { + /* set 'used' bit */ + memory->m_length |= 0x1; + + /* assign result */ + p = queue_cast(memory, __C__); + } + RTL_MEMORY_LEAVE(); + } + return (p); +} +#else /* FORCE_SYSALLOC */ +void* SAL_CALL rtl_allocateMemory (sal_Size n) SAL_THROW_EXTERN_C() +{ + return malloc((sal_Size)(n)); +} +#endif /* FORCE_SYSALLOC */ + +/* + * rtl_freeMemory. + */ +#ifndef FORCE_SYSALLOC +void SAL_CALL rtl_freeMemory (void * p) SAL_THROW_EXTERN_C() +{ + if (p) + { + memory_type * memory = queue_cast(p, -(__C__)); + + RTL_MEMORY_ENTER(); + DBG_MEMORY_VERIFY(memory); + + /* clear 'used' bit, enqueue */ + memory->m_length &= ~0x1; + + RTL_MEMORY_ENQUEUE (&memory); + if (memory) + { + /* free memory page */ + RTL_MEMORY_FREE(memory, memory->m_length); + } + RTL_MEMORY_LEAVE(); + } +} +#else /* FORCE_SYSALLOC */ +void SAL_CALL rtl_freeMemory (void * p) SAL_THROW_EXTERN_C() +{ + free(p); +} +#endif /* FORCE_SYSALLOC */ + +/* + * rtl_allocateZeroMemory. + */ +#ifndef FORCE_SYSALLOC +void* SAL_CALL rtl_allocateZeroMemory (sal_Size n) SAL_THROW_EXTERN_C() +{ + void * p = 0; + if (n > 0) + { + memory_type * memory = 0; + n = RTL_MEMORY_ALIGN(n, __Q__) + __C__; + + RTL_MEMORY_ENTER(); + RTL_MEMORY_DEQUEUE (&memory, n, alloc_label); /* NYI: demand zero */ + if (memory) + { + /* zero, set 'used' bit */ + memset ((char*)memory + __C__, 0, memory->m_length - __C__); + memory->m_length |= 0x1; + + /* assign result */ + p = queue_cast(memory, __C__); + } + RTL_MEMORY_LEAVE(); + } + return (p); +} +#else /* FORCE_SYSALLOC */ +void* SAL_CALL rtl_allocateZeroMemory (sal_Size n) SAL_THROW_EXTERN_C() +{ + return calloc((sal_Size)(n), 1); +} +#endif /* FORCE_SYSALLOC */ + +/* + * rtl_freeZeroMemory. + */ +#ifndef FORCE_SYSALLOC +void SAL_CALL rtl_freeZeroMemory (void * p, sal_Size n) SAL_THROW_EXTERN_C() +{ + (void) n; /* unused */ + if (p) + { + memory_type * memory = queue_cast(p, -(__C__)); + + RTL_MEMORY_ENTER(); + DBG_MEMORY_VERIFY(memory); + + /* clear 'used' bit, zero, enqueue */ + memory->m_length &= ~0x1; + memset ((char*)memory + __C__, 0, memory->m_length - __C__); + + RTL_MEMORY_ENQUEUE (&memory); /* NYI: demand zero */ + if (memory) + { + /* free memory page */ + RTL_MEMORY_FREE(memory, memory->m_length); + } + RTL_MEMORY_LEAVE(); + } +} +#else /* FORCE_SYSALLOC */ +void SAL_CALL rtl_freeZeroMemory (void * p, sal_Size n) SAL_THROW_EXTERN_C() +{ + if (p) + { + memset(p, 0, n); + free(p); + } +} +#endif /* FORCE_SYSALLOC */ + +/*=========================================================================== + * + * The End. + * + *=========================================================================*/ diff --git a/sal/rtl/source/alloc_arena.c b/sal/rtl/source/alloc_arena.c new file mode 100644 index 000000000000..1a74c7e36cae --- /dev/null +++ b/sal/rtl/source/alloc_arena.c @@ -0,0 +1,1396 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define _BSD_SOURCE /* sys/mman.h: MAP_ANON */ +#include "alloc_arena.h" + +#ifndef INCLUDED_RTL_ARENA_IMPL_H +#include "alloc_impl.h" +#endif +#include "internal/once.h" +#include "sal/macros.h" +#include "osl/diagnose.h" + +#ifndef INCLUDED_STRING_H +#include <string.h> +#endif + +#ifndef INCLUDED_STDIO_H +#include <stdio.h> +#endif + +#include "sal/types.h" + +#ifdef OS2 +#undef OSL_TRACE +#define OSL_TRACE 1 ? ((void)0) : _OSL_GLOBAL osl_trace +#define INCL_DOS +#include <os2.h> +#endif + +/* ================================================================= * + * + * arena internals. + * + * ================================================================= */ + +/** g_arena_list + * @internal + */ +struct rtl_arena_list_st +{ + rtl_memory_lock_type m_lock; + rtl_arena_type m_arena_head; +}; + +static struct rtl_arena_list_st g_arena_list; + + +/** gp_arena_arena + * provided for arena_type allocations, and hash_table resizing. + * + * @internal + */ +static rtl_arena_type * gp_arena_arena = 0; + + +/** gp_machdep_arena + * + * Low level virtual memory (pseudo) arena + * (platform dependent implementation) + * + * @internal + */ +static rtl_arena_type * gp_machdep_arena = 0; + + +static void * +SAL_CALL rtl_machdep_alloc ( + rtl_arena_type * pArena, + sal_Size * pSize +); + +static void +SAL_CALL rtl_machdep_free ( + rtl_arena_type * pArena, + void * pAddr, + sal_Size nSize +); + +static sal_Size +rtl_machdep_pagesize (void); + + +/** gp_default_arena + */ +rtl_arena_type * gp_default_arena = 0; + + +/** rtl_arena_init() + * @internal + */ +static int +rtl_arena_init (void); + + +/* ================================================================= */ + +/** rtl_arena_segment_constructor() + */ +static int +rtl_arena_segment_constructor (void * obj) +{ + rtl_arena_segment_type * segment = (rtl_arena_segment_type*)(obj); + + QUEUE_START_NAMED(segment, s); + QUEUE_START_NAMED(segment, f); + + return (1); +} + + +/** rtl_arena_segment_destructor() + */ +static void +rtl_arena_segment_destructor (void * obj) +{ +#if OSL_DEBUG_LEVEL == 0 + (void) obj; /* unused */ +#else /* OSL_DEBUG_LEVEL */ + rtl_arena_segment_type * segment = (rtl_arena_segment_type*)(obj); + + OSL_ASSERT(QUEUE_STARTED_NAMED(segment, s)); + OSL_ASSERT(QUEUE_STARTED_NAMED(segment, f)); +#endif /* OSL_DEBUG_LEVEL */ +} + +/* ================================================================= */ + +/** rtl_arena_segment_populate() + * + * @precond arena->m_lock acquired. + */ +static int +rtl_arena_segment_populate ( + rtl_arena_type * arena +) +{ + rtl_arena_segment_type *span; + sal_Size size = rtl_machdep_pagesize(); + + span = rtl_machdep_alloc(gp_machdep_arena, &size); + if (span != 0) + { + rtl_arena_segment_type *first, *last, *head; + sal_Size count = size / sizeof(rtl_arena_segment_type); + + /* insert onto reserve span list */ + QUEUE_INSERT_TAIL_NAMED(&(arena->m_segment_reserve_span_head), span, s); + QUEUE_START_NAMED(span, f); + span->m_addr = (sal_uIntPtr)(span); + span->m_size = size; + span->m_type = RTL_ARENA_SEGMENT_TYPE_SPAN; + + /* insert onto reserve list */ + head = &(arena->m_segment_reserve_head); + for (first = span + 1, last = span + count; first < last; ++first) + { + QUEUE_INSERT_TAIL_NAMED(head, first, s); + QUEUE_START_NAMED(first, f); + first->m_addr = 0; + first->m_size = 0; + first->m_type = 0; + } + } + return (span != 0); +} + + +/** rtl_arena_segment_get() + * + * @precond arena->m_lock acquired. + * @precond (*ppSegment == 0) + */ +static RTL_MEMORY_INLINE void +rtl_arena_segment_get ( + rtl_arena_type * arena, + rtl_arena_segment_type ** ppSegment +) +{ + rtl_arena_segment_type * head; + + OSL_ASSERT(*ppSegment == 0); + + head = &(arena->m_segment_reserve_head); + if ((head->m_snext != head) || rtl_arena_segment_populate (arena)) + { + (*ppSegment) = head->m_snext; + QUEUE_REMOVE_NAMED((*ppSegment), s); + } +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(rtl_arena_segment_get) +#endif + + +/** rtl_arena_segment_put() + * + * @precond arena->m_lock acquired. + * @postcond (*ppSegment == 0) + */ +static RTL_MEMORY_INLINE void +rtl_arena_segment_put ( + rtl_arena_type * arena, + rtl_arena_segment_type ** ppSegment +) +{ + rtl_arena_segment_type * head; + + OSL_ASSERT(QUEUE_STARTED_NAMED((*ppSegment), s)); + OSL_ASSERT(QUEUE_STARTED_NAMED((*ppSegment), f)); + + (*ppSegment)->m_addr = 0; + (*ppSegment)->m_size = 0; + + OSL_ASSERT((*ppSegment)->m_type != RTL_ARENA_SEGMENT_TYPE_HEAD); + (*ppSegment)->m_type = 0; + + /* keep as reserve */ + head = &(arena->m_segment_reserve_head); + QUEUE_INSERT_HEAD_NAMED(head, (*ppSegment), s); + + /* clear */ + (*ppSegment) = 0; +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(rtl_arena_segment_put) +#endif + +/* ================================================================= */ + +/** rtl_arena_freelist_insert() + * + * @precond arena->m_lock acquired. + */ +static RTL_MEMORY_INLINE void +rtl_arena_freelist_insert ( + rtl_arena_type * arena, + rtl_arena_segment_type * segment +) +{ + rtl_arena_segment_type * head; + + head = &(arena->m_freelist_head[highbit(segment->m_size) - 1]); + QUEUE_INSERT_TAIL_NAMED(head, segment, f); + + arena->m_freelist_bitmap |= head->m_size; +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(rtl_arena_freelist_insert) +#endif /* __SUNPRO_C */ + + +/** rtl_arena_freelist_remove() + * + * @precond arena->m_lock acquired. + */ +static RTL_MEMORY_INLINE void +rtl_arena_freelist_remove ( + rtl_arena_type * arena, + rtl_arena_segment_type * segment +) +{ + if ((segment->m_fnext->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD) && + (segment->m_fprev->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD) ) + { + rtl_arena_segment_type * head; + + head = segment->m_fprev; + OSL_ASSERT(arena->m_freelist_bitmap & head->m_size); + arena->m_freelist_bitmap ^= head->m_size; + } + QUEUE_REMOVE_NAMED(segment, f); +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(rtl_arena_freelist_remove) +#endif /* __SUNPRO_C */ + + +/* ================================================================= */ + +/** RTL_ARENA_HASH_INDEX() + */ +#define RTL_ARENA_HASH_INDEX_IMPL(a, s, q, m) \ + ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m)) + +#define RTL_ARENA_HASH_INDEX(arena, addr) \ + RTL_ARENA_HASH_INDEX_IMPL((addr), (arena)->m_hash_shift, (arena)->m_quantum_shift, ((arena)->m_hash_size - 1)) + +/** rtl_arena_hash_rescale() + * + * @precond arena->m_lock released. + */ +static void +rtl_arena_hash_rescale ( + rtl_arena_type * arena, + sal_Size new_size +) +{ + rtl_arena_segment_type ** new_table; + sal_Size new_bytes; + + new_bytes = new_size * sizeof(rtl_arena_segment_type*); + new_table = (rtl_arena_segment_type **)rtl_arena_alloc (gp_arena_arena, &new_bytes); + + if (new_table != 0) + { + rtl_arena_segment_type ** old_table; + sal_Size old_size, i; + + memset (new_table, 0, new_bytes); + + RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock)); + + old_table = arena->m_hash_table; + old_size = arena->m_hash_size; + + OSL_TRACE( + "rtl_arena_hash_rescale(\"%s\"): " + "nseg: %"PRIu64" (ave: %"PRIu64"), frees: %"PRIu64" " + "[old_size: %lu, new_size: %lu]", + arena->m_name, + arena->m_stats.m_alloc - arena->m_stats.m_free, + (arena->m_stats.m_alloc - arena->m_stats.m_free) >> arena->m_hash_shift, + arena->m_stats.m_free, + old_size, new_size + ); + +#if 0 /* DBG */ + int i; + for (i = 0; i < arena->m_hash_size; i++) + { + sal_Size k = 0; rtl_arena_segment_type ** segpp = &(arena->m_hash_table[i]); + while (*segpp) + { + k += 1; + segpp = &((*segpp)->m_fnext); + } + fprintf(stdout, "%d, ", k); + } + fprintf(stdout, "\n"); +#endif /* DBG */ + + arena->m_hash_table = new_table; + arena->m_hash_size = new_size; + arena->m_hash_shift = highbit(arena->m_hash_size) - 1; + + for (i = 0; i < old_size; i++) + { + rtl_arena_segment_type * curr = old_table[i]; + while (curr != 0) + { + rtl_arena_segment_type * next = curr->m_fnext; + rtl_arena_segment_type ** head; + + head = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, curr->m_addr)]); + curr->m_fnext = (*head); + (*head) = curr; + + curr = next; + } + old_table[i] = 0; + } + + RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); + + if (old_table != arena->m_hash_table_0) + { + sal_Size old_bytes = old_size * sizeof(rtl_arena_segment_type*); + rtl_arena_free (gp_arena_arena, old_table, old_bytes); + } + } +} + + +/** rtl_arena_hash_insert() + * ...and update stats. + */ +static RTL_MEMORY_INLINE void +rtl_arena_hash_insert ( + rtl_arena_type * arena, + rtl_arena_segment_type * segment +) +{ + rtl_arena_segment_type ** ppSegment; + + ppSegment = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, segment->m_addr)]); + + segment->m_fnext = (*ppSegment); + (*ppSegment) = segment; + + arena->m_stats.m_alloc += 1; + arena->m_stats.m_mem_alloc += segment->m_size; +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(rtl_arena_hash_insert) +#endif /* __SUNPRO_C */ + + +/** rtl_arena_hash_remove() + * ...and update stats. + */ +static rtl_arena_segment_type * +rtl_arena_hash_remove ( + rtl_arena_type * arena, + sal_uIntPtr addr, + sal_Size size +) +{ + rtl_arena_segment_type *segment, **segpp; + sal_Size lookups = 0; + +#if OSL_DEBUG_LEVEL == 0 + (void) size; /* unused */ +#endif /* OSL_DEBUG_LEVEL */ + + segpp = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, addr)]); + while ((segment = *segpp) != 0) + { + if (segment->m_addr == addr) + { + *segpp = segment->m_fnext, segment->m_fnext = segment->m_fprev = segment; + break; + } + + /* update lookup miss stats */ + lookups += 1; + segpp = &(segment->m_fnext); + } + + OSL_POSTCOND(segment != 0, "rtl_arena_hash_remove(): bad free."); + if (segment != 0) + { + OSL_POSTCOND(segment->m_size == size, "rtl_arena_hash_remove(): wrong size."); + + arena->m_stats.m_free += 1; + arena->m_stats.m_mem_alloc -= segment->m_size; + + if (lookups > 1) + { + sal_Size nseg = (sal_Size)(arena->m_stats.m_alloc - arena->m_stats.m_free); + if (nseg > 4 * arena->m_hash_size) + { + if (!(arena->m_flags & RTL_ARENA_FLAG_RESCALE)) + { + sal_Size ave = nseg >> arena->m_hash_shift; + sal_Size new_size = arena->m_hash_size << (highbit(ave) - 1); + + arena->m_flags |= RTL_ARENA_FLAG_RESCALE; + RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); + rtl_arena_hash_rescale (arena, new_size); + RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock)); + arena->m_flags &= ~RTL_ARENA_FLAG_RESCALE; + } + } + } + } + + return (segment); +} + +/* ================================================================= */ + +/** rtl_arena_segment_alloc() + * allocate (and remove) segment from freelist + * + * @precond arena->m_lock acquired + * @precond (*ppSegment == 0) + */ +static int +rtl_arena_segment_alloc ( + rtl_arena_type * arena, + sal_Size size, + rtl_arena_segment_type ** ppSegment +) +{ + int index = 0; + + OSL_ASSERT(*ppSegment == 0); + if (!RTL_MEMORY_ISP2(size)) + { + int msb = highbit(size); + if (RTL_ARENA_FREELIST_SIZE == SAL_INT_CAST(size_t, msb)) + { + /* highest possible freelist: fall back to first fit */ + rtl_arena_segment_type *head, *segment; + + head = &(arena->m_freelist_head[msb - 1]); + for (segment = head->m_fnext; segment != head; segment = segment->m_fnext) + { + if (segment->m_size >= size) + { + /* allocate first fit segment */ + (*ppSegment) = segment; + break; + } + } + goto dequeue_and_leave; + } + + /* roundup to next power of 2 */ + size = (1UL << msb); + } + + index = lowbit(RTL_MEMORY_P2ALIGN(arena->m_freelist_bitmap, size)); + if (index > 0) + { + /* instant fit: allocate first free segment */ + rtl_arena_segment_type *head; + + head = &(arena->m_freelist_head[index - 1]); + (*ppSegment) = head->m_fnext; + OSL_ASSERT((*ppSegment) != head); + } + +dequeue_and_leave: + if (*ppSegment != 0) + { + /* remove from freelist */ + rtl_arena_freelist_remove (arena, (*ppSegment)); + } + return (*ppSegment != 0); +} + + +/** rtl_arena_segment_create() + * import new (span) segment from source arena + * + * @precond arena->m_lock acquired + * @precond (*ppSegment == 0) + */ +static int +rtl_arena_segment_create ( + rtl_arena_type * arena, + sal_Size size, + rtl_arena_segment_type ** ppSegment +) +{ + OSL_ASSERT((*ppSegment) == 0); + if (arena->m_source_alloc != 0) + { + rtl_arena_segment_get (arena, ppSegment); + if (*ppSegment != 0) + { + rtl_arena_segment_type * span = 0; + rtl_arena_segment_get (arena, &span); + if (span != 0) + { + /* import new span from source arena */ + RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); + + span->m_size = size; + span->m_addr = (sal_uIntPtr)(arena->m_source_alloc)( + arena->m_source_arena, &(span->m_size)); + + RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock)); + if (span->m_addr != 0) + { + /* insert onto segment list, update stats */ + span->m_type = RTL_ARENA_SEGMENT_TYPE_SPAN; + QUEUE_INSERT_HEAD_NAMED(&(arena->m_segment_head), span, s); + arena->m_stats.m_mem_total += span->m_size; + + (*ppSegment)->m_addr = span->m_addr; + (*ppSegment)->m_size = span->m_size; + (*ppSegment)->m_type = RTL_ARENA_SEGMENT_TYPE_FREE; + QUEUE_INSERT_HEAD_NAMED(span, (*ppSegment), s); + + /* report success */ + return (1); + } + rtl_arena_segment_put (arena, &span); + } + rtl_arena_segment_put (arena, ppSegment); + } + } + return (0); +} + + +/** rtl_arena_segment_coalesce() + * mark as free and join with adjacent free segment(s) + * + * @precond arena->m_lock acquired + * @precond segment marked 'used' + */ +static void +rtl_arena_segment_coalesce ( + rtl_arena_type * arena, + rtl_arena_segment_type * segment +) +{ + rtl_arena_segment_type *next, *prev; + + /* mark segment free */ + OSL_ASSERT(segment->m_type == RTL_ARENA_SEGMENT_TYPE_USED); + segment->m_type = RTL_ARENA_SEGMENT_TYPE_FREE; + + /* try to merge w/ next segment */ + next = segment->m_snext; + if (next->m_type == RTL_ARENA_SEGMENT_TYPE_FREE) + { + OSL_ASSERT(segment->m_addr + segment->m_size == next->m_addr); + segment->m_size += next->m_size; + + /* remove from freelist */ + rtl_arena_freelist_remove (arena, next); + + /* remove from segment list */ + QUEUE_REMOVE_NAMED(next, s); + + /* release segment descriptor */ + rtl_arena_segment_put (arena, &next); + } + + /* try to merge w/ prev segment */ + prev = segment->m_sprev; + if (prev->m_type == RTL_ARENA_SEGMENT_TYPE_FREE) + { + OSL_ASSERT(prev->m_addr + prev->m_size == segment->m_addr); + segment->m_addr = prev->m_addr; + segment->m_size += prev->m_size; + + /* remove from freelist */ + rtl_arena_freelist_remove (arena, prev); + + /* remove from segment list */ + QUEUE_REMOVE_NAMED(prev, s); + + /* release segment descriptor */ + rtl_arena_segment_put (arena, &prev); + } +} + +/* ================================================================= */ + +/** rtl_arena_constructor() + */ +static void +rtl_arena_constructor (void * obj) +{ + rtl_arena_type * arena = (rtl_arena_type*)(obj); + rtl_arena_segment_type * head; + size_t i; + + memset (arena, 0, sizeof(rtl_arena_type)); + + QUEUE_START_NAMED(arena, arena_); + + (void) RTL_MEMORY_LOCK_INIT(&(arena->m_lock)); + + head = &(arena->m_segment_reserve_span_head); + rtl_arena_segment_constructor (head); + head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD; + + head = &(arena->m_segment_reserve_head); + rtl_arena_segment_constructor (head); + head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD; + + head = &(arena->m_segment_head); + rtl_arena_segment_constructor (head); + head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD; + + for (i = 0; i < RTL_ARENA_FREELIST_SIZE; i++) + { + head = &(arena->m_freelist_head[i]); + rtl_arena_segment_constructor (head); + + head->m_size = (1UL << i); + head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD; + } + + arena->m_hash_table = arena->m_hash_table_0; + arena->m_hash_size = RTL_ARENA_HASH_SIZE; + arena->m_hash_shift = highbit(arena->m_hash_size) - 1; +} + + +/** rtl_arena_destructor() + */ +static void +rtl_arena_destructor (void * obj) +{ + rtl_arena_type * arena = (rtl_arena_type*)(obj); + rtl_arena_segment_type * head; + size_t i; + + OSL_ASSERT(QUEUE_STARTED_NAMED(arena, arena_)); + + RTL_MEMORY_LOCK_DESTROY(&(arena->m_lock)); + + head = &(arena->m_segment_reserve_span_head); + OSL_ASSERT(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD); + rtl_arena_segment_destructor (head); + + head = &(arena->m_segment_reserve_head); + OSL_ASSERT(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD); + rtl_arena_segment_destructor (head); + + head = &(arena->m_segment_head); + OSL_ASSERT(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD); + rtl_arena_segment_destructor (head); + + for (i = 0; i < RTL_ARENA_FREELIST_SIZE; i++) + { + head = &(arena->m_freelist_head[i]); + + OSL_ASSERT(head->m_size == (1UL << i)); + OSL_ASSERT(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD); + + rtl_arena_segment_destructor (head); + } + + OSL_ASSERT(arena->m_hash_table == arena->m_hash_table_0); + OSL_ASSERT(arena->m_hash_size == RTL_ARENA_HASH_SIZE); + OSL_ASSERT( + arena->m_hash_shift == + SAL_INT_CAST(unsigned, highbit(arena->m_hash_size) - 1)); +} + +/* ================================================================= */ + +/** rtl_arena_activate() + */ +static rtl_arena_type * +rtl_arena_activate ( + rtl_arena_type * arena, + const char * name, + sal_Size quantum, + sal_Size quantum_cache_max, + rtl_arena_type * source_arena, + void * (SAL_CALL * source_alloc)(rtl_arena_type *, sal_Size *), + void (SAL_CALL * source_free) (rtl_arena_type *, void *, sal_Size) +) +{ + OSL_ASSERT(arena != 0); + if (arena != 0) + { + (void) snprintf (arena->m_name, sizeof(arena->m_name), "%s", name); + + if (!RTL_MEMORY_ISP2(quantum)) + { + /* roundup to next power of 2 */ + quantum = (1UL << highbit(quantum)); + } + quantum_cache_max = RTL_MEMORY_P2ROUNDUP(quantum_cache_max, quantum); + + arena->m_quantum = quantum; + arena->m_quantum_shift = highbit(arena->m_quantum) - 1; + arena->m_qcache_max = quantum_cache_max; + + arena->m_source_arena = source_arena; + arena->m_source_alloc = source_alloc; + arena->m_source_free = source_free; + + if (arena->m_qcache_max > 0) + { + char name[RTL_ARENA_NAME_LENGTH + 1]; + int i, n = (arena->m_qcache_max >> arena->m_quantum_shift); + + sal_Size size = n * sizeof(rtl_cache_type*); + arena->m_qcache_ptr = (rtl_cache_type**)rtl_arena_alloc (gp_arena_arena, &size); + if (!(arena->m_qcache_ptr)) + { + /* out of memory */ + return (0); + } + for (i = 1; i <= n; i++) + { + size = i * arena->m_quantum; + (void) snprintf (name, sizeof(name), "%s_%lu", arena->m_name, size); + arena->m_qcache_ptr[i - 1] = rtl_cache_create(name, size, 0, NULL, NULL, NULL, NULL, arena, RTL_CACHE_FLAG_QUANTUMCACHE); + } + } + + /* insert into arena list */ + RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock)); + QUEUE_INSERT_TAIL_NAMED(&(g_arena_list.m_arena_head), arena, arena_); + RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock)); + } + return (arena); +} + +/** rtl_arena_deactivate() + */ +static void +rtl_arena_deactivate ( + rtl_arena_type * arena +) +{ + rtl_arena_segment_type * head, * segment; + + /* remove from arena list */ + RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock)); + QUEUE_REMOVE_NAMED(arena, arena_); + RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock)); + + /* cleanup quantum cache(s) */ + if ((arena->m_qcache_max > 0) && (arena->m_qcache_ptr != 0)) + { + int i, n = (arena->m_qcache_max >> arena->m_quantum_shift); + for (i = 1; i <= n; i++) + { + if (arena->m_qcache_ptr[i - 1] != 0) + { + rtl_cache_destroy (arena->m_qcache_ptr[i - 1]); + arena->m_qcache_ptr[i - 1] = 0; + } + } + rtl_arena_free ( + gp_arena_arena, + arena->m_qcache_ptr, + n * sizeof(rtl_cache_type*)); + + arena->m_qcache_ptr = 0; + } + + /* check for leaked segments */ + OSL_TRACE( + "rtl_arena_deactivate(\"%s\"): " + "allocs: %"PRIu64", frees: %"PRIu64"; total: %lu, used: %lu", + arena->m_name, + arena->m_stats.m_alloc, arena->m_stats.m_free, + arena->m_stats.m_mem_total, arena->m_stats.m_mem_alloc + ); + if (arena->m_stats.m_alloc > arena->m_stats.m_free) + { + sal_Size i, n; + + OSL_TRACE( + "rtl_arena_deactivate(\"%s\"): " + "cleaning up %"PRIu64" leaked segment(s) [%lu bytes]", + arena->m_name, + arena->m_stats.m_alloc - arena->m_stats.m_free, + arena->m_stats.m_mem_alloc + ); + + /* cleanup still used segment(s) */ + for (i = 0, n = arena->m_hash_size; i < n; i++) + { + while ((segment = arena->m_hash_table[i]) != 0) + { + /* pop from hash table */ + arena->m_hash_table[i] = segment->m_fnext, segment->m_fnext = segment->m_fprev = segment; + + /* coalesce w/ adjacent free segment(s) */ + rtl_arena_segment_coalesce (arena, segment); + + /* insert onto freelist */ + rtl_arena_freelist_insert (arena, segment); + } + } + } + + /* cleanup hash table */ + if (arena->m_hash_table != arena->m_hash_table_0) + { + rtl_arena_free ( + gp_arena_arena, + arena->m_hash_table, + arena->m_hash_size * sizeof(rtl_arena_segment_type*)); + + arena->m_hash_table = arena->m_hash_table_0; + arena->m_hash_size = RTL_ARENA_HASH_SIZE; + arena->m_hash_shift = highbit(arena->m_hash_size) - 1; + } + + /* cleanup segment list */ + head = &(arena->m_segment_head); + for (segment = head->m_snext; segment != head; segment = head->m_snext) + { + if (segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE) + { + /* remove from freelist */ + rtl_arena_freelist_remove (arena, segment); + } + else + { + /* can have only free and span segments here */ + OSL_ASSERT(segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN); + } + + /* remove from segment list */ + QUEUE_REMOVE_NAMED(segment, s); + + /* release segment descriptor */ + rtl_arena_segment_put (arena, &segment); + } + + /* cleanup segment reserve list */ + head = &(arena->m_segment_reserve_head); + for (segment = head->m_snext; segment != head; segment = head->m_snext) + { + /* remove from segment list */ + QUEUE_REMOVE_NAMED(segment, s); + } + + /* cleanup segment reserve span(s) */ + head = &(arena->m_segment_reserve_span_head); + for (segment = head->m_snext; segment != head; segment = head->m_snext) + { + /* can have only span segments here */ + OSL_ASSERT(segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN); + + /* remove from segment list */ + QUEUE_REMOVE_NAMED(segment, s); + + /* return span to g_machdep_arena */ + rtl_machdep_free (gp_machdep_arena, (void*)(segment->m_addr), segment->m_size); + } +} + +/* ================================================================= * + * + * arena implementation. + * + * ================================================================= */ + +/** rtl_arena_create() + */ +rtl_arena_type * +SAL_CALL rtl_arena_create ( + const char * name, + sal_Size quantum, + sal_Size quantum_cache_max, + rtl_arena_type * source_arena, + void * (SAL_CALL * source_alloc)(rtl_arena_type *, sal_Size *), + void (SAL_CALL * source_free) (rtl_arena_type *, void *, sal_Size), + int flags +) SAL_THROW_EXTERN_C() +{ + rtl_arena_type * result = 0; + sal_Size size = sizeof(rtl_arena_type); + + (void) flags; /* unused */ + +try_alloc: + result = (rtl_arena_type*)rtl_arena_alloc (gp_arena_arena, &size); + if (result != 0) + { + rtl_arena_type * arena = result; + rtl_arena_constructor (arena); + + if (!source_arena) + { + OSL_ASSERT(gp_default_arena != 0); + source_arena = gp_default_arena; + } + + result = rtl_arena_activate ( + arena, + name, + quantum, + quantum_cache_max, + source_arena, + source_alloc, + source_free + ); + + if (result == 0) + { + rtl_arena_deactivate (arena); + rtl_arena_destructor (arena); + rtl_arena_free (gp_arena_arena, arena, size); + } + } + else if (gp_arena_arena == 0) + { + if (rtl_arena_init()) + { + /* try again */ + goto try_alloc; + } + } + return (result); +} + +/** rtl_arena_destroy() + */ +void +SAL_CALL rtl_arena_destroy ( + rtl_arena_type * arena +) +{ + if (arena != 0) + { + rtl_arena_deactivate (arena); + rtl_arena_destructor (arena); + rtl_arena_free (gp_arena_arena, arena, sizeof(rtl_arena_type)); + } +} + +/** rtl_arena_alloc() + */ +void * +SAL_CALL rtl_arena_alloc ( + rtl_arena_type * arena, + sal_Size * pSize +) SAL_THROW_EXTERN_C() +{ + void * addr = 0; + + if ((arena != 0) && (pSize != 0)) + { + sal_Size size = RTL_MEMORY_ALIGN((*pSize), arena->m_quantum); + if (size > arena->m_qcache_max) + { + /* allocate from segment list */ + rtl_arena_segment_type *segment = 0; + + RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock)); + if (rtl_arena_segment_alloc (arena, size, &segment) || + rtl_arena_segment_create(arena, size, &segment) ) + { + /* shrink to fit */ + sal_Size oversize; + + /* mark segment used */ + OSL_ASSERT(segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE); + segment->m_type = RTL_ARENA_SEGMENT_TYPE_USED; + + /* resize */ + OSL_ASSERT(segment->m_size >= size); + oversize = segment->m_size - size; + if (oversize >= SAL_MAX(arena->m_quantum, arena->m_qcache_max)) + { + rtl_arena_segment_type * remainder = 0; + rtl_arena_segment_get (arena, &remainder); + if (remainder != 0) + { + segment->m_size = size; + + remainder->m_addr = segment->m_addr + segment->m_size; + remainder->m_size = oversize; + remainder->m_type = RTL_ARENA_SEGMENT_TYPE_FREE; + QUEUE_INSERT_HEAD_NAMED(segment, remainder, s); + + rtl_arena_freelist_insert (arena, remainder); + } + } + + rtl_arena_hash_insert (arena, segment); + + (*pSize) = segment->m_size; + addr = (void*)(segment->m_addr); + } + RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); + } + else if (size > 0) + { + /* allocate from quantum cache(s) */ + int index = (size >> arena->m_quantum_shift) - 1; + OSL_ASSERT (arena->m_qcache_ptr[index] != 0); + + addr = rtl_cache_alloc (arena->m_qcache_ptr[index]); + if (addr != 0) + (*pSize) = size; + } + } + return (addr); +} + +/** rtl_arena_free() + */ +void +SAL_CALL rtl_arena_free ( + rtl_arena_type * arena, + void * addr, + sal_Size size +) SAL_THROW_EXTERN_C() +{ + if (arena != 0) + { + size = RTL_MEMORY_ALIGN(size, arena->m_quantum); + if (size > arena->m_qcache_max) + { + /* free to segment list */ + rtl_arena_segment_type * segment; + + RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock)); + + segment = rtl_arena_hash_remove (arena, (sal_uIntPtr)(addr), size); + if (segment != 0) + { + rtl_arena_segment_type *next, *prev; + + /* coalesce w/ adjacent free segment(s) */ + rtl_arena_segment_coalesce (arena, segment); + + /* determine (new) next and prev segment */ + next = segment->m_snext, prev = segment->m_sprev; + + /* entire span free when prev is a span, and next is either a span or a list head */ + if (((prev->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN)) && + ((next->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN) || + (next->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD)) ) + { + OSL_ASSERT((prev->m_addr == segment->m_addr) && + (prev->m_size == segment->m_size) ); + + if (arena->m_source_free) + { + addr = (void*)(prev->m_addr); + size = prev->m_size; + + /* remove from segment list */ + QUEUE_REMOVE_NAMED(segment, s); + + /* release segment descriptor */ + rtl_arena_segment_put (arena, &segment); + + /* remove from segment list */ + QUEUE_REMOVE_NAMED(prev, s); + + /* release (span) segment descriptor */ + rtl_arena_segment_put (arena, &prev); + + /* update stats, return span to source arena */ + arena->m_stats.m_mem_total -= size; + RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); + + (arena->m_source_free)(arena->m_source_arena, addr, size); + return; + } + } + + /* insert onto freelist */ + rtl_arena_freelist_insert (arena, segment); + } + + RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock)); + } + else if (size > 0) + { + /* free to quantum cache(s) */ + int index = (size >> arena->m_quantum_shift) - 1; + OSL_ASSERT (arena->m_qcache_ptr[index] != 0); + + rtl_cache_free (arena->m_qcache_ptr[index], addr); + } + } +} + +/* ================================================================= * + * + * machdep internals. + * + * ================================================================= */ + +#if defined(SAL_UNX) +#include <sys/mman.h> +#elif defined(SAL_W32) || defined(SAL_OS2) +#define MAP_FAILED 0 +#endif /* SAL_UNX || SAL_W32 */ + +/** rtl_machdep_alloc() + */ +static void * +SAL_CALL rtl_machdep_alloc ( + rtl_arena_type * pArena, + sal_Size * pSize +) +{ + void * addr; + sal_Size size = (*pSize); + + OSL_PRECOND(pArena == gp_machdep_arena, "rtl_machdep_alloc(): invalid argument"); + +#if defined(SOLARIS) && defined(SPARC) + /* see @ mmap(2) man pages */ + size += (pArena->m_quantum + pArena->m_quantum); /* "red-zone" pages */ + if (size > (4 << 20)) + size = RTL_MEMORY_P2ROUNDUP(size, (4 << 20)); + else if (size > (512 << 10)) + size = RTL_MEMORY_P2ROUNDUP(size, (512 << 10)); + else + size = RTL_MEMORY_P2ROUNDUP(size, (64 << 10)); + size -= (pArena->m_quantum + pArena->m_quantum); /* "red-zone" pages */ +#else + /* default allocation granularity */ + size = RTL_MEMORY_P2ROUNDUP(size, SAL_MAX(pArena->m_quantum, 64 << 10)); +#endif + +#if defined(SAL_UNX) + addr = mmap (NULL, (size_t)(size), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +#elif defined(SAL_W32) + addr = VirtualAlloc (NULL, (SIZE_T)(size), MEM_COMMIT, PAGE_READWRITE); +#elif defined(SAL_OS2) + { + APIRET rc; + addr = 0; + // Use DosAlloc* to get a 4KB page aligned address. + rc = DosAllocMem( &addr, size, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY); + if (rc) { + fprintf( stderr, "sal3::DosAllocMem failed rc=%d\n", rc); + addr = 0; + } + } +#endif /* (SAL_UNX || SAL_W32 || SAL_OS2) */ + + if (addr != MAP_FAILED) + { + pArena->m_stats.m_alloc += 1; + pArena->m_stats.m_mem_total += size; + pArena->m_stats.m_mem_alloc += size; + + (*pSize) = size; + return (addr); + } + return (NULL); +} + +/** rtl_machdep_free() + */ +static void +SAL_CALL rtl_machdep_free ( + rtl_arena_type * pArena, + void * pAddr, + sal_Size nSize +) +{ + OSL_PRECOND(pArena == gp_machdep_arena, "rtl_machdep_free(): invalid argument"); + + pArena->m_stats.m_free += 1; + pArena->m_stats.m_mem_total -= nSize; + pArena->m_stats.m_mem_alloc -= nSize; + +#if defined(SAL_UNX) + (void) munmap(pAddr, nSize); +#elif defined(SAL_W32) + (void) VirtualFree ((LPVOID)(pAddr), (SIZE_T)(0), MEM_RELEASE); +#elif defined(SAL_OS2) + (void) DosFreeMem( pAddr); +#endif /* (SAL_UNX || SAL_W32) */ +} + +/** rtl_machdep_pagesize() + */ +static sal_Size +rtl_machdep_pagesize (void) +{ +#if defined(SAL_UNX) +#if defined(FREEBSD) || defined(NETBSD) + return ((sal_Size)getpagesize()); +#else /* POSIX */ + return ((sal_Size)sysconf(_SC_PAGESIZE)); +#endif /* xBSD || POSIX */ +#elif defined(SAL_W32) + SYSTEM_INFO info; + GetSystemInfo (&info); + return ((sal_Size)(info.dwPageSize)); +#elif defined(SAL_OS2) + ULONG ulPageSize; + DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE, &ulPageSize, sizeof(ULONG)); + return ((sal_Size)ulPageSize); +#endif /* (SAL_UNX || SAL_W32) */ +} + +/* ================================================================= * + * + * arena initialization. + * + * ================================================================= */ + +static void +rtl_arena_once_init (void) +{ + { + /* list of arenas */ + RTL_MEMORY_LOCK_INIT(&(g_arena_list.m_lock)); + rtl_arena_constructor (&(g_arena_list.m_arena_head)); + } + { + /* machdep (pseudo) arena */ + static rtl_arena_type g_machdep_arena; + + OSL_ASSERT(gp_machdep_arena == 0); + rtl_arena_constructor (&g_machdep_arena); + + gp_machdep_arena = rtl_arena_activate ( + &g_machdep_arena, + "rtl_machdep_arena", + rtl_machdep_pagesize(), + 0, /* no quantum caching */ + 0, 0, 0 /* no source */ + ); + OSL_ASSERT(gp_machdep_arena != 0); + } + { + /* default arena */ + static rtl_arena_type g_default_arena; + + OSL_ASSERT(gp_default_arena == 0); + rtl_arena_constructor (&g_default_arena); + + gp_default_arena = rtl_arena_activate ( + &g_default_arena, + "rtl_default_arena", + rtl_machdep_pagesize(), + 0, /* no quantum caching */ + gp_machdep_arena, /* source */ + rtl_machdep_alloc, + rtl_machdep_free + ); + OSL_ASSERT(gp_default_arena != 0); + } + { + /* arena internal arena */ + static rtl_arena_type g_arena_arena; + + OSL_ASSERT(gp_arena_arena == 0); + rtl_arena_constructor (&g_arena_arena); + + gp_arena_arena = rtl_arena_activate ( + &g_arena_arena, + "rtl_arena_internal_arena", + 64, /* quantum */ + 0, /* no quantum caching */ + gp_default_arena, /* source */ + rtl_arena_alloc, + rtl_arena_free + ); + OSL_ASSERT(gp_arena_arena != 0); + } +} + +static int +rtl_arena_init (void) +{ + static sal_once_type g_once = SAL_ONCE_INIT; + SAL_ONCE(&g_once, rtl_arena_once_init); + return (gp_arena_arena != 0); +} + +/* ================================================================= */ + +#if defined(__GNUC__) +static void rtl_arena_fini (void) __attribute__((destructor)); +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma fini(rtl_arena_fini) +static void rtl_arena_fini (void); +#endif /* __GNUC__ || __SUNPRO_C */ + +void +rtl_arena_fini (void) +{ + if (gp_arena_arena != 0) + { + rtl_arena_type * arena, * head; + + RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock)); + head = &(g_arena_list.m_arena_head); + + for (arena = head->m_arena_next; arena != head; arena = arena->m_arena_next) + { + OSL_TRACE( + "rtl_arena_fini(\"%s\"): " + "allocs: %"PRIu64", frees: %"PRIu64"; total: %lu, used: %lu", + arena->m_name, + arena->m_stats.m_alloc, arena->m_stats.m_free, + arena->m_stats.m_mem_total, arena->m_stats.m_mem_alloc + ); + } + RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock)); + } +} + +/* ================================================================= */ diff --git a/sal/rtl/source/alloc_arena.h b/sal/rtl/source/alloc_arena.h new file mode 100644 index 000000000000..45907802dba9 --- /dev/null +++ b/sal/rtl/source/alloc_arena.h @@ -0,0 +1,137 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_RTL_ALLOC_ARENA_H +#define INCLUDED_RTL_ALLOC_ARENA_H + +#include "sal/types.h" +#include "rtl/alloc.h" +#include "alloc_impl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** rtl_arena_stat_type + * @internal + */ +typedef struct rtl_arena_stat_st rtl_arena_stat_type; +struct rtl_arena_stat_st +{ + sal_uInt64 m_alloc; + sal_uInt64 m_free; + + sal_Size m_mem_total; + sal_Size m_mem_alloc; +}; + + +/** rtl_arena_segment_type + * @internal + */ +#define RTL_ARENA_SEGMENT_TYPE_HEAD ((sal_Size)(0x01)) +#define RTL_ARENA_SEGMENT_TYPE_SPAN ((sal_Size)(0x02)) +#define RTL_ARENA_SEGMENT_TYPE_FREE ((sal_Size)(0x04)) +#define RTL_ARENA_SEGMENT_TYPE_USED ((sal_Size)(0x08)) + +typedef struct rtl_arena_segment_st rtl_arena_segment_type; +struct rtl_arena_segment_st +{ + /* segment list linkage */ + rtl_arena_segment_type * m_snext; + rtl_arena_segment_type * m_sprev; + + /* free/used list linkage */ + rtl_arena_segment_type * m_fnext; + rtl_arena_segment_type * m_fprev; + + /* segment description */ + sal_uIntPtr m_addr; + sal_Size m_size; + sal_Size m_type; +}; + + +/** rtl_arena_type + * @internal + */ +#define RTL_ARENA_FREELIST_SIZE (sizeof(void*) * 8) +#define RTL_ARENA_HASH_SIZE 64 + +#define RTL_ARENA_FLAG_RESCALE 1 /* within hash rescale operation */ + +struct rtl_arena_st +{ + /* linkage */ + rtl_arena_type * m_arena_next; + rtl_arena_type * m_arena_prev; + + /* properties */ + char m_name[RTL_ARENA_NAME_LENGTH + 1]; + long m_flags; + + rtl_memory_lock_type m_lock; + rtl_arena_stat_type m_stats; + + rtl_arena_type * m_source_arena; + void * (SAL_CALL * m_source_alloc)(rtl_arena_type *, sal_Size *); + void (SAL_CALL * m_source_free) (rtl_arena_type *, void *, sal_Size); + + sal_Size m_quantum; + sal_Size m_quantum_shift; /* log2(m_quantum) */ + + rtl_arena_segment_type m_segment_reserve_span_head; + rtl_arena_segment_type m_segment_reserve_head; + + rtl_arena_segment_type m_segment_head; + + rtl_arena_segment_type m_freelist_head[RTL_ARENA_FREELIST_SIZE]; + sal_Size m_freelist_bitmap; + + rtl_arena_segment_type ** m_hash_table; + rtl_arena_segment_type * m_hash_table_0[RTL_ARENA_HASH_SIZE]; + sal_Size m_hash_size; /* m_hash_mask + 1 */ + sal_Size m_hash_shift; /* log2(m_hash_size) */ + + sal_Size m_qcache_max; + rtl_cache_type ** m_qcache_ptr; +}; + + +/** gp_default_arena + * default arena with pagesize quantum + * + * @internal + */ +extern rtl_arena_type * gp_default_arena; + + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_RTL_ALLOC_ARENA_H */ diff --git a/sal/rtl/source/alloc_cache.c b/sal/rtl/source/alloc_cache.c new file mode 100644 index 000000000000..4e2c030fb3a6 --- /dev/null +++ b/sal/rtl/source/alloc_cache.c @@ -0,0 +1,1721 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "alloc_cache.h" +#include "alloc_impl.h" +#include "alloc_arena.h" +#include "internal/once.h" +#include "sal/macros.h" +#include "osl/diagnose.h" + +#ifndef INCLUDED_STRING_H +#include <string.h> +#endif + +#ifndef INCLUDED_STDIO_H +#include <stdio.h> +#endif + +#ifdef OS2 +#undef OSL_TRACE +#define OSL_TRACE 1 ? ((void)0) : _OSL_GLOBAL osl_trace +#endif + +/* ================================================================= * + * + * cache internals. + * + * ================================================================= */ + +/** g_cache_list + * @internal + */ +struct rtl_cache_list_st +{ + rtl_memory_lock_type m_lock; + rtl_cache_type m_cache_head; + +#if defined(SAL_UNX) || defined(SAL_OS2) + pthread_t m_update_thread; + pthread_cond_t m_update_cond; +#elif defined(SAL_W32) + HANDLE m_update_thread; + HANDLE m_update_cond; +#endif /* SAL_UNX || SAL_W32 */ + int m_update_done; +}; + +static struct rtl_cache_list_st g_cache_list; + + +/** gp_cache_arena + * provided for cache_type allocations, and hash_table resizing. + * + * @internal + */ +static rtl_arena_type * gp_cache_arena = 0; + + +/** gp_cache_magazine_cache + * @internal + */ +static rtl_cache_type * gp_cache_magazine_cache = 0; + + +/** gp_cache_slab_cache + * @internal + */ +static rtl_cache_type * gp_cache_slab_cache = 0; + + +/** gp_cache_bufctl_cache + * @internal + */ +static rtl_cache_type * gp_cache_bufctl_cache = 0; + + +/** rtl_cache_init() + * @internal + */ +static int +rtl_cache_init (void); + + +/* ================================================================= */ + +/** RTL_CACHE_HASH_INDEX() + */ +#define RTL_CACHE_HASH_INDEX_IMPL(a, s, q, m) \ + ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m)) + +#define RTL_CACHE_HASH_INDEX(cache, addr) \ + RTL_CACHE_HASH_INDEX_IMPL((addr), (cache)->m_hash_shift, (cache)->m_type_shift, ((cache)->m_hash_size - 1)) + + +/** rtl_cache_hash_rescale() + */ +static void +rtl_cache_hash_rescale ( + rtl_cache_type * cache, + sal_Size new_size +) +{ + rtl_cache_bufctl_type ** new_table; + sal_Size new_bytes; + + new_bytes = new_size * sizeof(rtl_cache_bufctl_type*); + new_table = (rtl_cache_bufctl_type**)rtl_arena_alloc(gp_cache_arena, &new_bytes); + + if (new_table != 0) + { + rtl_cache_bufctl_type ** old_table; + sal_Size old_size, i; + + memset (new_table, 0, new_bytes); + + RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock)); + + old_table = cache->m_hash_table; + old_size = cache->m_hash_size; + + OSL_TRACE( + "rtl_cache_hash_rescale(\"%s\"): " + "nbuf: % " PRIu64 " (ave: %" PRIu64 "), frees: %" PRIu64 " " + "[old_size: %lu, new_size: %lu]", + cache->m_name, + cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free, + (cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free) >> cache->m_hash_shift, + cache->m_slab_stats.m_free, + old_size, new_size); + + cache->m_hash_table = new_table; + cache->m_hash_size = new_size; + cache->m_hash_shift = highbit(cache->m_hash_size) - 1; + + for (i = 0; i < old_size; i++) + { + rtl_cache_bufctl_type * curr = old_table[i]; + while (curr != 0) + { + rtl_cache_bufctl_type * next = curr->m_next; + rtl_cache_bufctl_type ** head; + + head = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, curr->m_addr)]); + curr->m_next = (*head); + (*head) = curr; + + curr = next; + } + old_table[i] = 0; + } + + RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); + + if (old_table != cache->m_hash_table_0) + { + sal_Size old_bytes = old_size * sizeof(rtl_cache_bufctl_type*); + rtl_arena_free (gp_cache_arena, old_table, old_bytes); + } + } +} + +/** rtl_cache_hash_insert() + */ +static RTL_MEMORY_INLINE sal_uIntPtr +rtl_cache_hash_insert ( + rtl_cache_type * cache, + rtl_cache_bufctl_type * bufctl +) +{ + rtl_cache_bufctl_type ** ppHead; + + ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, bufctl->m_addr)]); + + bufctl->m_next = (*ppHead); + (*ppHead) = bufctl; + + return (bufctl->m_addr); +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(rtl_cache_hash_insert) +#endif /* __SUNPRO_C */ + + +/** rtl_cache_hash_remove() + */ +static rtl_cache_bufctl_type * +rtl_cache_hash_remove ( + rtl_cache_type * cache, + sal_uIntPtr addr +) +{ + rtl_cache_bufctl_type ** ppHead; + rtl_cache_bufctl_type * bufctl; + sal_Size lookups = 0; + + ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, addr)]); + while ((bufctl = *ppHead) != 0) + { + if (bufctl->m_addr == addr) + { + *ppHead = bufctl->m_next, bufctl->m_next = 0; + break; + } + + lookups += 1; + ppHead = &(bufctl->m_next); + } + + OSL_ASSERT (bufctl != 0); /* bad free */ + + if (lookups > 1) + { + sal_Size nbuf = (sal_Size)(cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free); + if (nbuf > 4 * cache->m_hash_size) + { + if (!(cache->m_features & RTL_CACHE_FEATURE_RESCALE)) + { + sal_Size ave = nbuf >> cache->m_hash_shift; + sal_Size new_size = cache->m_hash_size << (highbit(ave) - 1); + + cache->m_features |= RTL_CACHE_FEATURE_RESCALE; + RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); + rtl_cache_hash_rescale (cache, new_size); + RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock)); + cache->m_features &= ~RTL_CACHE_FEATURE_RESCALE; + } + } + } + + return (bufctl); +} + +/* ================================================================= */ + +/** RTL_CACHE_SLAB() + */ +#define RTL_CACHE_SLAB(addr, size) \ + (((rtl_cache_slab_type*)(RTL_MEMORY_P2END((sal_uIntPtr)(addr), (size)))) - 1) + + +/** rtl_cache_slab_constructor() + */ +static int +rtl_cache_slab_constructor (void * obj, void * arg) +{ + rtl_cache_slab_type * slab = (rtl_cache_slab_type*)(obj); + + (void) arg; /* unused */ + + QUEUE_START_NAMED(slab, slab_); + slab->m_ntypes = 0; + + return (1); +} + + +/** rtl_cache_slab_destructor() + */ +static void +rtl_cache_slab_destructor (void * obj, void * arg) +{ +#if OSL_DEBUG_LEVEL == 0 + (void) obj; /* unused */ +#else /* OSL_DEBUG_LEVEL */ + rtl_cache_slab_type * slab = (rtl_cache_slab_type*)(obj); + + /* assure removed from queue(s) */ + OSL_ASSERT(QUEUE_STARTED_NAMED(slab, slab_)); + + /* assure no longer referenced */ + OSL_ASSERT(slab->m_ntypes == 0); +#endif /* OSL_DEBUG_LEVEL */ + + (void) arg; /* unused */ +} + + +/** rtl_cache_slab_create() + * + * @precond cache->m_slab_lock released. + */ +static rtl_cache_slab_type * +rtl_cache_slab_create ( + rtl_cache_type * cache +) +{ + rtl_cache_slab_type * slab = 0; + void * addr; + sal_Size size; + + size = cache->m_slab_size; + addr = rtl_arena_alloc (cache->m_source, &size); + if (addr != 0) + { + OSL_ASSERT(size >= cache->m_slab_size); + + if (cache->m_features & RTL_CACHE_FEATURE_HASH) + { + /* allocate slab struct from slab cache */ + OSL_ASSERT (cache != gp_cache_slab_cache); + slab = (rtl_cache_slab_type*)rtl_cache_alloc (gp_cache_slab_cache); + } + else + { + /* construct embedded slab struct */ + slab = RTL_CACHE_SLAB(addr, cache->m_slab_size); + (void) rtl_cache_slab_constructor (slab, 0); + } + if (slab != 0) + { + slab->m_data = (sal_uIntPtr)(addr); + + /* dynamic freelist initialization */ + slab->m_bp = slab->m_data; + slab->m_sp = 0; + } + else + { + rtl_arena_free (cache->m_source, addr, size); + } + } + return (slab); +} + + +/** rtl_cache_slab_destroy() + * + * @precond cache->m_slab_lock released. + */ +static void +rtl_cache_slab_destroy ( + rtl_cache_type * cache, + rtl_cache_slab_type * slab +) +{ + void * addr = (void*)(slab->m_data); + sal_Size refcnt = slab->m_ntypes; slab->m_ntypes = 0; + + if (cache->m_features & RTL_CACHE_FEATURE_HASH) + { + /* cleanup bufctl(s) for free buffer(s) */ + sal_Size ntypes = (slab->m_bp - slab->m_data) / cache->m_type_size; + for (ntypes -= refcnt; slab->m_sp != 0; ntypes--) + { + rtl_cache_bufctl_type * bufctl = slab->m_sp; + + /* pop from freelist */ + slab->m_sp = bufctl->m_next, bufctl->m_next = 0; + + /* return bufctl struct to bufctl cache */ + rtl_cache_free (gp_cache_bufctl_cache, bufctl); + } + OSL_ASSERT(ntypes == 0); + + /* return slab struct to slab cache */ + rtl_cache_free (gp_cache_slab_cache, slab); + } + else + { + /* destruct embedded slab struct */ + rtl_cache_slab_destructor (slab, 0); + } + + if ((refcnt == 0) || (cache->m_features & RTL_CACHE_FEATURE_BULKDESTROY)) + { + /* free memory */ + rtl_arena_free (cache->m_source, addr, cache->m_slab_size); + } +} + + +/** rtl_cache_slab_populate() + * + * @precond cache->m_slab_lock acquired. + */ +static int +rtl_cache_slab_populate ( + rtl_cache_type * cache +) +{ + rtl_cache_slab_type * slab; + + RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); + slab = rtl_cache_slab_create (cache); + RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock)); + if (slab != 0) + { + /* update buffer start addr w/ current color */ + slab->m_bp += cache->m_ncolor; + + /* update color for next slab */ + cache->m_ncolor += cache->m_type_align; + if (cache->m_ncolor > cache->m_ncolor_max) + cache->m_ncolor = 0; + + /* update stats */ + cache->m_slab_stats.m_mem_total += cache->m_slab_size; + + /* insert onto 'free' queue */ + QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_); + } + return (slab != 0); +} + +/* ================================================================= */ + +/** rtl_cache_slab_alloc() + * + * Allocate a buffer from slab layer; used by magazine layer. + */ +static void * +rtl_cache_slab_alloc ( + rtl_cache_type * cache +) +{ + void * addr = 0; + rtl_cache_slab_type * head; + + RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock)); + + head = &(cache->m_free_head); + if ((head->m_slab_next != head) || rtl_cache_slab_populate (cache)) + { + rtl_cache_slab_type * slab; + rtl_cache_bufctl_type * bufctl; + + slab = head->m_slab_next; + OSL_ASSERT(slab->m_ntypes < cache->m_ntypes); + + if (slab->m_sp == 0) + { + /* initialize bufctl w/ current 'slab->m_bp' */ + OSL_ASSERT (slab->m_bp < slab->m_data + cache->m_ntypes * cache->m_type_size + cache->m_ncolor_max); + if (cache->m_features & RTL_CACHE_FEATURE_HASH) + { + /* allocate bufctl */ + OSL_ASSERT (cache != gp_cache_bufctl_cache); + bufctl = (rtl_cache_bufctl_type*)rtl_cache_alloc (gp_cache_bufctl_cache); + if (bufctl == 0) + { + /* out of memory */ + RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); + return (0); + } + + bufctl->m_addr = slab->m_bp; + bufctl->m_slab = (sal_uIntPtr)(slab); + } + else + { + /* embedded bufctl */ + bufctl = (rtl_cache_bufctl_type*)(slab->m_bp); + } + bufctl->m_next = 0; + + /* update 'slab->m_bp' to next free buffer */ + slab->m_bp += cache->m_type_size; + + /* assign bufctl to freelist */ + slab->m_sp = bufctl; + } + + /* pop front */ + bufctl = slab->m_sp; + slab->m_sp = bufctl->m_next; + + /* increment usage, check for full slab */ + if ((slab->m_ntypes += 1) == cache->m_ntypes) + { + /* remove from 'free' queue */ + QUEUE_REMOVE_NAMED(slab, slab_); + + /* insert onto 'used' queue (tail) */ + QUEUE_INSERT_TAIL_NAMED(&(cache->m_used_head), slab, slab_); + } + + /* update stats */ + cache->m_slab_stats.m_alloc += 1; + cache->m_slab_stats.m_mem_alloc += cache->m_type_size; + + if (cache->m_features & RTL_CACHE_FEATURE_HASH) + addr = (void*)rtl_cache_hash_insert (cache, bufctl); + else + addr = bufctl; + } + + RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); + return (addr); +} + + +/** rtl_cache_slab_free() + * + * Return a buffer to slab layer; used by magazine layer. + */ +static void +rtl_cache_slab_free ( + rtl_cache_type * cache, + void * addr +) +{ + rtl_cache_bufctl_type * bufctl; + rtl_cache_slab_type * slab; + + RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock)); + + /* determine slab from addr */ + if (cache->m_features & RTL_CACHE_FEATURE_HASH) + { + bufctl = rtl_cache_hash_remove (cache, (sal_uIntPtr)(addr)); + slab = (bufctl != 0) ? (rtl_cache_slab_type*)(bufctl->m_slab) : 0; + } + else + { + /* embedded slab struct */ + bufctl = (rtl_cache_bufctl_type*)(addr); + slab = RTL_CACHE_SLAB(addr, cache->m_slab_size); + } + + if (slab != 0) + { + /* check for full slab */ + if (slab->m_ntypes == cache->m_ntypes) + { + /* remove from 'used' queue */ + QUEUE_REMOVE_NAMED(slab, slab_); + + /* insert onto 'free' queue (head) */ + QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_); + } + + /* push front */ + bufctl->m_next = slab->m_sp; + slab->m_sp = bufctl; + + /* update stats */ + cache->m_slab_stats.m_free += 1; + cache->m_slab_stats.m_mem_alloc -= cache->m_type_size; + + /* decrement usage, check for empty slab */ + if ((slab->m_ntypes -= 1) == 0) + { + /* remove from 'free' queue */ + QUEUE_REMOVE_NAMED(slab, slab_); + + /* update stats */ + cache->m_slab_stats.m_mem_total -= cache->m_slab_size; + + /* free 'empty' slab */ + RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); + rtl_cache_slab_destroy (cache, slab); + return; + } + } + + RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock)); +} + +/* ================================================================= */ + +/** rtl_cache_magazine_constructor() + */ +static int +rtl_cache_magazine_constructor (void * obj, void * arg) +{ + rtl_cache_magazine_type * mag = (rtl_cache_magazine_type*)(obj); + /* @@@ sal_Size size = (sal_Size)(arg); @@@ */ + + (void) arg; /* unused */ + + mag->m_mag_next = 0; + mag->m_mag_size = RTL_CACHE_MAGAZINE_SIZE; + mag->m_mag_used = 0; + + return (1); +} + + +/** rtl_cache_magazine_destructor() + */ +static void +rtl_cache_magazine_destructor (void * obj, void * arg) +{ +#if OSL_DEBUG_LEVEL == 0 + (void) obj; /* unused */ +#else /* OSL_DEBUG_LEVEL */ + rtl_cache_magazine_type * mag = (rtl_cache_magazine_type*)(obj); + + /* assure removed from queue(s) */ + OSL_ASSERT(mag->m_mag_next == 0); + + /* assure no longer referenced */ + OSL_ASSERT(mag->m_mag_used == 0); +#endif /* OSL_DEBUG_LEVEL */ + + (void) arg; /* unused */ +} + + +/** rtl_cache_magazine_clear() + */ +static void +rtl_cache_magazine_clear ( + rtl_cache_type * cache, + rtl_cache_magazine_type * mag +) +{ + for (; mag->m_mag_used > 0; --mag->m_mag_used) + { + void * obj = mag->m_objects[mag->m_mag_used - 1]; + mag->m_objects[mag->m_mag_used - 1] = 0; + + if (cache->m_destructor != 0) + { + /* destruct object */ + (cache->m_destructor)(obj, cache->m_userarg); + } + + /* return buffer to slab layer */ + rtl_cache_slab_free (cache, obj); + } +} + +/* ================================================================= */ + +/** rtl_cache_depot_enqueue() + * + * @precond cache->m_depot_lock acquired. + */ +static RTL_MEMORY_INLINE void +rtl_cache_depot_enqueue ( + rtl_cache_depot_type * depot, + rtl_cache_magazine_type * mag +) +{ + /* enqueue empty magazine */ + mag->m_mag_next = depot->m_mag_next; + depot->m_mag_next = mag; + + /* update depot stats */ + depot->m_mag_count++; +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(rtl_cache_depot_enqueue) +#endif /* __SUNPRO_C */ + + +/** rtl_cache_depot_dequeue() + * + * @precond cache->m_depot_lock acquired. + */ +static RTL_MEMORY_INLINE rtl_cache_magazine_type * +rtl_cache_depot_dequeue ( + rtl_cache_depot_type * depot +) +{ + rtl_cache_magazine_type * mag = 0; + if (depot->m_mag_count > 0) + { + /* dequeue magazine */ + OSL_ASSERT(depot->m_mag_next != 0); + + mag = depot->m_mag_next; + depot->m_mag_next = mag->m_mag_next; + mag->m_mag_next = 0; + + /* update depot stats */ + depot->m_mag_count--; + depot->m_curr_min = SAL_MIN(depot->m_curr_min, depot->m_mag_count); + } + return (mag); +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(rtl_cache_depot_dequeue) +#endif /* __SUNPRO_C */ + + +/** rtl_cache_depot_exchange_alloc() + * + * @precond cache->m_depot_lock acquired. + */ +static RTL_MEMORY_INLINE rtl_cache_magazine_type * +rtl_cache_depot_exchange_alloc ( + rtl_cache_type * cache, + rtl_cache_magazine_type * empty +) +{ + rtl_cache_magazine_type * full; + + OSL_ASSERT((empty == 0) || (empty->m_mag_used == 0)); + + /* dequeue full magazine */ + full = rtl_cache_depot_dequeue (&(cache->m_depot_full)); + if ((full != 0) && (empty != 0)) + { + /* enqueue empty magazine */ + rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty); + } + + OSL_ASSERT((full == 0) || (full->m_mag_used > 0)); + + return (full); +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(rtl_cache_depot_exchange_alloc) +#endif /* __SUNPRO_C */ + + +/** rtl_cache_depot_exchange_free() + * + * @precond cache->m_depot_lock acquired. + */ +static RTL_MEMORY_INLINE rtl_cache_magazine_type * +rtl_cache_depot_exchange_free ( + rtl_cache_type * cache, + rtl_cache_magazine_type * full +) +{ + rtl_cache_magazine_type * empty; + + OSL_ASSERT((full == 0) || (full->m_mag_used > 0)); + + /* dequeue empty magazine */ + empty = rtl_cache_depot_dequeue (&(cache->m_depot_empty)); + if ((empty != 0) && (full != 0)) + { + /* enqueue full magazine */ + rtl_cache_depot_enqueue (&(cache->m_depot_full), full); + } + + OSL_ASSERT((empty == 0) || (empty->m_mag_used == 0)); + + return (empty); +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(rtl_cache_depot_exchange_free) +#endif /* __SUNPRO_C */ + + +/** rtl_cache_depot_populate() + * + * @precond cache->m_depot_lock acquired. + */ +static int +rtl_cache_depot_populate ( + rtl_cache_type * cache +) +{ + rtl_cache_magazine_type * empty = 0; + + if (cache->m_magazine_cache != 0) + { + /* allocate new empty magazine */ + RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); + empty = (rtl_cache_magazine_type*)rtl_cache_alloc (cache->m_magazine_cache); + RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock)); + if (empty != 0) + { + /* enqueue (new) empty magazine */ + rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty); + } + } + return (empty != 0); +} + +/* ================================================================= */ + +/** rtl_cache_constructor() + */ +static int +rtl_cache_constructor (void * obj) +{ + rtl_cache_type * cache = (rtl_cache_type*)(obj); + + memset (cache, 0, sizeof(rtl_cache_type)); + + /* linkage */ + QUEUE_START_NAMED(cache, cache_); + + /* slab layer */ + (void)RTL_MEMORY_LOCK_INIT(&(cache->m_slab_lock)); + + QUEUE_START_NAMED(&(cache->m_free_head), slab_); + QUEUE_START_NAMED(&(cache->m_used_head), slab_); + + cache->m_hash_table = cache->m_hash_table_0; + cache->m_hash_size = RTL_CACHE_HASH_SIZE; + cache->m_hash_shift = highbit(cache->m_hash_size) - 1; + + /* depot layer */ + (void)RTL_MEMORY_LOCK_INIT(&(cache->m_depot_lock)); + + return (1); +} + +/** rtl_cache_destructor() + */ +static void +rtl_cache_destructor (void * obj) +{ + rtl_cache_type * cache = (rtl_cache_type*)(obj); + + /* linkage */ + OSL_ASSERT(QUEUE_STARTED_NAMED(cache, cache_)); + + /* slab layer */ + (void)RTL_MEMORY_LOCK_DESTROY(&(cache->m_slab_lock)); + + OSL_ASSERT(QUEUE_STARTED_NAMED(&(cache->m_free_head), slab_)); + OSL_ASSERT(QUEUE_STARTED_NAMED(&(cache->m_used_head), slab_)); + + OSL_ASSERT(cache->m_hash_table == cache->m_hash_table_0); + OSL_ASSERT(cache->m_hash_size == RTL_CACHE_HASH_SIZE); + OSL_ASSERT(cache->m_hash_shift == (sal_Size)(highbit(cache->m_hash_size) - 1)); + + /* depot layer */ + (void)RTL_MEMORY_LOCK_DESTROY(&(cache->m_depot_lock)); +} + +/* ================================================================= */ + +/** rtl_cache_activate() + */ +static rtl_cache_type * +rtl_cache_activate ( + rtl_cache_type * cache, + const char * name, + size_t objsize, + size_t objalign, + int (SAL_CALL * constructor)(void * obj, void * userarg), + void (SAL_CALL * destructor) (void * obj, void * userarg), + void (SAL_CALL * reclaim) (void * userarg), + void * userarg, + rtl_arena_type * source, + int flags +) +{ + OSL_ASSERT(cache != 0); + if (cache != 0) + { + sal_Size slabsize; + + snprintf (cache->m_name, sizeof(cache->m_name), "%s", name); + + /* ensure minimum size (embedded bufctl linkage) */ + objsize = SAL_MAX(objsize, sizeof(rtl_cache_bufctl_type*)); + + if (objalign == 0) + { + /* determine default alignment */ + if (objsize >= RTL_MEMORY_ALIGNMENT_8) + objalign = RTL_MEMORY_ALIGNMENT_8; + else + objalign = RTL_MEMORY_ALIGNMENT_4; + } + else + { + /* ensure minimum alignment */ + objalign = SAL_MAX(objalign, RTL_MEMORY_ALIGNMENT_4); + } + OSL_ASSERT(RTL_MEMORY_ISP2(objalign)); + + cache->m_type_size = objsize = RTL_MEMORY_P2ROUNDUP(objsize, objalign); + cache->m_type_align = objalign; + cache->m_type_shift = highbit(cache->m_type_size) - 1; + + cache->m_constructor = constructor; + cache->m_destructor = destructor; + cache->m_reclaim = reclaim; + cache->m_userarg = userarg; + + /* slab layer */ + cache->m_source = source; + + slabsize = source->m_quantum; /* minimum slab size */ + if (flags & RTL_CACHE_FLAG_QUANTUMCACHE) + { + /* next power of 2 above 3 * qcache_max */ + slabsize = SAL_MAX(slabsize, (1UL << highbit(3 * source->m_qcache_max))); + } + else + { + /* waste at most 1/8 of slab */ + slabsize = SAL_MAX(slabsize, cache->m_type_size * 8); + } + + slabsize = RTL_MEMORY_P2ROUNDUP(slabsize, source->m_quantum); + if (!RTL_MEMORY_ISP2(slabsize)) + slabsize = 1UL << highbit(slabsize); + cache->m_slab_size = slabsize; + + if (cache->m_slab_size > source->m_quantum) + { + OSL_ASSERT(gp_cache_slab_cache != 0); + OSL_ASSERT(gp_cache_bufctl_cache != 0); + + cache->m_features |= RTL_CACHE_FEATURE_HASH; + cache->m_ntypes = cache->m_slab_size / cache->m_type_size; + cache->m_ncolor_max = cache->m_slab_size % cache->m_type_size; + } + else + { + /* embedded slab struct */ + cache->m_ntypes = (cache->m_slab_size - sizeof(rtl_cache_slab_type)) / cache->m_type_size; + cache->m_ncolor_max = (cache->m_slab_size - sizeof(rtl_cache_slab_type)) % cache->m_type_size; + } + + OSL_ASSERT(cache->m_ntypes > 0); + cache->m_ncolor = 0; + + if (flags & RTL_CACHE_FLAG_BULKDESTROY) + { + /* allow bulk slab delete upon cache deactivation */ + cache->m_features |= RTL_CACHE_FEATURE_BULKDESTROY; + } + + /* magazine layer */ + if (!(flags & RTL_CACHE_FLAG_NOMAGAZINE)) + { + OSL_ASSERT(gp_cache_magazine_cache != 0); + cache->m_magazine_cache = gp_cache_magazine_cache; + } + + /* insert into cache list */ + RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); + QUEUE_INSERT_TAIL_NAMED(&(g_cache_list.m_cache_head), cache, cache_); + RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); + } + return (cache); +} + +/** rtl_cache_deactivate() + */ +static void +rtl_cache_deactivate ( + rtl_cache_type * cache +) +{ + /* remove from cache list */ + RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); + QUEUE_REMOVE_NAMED(cache, cache_); + RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); + + /* cleanup magazine layer */ + if (cache->m_magazine_cache != 0) + { + rtl_cache_type * mag_cache; + rtl_cache_magazine_type * mag; + + /* prevent recursion */ + mag_cache = cache->m_magazine_cache, cache->m_magazine_cache = 0; + + /* cleanup cpu layer */ + if ((mag = cache->m_cpu_curr) != 0) + { + cache->m_cpu_curr = 0; + rtl_cache_magazine_clear (cache, mag); + rtl_cache_free (mag_cache, mag); + } + if ((mag = cache->m_cpu_prev) != 0) + { + cache->m_cpu_prev = 0; + rtl_cache_magazine_clear (cache, mag); + rtl_cache_free (mag_cache, mag); + } + + /* cleanup depot layer */ + while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_full))) != 0) + { + rtl_cache_magazine_clear (cache, mag); + rtl_cache_free (mag_cache, mag); + } + while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_empty))) != 0) + { + rtl_cache_magazine_clear (cache, mag); + rtl_cache_free (mag_cache, mag); + } + } + + OSL_TRACE( + "rtl_cache_deactivate(\"%s\"): " + "[slab]: allocs: %"PRIu64", frees: %"PRIu64"; total: %lu, used: %lu; " + "[cpu]: allocs: %"PRIu64", frees: %"PRIu64"; " + "[total]: allocs: %"PRIu64", frees: %"PRIu64"", + cache->m_name, + cache->m_slab_stats.m_alloc, cache->m_slab_stats.m_free, + cache->m_slab_stats.m_mem_total, cache->m_slab_stats.m_mem_alloc, + cache->m_cpu_stats.m_alloc, cache->m_cpu_stats.m_free, + cache->m_slab_stats.m_alloc + cache->m_cpu_stats.m_alloc, + cache->m_slab_stats.m_free + cache->m_cpu_stats.m_free + ); + + /* cleanup slab layer */ + if (cache->m_slab_stats.m_alloc > cache->m_slab_stats.m_free) + { + OSL_TRACE( + "rtl_cache_deactivate(\"%s\"): " + "cleaning up %"PRIu64" leaked buffer(s) [%lu bytes] [%lu total]", + cache->m_name, + cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free, + cache->m_slab_stats.m_mem_alloc, cache->m_slab_stats.m_mem_total + ); + + if (cache->m_features & RTL_CACHE_FEATURE_HASH) + { + /* cleanup bufctl(s) for leaking buffer(s) */ + sal_Size i, n = cache->m_hash_size; + for (i = 0; i < n; i++) + { + rtl_cache_bufctl_type * bufctl; + while ((bufctl = cache->m_hash_table[i]) != 0) + { + /* pop from hash table */ + cache->m_hash_table[i] = bufctl->m_next, bufctl->m_next = 0; + + /* return to bufctl cache */ + rtl_cache_free (gp_cache_bufctl_cache, bufctl); + } + } + } + { + /* force cleanup of remaining slabs */ + rtl_cache_slab_type *head, *slab; + + head = &(cache->m_used_head); + for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next) + { + /* remove from 'used' queue */ + QUEUE_REMOVE_NAMED(slab, slab_); + + /* update stats */ + cache->m_slab_stats.m_mem_total -= cache->m_slab_size; + + /* free slab */ + rtl_cache_slab_destroy (cache, slab); + } + + head = &(cache->m_free_head); + for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next) + { + /* remove from 'free' queue */ + QUEUE_REMOVE_NAMED(slab, slab_); + + /* update stats */ + cache->m_slab_stats.m_mem_total -= cache->m_slab_size; + + /* free slab */ + rtl_cache_slab_destroy (cache, slab); + } + } + } + + if (cache->m_hash_table != cache->m_hash_table_0) + { + rtl_arena_free ( + gp_cache_arena, + cache->m_hash_table, + cache->m_hash_size * sizeof(rtl_cache_bufctl_type*)); + + cache->m_hash_table = cache->m_hash_table_0; + cache->m_hash_size = RTL_CACHE_HASH_SIZE; + cache->m_hash_shift = highbit(cache->m_hash_size) - 1; + } +} + +/* ================================================================= * + * + * cache implementation. + * + * ================================================================= */ + +/** rtl_cache_create() + */ +rtl_cache_type * +SAL_CALL rtl_cache_create ( + const char * name, + sal_Size objsize, + sal_Size objalign, + int (SAL_CALL * constructor)(void * obj, void * userarg), + void (SAL_CALL * destructor) (void * obj, void * userarg), + void (SAL_CALL * reclaim) (void * userarg), + void * userarg, + rtl_arena_type * source, + int flags +) SAL_THROW_EXTERN_C() +{ + rtl_cache_type * result = 0; + sal_Size size = sizeof(rtl_cache_type); + +try_alloc: + result = (rtl_cache_type*)rtl_arena_alloc (gp_cache_arena, &size); + if (result != 0) + { + rtl_cache_type * cache = result; + (void) rtl_cache_constructor (cache); + + if (!source) + { + /* use default arena */ + OSL_ASSERT(gp_default_arena != 0); + source = gp_default_arena; + } + + result = rtl_cache_activate ( + cache, + name, + objsize, + objalign, + constructor, + destructor, + reclaim, + userarg, + source, + flags + ); + + if (result == 0) + { + /* activation failed */ + rtl_cache_deactivate (cache); + rtl_cache_destructor (cache); + rtl_arena_free (gp_cache_arena, cache, size); + } + } + else if (gp_cache_arena == 0) + { + if (rtl_cache_init()) + { + /* try again */ + goto try_alloc; + } + } + return (result); +} + +/** rtl_cache_destroy() + */ +void SAL_CALL rtl_cache_destroy ( + rtl_cache_type * cache +) SAL_THROW_EXTERN_C() +{ + if (cache != 0) + { + rtl_cache_deactivate (cache); + rtl_cache_destructor (cache); + rtl_arena_free (gp_cache_arena, cache, sizeof(rtl_cache_type)); + } +} + +/** rtl_cache_alloc() + */ +void * +SAL_CALL rtl_cache_alloc ( + rtl_cache_type * cache +) SAL_THROW_EXTERN_C() +{ + void * obj = 0; + + if (cache == 0) + return (0); + + if (cache->m_cpu_curr != 0) + { + RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock)); + + for (;;) + { + /* take object from magazine layer */ + rtl_cache_magazine_type *curr, *prev, *temp; + + curr = cache->m_cpu_curr; + if ((curr != 0) && (curr->m_mag_used > 0)) + { + obj = curr->m_objects[--curr->m_mag_used]; + cache->m_cpu_stats.m_alloc += 1; + RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); + + return (obj); + } + + prev = cache->m_cpu_prev; + if ((prev != 0) && (prev->m_mag_used > 0)) + { + temp = cache->m_cpu_curr; + cache->m_cpu_curr = cache->m_cpu_prev; + cache->m_cpu_prev = temp; + + continue; + } + + temp = rtl_cache_depot_exchange_alloc (cache, prev); + if (temp != 0) + { + cache->m_cpu_prev = cache->m_cpu_curr; + cache->m_cpu_curr = temp; + + continue; + } + + /* no full magazine: fall through to slab layer */ + break; + } + + RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); + } + + /* alloc buffer from slab layer */ + obj = rtl_cache_slab_alloc (cache); + if ((obj != 0) && (cache->m_constructor != 0)) + { + /* construct object */ + if (!((cache->m_constructor)(obj, cache->m_userarg))) + { + /* construction failure */ + rtl_cache_slab_free (cache, obj), obj = 0; + } + } + + return (obj); +} + +/** rtl_cache_free() + */ +void +SAL_CALL rtl_cache_free ( + rtl_cache_type * cache, + void * obj +) SAL_THROW_EXTERN_C() +{ + if ((obj != 0) && (cache != 0)) + { + RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock)); + + for (;;) + { + /* return object to magazine layer */ + rtl_cache_magazine_type *curr, *prev, *temp; + + curr = cache->m_cpu_curr; + if ((curr != 0) && (curr->m_mag_used < curr->m_mag_size)) + { + curr->m_objects[curr->m_mag_used++] = obj; + cache->m_cpu_stats.m_free += 1; + RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); + + return; + } + + prev = cache->m_cpu_prev; + if ((prev != 0) && (prev->m_mag_used == 0)) + { + temp = cache->m_cpu_curr; + cache->m_cpu_curr = cache->m_cpu_prev; + cache->m_cpu_prev = temp; + + continue; + } + + temp = rtl_cache_depot_exchange_free (cache, prev); + if (temp != 0) + { + cache->m_cpu_prev = cache->m_cpu_curr; + cache->m_cpu_curr = temp; + + continue; + } + + if (rtl_cache_depot_populate(cache) != 0) + { + continue; + } + + /* no empty magazine: fall through to slab layer */ + break; + } + + RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); + + /* no space for constructed object in magazine layer */ + if (cache->m_destructor != 0) + { + /* destruct object */ + (cache->m_destructor)(obj, cache->m_userarg); + } + + /* return buffer to slab layer */ + rtl_cache_slab_free (cache, obj); + } +} + +/* ================================================================= * + * + * cache wsupdate (machdep) internals. + * + * ================================================================= */ + +/** rtl_cache_wsupdate_init() + * + * @precond g_cache_list.m_lock initialized + */ +static void +rtl_cache_wsupdate_init (void); + + +/** rtl_cache_wsupdate_wait() + * + * @precond g_cache_list.m_lock acquired + */ +static void +rtl_cache_wsupdate_wait ( + unsigned int seconds +); + +/** rtl_cache_wsupdate_fini() + * + */ +static void +rtl_cache_wsupdate_fini (void); + +/* ================================================================= */ + +#if defined(SAL_UNX) || defined(SAL_OS2) + +#include <sys/time.h> + +static void * +rtl_cache_wsupdate_all (void * arg); + +static void +rtl_cache_wsupdate_init (void) +{ + RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); + g_cache_list.m_update_done = 0; + (void) pthread_cond_init (&(g_cache_list.m_update_cond), NULL); + if (pthread_create ( + &(g_cache_list.m_update_thread), NULL, rtl_cache_wsupdate_all, (void*)(10)) != 0) + { + /* failure */ + g_cache_list.m_update_thread = (pthread_t)(0); + } + RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); +} + +static void +rtl_cache_wsupdate_wait (unsigned int seconds) +{ + if (seconds > 0) + { + struct timeval now; + struct timespec wakeup; + + gettimeofday(&now, 0); + wakeup.tv_sec = now.tv_sec + (seconds); + wakeup.tv_nsec = now.tv_usec * 1000; + + (void) pthread_cond_timedwait ( + &(g_cache_list.m_update_cond), + &(g_cache_list.m_lock), + &wakeup); + } +} + +static void +rtl_cache_wsupdate_fini (void) +{ + RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); + g_cache_list.m_update_done = 1; + pthread_cond_signal (&(g_cache_list.m_update_cond)); + RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); + + if (g_cache_list.m_update_thread != (pthread_t)(0)) + pthread_join (g_cache_list.m_update_thread, NULL); +} + +/* ================================================================= */ + +#elif defined(SAL_W32) + +static DWORD WINAPI +rtl_cache_wsupdate_all (void * arg); + +static void +rtl_cache_wsupdate_init (void) +{ + DWORD dwThreadId; + + RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); + g_cache_list.m_update_done = 0; + g_cache_list.m_update_cond = CreateEvent (0, TRUE, FALSE, 0); + + g_cache_list.m_update_thread = + CreateThread (NULL, 0, rtl_cache_wsupdate_all, (LPVOID)(10), 0, &dwThreadId); + RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); +} + +static void +rtl_cache_wsupdate_wait (unsigned int seconds) +{ + if (seconds > 0) + { + RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); + WaitForSingleObject (g_cache_list.m_update_cond, (DWORD)(seconds * 1000)); + RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); + } +} + +static void +rtl_cache_wsupdate_fini (void) +{ + RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); + g_cache_list.m_update_done = 1; + SetEvent (g_cache_list.m_update_cond); + RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); + + WaitForSingleObject (g_cache_list.m_update_thread, INFINITE); +} + +#endif /* SAL_UNX || SAL_W32 */ + +/* ================================================================= */ + +/** rtl_cache_depot_wsupdate() + * update depot stats and purge excess magazines. + * + * @precond cache->m_depot_lock acquired + */ +static void +rtl_cache_depot_wsupdate ( + rtl_cache_type * cache, + rtl_cache_depot_type * depot +) +{ + sal_Size npurge; + + depot->m_prev_min = depot->m_curr_min; + depot->m_curr_min = depot->m_mag_count; + + npurge = SAL_MIN(depot->m_curr_min, depot->m_prev_min); + for (; npurge > 0; npurge--) + { + rtl_cache_magazine_type * mag = rtl_cache_depot_dequeue (depot); + if (mag != 0) + { + RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); + rtl_cache_magazine_clear (cache, mag); + rtl_cache_free (cache->m_magazine_cache, mag); + RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock)); + } + } +} + +/** rtl_cache_wsupdate() + * + * @precond cache->m_depot_lock released + */ +static void +rtl_cache_wsupdate ( + rtl_cache_type * cache +) +{ + if (cache->m_magazine_cache != 0) + { + RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock)); + + OSL_TRACE( + "rtl_cache_wsupdate(\"%s\") " + "[depot: count, curr_min, prev_min] " + "full: %lu, %lu, %lu; empty: %lu, %lu, %lu", + cache->m_name, + cache->m_depot_full.m_mag_count, + cache->m_depot_full.m_curr_min, + cache->m_depot_full.m_prev_min, + cache->m_depot_empty.m_mag_count, + cache->m_depot_empty.m_curr_min, + cache->m_depot_empty.m_prev_min + ); + + rtl_cache_depot_wsupdate (cache, &(cache->m_depot_full)); + rtl_cache_depot_wsupdate (cache, &(cache->m_depot_empty)); + + RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock)); + } +} + +/** rtl_cache_wsupdate_all() + * + */ +#if defined(SAL_UNX) || defined(SAL_OS2) +static void * +#elif defined(SAL_W32) +static DWORD WINAPI +#endif /* SAL_UNX || SAL_W32 */ +rtl_cache_wsupdate_all (void * arg) +{ + unsigned int seconds = (unsigned int)SAL_INT_CAST(sal_uIntPtr, arg); + + RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); + while (!g_cache_list.m_update_done) + { + rtl_cache_wsupdate_wait (seconds); + if (!g_cache_list.m_update_done) + { + rtl_cache_type * head, * cache; + + head = &(g_cache_list.m_cache_head); + for (cache = head->m_cache_next; + cache != head; + cache = cache->m_cache_next) + { + rtl_cache_wsupdate (cache); + } + } + } + RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); + + return (0); +} + +/* ================================================================= * + * + * cache initialization. + * + * ================================================================= */ + +static void +rtl_cache_once_init (void) +{ + { + /* list of caches */ + RTL_MEMORY_LOCK_INIT(&(g_cache_list.m_lock)); + (void) rtl_cache_constructor (&(g_cache_list.m_cache_head)); + } + { + /* cache: internal arena */ + OSL_ASSERT(gp_cache_arena == 0); + + gp_cache_arena = rtl_arena_create ( + "rtl_cache_internal_arena", + 64, /* quantum */ + 0, /* no quantum caching */ + NULL, /* default source */ + rtl_arena_alloc, + rtl_arena_free, + 0 /* flags */ + ); + OSL_ASSERT(gp_cache_arena != 0); + + /* check 'gp_default_arena' initialization */ + OSL_ASSERT(gp_default_arena != 0); + } + { + /* cache: magazine cache */ + static rtl_cache_type g_cache_magazine_cache; + + OSL_ASSERT(gp_cache_magazine_cache == 0); + (void) rtl_cache_constructor (&g_cache_magazine_cache); + + gp_cache_magazine_cache = rtl_cache_activate ( + &g_cache_magazine_cache, + "rtl_cache_magazine_cache", + sizeof(rtl_cache_magazine_type), /* objsize */ + 0, /* objalign */ + rtl_cache_magazine_constructor, + rtl_cache_magazine_destructor, + 0, /* reclaim */ + 0, /* userarg: NYI */ + gp_default_arena, /* source */ + RTL_CACHE_FLAG_NOMAGAZINE /* during bootstrap; activated below */ + ); + OSL_ASSERT(gp_cache_magazine_cache != 0); + + /* activate magazine layer */ + g_cache_magazine_cache.m_magazine_cache = gp_cache_magazine_cache; + } + { + /* cache: slab (struct) cache */ + static rtl_cache_type g_cache_slab_cache; + + OSL_ASSERT(gp_cache_slab_cache == 0); + (void) rtl_cache_constructor (&g_cache_slab_cache); + + gp_cache_slab_cache = rtl_cache_activate ( + &g_cache_slab_cache, + "rtl_cache_slab_cache", + sizeof(rtl_cache_slab_type), /* objsize */ + 0, /* objalign */ + rtl_cache_slab_constructor, + rtl_cache_slab_destructor, + 0, /* reclaim */ + 0, /* userarg: none */ + gp_default_arena, /* source */ + 0 /* flags: none */ + ); + OSL_ASSERT(gp_cache_slab_cache != 0); + } + { + /* cache: bufctl cache */ + static rtl_cache_type g_cache_bufctl_cache; + + OSL_ASSERT(gp_cache_bufctl_cache == 0); + (void) rtl_cache_constructor (&g_cache_bufctl_cache); + + gp_cache_bufctl_cache = rtl_cache_activate ( + &g_cache_bufctl_cache, + "rtl_cache_bufctl_cache", + sizeof(rtl_cache_bufctl_type), /* objsize */ + 0, /* objalign */ + 0, /* constructor */ + 0, /* destructor */ + 0, /* reclaim */ + 0, /* userarg */ + gp_default_arena, /* source */ + 0 /* flags: none */ + ); + OSL_ASSERT(gp_cache_bufctl_cache != 0); + } + + rtl_cache_wsupdate_init(); +} + +static int +rtl_cache_init (void) +{ + static sal_once_type g_once = SAL_ONCE_INIT; + SAL_ONCE(&g_once, rtl_cache_once_init); + return (gp_cache_arena != 0); +} + +/* ================================================================= */ + +#if defined(__GNUC__) +static void rtl_cache_fini (void) __attribute__((destructor)); +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma fini(rtl_cache_fini) +static void rtl_cache_fini (void); +#endif /* __GNUC__ || __SUNPRO_C */ + +void +rtl_cache_fini (void) +{ + if (gp_cache_arena != 0) + { + rtl_cache_type * cache, * head; + + rtl_cache_wsupdate_fini(); + + if (gp_cache_bufctl_cache != 0) + { + cache = gp_cache_bufctl_cache, gp_cache_bufctl_cache = 0; + rtl_cache_deactivate (cache); + rtl_cache_destructor (cache); + } + if (gp_cache_slab_cache != 0) + { + cache = gp_cache_slab_cache, gp_cache_slab_cache = 0; + rtl_cache_deactivate (cache); + rtl_cache_destructor (cache); + } + if (gp_cache_magazine_cache != 0) + { + cache = gp_cache_magazine_cache, gp_cache_magazine_cache = 0; + rtl_cache_deactivate (cache); + rtl_cache_destructor (cache); + } + if (gp_cache_arena != 0) + { + rtl_arena_destroy (gp_cache_arena); + gp_cache_arena = 0; + } + + RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock)); + head = &(g_cache_list.m_cache_head); + for (cache = head->m_cache_next; cache != head; cache = cache->m_cache_next) + { + OSL_TRACE( + "rtl_cache_fini(\"%s\") " + "[slab]: allocs: %"PRIu64", frees: %"PRIu64"; total: %lu, used: %lu; " + "[cpu]: allocs: %"PRIu64", frees: %"PRIu64"; " + "[total]: allocs: %"PRIu64", frees: %"PRIu64"", + cache->m_name, + cache->m_slab_stats.m_alloc, cache->m_slab_stats.m_free, + cache->m_slab_stats.m_mem_total, cache->m_slab_stats.m_mem_alloc, + cache->m_cpu_stats.m_alloc, cache->m_cpu_stats.m_free, + cache->m_slab_stats.m_alloc + cache->m_cpu_stats.m_alloc, + cache->m_slab_stats.m_free + cache->m_cpu_stats.m_free + ); + } + RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock)); + } +} + +/* ================================================================= */ diff --git a/sal/rtl/source/alloc_cache.h b/sal/rtl/source/alloc_cache.h new file mode 100644 index 000000000000..9fed61806fde --- /dev/null +++ b/sal/rtl/source/alloc_cache.h @@ -0,0 +1,182 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_RTL_ALLOC_CACHE_H +#define INCLUDED_RTL_ALLOC_CACHE_H + +#include "sal/types.h" +#include "rtl/alloc.h" +#include "alloc_impl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** rtl_cache_stat_type + * @internal + */ +typedef struct rtl_cache_stat_st rtl_cache_stat_type; +struct rtl_cache_stat_st +{ + sal_uInt64 m_alloc; + sal_uInt64 m_free; + + sal_Size m_mem_total; + sal_Size m_mem_alloc; +}; + + +/** rtl_cache_bufctl_type + * @internal + */ +typedef struct rtl_cache_bufctl_st rtl_cache_bufctl_type; +struct rtl_cache_bufctl_st +{ + rtl_cache_bufctl_type * m_next; /* linkage */ + + sal_uIntPtr m_addr; /* buffer address */ + sal_uIntPtr m_slab; /* parent slab address */ +}; + + +/** rtl_cache_slab_type + * @internal + */ +typedef struct rtl_cache_slab_st rtl_cache_slab_type; +struct rtl_cache_slab_st +{ + rtl_cache_slab_type * m_slab_next; /* slab linkage */ + rtl_cache_slab_type * m_slab_prev; /* slab linkage */ + + sal_Size m_ntypes; /* number of buffers used */ + sal_uIntPtr m_data; /* buffer start addr */ + + sal_uIntPtr m_bp; /* free buffer linkage 'base pointer' */ + rtl_cache_bufctl_type * m_sp; /* free buffer linkage 'stack pointer' */ +}; + + +/** rtl_cache_magazine_type + * @internal + */ +#define RTL_CACHE_MAGAZINE_SIZE 61 + +typedef struct rtl_cache_magazine_st rtl_cache_magazine_type; +struct rtl_cache_magazine_st +{ + rtl_cache_magazine_type * m_mag_next; /* depot linkage */ + + sal_Size m_mag_size; + sal_Size m_mag_used; + + void * m_objects[RTL_CACHE_MAGAZINE_SIZE]; +}; + + +/** rtl_cache_depot_type + * @internal + */ +typedef struct rtl_cache_depot_st rtl_cache_depot_type; +struct rtl_cache_depot_st +{ + /* magazine list */ + rtl_cache_magazine_type * m_mag_next; /* linkage */ + sal_Size m_mag_count; /* count */ + + /* working set parameters */ + sal_Size m_curr_min; + sal_Size m_prev_min; +}; + + +/** rtl_cache_type + * @internal + */ +#define RTL_CACHE_HASH_SIZE 8 + +#define RTL_CACHE_FEATURE_HASH 1 +#define RTL_CACHE_FEATURE_BULKDESTROY 2 +#define RTL_CACHE_FEATURE_RESCALE 4 /* within hash rescale operation */ + +struct rtl_cache_st +{ + /* linkage */ + rtl_cache_type * m_cache_next; + rtl_cache_type * m_cache_prev; + + /* properties */ + char m_name[RTL_CACHE_NAME_LENGTH + 1]; + long m_features; + + sal_Size m_type_size; /* const */ + sal_Size m_type_align; /* const */ + sal_Size m_type_shift; /* log2(m_type_size); const */ + + int (SAL_CALL * m_constructor)(void * obj, void * userarg); /* const */ + void (SAL_CALL * m_destructor) (void * obj, void * userarg); /* const */ + void (SAL_CALL * m_reclaim) (void * userarg); /* const */ + void * m_userarg; + + /* slab layer */ + rtl_memory_lock_type m_slab_lock; + rtl_cache_stat_type m_slab_stats; + + rtl_arena_type * m_source; /* slab supplier; const */ + sal_Size m_slab_size; /* const */ + sal_Size m_ntypes; /* number of buffers per slab; const */ + sal_Size m_ncolor; /* next slab color */ + sal_Size m_ncolor_max; /* max. slab color */ + + rtl_cache_slab_type m_free_head; + rtl_cache_slab_type m_used_head; + + rtl_cache_bufctl_type ** m_hash_table; + rtl_cache_bufctl_type * m_hash_table_0[RTL_CACHE_HASH_SIZE]; + sal_Size m_hash_size; /* m_hash_mask + 1 */ + sal_Size m_hash_shift; /* log2(m_hash_size) */ + + /* depot layer */ + rtl_memory_lock_type m_depot_lock; + + rtl_cache_depot_type m_depot_empty; + rtl_cache_depot_type m_depot_full; + + rtl_cache_type * m_magazine_cache; /* magazine supplier; const */ + + /* cpu layer */ + rtl_cache_magazine_type * m_cpu_curr; + rtl_cache_magazine_type * m_cpu_prev; + + rtl_cache_stat_type m_cpu_stats; +}; + + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_RTL_ALLOC_CACHE_H */ diff --git a/sal/rtl/source/alloc_global.c b/sal/rtl/source/alloc_global.c new file mode 100644 index 000000000000..5137f868127d --- /dev/null +++ b/sal/rtl/source/alloc_global.c @@ -0,0 +1,357 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "rtl/alloc.h" + +#ifndef INCLUDED_STRING_H +#include <string.h> +#define INCLUDED_STRING_H +#endif + +#if !defined(FORCE_SYSALLOC) + +/* ================================================================= * + * + * custom allocator includes. + * + * ================================================================= */ + +#ifndef INCLUDED_STDIO_H +#include <stdio.h> +#define INCLUDED_STDIO_H +#endif +#include "alloc_impl.h" +#include "internal/once.h" +#include "sal/macros.h" +#include "osl/diagnose.h" + +/* ================================================================= * + * + * custom allocator internals. + * + * ================================================================= */ + +static const sal_Size g_alloc_sizes[] = +{ + /* powers of 2**(1/4) */ + 4 * 4, 6 * 4, + 4 * 8, 5 * 8, 6 * 8, 7 * 8, + 4 * 16, 5 * 16, 6 * 16, 7 * 16, + 4 * 32, 5 * 32, 6 * 32, 7 * 32, + 4 * 64, 5 * 64, 6 * 64, 7 * 64, + 4 * 128, 5 * 128, 6 * 128, 7 * 128, + 4 * 256, 5 * 256, 6 * 256, 7 * 256, + 4 * 512, 5 * 512, 6 * 512, 7 * 512, + 4 * 1024, 5 * 1024, 6 * 1024, 7 * 1024, + 4 * 2048, 5 * 2048, 6 * 2048, 7 * 2048, + 4 * 4096 +}; + +#define RTL_MEMORY_CACHED_LIMIT 4 * 4096 +#define RTL_MEMORY_CACHED_SIZES (sizeof(g_alloc_sizes) / sizeof(g_alloc_sizes[0])) + +static rtl_cache_type * g_alloc_caches[RTL_MEMORY_CACHED_SIZES] = +{ + 0, +}; + +#define RTL_MEMALIGN 8 +#define RTL_MEMALIGN_SHIFT 3 + +static rtl_cache_type * g_alloc_table[RTL_MEMORY_CACHED_LIMIT >> RTL_MEMALIGN_SHIFT] = +{ + 0, +}; + +static rtl_arena_type * gp_alloc_arena = 0; + +/* ================================================================= * + * + * custom allocator initialization / finalization. + * + * ================================================================= */ + +static void +rtl_memory_once_init (void) +{ + { + /* global memory arena */ + OSL_ASSERT(gp_alloc_arena == 0); + + gp_alloc_arena = rtl_arena_create ( + "rtl_alloc_arena", + 2048, /* quantum */ + 0, /* w/o quantum caching */ + 0, /* default source */ + rtl_arena_alloc, + rtl_arena_free, + 0 /* flags */ + ); + OSL_ASSERT(gp_alloc_arena != 0); + } + { + sal_Size size; + int i, n = RTL_MEMORY_CACHED_SIZES; + + for (i = 0; i < n; i++) + { + char name[RTL_CACHE_NAME_LENGTH + 1]; + (void) snprintf (name, sizeof(name), "rtl_alloc_%lu", g_alloc_sizes[i]); + g_alloc_caches[i] = rtl_cache_create (name, g_alloc_sizes[i], 0, NULL, NULL, NULL, NULL, NULL, 0); + } + + size = RTL_MEMALIGN; + for (i = 0; i < n; i++) + { + while (size <= g_alloc_sizes[i]) + { + g_alloc_table[(size - 1) >> RTL_MEMALIGN_SHIFT] = g_alloc_caches[i]; + size += RTL_MEMALIGN; + } + } + } +} + +static int +rtl_memory_init (void) +{ + static sal_once_type g_once = SAL_ONCE_INIT; + SAL_ONCE(&g_once, rtl_memory_once_init); + return (gp_alloc_arena != 0); +} + +/* ================================================================= */ + +/* + Issue http://udk.openoffice.org/issues/show_bug.cgi?id=92388 + + Mac OS X does not seem to support "__cxa__atexit", thus leading + to the situation that "__attribute__((destructor))__" functions + (in particular "rtl_memory_fini") become called _before_ global + C++ object d'tors. + + Delegated the call to "rtl_memory_fini" into a dummy C++ object, + see memory_fini.cxx . +*/ +#if defined(__GNUC__) && !defined(MACOSX) +static void rtl_memory_fini (void) __attribute__((destructor)); +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma fini(rtl_memory_fini) +static void rtl_memory_fini (void); +#endif /* __GNUC__ || __SUNPRO_C */ + +void +rtl_memory_fini (void) +{ + int i, n; + + /* clear g_alloc_table */ + memset (g_alloc_table, 0, sizeof(g_alloc_table)); + + /* cleanup g_alloc_caches */ + for (i = 0, n = RTL_MEMORY_CACHED_SIZES; i < n; i++) + { + if (g_alloc_caches[i] != 0) + { + rtl_cache_destroy (g_alloc_caches[i]); + g_alloc_caches[i] = 0; + } + } + + /* cleanup gp_alloc_arena */ + if (gp_alloc_arena != 0) + { + rtl_arena_destroy (gp_alloc_arena); + gp_alloc_arena = 0; + } +} + +/* ================================================================= * + * + * custom allocator implemenation. + * + * ================================================================= */ + +void * +SAL_CALL rtl_allocateMemory (sal_Size n) SAL_THROW_EXTERN_C() +{ + void * p = 0; + if (n > 0) + { + char * addr; + sal_Size size = RTL_MEMORY_ALIGN(n + RTL_MEMALIGN, RTL_MEMALIGN); + + OSL_ASSERT(RTL_MEMALIGN >= sizeof(sal_Size)); + if (n >= SAL_MAX_SIZE - (RTL_MEMALIGN + RTL_MEMALIGN - 1)) + { + /* requested size too large for roundup alignment */ + return 0; + } + +try_alloc: + if (size <= RTL_MEMORY_CACHED_LIMIT) + addr = (char*)rtl_cache_alloc(g_alloc_table[(size - 1) >> RTL_MEMALIGN_SHIFT]); + else + addr = (char*)rtl_arena_alloc (gp_alloc_arena, &size); + + if (addr != 0) + { + ((sal_Size*)(addr))[0] = size; + p = addr + RTL_MEMALIGN; + } + else if (gp_alloc_arena == 0) + { + if (rtl_memory_init()) + { + /* try again */ + goto try_alloc; + } + } + } + return (p); +} + +/* ================================================================= */ + +void SAL_CALL rtl_freeMemory (void * p) SAL_THROW_EXTERN_C() +{ + if (p != 0) + { + char * addr = (char*)(p) - RTL_MEMALIGN; + sal_Size size = ((sal_Size*)(addr))[0]; + + if (size <= RTL_MEMORY_CACHED_LIMIT) + rtl_cache_free(g_alloc_table[(size - 1) >> RTL_MEMALIGN_SHIFT], addr); + else + rtl_arena_free (gp_alloc_arena, addr, size); + } +} + +/* ================================================================= */ + +void * SAL_CALL rtl_reallocateMemory (void * p, sal_Size n) SAL_THROW_EXTERN_C() +{ + if (n > 0) + { + if (p != 0) + { + void * p_old = p; + sal_Size n_old = ((sal_Size*)( (char*)(p) - RTL_MEMALIGN ))[0] - RTL_MEMALIGN; + + p = rtl_allocateMemory (n); + if (p != 0) + { + memcpy (p, p_old, SAL_MIN(n, n_old)); + rtl_freeMemory (p_old); + } + } + else + { + p = rtl_allocateMemory (n); + } + } + else if (p != 0) + { + rtl_freeMemory (p), p = 0; + } + return (p); +} + +#else /* FORCE_SYSALLOC */ + +/* ================================================================= * + * + * system allocator includes. + * + * ================================================================= */ + +#ifndef INCLUDED_STDLIB_H +#include <stdlib.h> +#define INCLUDED_STDLIB_H +#endif + +/* ================================================================= * + * + * system allocator implemenation. + * + * ================================================================= */ + +void * SAL_CALL rtl_allocateMemory (sal_Size n) +{ + return malloc (n); +} + +/* ================================================================= */ + +void SAL_CALL rtl_freeMemory (void * p) +{ + free (p); +} + +/* ================================================================= */ + +void * SAL_CALL rtl_reallocateMemory (void * p, sal_Size n) +{ + return realloc (p, n); +} + +/* ================================================================= */ + +void +rtl_memory_fini (void) +{ + /* nothing to do */ +} + +#endif /* FORCE_SYSALLOC */ + +/* ================================================================= * + * + * rtl_(allocate|free)ZeroMemory() implemenation. + * + * ================================================================= */ + +void * SAL_CALL rtl_allocateZeroMemory (sal_Size n) SAL_THROW_EXTERN_C() +{ + void * p = rtl_allocateMemory (n); + if (p != 0) + memset (p, 0, n); + return (p); +} + +/* ================================================================= */ + +void SAL_CALL rtl_freeZeroMemory (void * p, sal_Size n) SAL_THROW_EXTERN_C() +{ + if (p != 0) + { + memset (p, 0, n); + rtl_freeMemory (p); + } +} + +/* ================================================================= */ diff --git a/sal/rtl/source/alloc_impl.h b/sal/rtl/source/alloc_impl.h new file mode 100644 index 000000000000..d3d1924ddf91 --- /dev/null +++ b/sal/rtl/source/alloc_impl.h @@ -0,0 +1,247 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_RTL_ALLOC_IMPL_H +#define INCLUDED_RTL_ALLOC_IMPL_H + +#include "sal/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Alignment macros + */ +#if SAL_TYPES_ALIGNMENT4 > 1 +#define RTL_MEMORY_ALIGNMENT_4 SAL_TYPES_ALIGNMENT4 +#else +#define RTL_MEMORY_ALIGNMENT_4 sizeof(int) +#endif /* SAL_TYPES_ALIGNMENT4 */ + +#if SAL_TYPES_ALIGNMENT8 > 1 +#define RTL_MEMORY_ALIGNMENT_8 SAL_TYPES_ALIGNMENT8 +#else +#define RTL_MEMORY_ALIGNMENT_8 sizeof(void*) +#endif /* SAL_TYPES_ALIGNMENT8 */ + +#if 0 /* @@@ */ +#define RTL_MEMORY_ALIGNMENT_1 8 +#define RTL_MEMORY_ALIGNMENT_2 (sizeof(void*) * 2) +#endif /* @@@ */ + +#define RTL_MEMORY_ALIGN(value, align) (((value) + ((align) - 1)) & ~((align) - 1)) + +#define RTL_MEMORY_ISP2(value) (((value) & ((value) - 1)) == 0) +#define RTL_MEMORY_P2ALIGN(value, align) ((value) & -(sal_IntPtr)(align)) + +#define RTL_MEMORY_P2ROUNDUP(value, align) \ + (-(-(sal_IntPtr)(value) & -(sal_IntPtr)(align))) +#define RTL_MEMORY_P2END(value, align) \ + (-(~(sal_IntPtr)(value) & -(sal_IntPtr)(align))) + + +/** Function inlining macros + * (compiler dependent) + */ +#ifndef RTL_MEMORY_INLINE +#if defined(__GNUC__) +#define RTL_MEMORY_INLINE __inline__ +#elif defined(_MSC_VER) +#define RTL_MEMORY_INLINE __inline +#else +#define RTL_MEMORY_INLINE +#endif /* __GNUC__ || _MSC_VER */ +#endif /* RTL_MEMORY_INLINE */ + + +/** printf() format specifier(s) + * (from C90 <sys/int_fmtio.h>) + */ +#ifndef PRIu64 +#if defined(_MSC_VER) +#define PRIu64 "I64u" +#else /* !_MSC_VER */ +#define PRIu64 "llu" +#endif /* !_MSC_VER */ +#endif /* PRIu64 */ + + +/** highbit(): log2() + 1 + * (complexity O(1)) + */ +static RTL_MEMORY_INLINE int +highbit(sal_Size n) +{ + register int k = 1; + + if (n == 0) + return (0); +#if SAL_TYPES_SIZEOFLONG == 8 + if (n & 0xffffffff00000000ul) + k |= 32, n >>= 32; +#endif + if (n & 0xffff0000) + k |= 16, n >>= 16; + if (n & 0xff00) + k |= 8, n >>= 8; + if (n & 0xf0) + k |= 4, n >>= 4; + if (n & 0x0c) + k |= 2, n >>= 2; + if (n & 0x02) + k++; + + return (k); +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(highbit) +#endif /* __SUNPRO_C */ + + +/** lowbit(): find first bit set + * (complexity O(1)) + */ +static RTL_MEMORY_INLINE int +lowbit(sal_Size n) +{ + register int k = 1; + + if (n == 0) + return (0); +#if SAL_TYPES_SIZEOFLONG == 8 + if (!(n & 0xffffffff)) + k |= 32, n >>= 32; +#endif + if (!(n & 0xffff)) + k |= 16, n >>= 16; + if (!(n & 0xff)) + k |= 8, n >>= 8; + if (!(n & 0xf)) + k |= 4, n >>= 4; + if (!(n & 0x3)) + k |= 2, n >>= 2; + if (!(n & 0x1)) + k++; + return (k); +} + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma inline(lowbit) +#endif /* __SUNPRO_C */ + + +/** Queue manipulation macros + * (doubly linked circular list) + * (complexity O(1)) + */ +#define QUEUE_STARTED_NAMED(entry, name) \ + (((entry)->m_##name##next == (entry)) && ((entry)->m_##name##prev == (entry))) + +#define QUEUE_START_NAMED(entry, name) \ +{ \ + (entry)->m_##name##next = (entry); \ + (entry)->m_##name##prev = (entry); \ +} + +#define QUEUE_REMOVE_NAMED(entry, name) \ +{ \ + (entry)->m_##name##prev->m_##name##next = (entry)->m_##name##next; \ + (entry)->m_##name##next->m_##name##prev = (entry)->m_##name##prev; \ + QUEUE_START_NAMED(entry, name); \ +} + +#define QUEUE_INSERT_HEAD_NAMED(head, entry, name) \ +{ \ + (entry)->m_##name##prev = (head); \ + (entry)->m_##name##next = (head)->m_##name##next; \ + (head)->m_##name##next = (entry); \ + (entry)->m_##name##next->m_##name##prev = (entry); \ +} + +#define QUEUE_INSERT_TAIL_NAMED(head, entry, name) \ +{ \ + (entry)->m_##name##next = (head); \ + (entry)->m_##name##prev = (head)->m_##name##prev; \ + (head)->m_##name##prev = (entry); \ + (entry)->m_##name##prev->m_##name##next = (entry); \ +} + + +/** rtl_memory_lock_type + * (platform dependent) + */ +#if defined(SAL_UNX) || defined(SAL_OS2) + +#include <unistd.h> +#include <pthread.h> + +typedef pthread_mutex_t rtl_memory_lock_type; + +#define RTL_MEMORY_LOCK_INIT(lock) pthread_mutex_init((lock), NULL) +#define RTL_MEMORY_LOCK_DESTROY(lock) pthread_mutex_destroy((lock)) + +#define RTL_MEMORY_LOCK_ACQUIRE(lock) pthread_mutex_lock((lock)) +#define RTL_MEMORY_LOCK_RELEASE(lock) pthread_mutex_unlock((lock)) + +#elif defined(SAL_W32) + +#define WIN32_LEAN_AND_MEAN +#ifdef _MSC_VER +#pragma warning(push,1) /* disable warnings within system headers */ +#endif +#include <windows.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +typedef CRITICAL_SECTION rtl_memory_lock_type; + +#define RTL_MEMORY_LOCK_INIT(lock) InitializeCriticalSection((lock)) +#define RTL_MEMORY_LOCK_DESTROY(lock) DeleteCriticalSection((lock)) + +#define RTL_MEMORY_LOCK_ACQUIRE(lock) EnterCriticalSection((lock)) +#define RTL_MEMORY_LOCK_RELEASE(lock) LeaveCriticalSection((lock)) + +#else +#error Unknown platform +#endif /* SAL_UNX | SAL_W32 */ + + +/** Cache creation flags. + * @internal + */ +#define RTL_CACHE_FLAG_NOMAGAZINE (1 << 13) /* w/o magazine layer */ +#define RTL_CACHE_FLAG_QUANTUMCACHE (2 << 13) /* used as arena quantum cache */ + + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDED_RTL_ALLOC_IMPL_H */ diff --git a/sal/rtl/source/bootstrap.cxx b/sal/rtl/source/bootstrap.cxx new file mode 100644 index 000000000000..cc7d3336c2d2 --- /dev/null +++ b/sal/rtl/source/bootstrap.cxx @@ -0,0 +1,1059 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "rtl/bootstrap.h" +#include "rtl/bootstrap.hxx" +#include <osl/diagnose.h> +#include <osl/module.h> +#include <osl/process.h> +#include <osl/file.hxx> +#include <osl/mutex.hxx> +#include <osl/profile.hxx> +#include <osl/security.hxx> +#include <rtl/alloc.h> +#include <rtl/string.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <rtl/byteseq.hxx> +#include <rtl/instance.hxx> +#include <rtl/malformeduriexception.hxx> +#include <rtl/uri.hxx> +#include "rtl/allocator.hxx" + +#include "macro.hxx" + +#include <hash_map> +#include <list> + +#define MY_STRING_(x) # x +#define MY_STRING(x) MY_STRING_(x) + +//---------------------------------------------------------------------------- + +using osl::DirectoryItem; +using osl::FileStatus; + +using rtl::OString; +using rtl::OUString; +using rtl::OUStringToOString; + +struct Bootstrap_Impl; + +namespace { + +static char const VND_SUN_STAR_PATHNAME[] = "vnd.sun.star.pathname:"; + +bool isPathnameUrl(rtl::OUString const & url) { + return url.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(VND_SUN_STAR_PATHNAME)); +} + +bool resolvePathnameUrl(rtl::OUString * url) { + OSL_ASSERT(url != NULL); + if (!isPathnameUrl(*url) || + (osl::FileBase::getFileURLFromSystemPath( + url->copy(RTL_CONSTASCII_LENGTH(VND_SUN_STAR_PATHNAME)), *url) == + osl::FileBase::E_None)) + { + return true; + } else { + *url = rtl::OUString(); + return false; + } +} + +enum LookupMode { + LOOKUP_MODE_NORMAL, LOOKUP_MODE_URE_BOOTSTRAP, + LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION }; + +struct ExpandRequestLink { + ExpandRequestLink const * next; + Bootstrap_Impl const * file; + rtl::OUString key; +}; + +rtl::OUString expandMacros( + Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode, + ExpandRequestLink const * requestStack); + +rtl::OUString recursivelyExpandMacros( + Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode, + Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey, + ExpandRequestLink const * requestStack) +{ + for (; requestStack != NULL; requestStack = requestStack->next) { + if (requestStack->file == requestFile && + requestStack->key == requestKey) + { + return rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("***RECURSION DETECTED***")); + } + } + ExpandRequestLink link = { requestStack, requestFile, requestKey }; + return expandMacros(file, text, mode, &link); +} + +} + +//---------------------------------------------------------------------------- + +struct rtl_bootstrap_NameValue +{ + OUString sName; + OUString sValue; + + inline rtl_bootstrap_NameValue() SAL_THROW( () ) + {} + inline rtl_bootstrap_NameValue( + OUString const & name, OUString const & value ) SAL_THROW( () ) + : sName( name ), + sValue( value ) + {} +}; + +typedef std::list< + rtl_bootstrap_NameValue, + rtl::Allocator< rtl_bootstrap_NameValue > +> NameValueList; + +bool find( + NameValueList const & list, rtl::OUString const & key, + rtl::OUString * value) +{ + OSL_ASSERT(value != NULL); + for (NameValueList::const_iterator i(list.begin()); i != list.end(); ++i) { + if (i->sName == key) { + *value = i->sValue; + return true; + } + } + return false; +} + +namespace { + struct rtl_bootstrap_set_list : + public rtl::Static< NameValueList, rtl_bootstrap_set_list > {}; +} + +//---------------------------------------------------------------------------- + +static sal_Bool getFromCommandLineArgs( + rtl::OUString const & key, rtl::OUString * value ) +{ + OSL_ASSERT(value != NULL); + static NameValueList *pNameValueList = 0; + if( ! pNameValueList ) + { + static NameValueList nameValueList; + + sal_Int32 nArgCount = osl_getCommandArgCount(); + for(sal_Int32 i = 0; i < nArgCount; ++ i) + { + rtl_uString *pArg = 0; + osl_getCommandArg( i, &pArg ); + if( ('-' == pArg->buffer[0] || '/' == pArg->buffer[0] ) && + 'e' == pArg->buffer[1] && + 'n' == pArg->buffer[2] && + 'v' == pArg->buffer[3] && + ':' == pArg->buffer[4] ) + { + sal_Int32 nIndex = rtl_ustr_indexOfChar( pArg->buffer, '=' ); + if( nIndex >= 0 ) + { + + rtl_bootstrap_NameValue nameValue; + nameValue.sName = OUString( &(pArg->buffer[5]), nIndex - 5 ); + nameValue.sValue = OUString( &(pArg->buffer[nIndex+1]) ); + if( i == nArgCount-1 && + nameValue.sValue.getLength() && + nameValue.sValue[nameValue.sValue.getLength()-1] == 13 ) + { + // avoid the 13 linefeed for the last argument, + // when the executable is started from a script, + // that was edited on windows + nameValue.sValue = nameValue.sValue.copy(0,nameValue.sValue.getLength()-1); + } + nameValueList.push_back( nameValue ); + } + } + rtl_uString_release( pArg ); + } + pNameValueList = &nameValueList; + } + + sal_Bool found = sal_False; + + for( NameValueList::iterator ii = pNameValueList->begin() ; + ii != pNameValueList->end() ; + ++ii ) + { + if( (*ii).sName.equals(key) ) + { + *value = (*ii).sValue; + found = sal_True; + break; + } + } + + return found; +} + +//---------------------------------------------------------------------------- + +extern "C" oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl ( + rtl_uString ** ppFileURL) SAL_THROW_EXTERN_C(); + +inline void getExecutableFile_Impl (rtl_uString ** ppFileURL) +{ + osl_bootstrap_getExecutableFile_Impl (ppFileURL); +} + +//---------------------------------------------------------------------------- + +static void getExecutableDirectory_Impl (rtl_uString ** ppDirURL) +{ + OUString fileName; + getExecutableFile_Impl (&(fileName.pData)); + + sal_Int32 nDirEnd = fileName.lastIndexOf('/'); + OSL_ENSURE(nDirEnd >= 0, "Cannot locate executable directory"); + + rtl_uString_newFromStr_WithLength(ppDirURL,fileName.getStr(),nDirEnd); +} + +//---------------------------------------------------------------------------- + +static OUString & getIniFileName_Impl() +{ + static OUString *pStaticName = 0; + if( ! pStaticName ) + { + OUString fileName; + + if(getFromCommandLineArgs( + OUString(RTL_CONSTASCII_USTRINGPARAM("INIFILENAME")), &fileName)) + { + resolvePathnameUrl(&fileName); + } + else + { + getExecutableFile_Impl (&(fileName.pData)); + + // get rid of a potential executable extension + OUString progExt (RTL_CONSTASCII_USTRINGPARAM(".bin")); + if(fileName.getLength() > progExt.getLength() + && fileName.copy(fileName.getLength() - progExt.getLength()).equalsIgnoreAsciiCase(progExt)) + fileName = fileName.copy(0, fileName.getLength() - progExt.getLength()); + + progExt = OUString::createFromAscii(".exe"); + if(fileName.getLength() > progExt.getLength() + && fileName.copy(fileName.getLength() - progExt.getLength()).equalsIgnoreAsciiCase(progExt)) + fileName = fileName.copy(0, fileName.getLength() - progExt.getLength()); + + // append config file suffix + fileName += OUString(RTL_CONSTASCII_USTRINGPARAM(SAL_CONFIGFILE(""))); + } + + static OUString theFileName; + if(fileName.getLength()) + theFileName = fileName; + + pStaticName = &theFileName; + } + + return *pStaticName; +} + +//---------------------------------------------------------------------------- + +static inline bool path_exists( OUString const & path ) +{ + DirectoryItem dirItem; + return (DirectoryItem::E_None == DirectoryItem::get( path, dirItem )); +} + +//---------------------------------------------------------------------------- +// #111772# +// ensure the given file url has no final slash + +inline void EnsureNoFinalSlash (rtl::OUString & url) +{ + sal_Int32 i = url.getLength(); + if (i > 0 && url[i - 1] == '/') { + url = url.copy(0, i - 1); + } +} + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +struct Bootstrap_Impl +{ + sal_Int32 _nRefCount; + Bootstrap_Impl * _base_ini; + + NameValueList _nameValueList; + OUString _iniName; + + explicit Bootstrap_Impl (OUString const & rIniName); + ~Bootstrap_Impl(); + + static void * operator new (std::size_t n) SAL_THROW(()) + { return rtl_allocateMemory (sal_uInt32(n)); } + static void operator delete (void * p , std::size_t) SAL_THROW(()) + { rtl_freeMemory (p); } + + bool getValue( + rtl::OUString const & key, rtl_uString ** value, + rtl_uString * defaultValue, LookupMode mode, bool override, + ExpandRequestLink const * requestStack) const; + bool getDirectValue( + rtl::OUString const & key, rtl_uString ** value, LookupMode mode, + ExpandRequestLink const * requestStack) const; + bool getAmbienceValue( + rtl::OUString const & key, rtl_uString ** value, LookupMode mode, + ExpandRequestLink const * requestStack) const; + void expandValue( + rtl_uString ** value, rtl::OUString const & text, LookupMode mode, + Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey, + ExpandRequestLink const * requestStack) const; +}; + +//---------------------------------------------------------------------------- + +Bootstrap_Impl::Bootstrap_Impl( OUString const & rIniName ) + : _nRefCount( 0 ), + _base_ini( 0 ), + _iniName (rIniName) +{ + OUString base_ini( getIniFileName_Impl() ); + // normalize path + FileStatus status( FileStatusMask_FileURL ); + DirectoryItem dirItem; + if (DirectoryItem::E_None == DirectoryItem::get( base_ini, dirItem ) && + DirectoryItem::E_None == dirItem.getFileStatus( status )) + { + base_ini = status.getFileURL(); + if (! rIniName.equals( base_ini )) + { + _base_ini = static_cast< Bootstrap_Impl * >( + rtl_bootstrap_args_open( base_ini.pData ) ); + } + } + +#if OSL_DEBUG_LEVEL > 1 + OString sFile = OUStringToOString(_iniName, RTL_TEXTENCODING_ASCII_US); + OSL_TRACE(__FILE__" -- Bootstrap_Impl() - %s\n", sFile.getStr()); +#endif /* OSL_DEBUG_LEVEL > 1 */ + + oslFileHandle handle; + if (_iniName.getLength() && + osl_File_E_None == osl_openFile(_iniName.pData, &handle, osl_File_OpenFlag_Read)) + { + rtl::ByteSequence seq; + + while (osl_File_E_None == osl_readLine(handle , (sal_Sequence **)&seq)) + { + OString line( (const sal_Char *) seq.getConstArray(), seq.getLength() ); + sal_Int32 nIndex = line.indexOf('='); + if (nIndex >= 1) + { + struct rtl_bootstrap_NameValue nameValue; + nameValue.sName = OStringToOUString( + line.copy(0,nIndex).trim(), RTL_TEXTENCODING_ASCII_US ); + nameValue.sValue = OStringToOUString( + line.copy(nIndex+1).trim(), RTL_TEXTENCODING_UTF8 ); + +#if OSL_DEBUG_LEVEL > 1 + OString name_tmp = OUStringToOString(nameValue.sName, RTL_TEXTENCODING_ASCII_US); + OString value_tmp = OUStringToOString(nameValue.sValue, RTL_TEXTENCODING_UTF8); + OSL_TRACE( + __FILE__" -- pushing: name=%s value=%s\n", + name_tmp.getStr(), value_tmp.getStr() ); +#endif /* OSL_DEBUG_LEVEL > 1 */ + + _nameValueList.push_back(nameValue); + } + } + osl_closeFile(handle); + } +#if OSL_DEBUG_LEVEL > 1 + else + { + OString file_tmp = OUStringToOString(_iniName, RTL_TEXTENCODING_ASCII_US); + OSL_TRACE( __FILE__" -- couldn't open file: %s", file_tmp.getStr() ); + } +#endif /* OSL_DEBUG_LEVEL > 1 */ +} + +//---------------------------------------------------------------------------- + +Bootstrap_Impl::~Bootstrap_Impl() +{ + if (_base_ini != 0) + rtl_bootstrap_args_close( _base_ini ); +} + +//---------------------------------------------------------------------------- + +namespace { + +Bootstrap_Impl * get_static_bootstrap_handle() SAL_THROW(()) +{ + osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); + static Bootstrap_Impl * s_handle = 0; + if (s_handle == 0) + { + OUString iniName (getIniFileName_Impl()); + s_handle = static_cast< Bootstrap_Impl * >( + rtl_bootstrap_args_open( iniName.pData ) ); + if (s_handle == 0) + { + Bootstrap_Impl * that = new Bootstrap_Impl( iniName ); + ++that->_nRefCount; + s_handle = that; + } + } + return s_handle; +} + +struct FundamentalIniData { + rtlBootstrapHandle ini; + + FundamentalIniData() { + OUString uri; + ini = + ((static_cast< Bootstrap_Impl * >(get_static_bootstrap_handle())-> + getValue( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("URE_BOOTSTRAP")), + &uri.pData, 0, LOOKUP_MODE_NORMAL, false, 0)) && + resolvePathnameUrl(&uri)) + ? rtl_bootstrap_args_open(uri.pData) : NULL; + } + + ~FundamentalIniData() { rtl_bootstrap_args_close(ini); } + +private: + FundamentalIniData(FundamentalIniData &); // not defined + void operator =(FundamentalIniData &); // not defined +}; + +struct FundamentalIni: public rtl::Static< FundamentalIniData, FundamentalIni > +{}; + +} + +bool Bootstrap_Impl::getValue( + rtl::OUString const & key, rtl_uString ** value, rtl_uString * defaultValue, + LookupMode mode, bool override, ExpandRequestLink const * requestStack) + const +{ + if (mode == LOOKUP_MODE_NORMAL && + key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("URE_BOOTSTRAP"))) + { + mode = LOOKUP_MODE_URE_BOOTSTRAP; + } + if (override && getDirectValue(key, value, mode, requestStack)) { + return true; + } + if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_OS"))) { + rtl_uString_assign( + value, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(THIS_OS)).pData); + return true; + } + if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_ARCH"))) { + rtl_uString_assign( + value, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(THIS_ARCH)).pData); + return true; + } + if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_CPPU_ENV"))) { + rtl_uString_assign( + value, + (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(MY_STRING(CPPU_ENV))). + pData)); + return true; + } + if (key.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("ORIGIN"))) { + rtl_uString_assign( + value, + _iniName.copy( + 0, std::max<sal_Int32>(0, _iniName.lastIndexOf('/'))).pData); + return true; + } + if (getAmbienceValue(key, value, mode, requestStack)) { + return true; + } + if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSUSERCONFIG"))) { + rtl::OUString v; + bool b = osl::Security().getConfigDir(v); + EnsureNoFinalSlash(v); + rtl_uString_assign(value, v.pData); + return b; + } + if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSUSERHOME"))) { + rtl::OUString v; + bool b = osl::Security().getHomeDir(v); + EnsureNoFinalSlash(v); + rtl_uString_assign(value, v.pData); + return b; + } + if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSBINDIR"))) { + getExecutableDirectory_Impl(value); + return true; + } + if (_base_ini != NULL && + _base_ini->getDirectValue(key, value, mode, requestStack)) + { + return true; + } + if (!override && getDirectValue(key, value, mode, requestStack)) { + return true; + } + if (mode == LOOKUP_MODE_NORMAL) { + FundamentalIniData const & d = FundamentalIni::get(); + Bootstrap_Impl const * b = static_cast<Bootstrap_Impl const *>(d.ini); + if (b != NULL && b != this && + b->getDirectValue(key, value, mode, requestStack)) + { + return true; + } + } + if (defaultValue != NULL) { + rtl_uString_assign(value, defaultValue); + return true; + } + rtl_uString_new(value); + return false; +} + +bool Bootstrap_Impl::getDirectValue( + rtl::OUString const & key, rtl_uString ** value, LookupMode mode, + ExpandRequestLink const * requestStack) const +{ + rtl::OUString v; + if (find(_nameValueList, key, &v)) { + expandValue(value, v, mode, this, key, requestStack); + return true; + } else { + return false; + } +} + +bool Bootstrap_Impl::getAmbienceValue( + rtl::OUString const & key, rtl_uString ** value, LookupMode mode, + ExpandRequestLink const * requestStack) const +{ + rtl::OUString v; + bool f; + { + osl::MutexGuard g(osl::Mutex::getGlobalMutex()); + f = find(rtl_bootstrap_set_list::get(), key, &v); + } + if (f || getFromCommandLineArgs(key, &v) || + osl_getEnvironment(key.pData, &v.pData) == osl_Process_E_None) + { + expandValue(value, v, mode, NULL, key, requestStack); + return true; + } else { + return false; + } +} + +void Bootstrap_Impl::expandValue( + rtl_uString ** value, rtl::OUString const & text, LookupMode mode, + Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey, + ExpandRequestLink const * requestStack) const +{ + rtl_uString_assign( + value, + (mode == LOOKUP_MODE_URE_BOOTSTRAP && isPathnameUrl(text) ? + text : + recursivelyExpandMacros( + this, text, + (mode == LOOKUP_MODE_URE_BOOTSTRAP ? + LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION : mode), + requestFile, requestKey, requestStack)).pData); +} + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +namespace { + +struct bootstrap_map { + // map<> may be preferred here, but hash_map<> is implemented fully inline, + // thus there is no need to link against the stlport: + typedef std::hash_map< + rtl::OUString, Bootstrap_Impl *, + rtl::OUStringHash, std::equal_to< rtl::OUString >, + rtl::Allocator< OUString > > t; + + // get and release must only be called properly synchronized via some mutex + // (e.g., osl::Mutex::getGlobalMutex()): + + static t * get() { + if (m_map == NULL) { + m_map = new t; + } + return m_map; + } + + static void release() { + if (m_map != NULL && m_map->empty()) { + delete m_map; + m_map = NULL; + } + } + +private: + bootstrap_map(); // not defined + + static t * m_map; +}; + +bootstrap_map::t * bootstrap_map::m_map = NULL; + +} + +//---------------------------------------------------------------------------- + +rtlBootstrapHandle SAL_CALL rtl_bootstrap_args_open ( + rtl_uString * pIniName +) SAL_THROW_EXTERN_C() +{ + OUString iniName( pIniName ); + + // normalize path + FileStatus status( FileStatusMask_FileURL ); + DirectoryItem dirItem; + if (DirectoryItem::E_None != DirectoryItem::get( iniName, dirItem ) || + DirectoryItem::E_None != dirItem.getFileStatus( status )) + { + return 0; + } + iniName = status.getFileURL(); + + Bootstrap_Impl * that; + osl::ResettableMutexGuard guard( osl::Mutex::getGlobalMutex() ); + bootstrap_map::t* p_bootstrap_map = bootstrap_map::get(); + bootstrap_map::t::const_iterator iFind( p_bootstrap_map->find( iniName ) ); + if (iFind == p_bootstrap_map->end()) + { + bootstrap_map::release(); + guard.clear(); + that = new Bootstrap_Impl( iniName ); + guard.reset(); + p_bootstrap_map = bootstrap_map::get(); + iFind = p_bootstrap_map->find( iniName ); + if (iFind == p_bootstrap_map->end()) + { + ++that->_nRefCount; + ::std::pair< bootstrap_map::t::iterator, bool > insertion( + p_bootstrap_map->insert( + bootstrap_map::t::value_type( iniName, that ) ) ); + OSL_ASSERT( insertion.second ); + } + else + { + Bootstrap_Impl * obsolete = that; + that = iFind->second; + ++that->_nRefCount; + guard.clear(); + delete obsolete; + } + } + else + { + that = iFind->second; + ++that->_nRefCount; + } + return static_cast< rtlBootstrapHandle >( that ); +} + +//---------------------------------------------------------------------------- + +void SAL_CALL rtl_bootstrap_args_close ( + rtlBootstrapHandle handle +) SAL_THROW_EXTERN_C() +{ + if (handle == 0) + return; + Bootstrap_Impl * that = static_cast< Bootstrap_Impl * >( handle ); + + osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); + bootstrap_map::t* p_bootstrap_map = bootstrap_map::get(); + OSL_ASSERT( + p_bootstrap_map->find( that->_iniName )->second == that ); + --that->_nRefCount; + if (that->_nRefCount == 0) + { + ::std::size_t nLeaking = 8; // only hold up to 8 files statically + +#if OSL_DEBUG_LEVEL == 1 // nonpro + nLeaking = 0; +#elif OSL_DEBUG_LEVEL > 1 // debug + nLeaking = 1; +#endif /* OSL_DEBUG_LEVEL */ + + if (p_bootstrap_map->size() > nLeaking) + { + ::std::size_t erased = p_bootstrap_map->erase( that->_iniName ); + if (erased != 1) { + OSL_ASSERT( false ); + } + delete that; + } + bootstrap_map::release(); + } +} + +//---------------------------------------------------------------------------- + +sal_Bool SAL_CALL rtl_bootstrap_get_from_handle( + rtlBootstrapHandle handle, + rtl_uString * pName, + rtl_uString ** ppValue, + rtl_uString * pDefault +) SAL_THROW_EXTERN_C() +{ + osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); + + sal_Bool found = sal_False; + if(ppValue && pName) + { + if (handle == 0) + handle = get_static_bootstrap_handle(); + found = static_cast< Bootstrap_Impl * >( handle )->getValue( + pName, ppValue, pDefault, LOOKUP_MODE_NORMAL, false, NULL ); + } + + return found; +} + +//---------------------------------------------------------------------------- + +void SAL_CALL rtl_bootstrap_get_iniName_from_handle ( + rtlBootstrapHandle handle, + rtl_uString ** ppIniName +) SAL_THROW_EXTERN_C() +{ + if(ppIniName) + { + if(handle) + { + Bootstrap_Impl * pImpl = static_cast<Bootstrap_Impl*>(handle); + rtl_uString_assign(ppIniName, pImpl->_iniName.pData); + } + else + { + const OUString & iniName = getIniFileName_Impl(); + rtl_uString_assign(ppIniName, iniName.pData); + } + } +} + +//---------------------------------------------------------------------------- + +void SAL_CALL rtl_bootstrap_setIniFileName ( + rtl_uString * pName +) SAL_THROW_EXTERN_C() +{ + osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); + OUString & file = getIniFileName_Impl(); + file = pName; +} + +//---------------------------------------------------------------------------- + +sal_Bool SAL_CALL rtl_bootstrap_get ( + rtl_uString * pName, + rtl_uString ** ppValue, + rtl_uString * pDefault +) SAL_THROW_EXTERN_C() +{ + return rtl_bootstrap_get_from_handle(0, pName, ppValue, pDefault); +} + +//---------------------------------------------------------------------------- + +void SAL_CALL rtl_bootstrap_set ( + rtl_uString * pName, + rtl_uString * pValue +) SAL_THROW_EXTERN_C() +{ + const OUString name( pName ); + const OUString value( pValue ); + + osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); + + NameValueList& r_rtl_bootstrap_set_list = rtl_bootstrap_set_list::get(); + NameValueList::iterator iPos( r_rtl_bootstrap_set_list.begin() ); + NameValueList::iterator iEnd( r_rtl_bootstrap_set_list.end() ); + for ( ; iPos != iEnd; ++iPos ) + { + if (iPos->sName.equals( name )) + { + iPos->sValue = value; + return; + } + } + +#if OSL_DEBUG_LEVEL > 1 + OString cstr_name( OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ) ); + OString cstr_value( OUStringToOString( value, RTL_TEXTENCODING_ASCII_US ) ); + OSL_TRACE( + "bootstrap.cxx: explicitly setting: name=%s value=%s\n", + cstr_name.getStr(), cstr_value.getStr() ); +#endif /* OSL_DEBUG_LEVEL > 1 */ + + r_rtl_bootstrap_set_list.push_back( rtl_bootstrap_NameValue( name, value ) ); +} + +//---------------------------------------------------------------------------- + +void SAL_CALL rtl_bootstrap_expandMacros_from_handle ( + rtlBootstrapHandle handle, + rtl_uString ** macro +) SAL_THROW_EXTERN_C() +{ + if (handle == NULL) { + handle = get_static_bootstrap_handle(); + } + OUString expanded( expandMacros( static_cast< Bootstrap_Impl * >( handle ), + * reinterpret_cast< OUString const * >( macro ), + LOOKUP_MODE_NORMAL, NULL ) ); + rtl_uString_assign( macro, expanded.pData ); +} + +//---------------------------------------------------------------------------- + +void SAL_CALL rtl_bootstrap_expandMacros( + rtl_uString ** macro ) + SAL_THROW_EXTERN_C() +{ + rtl_bootstrap_expandMacros_from_handle(NULL, macro); +} + +void rtl_bootstrap_encode( rtl_uString const * value, rtl_uString ** encoded ) + SAL_THROW_EXTERN_C() +{ + OSL_ASSERT(value != NULL); + rtl::OUStringBuffer b; + for (sal_Int32 i = 0; i < value->length; ++i) { + sal_Unicode c = value->buffer[i]; + if (c == '$' || c == '\\') { + b.append(sal_Unicode('\\')); + } + b.append(c); + } + rtl_uString_assign(encoded, b.makeStringAndClear().pData); +} + +namespace { + +int hex(sal_Unicode c) { + return + c >= '0' && c <= '9' ? c - '0' : + c >= 'A' && c <= 'F' ? c - 'A' + 10 : + c >= 'a' && c <= 'f' ? c - 'a' + 10 : -1; +} + +sal_Unicode read(rtl::OUString const & text, sal_Int32 * pos, bool * escaped) { + OSL_ASSERT( + pos != NULL && *pos >= 0 && *pos < text.getLength() && escaped != NULL); + sal_Unicode c = text[(*pos)++]; + if (c == '\\') { + int n1, n2, n3, n4; + if (*pos < text.getLength() - 4 && text[*pos] == 'u' && + ((n1 = hex(text[*pos + 1])) >= 0) && + ((n2 = hex(text[*pos + 2])) >= 0) && + ((n3 = hex(text[*pos + 3])) >= 0) && + ((n4 = hex(text[*pos + 4])) >= 0)) + { + *pos += 5; + *escaped = true; + return static_cast< sal_Unicode >( + (n1 << 12) | (n2 << 8) | (n3 << 4) | n4); + } else if (*pos < text.getLength()) { + *escaped = true; + return text[(*pos)++]; + } + } + *escaped = false; + return c; +} + +rtl::OUString lookup( + Bootstrap_Impl const * file, LookupMode mode, bool override, + rtl::OUString const & key, ExpandRequestLink const * requestStack) +{ + rtl::OUString v; + (file == NULL ? get_static_bootstrap_handle() : file)->getValue( + key, &v.pData, NULL, mode, override, requestStack); + return v; +} + +rtl::OUString expandMacros( + Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode, + ExpandRequestLink const * requestStack) +{ + rtl::OUStringBuffer buf; + for (sal_Int32 i = 0; i < text.getLength();) { + bool escaped; + sal_Unicode c = read(text, &i, &escaped); + if (escaped || c != '$') { + buf.append(c); + } else { + if (i < text.getLength() && text[i] == '{') { + ++i; + sal_Int32 p = i; + sal_Int32 nesting = 0; + rtl::OUString seg[3]; + int n = 0; + while (i < text.getLength()) { + sal_Int32 j = i; + c = read(text, &i, &escaped); + if (!escaped) { + switch (c) { + case '{': + ++nesting; + break; + case '}': + if (nesting == 0) { + seg[n++] = text.copy(p, j - p); + goto done; + } else { + --nesting; + } + break; + case ':': + if (nesting == 0 && n < 2) { + seg[n++] = text.copy(p, j - p); + p = i; + } + break; + } + } + } + done: + for (int j = 0; j < n; ++j) { + seg[j] = expandMacros(file, seg[j], mode, requestStack); + } + if (n == 3 && seg[1].getLength() == 0) { + // For backward compatibility, treat ${file::key} the same + // as just ${file:key}: + seg[1] = seg[2]; + n = 2; + } + if (n == 1) { + buf.append(lookup(file, mode, false, seg[0], requestStack)); + } else if (n == 2) { + if (seg[0].equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM(".link"))) + { + osl::File f(seg[1]); + rtl::ByteSequence seq; + rtl::OUString line; + rtl::OUString url; + // Silently ignore any errors (is that good?): + if (f.open(OpenFlag_Read) == osl::FileBase::E_None && + f.readLine(seq) == osl::FileBase::E_None && + rtl_convertStringToUString( + &line.pData, + reinterpret_cast< char const * >( + seq.getConstArray()), + seq.getLength(), RTL_TEXTENCODING_UTF8, + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)) && + (osl::File::getFileURLFromSystemPath(line, url) == + osl::FileBase::E_None)) + { + try { + buf.append( + rtl::Uri::convertRelToAbs(seg[1], url)); + } catch (rtl::MalformedUriException &) {} + } + } else { + buf.append( + lookup( + static_cast< Bootstrap_Impl * >( + rtl::Bootstrap(seg[0]).getHandle()), + mode, false, seg[1], requestStack)); + } + } else if (seg[0].equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM(".override"))) + { + rtl::Bootstrap b(seg[1]); + Bootstrap_Impl * f = static_cast< Bootstrap_Impl * >( + b.getHandle()); + buf.append( + lookup(f, mode, f != NULL, seg[2], requestStack)); + } else { + // Going through osl::Profile, this code erroneously does + // not recursively expand macros in the resulting + // replacement text (and if it did, it would fail to detect + // cycles that pass through here): + buf.append( + rtl::OStringToOUString( + osl::Profile(seg[0]).readString( + rtl::OUStringToOString( + seg[1], RTL_TEXTENCODING_UTF8), + rtl::OUStringToOString( + seg[2], RTL_TEXTENCODING_UTF8), + rtl::OString()), + RTL_TEXTENCODING_UTF8)); + } + } else { + rtl::OUStringBuffer kbuf; + for (; i < text.getLength();) { + sal_Int32 j = i; + c = read(text, &j, &escaped); + if (!escaped && + (c == ' ' || c == '$' || c == '-' || c == '/' || + c == ';' || c == '\\')) + { + break; + } + kbuf.append(c); + i = j; + } + buf.append( + lookup( + file, mode, false, kbuf.makeStringAndClear(), + requestStack)); + } + } + } + return buf.makeStringAndClear(); +} + +} diff --git a/sal/rtl/source/byteseq.c b/sal/rtl/source/byteseq.c new file mode 100644 index 000000000000..42b905a8d78f --- /dev/null +++ b/sal/rtl/source/byteseq.c @@ -0,0 +1,254 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <osl/diagnose.h> +#include <osl/interlck.h> + +#include <rtl/byteseq.h> +#include <rtl/alloc.h> +#include <rtl/memory.h> + +/* static data to be referenced by all empty strings + * the refCount is predefined to 1 and must never become 0 ! + */ +static sal_Sequence aEmpty_rtl_ByteSeq = +{ + 1, /* sal_Int32 refCount; */ + 0, /* sal_Int32 length; */ + { 0 } /* sal_Unicode buffer[1]; */ +}; + +//================================================================================================== +void SAL_CALL rtl_byte_sequence_reference2One( + sal_Sequence ** ppSequence ) +{ + sal_Sequence * pSequence, * pNew; + sal_Int32 nElements; + + OSL_ENSURE( ppSequence, "### null ptr!" ); + pSequence = *ppSequence; + + if (pSequence->nRefCount > 1) + { + nElements = pSequence->nElements; + if (nElements) + { + pNew = (sal_Sequence *)rtl_allocateMemory( SAL_SEQUENCE_HEADER_SIZE + nElements ); + + if ( pNew != 0 ) + rtl_copyMemory( pNew->elements, pSequence->elements, nElements ); + + if (! osl_decrementInterlockedCount( &pSequence->nRefCount )) + rtl_freeMemory( pSequence ); + } + else + { + pNew = (sal_Sequence *)rtl_allocateMemory( SAL_SEQUENCE_HEADER_SIZE ); + } + + if ( pNew != 0 ) + { + pNew->nRefCount = 1; + pNew->nElements = nElements; + } + + *ppSequence = pNew; + } +} + +//================================================================================================== +void SAL_CALL rtl_byte_sequence_realloc( + sal_Sequence ** ppSequence, sal_Int32 nSize ) +{ + sal_Sequence * pSequence, * pNew; + sal_Int32 nElements; + + OSL_ENSURE( ppSequence, "### null ptr!" ); + pSequence = *ppSequence; + nElements = pSequence->nElements; + + if (nElements == nSize) + return; + + if (pSequence->nRefCount > 1) // split + { + pNew = (sal_Sequence *)rtl_allocateMemory( SAL_SEQUENCE_HEADER_SIZE + nSize ); + + if ( pNew != 0 ) + { + if (nSize > nElements) + { + rtl_copyMemory( pNew->elements, pSequence->elements, nElements ); + rtl_zeroMemory( pNew->elements + nElements, nSize - nElements ); + } + else + { + rtl_copyMemory( pNew->elements, pSequence->elements, nSize ); + } + } + + if (! osl_decrementInterlockedCount( &pSequence->nRefCount )) + rtl_freeMemory( pSequence ); + pSequence = pNew; + } + else + { + pSequence = (sal_Sequence *)rtl_reallocateMemory( + pSequence, SAL_SEQUENCE_HEADER_SIZE + nSize ); + } + + if ( pSequence != 0 ) + { + pSequence->nRefCount = 1; + pSequence->nElements = nSize; + } + + *ppSequence = pSequence; +} + +//================================================================================================== +void SAL_CALL rtl_byte_sequence_acquire( sal_Sequence *pSequence ) +{ + OSL_ASSERT( pSequence ); + osl_incrementInterlockedCount( &(pSequence->nRefCount) ); +} + +//================================================================================================== +void SAL_CALL rtl_byte_sequence_release( sal_Sequence *pSequence ) +{ + if ( pSequence != 0 ) + { + if (! osl_decrementInterlockedCount( &(pSequence->nRefCount )) ) + { + rtl_freeMemory( pSequence ); + } + } +} + +//================================================================================================== +void SAL_CALL rtl_byte_sequence_construct( sal_Sequence **ppSequence , sal_Int32 nLength ) +{ + OSL_ASSERT( ppSequence ); + if( *ppSequence ) + { + rtl_byte_sequence_release( *ppSequence ); + *ppSequence = 0; + } + + if( nLength ) + { + *ppSequence = (sal_Sequence *) rtl_allocateZeroMemory( SAL_SEQUENCE_HEADER_SIZE + nLength ); + + if ( *ppSequence != 0 ) + { + (*ppSequence)->nRefCount = 1; + (*ppSequence)->nElements = nLength; + } + } + else + { + *ppSequence = &aEmpty_rtl_ByteSeq; + rtl_byte_sequence_acquire( *ppSequence ); + } +} + +//================================================================================================== +void SAL_CALL rtl_byte_sequence_constructNoDefault( sal_Sequence **ppSequence , sal_Int32 nLength ) +{ + OSL_ASSERT( ppSequence ); + if( *ppSequence ) + { + rtl_byte_sequence_release( *ppSequence ); + *ppSequence = 0; + } + + *ppSequence = (sal_Sequence *) rtl_allocateMemory( SAL_SEQUENCE_HEADER_SIZE + nLength ); + + if ( *ppSequence != 0 ) + { + (*ppSequence)->nRefCount = 1; + (*ppSequence)->nElements = nLength; + } +} + +//================================================================================================== +void SAL_CALL rtl_byte_sequence_constructFromArray( + sal_Sequence **ppSequence, const sal_Int8 *pData , sal_Int32 nLength ) +{ + rtl_byte_sequence_constructNoDefault( ppSequence , nLength ); + if ( *ppSequence != 0 ) + rtl_copyMemory( (*ppSequence)->elements, pData, nLength ); +} + +//================================================================================================== +void SAL_CALL rtl_byte_sequence_assign( sal_Sequence **ppSequence , sal_Sequence *pSequence ) +{ + if ( *ppSequence != pSequence) + { + if( *ppSequence ) + { + rtl_byte_sequence_release( *ppSequence ); + } + *ppSequence = pSequence; + rtl_byte_sequence_acquire( *ppSequence ); + } +// else +// nothing to do + +} + +//================================================================================================== +sal_Bool SAL_CALL rtl_byte_sequence_equals( sal_Sequence *pSequence1 , sal_Sequence *pSequence2 ) +{ + OSL_ASSERT( pSequence1 ); + OSL_ASSERT( pSequence2 ); + if (pSequence1 == pSequence2) + { + return sal_True; + } + if (pSequence1->nElements != pSequence2->nElements) + { + return sal_False; + } + return (sal_Bool) + (rtl_compareMemory( + pSequence1->elements, pSequence2->elements, pSequence1->nElements ) + == 0); +} + + +//================================================================================================== +const sal_Int8 *SAL_CALL rtl_byte_sequence_getConstArray( sal_Sequence *pSequence ) +{ + return ((const sal_Int8*)(pSequence->elements)); +} + +//================================================================================================== +sal_Int32 SAL_CALL rtl_byte_sequence_getLength( sal_Sequence *pSequence ) +{ + return pSequence->nElements; +} diff --git a/sal/rtl/source/cipher.c b/sal/rtl/source/cipher.c new file mode 100644 index 000000000000..cb11f93cb8e4 --- /dev/null +++ b/sal/rtl/source/cipher.c @@ -0,0 +1,1363 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define _RTL_CIPHER_C_ "$Revision: 1.5 $" + +#include <sal/types.h> +#include <rtl/alloc.h> +#include <rtl/memory.h> +#include <rtl/cipher.h> + +/*======================================================================== + * + * rtlCipher internals. + * + *======================================================================*/ +#define RTL_CIPHER_NTOHL(c, l) \ + ((l) = ((sal_uInt32)(*((c)++))) << 24L, \ + (l) |= ((sal_uInt32)(*((c)++))) << 16L, \ + (l) |= ((sal_uInt32)(*((c)++))) << 8L, \ + (l) |= ((sal_uInt32)(*((c)++)))) + +#define RTL_CIPHER_HTONL(l, c) \ + (*((c)++) = (sal_uInt8)(((l) >> 24L) & 0xff), \ + *((c)++) = (sal_uInt8)(((l) >> 16L) & 0xff), \ + *((c)++) = (sal_uInt8)(((l) >> 8L) & 0xff), \ + *((c)++) = (sal_uInt8)(((l) ) & 0xff)) + +#define RTL_CIPHER_NTOHL64(c, xl, xr, n) \ +{ \ + (xl) = (xr) = 0; \ + (c) += (n); \ + switch ((n)) \ + { \ + case 8: (xr) = ((sal_uInt32)(*(--(c)))); \ + case 7: (xr) |= ((sal_uInt32)(*(--(c)))) << 8L; \ + case 6: (xr) |= ((sal_uInt32)(*(--(c)))) << 16L; \ + case 5: (xr) |= ((sal_uInt32)(*(--(c)))) << 24L; \ + case 4: (xl) = ((sal_uInt32)(*(--(c)))); \ + case 3: (xl) |= ((sal_uInt32)(*(--(c)))) << 8L; \ + case 2: (xl) |= ((sal_uInt32)(*(--(c)))) << 16L; \ + case 1: (xl) |= ((sal_uInt32)(*(--(c)))) << 24L; \ + } \ +} + +#define RTL_CIPHER_HTONL64(xl, xr, c, n) \ +{ \ + (c) += (n); \ + switch ((n)) \ + { \ + case 8: *(--(c)) = (sal_uInt8)(((xr) ) & 0xff); \ + case 7: *(--(c)) = (sal_uInt8)(((xr) >> 8L) & 0xff); \ + case 6: *(--(c)) = (sal_uInt8)(((xr) >> 16L) & 0xff); \ + case 5: *(--(c)) = (sal_uInt8)(((xr) >> 24L) & 0xff); \ + case 4: *(--(c)) = (sal_uInt8)(((xl) ) & 0xff); \ + case 3: *(--(c)) = (sal_uInt8)(((xl) >> 8L) & 0xff); \ + case 2: *(--(c)) = (sal_uInt8)(((xl) >> 16L) & 0xff); \ + case 1: *(--(c)) = (sal_uInt8)(((xl) >> 24L) & 0xff); \ + } \ +} + +typedef rtlCipherError (SAL_CALL cipher_init_t) ( + rtlCipher Cipher, + rtlCipherDirection Direction, + const sal_uInt8 *pKeyData, sal_Size nKeyLen, + const sal_uInt8 *pArgData, sal_Size nArgLen); + +typedef rtlCipherError (SAL_CALL cipher_update_t) ( + rtlCipher Cipher, + const void *pData, sal_Size nDatLen, + sal_uInt8 *pBuffer, sal_Size nBufLen); + +typedef void (SAL_CALL cipher_delete_t) (rtlCipher Cipher); + +/** Cipher_Impl. + */ +typedef struct cipher_impl_st +{ + rtlCipherAlgorithm m_algorithm; + rtlCipherDirection m_direction; + rtlCipherMode m_mode; + + cipher_init_t *m_init; + cipher_update_t *m_encode; + cipher_update_t *m_decode; + cipher_delete_t *m_delete; +} Cipher_Impl; + +/*======================================================================== + * + * rtlCipher implementation. + * + *======================================================================*/ +/* + * rtl_cipher_create. + */ +rtlCipher SAL_CALL rtl_cipher_create ( + rtlCipherAlgorithm Algorithm, + rtlCipherMode Mode) +{ + rtlCipher Cipher = (rtlCipher)NULL; + switch (Algorithm) + { + case rtl_Cipher_AlgorithmBF: + Cipher = rtl_cipher_createBF (Mode); + break; + + case rtl_Cipher_AlgorithmARCFOUR: + Cipher = rtl_cipher_createARCFOUR (Mode); + break; + + default: /* rtl_Cipher_AlgorithmInvalid */ + break; + } + return Cipher; +} + +/* + * rtl_cipher_init. + */ +rtlCipherError SAL_CALL rtl_cipher_init ( + rtlCipher Cipher, + rtlCipherDirection Direction, + const sal_uInt8 *pKeyData, sal_Size nKeyLen, + const sal_uInt8 *pArgData, sal_Size nArgLen) +{ + Cipher_Impl *pImpl = (Cipher_Impl*)Cipher; + if (pImpl == NULL) + return rtl_Cipher_E_Argument; + if (pImpl->m_init == NULL) + return rtl_Cipher_E_Unknown; + + return (pImpl->m_init)( + Cipher, Direction, pKeyData, nKeyLen, pArgData, nArgLen); +} + +/* + * rtl_cipher_encode. + */ +rtlCipherError SAL_CALL rtl_cipher_encode ( + rtlCipher Cipher, + const void *pData, sal_Size nDatLen, + sal_uInt8 *pBuffer, sal_Size nBufLen) +{ + Cipher_Impl *pImpl = (Cipher_Impl*)Cipher; + if (pImpl == NULL) + return rtl_Cipher_E_Argument; + if (pImpl->m_encode == NULL) + return rtl_Cipher_E_Unknown; + + return (pImpl->m_encode)(Cipher, pData, nDatLen, pBuffer, nBufLen); +} + +/* + * rtl_cipher_decode. + */ +rtlCipherError SAL_CALL rtl_cipher_decode ( + rtlCipher Cipher, + const void *pData, sal_Size nDatLen, + sal_uInt8 *pBuffer, sal_Size nBufLen) +{ + Cipher_Impl *pImpl = (Cipher_Impl*)Cipher; + if (pImpl == NULL) + return rtl_Cipher_E_Argument; + if (pImpl->m_decode == NULL) + return rtl_Cipher_E_Unknown; + + return (pImpl->m_decode)(Cipher, pData, nDatLen, pBuffer, nBufLen); +} + +/* + * rtl_cipher_destroy. + */ +void SAL_CALL rtl_cipher_destroy (rtlCipher Cipher) +{ + Cipher_Impl *pImpl = (Cipher_Impl*)Cipher; + if (pImpl && pImpl->m_delete) + pImpl->m_delete (Cipher); +} + +/*======================================================================== + * + * rtl_cipherBF (Blowfish) internals. + * + *======================================================================*/ +#define CIPHER_ROUNDS_BF 16 + +typedef struct cipherBF_key_st +{ + sal_uInt32 m_S[4][256]; + sal_uInt32 m_P[CIPHER_ROUNDS_BF + 2]; +} CipherKeyBF; + +typedef struct cipherBF_context_st +{ + CipherKeyBF m_key; + union + { + sal_uInt32 m_long[2]; + sal_uInt8 m_byte[8]; + } m_iv; + sal_uInt32 m_offset; +} CipherContextBF; + +typedef struct cipherBF_impl_st +{ + Cipher_Impl m_cipher; + CipherContextBF m_context; +} CipherBF_Impl; + +/** __rtl_cipherBF_init. + */ +static rtlCipherError __rtl_cipherBF_init ( + CipherContextBF *ctx, + rtlCipherMode eMode, + const sal_uInt8 *pKeyData, sal_Size nKeyLen, + const sal_uInt8 *pArgData, sal_Size nArgLen); + +/** __rtl_cipherBF_update. + */ +static rtlCipherError __rtl_cipherBF_update ( + CipherContextBF *ctx, + rtlCipherMode eMode, + rtlCipherDirection eDirection, + const sal_uInt8 *pData, sal_Size nDatLen, + sal_uInt8 *pBuffer, sal_Size nBufLen); + +/** __rtl_cipherBF_updateECB. + */ +static void __rtl_cipherBF_updateECB ( + CipherContextBF *ctx, + rtlCipherDirection direction, + const sal_uInt8 *pData, + sal_uInt8 *pBuffer, + sal_Size nLength); + +/** __rtl_cipherBF_updateCBC. + */ +static void __rtl_cipherBF_updateCBC ( + CipherContextBF *ctx, + rtlCipherDirection direction, + const sal_uInt8 *pData, + sal_uInt8 *pBuffer, + sal_Size nLength); + +/** __rtl_cipherBF_updateCFB. + */ +static void __rtl_cipherBF_updateCFB ( + CipherContextBF *ctx, + rtlCipherDirection direction, + const sal_uInt8 *pData, + sal_uInt8 *pBuffer); + +/** __rtl_cipher_encode. + */ +static void __rtl_cipherBF_encode ( + CipherKeyBF *key, sal_uInt32 *xl, sal_uInt32 *xr); + +/** __rtl_cipherBF_decode. + */ +static void __rtl_cipherBF_decode ( + CipherKeyBF *key, sal_uInt32 *xl, sal_uInt32 *xr); + +/** __rtl_cipherBF. + */ +static sal_uInt32 __rtl_cipherBF ( + CipherKeyBF *key, sal_uInt32 x); + +/** __rtl_cipherBF_key. + */ +static const CipherKeyBF __rtl_cipherBF_key = +{ + /* S */ + { + /* S[0] */ + { + /* 0 */ + 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L, + 0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L, + 0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L, + 0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL, + + /* 1 */ + 0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL, + 0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L, + 0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL, + 0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL, + + /* 2 */ + 0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L, + 0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L, + 0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL, + 0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL, + + /* 3 */ + 0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL, + 0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L, + 0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L, + 0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L, + + /* 4 */ + 0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L, + 0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L, + 0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL, + 0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L, + + /* 5 */ + 0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L, + 0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L, + 0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L, + 0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL, + + /* 6 */ + 0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L, + 0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL, + 0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL, + 0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L, + + /* 7 */ + 0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL, + 0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L, + 0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL, + 0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L, + + /* 8 */ + 0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L, + 0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL, + 0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L, + 0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L, + + /* 9 */ + 0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL, + 0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L, + 0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL, + 0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L, + + /* A */ + 0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L, + 0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL, + 0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L, + 0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L, + + /* B */ + 0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L, + 0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L, + 0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L, + 0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL, + + /* C */ + 0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL, + 0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L, + 0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L, + 0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L, + + /* D */ + 0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L, + 0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL, + 0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L, + 0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL, + + /* E */ + 0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL, + 0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L, + 0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L, + 0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L, + + /* F */ + 0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L, + 0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L, + 0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L, + 0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL + }, + + /* S[1] */ + { + 0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L, + 0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L, + 0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L, + 0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL, + + 0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L, + 0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L, + 0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL, + 0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L, + + 0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L, + 0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L, + 0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL, + 0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL, + + 0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L, + 0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L, + 0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L, + 0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L, + + 0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL, + 0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL, + 0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL, + 0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L, + + 0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL, + 0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L, + 0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L, + 0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL, + + 0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL, + 0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L, + 0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL, + 0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L, + + 0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL, + 0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL, + 0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L, + 0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L, + + 0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L, + 0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L, + 0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L, + 0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L, + + 0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L, + 0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL, + 0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L, + 0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL, + + 0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L, + 0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L, + 0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L, + 0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L, + + 0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L, + 0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L, + 0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L, + 0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L, + + 0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L, + 0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L, + 0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L, + 0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L, + + 0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L, + 0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L, + 0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L, + 0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L, + + 0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL, + 0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL, + 0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L, + 0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL, + + 0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L, + 0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L, + 0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L, + 0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L + }, + + /* S[2] */ + { + 0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L, + 0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L, + 0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL, + 0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L, + + 0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L, + 0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L, + 0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL, + 0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL, + + 0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL, + 0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L, + 0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L, + 0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL, + + 0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L, + 0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL, + 0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L, + 0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL, + + 0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L, + 0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL, + 0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L, + 0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL, + + 0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L, + 0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L, + 0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL, + 0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L, + + 0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L, + 0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L, + 0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L, + 0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL, + + 0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L, + 0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL, + 0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L, + 0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL, + + 0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L, + 0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL, + 0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL, + 0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL, + + 0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L, + 0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L, + 0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL, + 0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL, + + 0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL, + 0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL, + 0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL, + 0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L, + + 0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L, + 0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L, + 0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L, + 0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL, + + 0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL, + 0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L, + 0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L, + 0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L, + + 0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L, + 0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L, + 0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L, + 0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L, + + 0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L, + 0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L, + 0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L, + 0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL, + + 0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L, + 0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL, + 0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L, + 0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L + }, + + /* S[3] */ + { + 0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL, + 0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL, + 0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL, + 0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L, + + 0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L, + 0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L, + 0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L, + 0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L, + + 0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L, + 0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L, + 0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L, + 0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L, + + 0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L, + 0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L, + 0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L, + 0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL, + + 0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL, + 0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L, + 0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL, + 0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL, + + 0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL, + 0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L, + 0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL, + 0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL, + + 0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L, + 0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L, + 0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L, + 0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L, + + 0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL, + 0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL, + 0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L, + 0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L, + + 0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L, + 0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL, + 0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L, + 0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L, + + 0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L, + 0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL, + 0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L, + 0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L, + + 0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L, + 0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL, + 0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL, + 0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L, + + 0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L, + 0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L, + 0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L, + 0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL, + + 0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L, + 0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL, + 0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL, + 0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L, + + 0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L, + 0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL, + 0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L, + 0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL, + + 0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L, + 0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL, + 0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L, + 0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L, + + 0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL, + 0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L, + 0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL, + 0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L + } + }, + + /* P */ + { + 0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L, + 0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L, + 0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL, + 0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L, + 0x9216D5D9L, 0x8979FB1BL + } +}; + +/* + * __rtl_cipherBF_init. + */ +static rtlCipherError __rtl_cipherBF_init ( + CipherContextBF *ctx, + rtlCipherMode eMode, + const sal_uInt8 *pKeyData, sal_Size nKeyLen, + const sal_uInt8 *pArgData, sal_Size nArgLen) +{ + CipherKeyBF *key; + sal_uInt32 D, DL, DR; + sal_uInt16 i, j, k; + + key = &(ctx->m_key); + + rtl_copyMemory (key, &__rtl_cipherBF_key, sizeof (CipherKeyBF)); + rtl_zeroMemory (&(ctx->m_iv), sizeof(ctx->m_iv)); + ctx->m_offset = 0; + + for (i = 0, k = 0; i < CIPHER_ROUNDS_BF + 2; ++i) + { + D = 0; + for (j = 0; j < 4; ++j) + { + D = ((D << 8) | pKeyData[k]); + k++; + if (k >= nKeyLen) + k = 0; + } + key->m_P[i] ^= D; + } + + DL = 0; + DR = 0; + + for (i = 0; i < CIPHER_ROUNDS_BF + 2; i += 2) + { + __rtl_cipherBF_encode (key, &DL, &DR); + key->m_P[i ] = DL; + key->m_P[i + 1] = DR; + } + + for (i = 0; i < 4; ++i) + { + for (k = 0; k < 256; k += 2) + { + __rtl_cipherBF_encode (key, &DL, &DR); + key->m_S[i][k ] = DL; + key->m_S[i][k + 1] = DR; + } + } + + if (pArgData && nArgLen) + { + nArgLen = ((nArgLen < 8) ? nArgLen : 8); + if (eMode == rtl_Cipher_ModeStream) + { + rtl_copyMemory (ctx->m_iv.m_byte, pArgData, nArgLen); + } + else + { + RTL_CIPHER_NTOHL64 (pArgData, DL, DR, nArgLen); + ctx->m_iv.m_long[0] = DL; + ctx->m_iv.m_long[1] = DR; + } + } + + D = DL = DR = 0; + return rtl_Cipher_E_None; +} + +/* + * __rtl_cipherBF_update. + */ +static rtlCipherError __rtl_cipherBF_update ( + CipherContextBF *ctx, + rtlCipherMode eMode, + rtlCipherDirection eDirection, + const sal_uInt8 *pData, sal_Size nDatLen, + sal_uInt8 *pBuffer, sal_Size nBufLen) +{ + /* Check arguments. */ + if ((pData == NULL) || (pBuffer == NULL)) + return rtl_Cipher_E_Argument; + + if (!((0 < nDatLen) && (nDatLen <= nBufLen))) + return rtl_Cipher_E_BufferSize; + + /* Update. */ + if (eMode == rtl_Cipher_ModeECB) + { + /* Block mode. */ + while (nDatLen > 8) + { + __rtl_cipherBF_updateECB (ctx, eDirection, pData, pBuffer, 8); + nDatLen -= 8; + pData += 8; + pBuffer += 8; + } + __rtl_cipherBF_updateECB (ctx, eDirection, pData, pBuffer, nDatLen); + } + else if (eMode == rtl_Cipher_ModeCBC) + { + /* Block mode. */ + while (nDatLen > 8) + { + __rtl_cipherBF_updateCBC (ctx, eDirection, pData, pBuffer, 8); + nDatLen -= 8; + pData += 8; + pBuffer += 8; + } + __rtl_cipherBF_updateCBC (ctx, eDirection, pData, pBuffer, nDatLen); + } + else + { + /* Stream mode. */ + while (nDatLen > 0) + { + __rtl_cipherBF_updateCFB (ctx, eDirection, pData, pBuffer); + nDatLen -= 1; + pData += 1; + pBuffer += 1; + } + } + return rtl_Cipher_E_None; +} + +/* + * __rtl_cipherBF_updateECB. + */ +static void __rtl_cipherBF_updateECB ( + CipherContextBF *ctx, + rtlCipherDirection direction, + const sal_uInt8 *pData, + sal_uInt8 *pBuffer, + sal_Size nLength) +{ + CipherKeyBF *key; + sal_uInt32 DL, DR; + + key = &(ctx->m_key); + if (direction == rtl_Cipher_DirectionEncode) + { + RTL_CIPHER_NTOHL64(pData, DL, DR, nLength); + + __rtl_cipherBF_encode (key, &DL, &DR); + + RTL_CIPHER_HTONL(DL, pBuffer); + RTL_CIPHER_HTONL(DR, pBuffer); + } + else + { + RTL_CIPHER_NTOHL(pData, DL); + RTL_CIPHER_NTOHL(pData, DR); + + __rtl_cipherBF_decode (key, &DL, &DR); + + RTL_CIPHER_HTONL64(DL, DR, pBuffer, nLength); + } + DL = DR = 0; +} + +/* + * __rtl_cipherBF_updateCBC. + */ +static void __rtl_cipherBF_updateCBC ( + CipherContextBF *ctx, + rtlCipherDirection direction, + const sal_uInt8 *pData, + sal_uInt8 *pBuffer, + sal_Size nLength) +{ + CipherKeyBF *key; + sal_uInt32 DL, DR; + + key = &(ctx->m_key); + if (direction == rtl_Cipher_DirectionEncode) + { + RTL_CIPHER_NTOHL64(pData, DL, DR, nLength); + + DL ^= ctx->m_iv.m_long[0]; + DR ^= ctx->m_iv.m_long[1]; + + __rtl_cipherBF_encode (key, &DL, &DR); + + ctx->m_iv.m_long[0] = DL; + ctx->m_iv.m_long[1] = DR; + + RTL_CIPHER_HTONL(DL, pBuffer); + RTL_CIPHER_HTONL(DR, pBuffer); + } + else + { + sal_uInt32 IVL, IVR; + + RTL_CIPHER_NTOHL(pData, DL); + RTL_CIPHER_NTOHL(pData, DR); + + IVL = DL; + IVR = DR; + + __rtl_cipherBF_decode (key, &DL, &DR); + + DL ^= ctx->m_iv.m_long[0]; + DR ^= ctx->m_iv.m_long[1]; + + ctx->m_iv.m_long[0] = IVL; + ctx->m_iv.m_long[1] = IVR; + + RTL_CIPHER_HTONL64(DL, DR, pBuffer, nLength); + IVL = IVR = 0; + } + DL = DR = 0; +} + +/* + * __rtl_cipherBF_updateCFB. + */ +static void __rtl_cipherBF_updateCFB ( + CipherContextBF *ctx, + rtlCipherDirection direction, + const sal_uInt8 *pData, + sal_uInt8 *pBuffer) +{ + sal_uInt8 *iv; + sal_uInt32 k; + + iv = ctx->m_iv.m_byte; + k = ctx->m_offset; + + if (k == 0) + { + sal_uInt32 IVL, IVR; + + RTL_CIPHER_NTOHL64(iv, IVL, IVR, 8); + __rtl_cipherBF_encode (&(ctx->m_key), &IVL, &IVR); + RTL_CIPHER_HTONL64(IVL, IVR, iv, 8); + + IVL = IVR = 0; + } + + if (direction == rtl_Cipher_DirectionEncode) + { + iv[k] ^= *pData; + *pBuffer = iv[k]; + } + else + { + sal_uInt8 c = iv[k]; + iv[k] = *pData; + *pBuffer = *pData ^ c; + c = 0; + } + + ctx->m_offset = ((k + 1) & 0x07); + iv = NULL; +} + +/* + * __rtl_cipherBF_encode. + */ +static void __rtl_cipherBF_encode ( + CipherKeyBF *key, sal_uInt32 *xl, sal_uInt32 *xr) +{ + sal_uInt32 t, XL, XR; + sal_uInt16 i; + + XL = *xl; + XR = *xr; + + for (i = 0; i < CIPHER_ROUNDS_BF; ++i) + { + XL ^= key->m_P[i]; + XR ^= __rtl_cipherBF (key, XL); + + t = XL; + XL = XR; + XR = t; + } + + t = XL; + XL = XR; + XR = t; + + XR ^= key->m_P[CIPHER_ROUNDS_BF ]; + XL ^= key->m_P[CIPHER_ROUNDS_BF + 1]; + + *xl = XL; + *xr = XR; + + t = XL = XR = 0; +} + +/* + * __rtl_cipherBF_decode. + */ +static void __rtl_cipherBF_decode ( + CipherKeyBF *key, sal_uInt32 *xl, sal_uInt32 *xr) +{ + sal_uInt32 t, XL, XR; + sal_uInt16 i; + + XL = *xl; + XR = *xr; + + for (i = CIPHER_ROUNDS_BF + 1; i > 1; --i) + { + XL ^= key->m_P[i]; + XR ^= __rtl_cipherBF (key, XL); + + t = XL; + XL = XR; + XR = t; + } + + t = XL; + XL = XR; + XR = t; + + XR ^= key->m_P[1]; + XL ^= key->m_P[0]; + + *xl = XL; + *xr = XR; + + t = XL = XR = 0; +} + +/* + * __rtl_cipherBF. + */ +static sal_uInt32 __rtl_cipherBF (CipherKeyBF *key, sal_uInt32 x) +{ + sal_uInt16 a, b, c, d; + sal_uInt32 y; + + d = (sal_uInt16)(x & 0x00ff); + x >>= 8; + c = (sal_uInt16)(x & 0x00ff); + x >>= 8; + b = (sal_uInt16)(x & 0x00ff); + x >>= 8; + a = (sal_uInt16)(x & 0x00ff); + + y = key->m_S[0][a]; + y += key->m_S[1][b]; + y ^= key->m_S[2][c]; + y += key->m_S[3][d]; + + return y; +} + +/*======================================================================== + * + * rtl_cipherBF (Blowfish) implementation. + * + * Reference: + * Bruce Schneier: Applied Cryptography, 2nd edition, ch. 14.3 + * + *======================================================================*/ +/* + * rtl_cipher_createBF. + */ +rtlCipher SAL_CALL rtl_cipher_createBF (rtlCipherMode Mode) +{ + CipherBF_Impl *pImpl = (CipherBF_Impl*)NULL; + + if (Mode == rtl_Cipher_ModeInvalid) + return ((rtlCipher)NULL); + + pImpl = ((CipherBF_Impl*)rtl_allocateZeroMemory (sizeof (CipherBF_Impl))); + if (pImpl) + { + pImpl->m_cipher.m_algorithm = rtl_Cipher_AlgorithmBF; + pImpl->m_cipher.m_direction = rtl_Cipher_DirectionInvalid; + pImpl->m_cipher.m_mode = Mode; + + pImpl->m_cipher.m_init = rtl_cipher_initBF; + pImpl->m_cipher.m_encode = rtl_cipher_encodeBF; + pImpl->m_cipher.m_decode = rtl_cipher_decodeBF; + pImpl->m_cipher.m_delete = rtl_cipher_destroyBF; + } + return ((rtlCipher)pImpl); +} + +/* + * rtl_cipher_initBF. + */ +rtlCipherError SAL_CALL rtl_cipher_initBF ( + rtlCipher Cipher, + rtlCipherDirection Direction, + const sal_uInt8 *pKeyData, sal_Size nKeyLen, + const sal_uInt8 *pArgData, sal_Size nArgLen) +{ + CipherBF_Impl *pImpl = (CipherBF_Impl*)Cipher; + + if ((pImpl == NULL) || (pKeyData == NULL)) + return rtl_Cipher_E_Argument; + + if (!(pImpl->m_cipher.m_algorithm == rtl_Cipher_AlgorithmBF)) + return rtl_Cipher_E_Algorithm; + + if (!(Direction == rtl_Cipher_DirectionInvalid)) + pImpl->m_cipher.m_direction = Direction; + else + return rtl_Cipher_E_Direction; + + return __rtl_cipherBF_init ( + &(pImpl->m_context), pImpl->m_cipher.m_mode, + pKeyData, nKeyLen, pArgData, nArgLen); +} + +/* + * rtl_cipher_encodeBF. + */ +rtlCipherError SAL_CALL rtl_cipher_encodeBF ( + rtlCipher Cipher, + const void *pData, sal_Size nDatLen, + sal_uInt8 *pBuffer, sal_Size nBufLen) +{ + CipherBF_Impl *pImpl = (CipherBF_Impl*)Cipher; + if (pImpl == NULL) + return rtl_Cipher_E_Argument; + + if (!(pImpl->m_cipher.m_algorithm == rtl_Cipher_AlgorithmBF)) + return rtl_Cipher_E_Algorithm; + + if (pImpl->m_cipher.m_direction == rtl_Cipher_DirectionInvalid) + return rtl_Cipher_E_Direction; + if (pImpl->m_cipher.m_direction == rtl_Cipher_DirectionDecode) + return rtl_Cipher_E_Direction; + + return __rtl_cipherBF_update ( + &(pImpl->m_context), pImpl->m_cipher.m_mode, + rtl_Cipher_DirectionEncode, + (const sal_uInt8*)pData, nDatLen, pBuffer, nBufLen); +} + +/* + * rtl_cipher_decodeBF. + */ +rtlCipherError SAL_CALL rtl_cipher_decodeBF ( + rtlCipher Cipher, + const void *pData, sal_Size nDatLen, + sal_uInt8 *pBuffer, sal_Size nBufLen) +{ + CipherBF_Impl *pImpl = (CipherBF_Impl*)Cipher; + if (pImpl == NULL) + return rtl_Cipher_E_Argument; + + if (!(pImpl->m_cipher.m_algorithm == rtl_Cipher_AlgorithmBF)) + return rtl_Cipher_E_Algorithm; + + if (pImpl->m_cipher.m_direction == rtl_Cipher_DirectionInvalid) + return rtl_Cipher_E_Direction; + if (pImpl->m_cipher.m_direction == rtl_Cipher_DirectionEncode) + return rtl_Cipher_E_Direction; + + return __rtl_cipherBF_update ( + &(pImpl->m_context), pImpl->m_cipher.m_mode, + rtl_Cipher_DirectionDecode, + (const sal_uInt8*)pData, nDatLen, pBuffer, nBufLen); +} + +/* + * rtl_cipher_destroyBF. + */ +void SAL_CALL rtl_cipher_destroyBF (rtlCipher Cipher) +{ + CipherBF_Impl *pImpl = (CipherBF_Impl*)Cipher; + if (pImpl) + { + if (pImpl->m_cipher.m_algorithm == rtl_Cipher_AlgorithmBF) + rtl_freeZeroMemory (pImpl, sizeof (CipherBF_Impl)); + else + rtl_freeMemory (pImpl); + } +} + +/*======================================================================== + * + * rtl_cipher_ARCFOUR (RC4) internals. + * + *======================================================================*/ +#define CIPHER_CBLOCK_ARCFOUR 256 + +typedef struct cipherARCFOUR_context_st +{ + unsigned int m_S[CIPHER_CBLOCK_ARCFOUR]; + unsigned int m_X, m_Y; +} ContextARCFOUR_Impl; + +typedef struct cipherARCFOUR_impl_st +{ + Cipher_Impl m_cipher; + ContextARCFOUR_Impl m_context; +} CipherARCFOUR_Impl; + +/** rtl_cipherARCFOUR_update_Impl. + */ +static rtlCipherError rtl_cipherARCFOUR_update_Impl ( + ContextARCFOUR_Impl *ctx, + const sal_uInt8 *pData, sal_Size nDatLen, + sal_uInt8 *pBuffer, sal_Size nBufLen); + +/* + * rtl_cipherARCFOUR_init_Impl. + */ +static rtlCipherError rtl_cipherARCFOUR_init_Impl ( + ContextARCFOUR_Impl *ctx, + const sal_uInt8 *pKeyData, sal_Size nKeyLen) +{ + unsigned int K[CIPHER_CBLOCK_ARCFOUR]; + unsigned int *L, *S; + unsigned int x, y, t; + sal_Size n, k; + + S = &(ctx->m_S[0]); + + /* Initialize S linearly. */ + for (x = 0; x < CIPHER_CBLOCK_ARCFOUR; x++) + S[x] = x; + + /* Initialize K with key, repeat key as necessary. */ + for (L = K, n = CIPHER_CBLOCK_ARCFOUR; n > nKeyLen; n -= nKeyLen) + { + for (k = 0; k < nKeyLen; k++) L[k] = pKeyData[k]; + L += nKeyLen; + } + for (k = 0; k < n; k++) L[k] = pKeyData[k]; + + /* Initialize S with K. */ + for (x = 0, y = 0; x < CIPHER_CBLOCK_ARCFOUR; x++) + { + y = (y + S[x] + K[x]) % CIPHER_CBLOCK_ARCFOUR; + t = S[x], S[x] = S[y], S[y] = t; /* swap S[x] and S[y] */ + } + + /* Initialize counters X and Y. */ + ctx->m_X = 0; + ctx->m_Y = 0; + + return rtl_Cipher_E_None; +} + +/* + * rtl_cipherARCFOUR_update_Impl. + */ +static rtlCipherError rtl_cipherARCFOUR_update_Impl ( + ContextARCFOUR_Impl *ctx, + const sal_uInt8 *pData, sal_Size nDatLen, + sal_uInt8 *pBuffer, sal_Size nBufLen) +{ + register unsigned int *S; + register unsigned int x, y, t; + sal_Size k; + + /* Check arguments. */ + if ((pData == NULL) || (pBuffer == NULL)) + return rtl_Cipher_E_Argument; + + if (!((0 < nDatLen) && (nDatLen <= nBufLen))) + return rtl_Cipher_E_BufferSize; + + /* Update. */ + S = &(ctx->m_S[0]); + for (k = 0; k < nDatLen; k++) + { + /* Update counters X and Y. */ + x = ctx->m_X; + y = ctx->m_Y; + x = (x + 1 ) % CIPHER_CBLOCK_ARCFOUR; + y = (y + S[x]) % CIPHER_CBLOCK_ARCFOUR; + ctx->m_X = x; + ctx->m_Y = y; + + /* Swap S[x] and S[y]. */ + t = S[x], S[x] = S[y], S[y] = t; + + /* Evaluate next key byte S[t]. */ + t = (S[x] + S[y]) % CIPHER_CBLOCK_ARCFOUR; + pBuffer[k] = pData[k] ^ ((sal_uInt8)(S[t] & 0xff)); + } + + return rtl_Cipher_E_None; +} + +/*======================================================================== + * + * rtl_cipher_ARCFOUR (RC4) implementation. + * + * Reference: + * Bruce Schneier: Applied Cryptography, 2nd edition, ch. 17.1 + * + *======================================================================*/ +/* + * rtl_cipher_createARCFOUR. + */ +rtlCipher SAL_CALL rtl_cipher_createARCFOUR (rtlCipherMode Mode) +{ + CipherARCFOUR_Impl *pImpl = (CipherARCFOUR_Impl*)NULL; + + if (!(Mode == rtl_Cipher_ModeStream)) + return ((rtlCipher)NULL); + + pImpl = ((CipherARCFOUR_Impl*)rtl_allocateZeroMemory (sizeof (CipherARCFOUR_Impl))); + if (pImpl) + { + pImpl->m_cipher.m_algorithm = rtl_Cipher_AlgorithmARCFOUR; + pImpl->m_cipher.m_direction = rtl_Cipher_DirectionInvalid; + pImpl->m_cipher.m_mode = rtl_Cipher_ModeStream; + + pImpl->m_cipher.m_init = rtl_cipher_initARCFOUR; + pImpl->m_cipher.m_encode = rtl_cipher_encodeARCFOUR; + pImpl->m_cipher.m_decode = rtl_cipher_decodeARCFOUR; + pImpl->m_cipher.m_delete = rtl_cipher_destroyARCFOUR; + } + return ((rtlCipher)pImpl); +} + +/* + * rtl_cipher_initARCFOUR. + */ +rtlCipherError SAL_CALL rtl_cipher_initARCFOUR ( + rtlCipher Cipher, + rtlCipherDirection Direction, + const sal_uInt8 *pKeyData, sal_Size nKeyLen, + const sal_uInt8 *pArgData, sal_Size nArgLen) +{ + CipherARCFOUR_Impl *pImpl = (CipherARCFOUR_Impl*)Cipher; + (void) pArgData; // avoid warning + (void) nArgLen; // avoid warning + + if ((pImpl == NULL) || (pKeyData == NULL)) + return rtl_Cipher_E_Argument; + + if (!(pImpl->m_cipher.m_algorithm == rtl_Cipher_AlgorithmARCFOUR)) + return rtl_Cipher_E_Algorithm; + + if (!(Direction == rtl_Cipher_DirectionInvalid)) + pImpl->m_cipher.m_direction = Direction; + else + return rtl_Cipher_E_Direction; + + return rtl_cipherARCFOUR_init_Impl (&(pImpl->m_context), pKeyData, nKeyLen); +} + +/* + * rtl_cipher_encodeARCFOUR. + */ +rtlCipherError SAL_CALL rtl_cipher_encodeARCFOUR ( + rtlCipher Cipher, + const void *pData, sal_Size nDatLen, + sal_uInt8 *pBuffer, sal_Size nBufLen) +{ + CipherARCFOUR_Impl *pImpl = (CipherARCFOUR_Impl*)Cipher; + if (pImpl == NULL) + return rtl_Cipher_E_Argument; + + if (!(pImpl->m_cipher.m_algorithm == rtl_Cipher_AlgorithmARCFOUR)) + return rtl_Cipher_E_Algorithm; + + if (pImpl->m_cipher.m_direction == rtl_Cipher_DirectionInvalid) + return rtl_Cipher_E_Direction; + + return rtl_cipherARCFOUR_update_Impl ( + &(pImpl->m_context), + (const sal_uInt8*)pData, nDatLen, pBuffer, nBufLen); +} + +/* + * rtl_cipher_decodeARCFOUR. + */ +rtlCipherError SAL_CALL rtl_cipher_decodeARCFOUR ( + rtlCipher Cipher, + const void *pData, sal_Size nDatLen, + sal_uInt8 *pBuffer, sal_Size nBufLen) +{ + CipherARCFOUR_Impl *pImpl = (CipherARCFOUR_Impl*)Cipher; + if (pImpl == NULL) + return rtl_Cipher_E_Argument; + + if (!(pImpl->m_cipher.m_algorithm == rtl_Cipher_AlgorithmARCFOUR)) + return rtl_Cipher_E_Algorithm; + + if (pImpl->m_cipher.m_direction == rtl_Cipher_DirectionInvalid) + return rtl_Cipher_E_Direction; + + return rtl_cipherARCFOUR_update_Impl ( + &(pImpl->m_context), + (const sal_uInt8*)pData, nDatLen, pBuffer, nBufLen); +} + +/* + * rtl_cipher_destroyARCFOUR. + */ +void SAL_CALL rtl_cipher_destroyARCFOUR (rtlCipher Cipher) +{ + CipherARCFOUR_Impl *pImpl = (CipherARCFOUR_Impl*)Cipher; + if (pImpl) + { + if (pImpl->m_cipher.m_algorithm == rtl_Cipher_AlgorithmARCFOUR) + rtl_freeZeroMemory (pImpl, sizeof (CipherARCFOUR_Impl)); + else + rtl_freeMemory (pImpl); + } +} diff --git a/sal/rtl/source/cmdargs.cxx b/sal/rtl/source/cmdargs.cxx new file mode 100644 index 000000000000..dc14cf59d031 --- /dev/null +++ b/sal/rtl/source/cmdargs.cxx @@ -0,0 +1,109 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include <osl/mutex.hxx> +#include <rtl/process.h> +#include <rtl/ustring.hxx> + +namespace { + +rtl_uString ** g_ppCommandArgs = 0; +sal_uInt32 g_nCommandArgCount = 0; + +struct ArgHolder +{ + ~ArgHolder(); +}; + +ArgHolder::~ArgHolder() +{ + while (g_nCommandArgCount > 0) + rtl_uString_release (g_ppCommandArgs[--g_nCommandArgCount]); + + rtl_freeMemory (g_ppCommandArgs); + g_ppCommandArgs = 0; +} + +// The destructor of this static ArgHolder is "activated" by the assignments to +// g_ppCommandArgs and g_nCommandArgCount in init(): +ArgHolder argHolder; + +void init() +{ + osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); + if (!g_ppCommandArgs) + { + sal_Int32 i, n = osl_getCommandArgCount(); + + g_ppCommandArgs = + (rtl_uString**)rtl_allocateZeroMemory (n * sizeof(rtl_uString*)); + for (i = 0; i < n; i++) + { + rtl_uString * pArg = 0; + osl_getCommandArg (i, &pArg); + if (('-' == pArg->buffer[0] || '/' == pArg->buffer[0]) && + 'e' == pArg->buffer[1] && + 'n' == pArg->buffer[2] && + 'v' == pArg->buffer[3] && + ':' == pArg->buffer[4] && + rtl_ustr_indexOfChar (&(pArg->buffer[5]), '=') >= 0 ) + { + // ignore. + rtl_uString_release (pArg); + } + else + { + // assign. + g_ppCommandArgs[g_nCommandArgCount++] = pArg; + } + } + } +} + +} + +oslProcessError SAL_CALL rtl_getAppCommandArg ( + sal_uInt32 nArg, rtl_uString **ppCommandArg) +{ + init(); + oslProcessError result = osl_Process_E_NotFound; + if( nArg < g_nCommandArgCount ) + { + rtl_uString_assign( ppCommandArg, g_ppCommandArgs[nArg] ); + result = osl_Process_E_None; + } + return (result); +} + +sal_uInt32 SAL_CALL rtl_getAppCommandArgCount (void) +{ + init(); + return g_nCommandArgCount; +} diff --git a/sal/rtl/source/crc.c b/sal/rtl/source/crc.c new file mode 100644 index 000000000000..d8fd53c3b330 --- /dev/null +++ b/sal/rtl/source/crc.c @@ -0,0 +1,164 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define _RTL_CRC_C_ "$Revision: 1.3 $" + +#include <sal/types.h> +#include <rtl/crc.h> + +/*======================================================================== + * + * rtl_crc32Table (CRC polynomial 0xEDB88320). + * + *======================================================================*/ +static const sal_uInt32 rtl_crc32Table[256] = +{ + /* 0 */ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + + /* 1 */ + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + + /* 2 */ + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + + /* 3 */ + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + + /* 4 */ + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + + /* 5 */ + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + + /* 6 */ + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + + /* 7 */ + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + + /* 8 */ + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + + /* 9 */ + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + + /* A */ + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + + /* B */ + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + + /* C */ + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + + /* D */ + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + + /* E */ + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + + /* F */ + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +/*======================================================================== + * + * rtl_crc32 implementation. + * + *======================================================================*/ +#define UPDCRC32(crc, octet) \ + (rtl_crc32Table[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8)) + +/* + * rtl_crc32. + */ +sal_uInt32 SAL_CALL rtl_crc32 ( + sal_uInt32 Crc, + const void *Data, sal_uInt32 DatLen) +{ + if (Data) + { + register const sal_uInt8 *p = (const sal_uInt8 *)Data; + register const sal_uInt8 *q = p + DatLen; + + Crc = ~Crc; + while (p < q) + Crc = UPDCRC32(Crc, *(p++)); + Crc = ~Crc; + } + return Crc; +} + diff --git a/sal/rtl/source/debugprint.cxx b/sal/rtl/source/debugprint.cxx new file mode 100644 index 000000000000..9b86ca077446 --- /dev/null +++ b/sal/rtl/source/debugprint.cxx @@ -0,0 +1,58 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include <rtl/strbuf.hxx> +#include <rtl/ustring.hxx> + +const sal_Char *dbg_dump(const rtl::OString &rStr) +{ + static rtl::OStringBuffer aStr; + + aStr = rtl::OStringBuffer(rStr); + aStr.append(static_cast<char>(0)); + return aStr.getStr(); +} + +const sal_Char *dbg_dump(const rtl::OUString &rStr) +{ + return dbg_dump(rtl::OUStringToOString(rStr, RTL_TEXTENCODING_UTF8)); +} + +const sal_Char *dbg_dump(rtl_String *pStr) +{ + return dbg_dump(rtl::OString(pStr)); +} + +const sal_Char *dbg_dump(rtl_uString *pStr) +{ + return dbg_dump(rtl::OUString(pStr)); +} + +/* vi:set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/sal/rtl/source/digest.c b/sal/rtl/source/digest.c new file mode 100644 index 000000000000..1d07fdbdc167 --- /dev/null +++ b/sal/rtl/source/digest.c @@ -0,0 +1,2118 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define _RTL_DIGEST_C_ "$Revision: 1.9 $" + +#include <sal/types.h> +#include <sal/macros.h> +#include <osl/endian.h> +#include <rtl/alloc.h> +#include <rtl/memory.h> +#include <rtl/digest.h> + +/*======================================================================== + * + * rtlDigest internals. + * + *======================================================================*/ +#define RTL_DIGEST_CREATE(T) ((T*)(rtl_allocateZeroMemory(sizeof(T)))) + +#define RTL_DIGEST_ROTL(a,n) (((a) << (n)) | ((a) >> (32 - (n)))) + +#define RTL_DIGEST_HTONL(l,c) \ + (*((c)++) = (sal_uInt8)(((l) >> 24L) & 0xff), \ + *((c)++) = (sal_uInt8)(((l) >> 16L) & 0xff), \ + *((c)++) = (sal_uInt8)(((l) >> 8L) & 0xff), \ + *((c)++) = (sal_uInt8)(((l) ) & 0xff)) + +#define RTL_DIGEST_LTOC(l,c) \ + (*((c)++) = (sal_uInt8)(((l) ) & 0xff), \ + *((c)++) = (sal_uInt8)(((l) >> 8L) & 0xff), \ + *((c)++) = (sal_uInt8)(((l) >> 16L) & 0xff), \ + *((c)++) = (sal_uInt8)(((l) >> 24L) & 0xff)) + +typedef rtlDigestError (SAL_CALL Digest_init_t) ( + void *ctx, const sal_uInt8 *Data, sal_uInt32 DatLen); + +typedef void (SAL_CALL Digest_delete_t) (void *ctx); + +typedef rtlDigestError (SAL_CALL Digest_update_t) ( + void *ctx, const void *Data, sal_uInt32 DatLen); + +typedef rtlDigestError (SAL_CALL Digest_get_t) ( + void *ctx, sal_uInt8 *Buffer, sal_uInt32 BufLen); + +typedef struct digest_impl_st +{ + rtlDigestAlgorithm m_algorithm; + sal_uInt32 m_length; + + Digest_init_t *m_init; + Digest_delete_t *m_delete; + Digest_update_t *m_update; + Digest_get_t *m_get; +} Digest_Impl; + +/* + * __rtl_digest_swapLong. + */ +static void __rtl_digest_swapLong (sal_uInt32 *pData, sal_uInt32 nDatLen) +{ + register sal_uInt32 *X; + register int i, n; + + X = pData; + n = nDatLen; + + for (i = 0; i < n; i++) + X[i] = OSL_SWAPDWORD(X[i]); +} + +/*======================================================================== + * + * rtlDigest implementation. + * + *======================================================================*/ +/* + * rtl_digest_create. + */ +rtlDigest SAL_CALL rtl_digest_create (rtlDigestAlgorithm Algorithm) +{ + rtlDigest Digest = (rtlDigest)NULL; + switch (Algorithm) + { + case rtl_Digest_AlgorithmMD2: + Digest = rtl_digest_createMD2(); + break; + + case rtl_Digest_AlgorithmMD5: + Digest = rtl_digest_createMD5(); + break; + + case rtl_Digest_AlgorithmSHA: + Digest = rtl_digest_createSHA(); + break; + + case rtl_Digest_AlgorithmSHA1: + Digest = rtl_digest_createSHA1(); + break; + + case rtl_Digest_AlgorithmHMAC_MD5: + Digest = rtl_digest_createHMAC_MD5(); + break; + + case rtl_Digest_AlgorithmHMAC_SHA1: + Digest = rtl_digest_createHMAC_SHA1(); + break; + + default: /* rtl_Digest_AlgorithmInvalid */ + break; + } + return Digest; +} + +/* + * rtl_digest_queryAlgorithm. + */ +rtlDigestAlgorithm SAL_CALL rtl_digest_queryAlgorithm (rtlDigest Digest) +{ + Digest_Impl *pImpl = (Digest_Impl *)Digest; + if (pImpl) + return pImpl->m_algorithm; + else + return rtl_Digest_AlgorithmInvalid; +} + +/* + * rtl_digest_queryLength. + */ +sal_uInt32 SAL_CALL rtl_digest_queryLength (rtlDigest Digest) +{ + Digest_Impl *pImpl = (Digest_Impl *)Digest; + if (pImpl) + return pImpl->m_length; + else + return 0; +} + +/* + * rtl_digest_init. + */ +rtlDigestError SAL_CALL rtl_digest_init ( + rtlDigest Digest, const sal_uInt8 *pData, sal_uInt32 nDatLen) +{ + Digest_Impl *pImpl = (Digest_Impl *)Digest; + if (pImpl) + { + if (pImpl->m_init) + return pImpl->m_init (Digest, pData, nDatLen); + else + return rtl_Digest_E_None; + } + return rtl_Digest_E_Argument; +} + +/* + * rtl_digest_update. + */ +rtlDigestError SAL_CALL rtl_digest_update ( + rtlDigest Digest, const void *pData, sal_uInt32 nDatLen) +{ + Digest_Impl *pImpl = (Digest_Impl *)Digest; + if (pImpl && pImpl->m_update) + return pImpl->m_update (Digest, pData, nDatLen); + else + return rtl_Digest_E_Argument; +} + +/* + * rtl_digest_get. + */ +rtlDigestError SAL_CALL rtl_digest_get ( + rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + Digest_Impl *pImpl = (Digest_Impl *)Digest; + if (pImpl && pImpl->m_get) + return pImpl->m_get (Digest, pBuffer, nBufLen); + else + return rtl_Digest_E_Argument; +} + +/* + * rtl_digest_destroy. + */ +void SAL_CALL rtl_digest_destroy (rtlDigest Digest) +{ + Digest_Impl *pImpl = (Digest_Impl *)Digest; + if (pImpl && pImpl->m_delete) + pImpl->m_delete (Digest); +} + +/*======================================================================== + * + * rtl_digest_MD2 internals. + * + *======================================================================*/ +#define DIGEST_CBLOCK_MD2 16 +#define DIGEST_LBLOCK_MD2 16 + +typedef struct digestMD2_context_st +{ + sal_uInt32 m_nDatLen; + sal_uInt8 m_pData[DIGEST_CBLOCK_MD2]; + sal_uInt32 m_state[DIGEST_LBLOCK_MD2]; + sal_uInt32 m_chksum[DIGEST_LBLOCK_MD2]; +} DigestContextMD2; + +typedef struct digestMD2_impl_st +{ + Digest_Impl m_digest; + DigestContextMD2 m_context; +} DigestMD2_Impl; + +static void __rtl_digest_initMD2 (DigestContextMD2 *ctx); +static void __rtl_digest_updateMD2 (DigestContextMD2 *ctx); +static void __rtl_digest_endMD2 (DigestContextMD2 *ctx); + +static const sal_uInt32 S[256] = +{ + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, + 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, + 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, + 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, + 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, + 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, + 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, + 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, + 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, + 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, + 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, + 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, + 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, + 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, + 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, + 0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, + 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, + 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, + 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, + 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, + 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, + 0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, + 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, + 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, + 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, + 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, + 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, + 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, + 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, + 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14, +}; + +/* + * __rtl_digest_MD2. + */ +static const Digest_Impl __rtl_digest_MD2 = +{ + rtl_Digest_AlgorithmMD2, + RTL_DIGEST_LENGTH_MD2, + + NULL, + rtl_digest_destroyMD2, + rtl_digest_updateMD2, + rtl_digest_getMD2 +}; + +/* + * __rtl_digest_initMD2. + */ +static void __rtl_digest_initMD2 (DigestContextMD2 *ctx) +{ + rtl_zeroMemory (ctx, sizeof (DigestContextMD2)); +} + +/* + * __rtl_digest_updateMD2. + */ +static void __rtl_digest_updateMD2 (DigestContextMD2 *ctx) +{ + register sal_uInt8 *X; + register sal_uInt32 *sp1, *sp2; + register sal_uInt32 i, k, t; + + sal_uInt32 state[48]; + + X = ctx->m_pData; + sp1 = ctx->m_state; + sp2 = ctx->m_chksum; + + k = sp2[DIGEST_LBLOCK_MD2 - 1]; + for (i = 0; i < 16; i++) + { + state[i + 0] = sp1[i]; + state[i + 16] = t = X[i]; + state[i + 32] = t ^ sp1[i]; + k = sp2[i] ^= S[t^k]; + } + + t = 0; + for (i = 0; i < 18; i++) + { + for (k = 0; k < 48; k += 8) + { + t = state[k + 0] ^= S[t]; + t = state[k + 1] ^= S[t]; + t = state[k + 2] ^= S[t]; + t = state[k + 3] ^= S[t]; + t = state[k + 4] ^= S[t]; + t = state[k + 5] ^= S[t]; + t = state[k + 6] ^= S[t]; + t = state[k + 7] ^= S[t]; + } + t = ((t + i) & 0xff); + } + + rtl_copyMemory (sp1, state, 16 * sizeof(sal_uInt32)); + rtl_zeroMemory (state, 48 * sizeof(sal_uInt32)); +} + +/* + * __rtl_digest_endMD2. + */ +static void __rtl_digest_endMD2 (DigestContextMD2 *ctx) +{ + register sal_uInt8 *X; + register sal_uInt32 *C; + sal_uInt32 i, n; + + X = ctx->m_pData; + C = ctx->m_chksum; + n = DIGEST_CBLOCK_MD2 - ctx->m_nDatLen; + + for (i = ctx->m_nDatLen; i < DIGEST_CBLOCK_MD2; i++) + X[i] = (sal_uInt8)(n & 0xff); + __rtl_digest_updateMD2 (ctx); + + for (i = 0; i < DIGEST_CBLOCK_MD2; i++) + X[i] = (sal_uInt8)(C[i] & 0xff); + __rtl_digest_updateMD2 (ctx); +} + +/*======================================================================== + * + * rtl_digest_MD2 implementation. + * + *======================================================================*/ +/* + * rtl_digest_MD2. + */ +rtlDigestError SAL_CALL rtl_digest_MD2 ( + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestMD2_Impl digest; + rtlDigestError result; + + digest.m_digest = __rtl_digest_MD2; + __rtl_digest_initMD2 (&(digest.m_context)); + + result = rtl_digest_updateMD2 (&digest, pData, nDatLen); + if (result == rtl_Digest_E_None) + result = rtl_digest_getMD2 (&digest, pBuffer, nBufLen); + + rtl_zeroMemory (&digest, sizeof (digest)); + return (result); +} + +/* + * rtl_digest_createMD2. + */ +rtlDigest SAL_CALL rtl_digest_createMD2 (void) +{ + DigestMD2_Impl *pImpl = (DigestMD2_Impl*)NULL; + pImpl = RTL_DIGEST_CREATE(DigestMD2_Impl); + if (pImpl) + { + pImpl->m_digest = __rtl_digest_MD2; + __rtl_digest_initMD2 (&(pImpl->m_context)); + } + return ((rtlDigest)pImpl); +} + +/* + * rtl_digest_updateMD2. + */ +rtlDigestError SAL_CALL rtl_digest_updateMD2 ( + rtlDigest Digest, const void *pData, sal_uInt32 nDatLen) +{ + DigestMD2_Impl *pImpl = (DigestMD2_Impl *)Digest; + const sal_uInt8 *d = (const sal_uInt8 *)pData; + + DigestContextMD2 *ctx; + + if ((pImpl == NULL) || (pData == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmMD2)) + return rtl_Digest_E_Algorithm; + + if (nDatLen == 0) + return rtl_Digest_E_None; + + ctx = &(pImpl->m_context); + + if (ctx->m_nDatLen) + { + sal_uInt8 *p = ctx->m_pData + ctx->m_nDatLen; + sal_uInt32 n = DIGEST_CBLOCK_MD2 - ctx->m_nDatLen; + + if (nDatLen < n) + { + rtl_copyMemory (p, d, nDatLen); + ctx->m_nDatLen += nDatLen; + + return rtl_Digest_E_None; + } + + rtl_copyMemory (p, d, n); + d += n; + nDatLen -= n; + + __rtl_digest_updateMD2 (ctx); + ctx->m_nDatLen = 0; + } + + while (nDatLen >= DIGEST_CBLOCK_MD2) + { + rtl_copyMemory (ctx->m_pData, d, DIGEST_CBLOCK_MD2); + d += DIGEST_CBLOCK_MD2; + nDatLen -= DIGEST_CBLOCK_MD2; + + __rtl_digest_updateMD2 (ctx); + } + + rtl_copyMemory (ctx->m_pData, d, nDatLen); + ctx->m_nDatLen = nDatLen; + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_getMD2. + */ +rtlDigestError SAL_CALL rtl_digest_getMD2 ( + rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestMD2_Impl *pImpl = (DigestMD2_Impl *)Digest; + sal_uInt32 i; + + DigestContextMD2 *ctx; + + if ((pImpl == NULL) || (pBuffer == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmMD2)) + return rtl_Digest_E_Algorithm; + + if (!(pImpl->m_digest.m_length <= nBufLen)) + return rtl_Digest_E_BufferSize; + + ctx = &(pImpl->m_context); + + __rtl_digest_endMD2 (ctx); + for (i = 0; i < DIGEST_CBLOCK_MD2; i++) + pBuffer[i] = (sal_uInt8)(ctx->m_state[i] & 0xff); + __rtl_digest_initMD2 (ctx); + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_destroyMD2. + */ +void SAL_CALL rtl_digest_destroyMD2 (rtlDigest Digest) +{ + DigestMD2_Impl *pImpl = (DigestMD2_Impl *)Digest; + if (pImpl) + { + if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmMD2) + rtl_freeZeroMemory (pImpl, sizeof (DigestMD2_Impl)); + else + rtl_freeMemory (pImpl); + } +} + +/*======================================================================== + * + * rtl_digest_MD5 internals. + * + *======================================================================*/ +#define DIGEST_CBLOCK_MD5 64 +#define DIGEST_LBLOCK_MD5 16 + +typedef struct digestMD5_context_st +{ + sal_uInt32 m_nDatLen; + sal_uInt32 m_pData[DIGEST_LBLOCK_MD5]; + sal_uInt32 m_nA, m_nB, m_nC, m_nD; + sal_uInt32 m_nL, m_nH; +} DigestContextMD5; + +typedef struct digestMD5_impl_st +{ + Digest_Impl m_digest; + DigestContextMD5 m_context; +} DigestMD5_Impl; + +static void __rtl_digest_initMD5 (DigestContextMD5 *ctx); +static void __rtl_digest_updateMD5 (DigestContextMD5 *ctx); +static void __rtl_digest_endMD5 (DigestContextMD5 *ctx); + +#define F(x,y,z) ((((y) ^ (z)) & (x)) ^ (z)) +#define G(x,y,z) ((((x) ^ (y)) & (z)) ^ (y)) +#define H(x,y,z) ((x) ^ (y) ^ (z)) +#define I(x,y,z) (((x) | (~(z))) ^ (y)) + +#define R0(a,b,c,d,k,s,t) { \ + a += ((k) + (t) + F((b), (c), (d))); \ + a = RTL_DIGEST_ROTL(a, s); \ + a += b; } + +#define R1(a,b,c,d,k,s,t) { \ + a += ((k) + (t) + G((b), (c), (d))); \ + a = RTL_DIGEST_ROTL(a, s); \ + a += b; } + +#define R2(a,b,c,d,k,s,t) { \ + a += ((k) + (t) + H((b), (c), (d))); \ + a = RTL_DIGEST_ROTL(a, s); \ + a += b; } + +#define R3(a,b,c,d,k,s,t) { \ + a += ((k) + (t) + I((b), (c), (d))); \ + a = RTL_DIGEST_ROTL(a, s); \ + a += b; } + +/* + * __rtl_digest_MD5. + */ +static const Digest_Impl __rtl_digest_MD5 = +{ + rtl_Digest_AlgorithmMD5, + RTL_DIGEST_LENGTH_MD5, + + NULL, + rtl_digest_destroyMD5, + rtl_digest_updateMD5, + rtl_digest_getMD5 +}; + +/* + * __rtl_digest_initMD5. + */ +static void __rtl_digest_initMD5 (DigestContextMD5 *ctx) +{ + rtl_zeroMemory (ctx, sizeof (DigestContextMD5)); + + ctx->m_nA = (sal_uInt32)0x67452301L; + ctx->m_nB = (sal_uInt32)0xefcdab89L; + ctx->m_nC = (sal_uInt32)0x98badcfeL; + ctx->m_nD = (sal_uInt32)0x10325476L; +} + +/* + * __rtl_digest_updateMD5. + */ +static void __rtl_digest_updateMD5 (DigestContextMD5 *ctx) +{ + register sal_uInt32 A, B, C, D; + register sal_uInt32 *X; + + A = ctx->m_nA; + B = ctx->m_nB; + C = ctx->m_nC; + D = ctx->m_nD; + X = ctx->m_pData; + + R0 (A, B, C, D, X[ 0], 7, 0xd76aa478L); + R0 (D, A, B, C, X[ 1], 12, 0xe8c7b756L); + R0 (C, D, A, B, X[ 2], 17, 0x242070dbL); + R0 (B, C, D, A, X[ 3], 22, 0xc1bdceeeL); + R0 (A, B, C, D, X[ 4], 7, 0xf57c0fafL); + R0 (D, A, B, C, X[ 5], 12, 0x4787c62aL); + R0 (C, D, A, B, X[ 6], 17, 0xa8304613L); + R0 (B, C, D, A, X[ 7], 22, 0xfd469501L); + R0 (A, B, C, D, X[ 8], 7, 0x698098d8L); + R0 (D, A, B, C, X[ 9], 12, 0x8b44f7afL); + R0 (C, D, A, B, X[10], 17, 0xffff5bb1L); + R0 (B, C, D, A, X[11], 22, 0x895cd7beL); + R0 (A, B, C, D, X[12], 7, 0x6b901122L); + R0 (D, A, B, C, X[13], 12, 0xfd987193L); + R0 (C, D, A, B, X[14], 17, 0xa679438eL); + R0 (B, C, D, A, X[15], 22, 0x49b40821L); + + R1 (A, B, C, D, X[ 1], 5, 0xf61e2562L); + R1 (D, A, B, C, X[ 6], 9, 0xc040b340L); + R1 (C, D, A, B, X[11], 14, 0x265e5a51L); + R1 (B, C, D, A, X[ 0], 20, 0xe9b6c7aaL); + R1 (A, B, C, D, X[ 5], 5, 0xd62f105dL); + R1 (D, A, B, C, X[10], 9, 0x02441453L); + R1 (C, D, A, B, X[15], 14, 0xd8a1e681L); + R1 (B, C, D, A, X[ 4], 20, 0xe7d3fbc8L); + R1 (A, B, C, D, X[ 9], 5, 0x21e1cde6L); + R1 (D, A, B, C, X[14], 9, 0xc33707d6L); + R1 (C, D, A, B, X[ 3], 14, 0xf4d50d87L); + R1 (B, C, D, A, X[ 8], 20, 0x455a14edL); + R1 (A, B, C, D, X[13], 5, 0xa9e3e905L); + R1 (D, A, B, C, X[ 2], 9, 0xfcefa3f8L); + R1 (C, D, A, B, X[ 7], 14, 0x676f02d9L); + R1 (B, C, D, A, X[12], 20, 0x8d2a4c8aL); + + R2 (A, B, C, D, X[ 5], 4, 0xfffa3942L); + R2 (D, A, B, C, X[ 8], 11, 0x8771f681L); + R2 (C, D, A, B, X[11], 16, 0x6d9d6122L); + R2 (B, C, D, A, X[14], 23, 0xfde5380cL); + R2 (A, B, C, D, X[ 1], 4, 0xa4beea44L); + R2 (D, A, B, C, X[ 4], 11, 0x4bdecfa9L); + R2 (C, D, A, B, X[ 7], 16, 0xf6bb4b60L); + R2 (B, C, D, A, X[10], 23, 0xbebfbc70L); + R2 (A, B, C, D, X[13], 4, 0x289b7ec6L); + R2 (D, A, B, C, X[ 0], 11, 0xeaa127faL); + R2 (C, D, A, B, X[ 3], 16, 0xd4ef3085L); + R2 (B, C, D, A, X[ 6], 23, 0x04881d05L); + R2 (A, B, C, D, X[ 9], 4, 0xd9d4d039L); + R2 (D, A, B, C, X[12], 11, 0xe6db99e5L); + R2 (C, D, A, B, X[15], 16, 0x1fa27cf8L); + R2 (B, C, D, A, X[ 2], 23, 0xc4ac5665L); + + R3 (A, B, C, D, X[ 0], 6, 0xf4292244L); + R3 (D, A, B, C, X[ 7], 10, 0x432aff97L); + R3 (C, D, A, B, X[14], 15, 0xab9423a7L); + R3 (B, C, D, A, X[ 5], 21, 0xfc93a039L); + R3 (A, B, C, D, X[12], 6, 0x655b59c3L); + R3 (D, A, B, C, X[ 3], 10, 0x8f0ccc92L); + R3 (C, D, A, B, X[10], 15, 0xffeff47dL); + R3 (B, C, D, A, X[ 1], 21, 0x85845dd1L); + R3 (A, B, C, D, X[ 8], 6, 0x6fa87e4fL); + R3 (D, A, B, C, X[15], 10, 0xfe2ce6e0L); + R3 (C, D, A, B, X[ 6], 15, 0xa3014314L); + R3 (B, C, D, A, X[13], 21, 0x4e0811a1L); + R3 (A, B, C, D, X[ 4], 6, 0xf7537e82L); + R3 (D, A, B, C, X[11], 10, 0xbd3af235L); + R3 (C, D, A, B, X[ 2], 15, 0x2ad7d2bbL); + R3 (B, C, D, A, X[ 9], 21, 0xeb86d391L); + + ctx->m_nA += A; + ctx->m_nB += B; + ctx->m_nC += C; + ctx->m_nD += D; +} + +/* + * __rtl_digest_endMD5. + */ +static void __rtl_digest_endMD5 (DigestContextMD5 *ctx) +{ + static const sal_uInt8 end[4] = + { + 0x80, 0x00, 0x00, 0x00 + }; + register const sal_uInt8 *p = end; + + register sal_uInt32 *X; + register int i; + + X = ctx->m_pData; + i = (ctx->m_nDatLen >> 2); + +#ifdef OSL_BIGENDIAN + __rtl_digest_swapLong (X, i + 1); +#endif /* OSL_BIGENDIAN */ + + switch (ctx->m_nDatLen & 0x03) + { + case 1: X[i] &= 0x000000ff; break; + case 2: X[i] &= 0x0000ffff; break; + case 3: X[i] &= 0x00ffffff; break; + } + + switch (ctx->m_nDatLen & 0x03) + { + case 0: X[i] = ((sal_uInt32)(*(p++))) << 0L; + case 1: X[i] |= ((sal_uInt32)(*(p++))) << 8L; + case 2: X[i] |= ((sal_uInt32)(*(p++))) << 16L; + case 3: X[i] |= ((sal_uInt32)(*(p++))) << 24L; + } + + i += 1; + + if (i >= (DIGEST_LBLOCK_MD5 - 2)) + { + for (; i < DIGEST_LBLOCK_MD5; i++) + X[i] = 0; + __rtl_digest_updateMD5 (ctx); + i = 0; + } + + for (; i < (DIGEST_LBLOCK_MD5 - 2); i++) + X[i] = 0; + + X[DIGEST_LBLOCK_MD5 - 2] = ctx->m_nL; + X[DIGEST_LBLOCK_MD5 - 1] = ctx->m_nH; + + __rtl_digest_updateMD5 (ctx); +} + +/*======================================================================== + * + * rtl_digest_MD5 implementation. + * + *======================================================================*/ +/* + * rtl_digest_MD5. + */ +rtlDigestError SAL_CALL rtl_digest_MD5 ( + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestMD5_Impl digest; + rtlDigestError result; + + digest.m_digest = __rtl_digest_MD5; + __rtl_digest_initMD5 (&(digest.m_context)); + + result = rtl_digest_update (&digest, pData, nDatLen); + if (result == rtl_Digest_E_None) + result = rtl_digest_getMD5 (&digest, pBuffer, nBufLen); + + rtl_zeroMemory (&digest, sizeof (digest)); + return (result); +} + +/* + * rtl_digest_createMD5. + */ +rtlDigest SAL_CALL rtl_digest_createMD5 (void) +{ + DigestMD5_Impl *pImpl = (DigestMD5_Impl*)NULL; + pImpl = RTL_DIGEST_CREATE(DigestMD5_Impl); + if (pImpl) + { + pImpl->m_digest = __rtl_digest_MD5; + __rtl_digest_initMD5 (&(pImpl->m_context)); + } + return ((rtlDigest)pImpl); +} + +/* + * rtl_digest_updateMD5. + */ +rtlDigestError SAL_CALL rtl_digest_updateMD5 ( + rtlDigest Digest, const void *pData, sal_uInt32 nDatLen) +{ + DigestMD5_Impl *pImpl = (DigestMD5_Impl *)Digest; + const sal_uInt8 *d = (const sal_uInt8 *)pData; + + DigestContextMD5 *ctx; + sal_uInt32 len; + + if ((pImpl == NULL) || (pData == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmMD5)) + return rtl_Digest_E_Algorithm; + + if (nDatLen == 0) + return rtl_Digest_E_None; + + ctx = &(pImpl->m_context); + + len = ctx->m_nL + (nDatLen << 3); + if (len < ctx->m_nL) ctx->m_nH += 1; + ctx->m_nH += (nDatLen >> 29); + ctx->m_nL = len; + + if (ctx->m_nDatLen) + { + sal_uInt8 *p = (sal_uInt8 *)(ctx->m_pData) + ctx->m_nDatLen; + sal_uInt32 n = DIGEST_CBLOCK_MD5 - ctx->m_nDatLen; + + if (nDatLen < n) + { + rtl_copyMemory (p, d, nDatLen); + ctx->m_nDatLen += nDatLen; + + return rtl_Digest_E_None; + } + + rtl_copyMemory (p, d, n); + d += n; + nDatLen -= n; + +#ifdef OSL_BIGENDIAN + __rtl_digest_swapLong (ctx->m_pData, DIGEST_LBLOCK_MD5); +#endif /* OSL_BIGENDIAN */ + + __rtl_digest_updateMD5 (ctx); + ctx->m_nDatLen = 0; + } + + while (nDatLen >= DIGEST_CBLOCK_MD5) + { + rtl_copyMemory (ctx->m_pData, d, DIGEST_CBLOCK_MD5); + d += DIGEST_CBLOCK_MD5; + nDatLen -= DIGEST_CBLOCK_MD5; + +#ifdef OSL_BIGENDIAN + __rtl_digest_swapLong (ctx->m_pData, DIGEST_LBLOCK_MD5); +#endif /* OSL_BIGENDIAN */ + + __rtl_digest_updateMD5 (ctx); + } + + rtl_copyMemory (ctx->m_pData, d, nDatLen); + ctx->m_nDatLen = nDatLen; + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_getMD5. + */ +rtlDigestError SAL_CALL rtl_digest_getMD5 ( + rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestMD5_Impl *pImpl = (DigestMD5_Impl *)Digest; + sal_uInt8 *p = pBuffer; + + DigestContextMD5 *ctx; + + if ((pImpl == NULL) || (pBuffer == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmMD5)) + return rtl_Digest_E_Algorithm; + + if (!(pImpl->m_digest.m_length <= nBufLen)) + return rtl_Digest_E_BufferSize; + + ctx = &(pImpl->m_context); + + __rtl_digest_endMD5 (ctx); + RTL_DIGEST_LTOC (ctx->m_nA, p); + RTL_DIGEST_LTOC (ctx->m_nB, p); + RTL_DIGEST_LTOC (ctx->m_nC, p); + RTL_DIGEST_LTOC (ctx->m_nD, p); + __rtl_digest_initMD5 (ctx); + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_rawMD5. + */ +rtlDigestError SAL_CALL rtl_digest_rawMD5 ( + rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestMD5_Impl *pImpl = (DigestMD5_Impl *)Digest; + sal_uInt8 *p = pBuffer; + + DigestContextMD5 *ctx; + + if ((pImpl == NULL) || (pBuffer == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmMD5)) + return rtl_Digest_E_Algorithm; + + if (!(pImpl->m_digest.m_length <= nBufLen)) + return rtl_Digest_E_BufferSize; + + ctx = &(pImpl->m_context); + + /* __rtl_digest_endMD5 (ctx); *//* not finalized */ + RTL_DIGEST_LTOC (ctx->m_nA, p); + RTL_DIGEST_LTOC (ctx->m_nB, p); + RTL_DIGEST_LTOC (ctx->m_nC, p); + RTL_DIGEST_LTOC (ctx->m_nD, p); + __rtl_digest_initMD5 (ctx); + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_destroyMD5. + */ +void SAL_CALL rtl_digest_destroyMD5 (rtlDigest Digest) +{ + DigestMD5_Impl *pImpl = (DigestMD5_Impl *)Digest; + if (pImpl) + { + if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmMD5) + rtl_freeZeroMemory (pImpl, sizeof (DigestMD5_Impl)); + else + rtl_freeMemory (pImpl); + } +} + +/*======================================================================== + * + * rtl_digest_(SHA|SHA1) common internals. + * + *======================================================================*/ +#define DIGEST_CBLOCK_SHA 64 +#define DIGEST_LBLOCK_SHA 16 + +typedef sal_uInt32 DigestSHA_update_t (sal_uInt32 x); + +static sal_uInt32 __rtl_digest_updateSHA_0 (sal_uInt32 x); +static sal_uInt32 __rtl_digest_updateSHA_1 (sal_uInt32 x); + +typedef struct digestSHA_context_st +{ + DigestSHA_update_t *m_update; + sal_uInt32 m_nDatLen; + sal_uInt32 m_pData[DIGEST_LBLOCK_SHA]; + sal_uInt32 m_nA, m_nB, m_nC, m_nD, m_nE; + sal_uInt32 m_nL, m_nH; +} DigestContextSHA; + +typedef struct digestSHA_impl_st +{ + Digest_Impl m_digest; + DigestContextSHA m_context; +} DigestSHA_Impl; + +static void __rtl_digest_initSHA ( + DigestContextSHA *ctx, DigestSHA_update_t *fct); + +static void __rtl_digest_updateSHA (DigestContextSHA *ctx); +static void __rtl_digest_endSHA (DigestContextSHA *ctx); + +#define K_00_19 (sal_uInt32)0x5a827999L +#define K_20_39 (sal_uInt32)0x6ed9eba1L +#define K_40_59 (sal_uInt32)0x8f1bbcdcL +#define K_60_79 (sal_uInt32)0xca62c1d6L + +#define F_00_19(b,c,d) ((((c) ^ (d)) & (b)) ^ (d)) +#define F_20_39(b,c,d) ((b) ^ (c) ^ (d)) +#define F_40_59(b,c,d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) +#define F_60_79(b,c,d) F_20_39(b,c,d) + +#define BODY_X(i) \ + (X[(i)&0x0f] ^ X[((i)+2)&0x0f] ^ X[((i)+8)&0x0f] ^ X[((i)+13)&0x0f]) + +#define BODY_00_15(u,i,a,b,c,d,e,f) \ + (f) = X[i]; \ + (f) += (e) + K_00_19 + RTL_DIGEST_ROTL((a), 5) + F_00_19((b), (c), (d)); \ + (b) = RTL_DIGEST_ROTL((b), 30); + +#define BODY_16_19(u,i,a,b,c,d,e,f) \ + (f) = BODY_X((i)); \ + (f) = X[(i)&0x0f] = (u)((f)); \ + (f) += (e) + K_00_19 + RTL_DIGEST_ROTL((a), 5) + F_00_19((b), (c), (d)); \ + (b) = RTL_DIGEST_ROTL((b), 30); + +#define BODY_20_39(u,i,a,b,c,d,e,f) \ + (f) = BODY_X((i)); \ + (f) = X[(i)&0x0f] = (u)((f)); \ + (f) += (e) + K_20_39 + RTL_DIGEST_ROTL((a), 5) + F_20_39((b), (c), (d)); \ + (b) = RTL_DIGEST_ROTL((b), 30); + +#define BODY_40_59(u,i,a,b,c,d,e,f) \ + (f) = BODY_X((i)); \ + (f) = X[(i)&0x0f] = (u)((f)); \ + (f) += (e) + K_40_59 + RTL_DIGEST_ROTL((a), 5) + F_40_59((b), (c), (d)); \ + (b) = RTL_DIGEST_ROTL((b), 30); + +#define BODY_60_79(u,i,a,b,c,d,e,f) \ + (f) = BODY_X((i)); \ + (f) = X[(i)&0x0f] = (u)((f)); \ + (f) += (e) + K_60_79 + RTL_DIGEST_ROTL((a), 5) + F_60_79((b), (c), (d)); \ + (b) = RTL_DIGEST_ROTL((b), 30); + +/* + * __rtl_digest_initSHA. + */ +static void __rtl_digest_initSHA ( + DigestContextSHA *ctx, DigestSHA_update_t *fct) +{ + rtl_zeroMemory (ctx, sizeof (DigestContextSHA)); + ctx->m_update = fct; + + ctx->m_nA = (sal_uInt32)0x67452301L; + ctx->m_nB = (sal_uInt32)0xefcdab89L; + ctx->m_nC = (sal_uInt32)0x98badcfeL; + ctx->m_nD = (sal_uInt32)0x10325476L; + ctx->m_nE = (sal_uInt32)0xc3d2e1f0L; +} + +/* + * __rtl_digest_updateSHA. + */ +static void __rtl_digest_updateSHA (DigestContextSHA *ctx) +{ + register sal_uInt32 A, B, C, D, E, T; + register sal_uInt32 *X; + + register DigestSHA_update_t *U; + U = ctx->m_update; + + A = ctx->m_nA; + B = ctx->m_nB; + C = ctx->m_nC; + D = ctx->m_nD; + E = ctx->m_nE; + X = ctx->m_pData; + + BODY_00_15 (U, 0, A, B, C, D, E, T); + BODY_00_15 (U, 1, T, A, B, C, D, E); + BODY_00_15 (U, 2, E, T, A, B, C, D); + BODY_00_15 (U, 3, D, E, T, A, B, C); + BODY_00_15 (U, 4, C, D, E, T, A, B); + BODY_00_15 (U, 5, B, C, D, E, T, A); + BODY_00_15 (U, 6, A, B, C, D, E, T); + BODY_00_15 (U, 7, T, A, B, C, D, E); + BODY_00_15 (U, 8, E, T, A, B, C, D); + BODY_00_15 (U, 9, D, E, T, A, B, C); + BODY_00_15 (U, 10, C, D, E, T, A, B); + BODY_00_15 (U, 11, B, C, D, E, T, A); + BODY_00_15 (U, 12, A, B, C, D, E, T); + BODY_00_15 (U, 13, T, A, B, C, D, E); + BODY_00_15 (U, 14, E, T, A, B, C, D); + BODY_00_15 (U, 15, D, E, T, A, B, C); + BODY_16_19 (U, 16, C, D, E, T, A, B); + BODY_16_19 (U, 17, B, C, D, E, T, A); + BODY_16_19 (U, 18, A, B, C, D, E, T); + BODY_16_19 (U, 19, T, A, B, C, D, E); + + BODY_20_39 (U, 20, E, T, A, B, C, D); + BODY_20_39 (U, 21, D, E, T, A, B, C); + BODY_20_39 (U, 22, C, D, E, T, A, B); + BODY_20_39 (U, 23, B, C, D, E, T, A); + BODY_20_39 (U, 24, A, B, C, D, E, T); + BODY_20_39 (U, 25, T, A, B, C, D, E); + BODY_20_39 (U, 26, E, T, A, B, C, D); + BODY_20_39 (U, 27, D, E, T, A, B, C); + BODY_20_39 (U, 28, C, D, E, T, A, B); + BODY_20_39 (U, 29, B, C, D, E, T, A); + BODY_20_39 (U, 30, A, B, C, D, E, T); + BODY_20_39 (U, 31, T, A, B, C, D, E); + BODY_20_39 (U, 32, E, T, A, B, C, D); + BODY_20_39 (U, 33, D, E, T, A, B, C); + BODY_20_39 (U, 34, C, D, E, T, A, B); + BODY_20_39 (U, 35, B, C, D, E, T, A); + BODY_20_39 (U, 36, A, B, C, D, E, T); + BODY_20_39 (U, 37, T, A, B, C, D, E); + BODY_20_39 (U, 38, E, T, A, B, C, D); + BODY_20_39 (U, 39, D, E, T, A, B, C); + + BODY_40_59 (U, 40, C, D, E, T, A, B); + BODY_40_59 (U, 41, B, C, D, E, T, A); + BODY_40_59 (U, 42, A, B, C, D, E, T); + BODY_40_59 (U, 43, T, A, B, C, D, E); + BODY_40_59 (U, 44, E, T, A, B, C, D); + BODY_40_59 (U, 45, D, E, T, A, B, C); + BODY_40_59 (U, 46, C, D, E, T, A, B); + BODY_40_59 (U, 47, B, C, D, E, T, A); + BODY_40_59 (U, 48, A, B, C, D, E, T); + BODY_40_59 (U, 49, T, A, B, C, D, E); + BODY_40_59 (U, 50, E, T, A, B, C, D); + BODY_40_59 (U, 51, D, E, T, A, B, C); + BODY_40_59 (U, 52, C, D, E, T, A, B); + BODY_40_59 (U, 53, B, C, D, E, T, A); + BODY_40_59 (U, 54, A, B, C, D, E, T); + BODY_40_59 (U, 55, T, A, B, C, D, E); + BODY_40_59 (U, 56, E, T, A, B, C, D); + BODY_40_59 (U, 57, D, E, T, A, B, C); + BODY_40_59 (U, 58, C, D, E, T, A, B); + BODY_40_59 (U, 59, B, C, D, E, T, A); + + BODY_60_79 (U, 60, A, B, C, D, E, T); + BODY_60_79 (U, 61, T, A, B, C, D, E); + BODY_60_79 (U, 62, E, T, A, B, C, D); + BODY_60_79 (U, 63, D, E, T, A, B, C); + BODY_60_79 (U, 64, C, D, E, T, A, B); + BODY_60_79 (U, 65, B, C, D, E, T, A); + BODY_60_79 (U, 66, A, B, C, D, E, T); + BODY_60_79 (U, 67, T, A, B, C, D, E); + BODY_60_79 (U, 68, E, T, A, B, C, D); + BODY_60_79 (U, 69, D, E, T, A, B, C); + BODY_60_79 (U, 70, C, D, E, T, A, B); + BODY_60_79 (U, 71, B, C, D, E, T, A); + BODY_60_79 (U, 72, A, B, C, D, E, T); + BODY_60_79 (U, 73, T, A, B, C, D, E); + BODY_60_79 (U, 74, E, T, A, B, C, D); + BODY_60_79 (U, 75, D, E, T, A, B, C); + BODY_60_79 (U, 76, C, D, E, T, A, B); + BODY_60_79 (U, 77, B, C, D, E, T, A); + BODY_60_79 (U, 78, A, B, C, D, E, T); + BODY_60_79 (U, 79, T, A, B, C, D, E); + + ctx->m_nA += E; + ctx->m_nB += T; + ctx->m_nC += A; + ctx->m_nD += B; + ctx->m_nE += C; +} + +/* + * __rtl_digest_endSHA. + */ +static void __rtl_digest_endSHA (DigestContextSHA *ctx) +{ + static const sal_uInt8 end[4] = + { + 0x80, 0x00, 0x00, 0x00 + }; + register const sal_uInt8 *p = end; + + register sal_uInt32 *X; + register int i; + + X = ctx->m_pData; + i = (ctx->m_nDatLen >> 2); + +#ifdef OSL_BIGENDIAN + __rtl_digest_swapLong (X, i + 1); +#endif /* OSL_BIGENDIAN */ + + switch (ctx->m_nDatLen & 0x03) + { + case 1: X[i] &= 0x000000ff; break; + case 2: X[i] &= 0x0000ffff; break; + case 3: X[i] &= 0x00ffffff; break; + } + + switch (ctx->m_nDatLen & 0x03) + { + case 0: X[i] = ((sal_uInt32)(*(p++))) << 0L; + case 1: X[i] |= ((sal_uInt32)(*(p++))) << 8L; + case 2: X[i] |= ((sal_uInt32)(*(p++))) << 16L; + case 3: X[i] |= ((sal_uInt32)(*(p++))) << 24L; + } + + __rtl_digest_swapLong (X, i + 1); + + i += 1; + + if (i >= (DIGEST_LBLOCK_SHA - 2)) + { + for (; i < DIGEST_LBLOCK_SHA; i++) + X[i] = 0; + __rtl_digest_updateSHA (ctx); + i = 0; + } + + for (; i < (DIGEST_LBLOCK_SHA - 2); i++) + X[i] = 0; + + X[DIGEST_LBLOCK_SHA - 2] = ctx->m_nH; + X[DIGEST_LBLOCK_SHA - 1] = ctx->m_nL; + + __rtl_digest_updateSHA (ctx); +} + +/*======================================================================== + * + * rtl_digest_SHA internals. + * + *======================================================================*/ +/* + * __rtl_digest_SHA_0. + */ +static const Digest_Impl __rtl_digest_SHA_0 = +{ + rtl_Digest_AlgorithmSHA, + RTL_DIGEST_LENGTH_SHA, + + NULL, + rtl_digest_destroySHA, + rtl_digest_updateSHA, + rtl_digest_getSHA +}; + +/* + * __rtl_digest_updateSHA_0. + */ +static sal_uInt32 __rtl_digest_updateSHA_0 (sal_uInt32 x) +{ + return x; +} + +/*======================================================================== + * + * rtl_digest_SHA implementation. + * + *======================================================================*/ +/* + * rtl_digest_SHA. + */ +rtlDigestError SAL_CALL rtl_digest_SHA ( + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestSHA_Impl digest; + rtlDigestError result; + + digest.m_digest = __rtl_digest_SHA_0; + __rtl_digest_initSHA (&(digest.m_context), __rtl_digest_updateSHA_0); + + result = rtl_digest_updateSHA (&digest, pData, nDatLen); + if (result == rtl_Digest_E_None) + result = rtl_digest_getSHA (&digest, pBuffer, nBufLen); + + rtl_zeroMemory (&digest, sizeof (digest)); + return (result); +} + +/* + * rtl_digest_createSHA. + */ +rtlDigest SAL_CALL rtl_digest_createSHA (void) +{ + DigestSHA_Impl *pImpl = (DigestSHA_Impl*)NULL; + pImpl = RTL_DIGEST_CREATE(DigestSHA_Impl); + if (pImpl) + { + pImpl->m_digest = __rtl_digest_SHA_0; + __rtl_digest_initSHA (&(pImpl->m_context), __rtl_digest_updateSHA_0); + } + return ((rtlDigest)pImpl); +} + +/* + * rtl_digest_updateSHA. + */ +rtlDigestError SAL_CALL rtl_digest_updateSHA ( + rtlDigest Digest, const void *pData, sal_uInt32 nDatLen) +{ + DigestSHA_Impl *pImpl = (DigestSHA_Impl *)Digest; + const sal_uInt8 *d = (const sal_uInt8 *)pData; + + DigestContextSHA *ctx; + sal_uInt32 len; + + if ((pImpl == NULL) || (pData == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmSHA)) + return rtl_Digest_E_Algorithm; + + if (nDatLen == 0) + return rtl_Digest_E_None; + + ctx = &(pImpl->m_context); + + len = ctx->m_nL + (nDatLen << 3); + if (len < ctx->m_nL) ctx->m_nH += 1; + ctx->m_nH += (nDatLen >> 29); + ctx->m_nL = len; + + if (ctx->m_nDatLen) + { + sal_uInt8 *p = (sal_uInt8 *)(ctx->m_pData) + ctx->m_nDatLen; + sal_uInt32 n = DIGEST_CBLOCK_SHA - ctx->m_nDatLen; + + if (nDatLen < n) + { + rtl_copyMemory (p, d, nDatLen); + ctx->m_nDatLen += nDatLen; + + return rtl_Digest_E_None; + } + + rtl_copyMemory (p, d, n); + d += n; + nDatLen -= n; + +#ifndef OSL_BIGENDIAN + __rtl_digest_swapLong (ctx->m_pData, DIGEST_LBLOCK_SHA); +#endif /* OSL_BIGENDIAN */ + + __rtl_digest_updateSHA (ctx); + ctx->m_nDatLen = 0; + } + + while (nDatLen >= DIGEST_CBLOCK_SHA) + { + rtl_copyMemory (ctx->m_pData, d, DIGEST_CBLOCK_SHA); + d += DIGEST_CBLOCK_SHA; + nDatLen -= DIGEST_CBLOCK_SHA; + +#ifndef OSL_BIGENDIAN + __rtl_digest_swapLong (ctx->m_pData, DIGEST_LBLOCK_SHA); +#endif /* OSL_BIGENDIAN */ + + __rtl_digest_updateSHA (ctx); + } + + rtl_copyMemory (ctx->m_pData, d, nDatLen); + ctx->m_nDatLen = nDatLen; + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_getSHA. + */ +rtlDigestError SAL_CALL rtl_digest_getSHA ( + rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestSHA_Impl *pImpl = (DigestSHA_Impl *)Digest; + sal_uInt8 *p = pBuffer; + + DigestContextSHA *ctx; + + if ((pImpl == NULL) || (pBuffer == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmSHA)) + return rtl_Digest_E_Algorithm; + + if (!(pImpl->m_digest.m_length <= nBufLen)) + return rtl_Digest_E_BufferSize; + + ctx = &(pImpl->m_context); + + __rtl_digest_endSHA (ctx); + RTL_DIGEST_HTONL (ctx->m_nA, p); + RTL_DIGEST_HTONL (ctx->m_nB, p); + RTL_DIGEST_HTONL (ctx->m_nC, p); + RTL_DIGEST_HTONL (ctx->m_nD, p); + RTL_DIGEST_HTONL (ctx->m_nE, p); + __rtl_digest_initSHA (ctx, __rtl_digest_updateSHA_0); + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_destroySHA. + */ +void SAL_CALL rtl_digest_destroySHA (rtlDigest Digest) +{ + DigestSHA_Impl *pImpl = (DigestSHA_Impl *)Digest; + if (pImpl) + { + if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmSHA) + rtl_freeZeroMemory (pImpl, sizeof (DigestSHA_Impl)); + else + rtl_freeMemory (pImpl); + } +} + +/*======================================================================== + * + * rtl_digest_SHA1 internals. + * + *======================================================================*/ +/* + * __rtl_digest_SHA_1. + */ +static const Digest_Impl __rtl_digest_SHA_1 = +{ + rtl_Digest_AlgorithmSHA1, + RTL_DIGEST_LENGTH_SHA1, + + NULL, + rtl_digest_destroySHA1, + rtl_digest_updateSHA1, + rtl_digest_getSHA1 +}; + +/* + * __rtl_digest_updateSHA_1. + */ +static sal_uInt32 __rtl_digest_updateSHA_1 (sal_uInt32 x) +{ + return RTL_DIGEST_ROTL (x, 1); +} + +/*======================================================================== + * + * rtl_digest_SHA1 implementation. + * + *======================================================================*/ +/* + * rtl_digest_SHA1. + */ +rtlDigestError SAL_CALL rtl_digest_SHA1 ( + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestSHA_Impl digest; + rtlDigestError result; + + digest.m_digest = __rtl_digest_SHA_1; + __rtl_digest_initSHA (&(digest.m_context), __rtl_digest_updateSHA_1); + + result = rtl_digest_updateSHA1 (&digest, pData, nDatLen); + if (result == rtl_Digest_E_None) + result = rtl_digest_getSHA1 (&digest, pBuffer, nBufLen); + + rtl_zeroMemory (&digest, sizeof (digest)); + return (result); +} + +/* + * rtl_digest_createSHA1. + */ +rtlDigest SAL_CALL rtl_digest_createSHA1 (void) +{ + DigestSHA_Impl *pImpl = (DigestSHA_Impl*)NULL; + pImpl = RTL_DIGEST_CREATE(DigestSHA_Impl); + if (pImpl) + { + pImpl->m_digest = __rtl_digest_SHA_1; + __rtl_digest_initSHA (&(pImpl->m_context), __rtl_digest_updateSHA_1); + } + return ((rtlDigest)pImpl); +} + +/* + * rtl_digest_updateSHA1. + */ +rtlDigestError SAL_CALL rtl_digest_updateSHA1 ( + rtlDigest Digest, const void *pData, sal_uInt32 nDatLen) +{ + DigestSHA_Impl *pImpl = (DigestSHA_Impl *)Digest; + const sal_uInt8 *d = (const sal_uInt8 *)pData; + + DigestContextSHA *ctx; + sal_uInt32 len; + + if ((pImpl == NULL) || (pData == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmSHA1)) + return rtl_Digest_E_Algorithm; + + if (nDatLen == 0) + return rtl_Digest_E_None; + + ctx = &(pImpl->m_context); + + len = ctx->m_nL + (nDatLen << 3); + if (len < ctx->m_nL) ctx->m_nH += 1; + ctx->m_nH += (nDatLen >> 29); + ctx->m_nL = len; + + if (ctx->m_nDatLen) + { + sal_uInt8 *p = (sal_uInt8 *)(ctx->m_pData) + ctx->m_nDatLen; + sal_uInt32 n = DIGEST_CBLOCK_SHA - ctx->m_nDatLen; + + if (nDatLen < n) + { + rtl_copyMemory (p, d, nDatLen); + ctx->m_nDatLen += nDatLen; + + return rtl_Digest_E_None; + } + + rtl_copyMemory (p, d, n); + d += n; + nDatLen -= n; + +#ifndef OSL_BIGENDIAN + __rtl_digest_swapLong (ctx->m_pData, DIGEST_LBLOCK_SHA); +#endif /* OSL_BIGENDIAN */ + + __rtl_digest_updateSHA (ctx); + ctx->m_nDatLen = 0; + } + + while (nDatLen >= DIGEST_CBLOCK_SHA) + { + rtl_copyMemory (ctx->m_pData, d, DIGEST_CBLOCK_SHA); + d += DIGEST_CBLOCK_SHA; + nDatLen -= DIGEST_CBLOCK_SHA; + +#ifndef OSL_BIGENDIAN + __rtl_digest_swapLong (ctx->m_pData, DIGEST_LBLOCK_SHA); +#endif /* OSL_BIGENDIAN */ + + __rtl_digest_updateSHA (ctx); + } + + rtl_copyMemory (ctx->m_pData, d, nDatLen); + ctx->m_nDatLen = nDatLen; + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_getSHA1. + */ +rtlDigestError SAL_CALL rtl_digest_getSHA1 ( + rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestSHA_Impl *pImpl = (DigestSHA_Impl *)Digest; + sal_uInt8 *p = pBuffer; + + DigestContextSHA *ctx; + + if ((pImpl == NULL) || (pBuffer == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmSHA1)) + return rtl_Digest_E_Algorithm; + + if (!(pImpl->m_digest.m_length <= nBufLen)) + return rtl_Digest_E_BufferSize; + + ctx = &(pImpl->m_context); + + __rtl_digest_endSHA (ctx); + RTL_DIGEST_HTONL (ctx->m_nA, p); + RTL_DIGEST_HTONL (ctx->m_nB, p); + RTL_DIGEST_HTONL (ctx->m_nC, p); + RTL_DIGEST_HTONL (ctx->m_nD, p); + RTL_DIGEST_HTONL (ctx->m_nE, p); + __rtl_digest_initSHA (ctx, __rtl_digest_updateSHA_1); + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_destroySHA1. + */ +void SAL_CALL rtl_digest_destroySHA1 (rtlDigest Digest) +{ + DigestSHA_Impl *pImpl = (DigestSHA_Impl *)Digest; + if (pImpl) + { + if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmSHA1) + rtl_freeZeroMemory (pImpl, sizeof (DigestSHA_Impl)); + else + rtl_freeMemory (pImpl); + } +} + +/*======================================================================== + * + * rtl_digest_HMAC_MD5 internals. + * + *======================================================================*/ +#define DIGEST_CBLOCK_HMAC_MD5 64 + +typedef struct _contextHMAC_MD5_st +{ + DigestMD5_Impl m_hash; + sal_uInt8 m_opad[DIGEST_CBLOCK_HMAC_MD5]; +} ContextHMAC_MD5; + +typedef struct _digestHMAC_MD5_impl_st +{ + Digest_Impl m_digest; + ContextHMAC_MD5 m_context; +} DigestHMAC_MD5_Impl; + +static void __rtl_digest_initHMAC_MD5 (ContextHMAC_MD5 * ctx); +static void __rtl_digest_ipadHMAC_MD5 (ContextHMAC_MD5 * ctx); +static void __rtl_digest_opadHMAC_MD5 (ContextHMAC_MD5 * ctx); + +/* + * __rtl_digest_HMAC_MD5. + */ +static const Digest_Impl __rtl_digest_HMAC_MD5 = +{ + rtl_Digest_AlgorithmHMAC_MD5, + RTL_DIGEST_LENGTH_MD5, + + rtl_digest_initHMAC_MD5, + rtl_digest_destroyHMAC_MD5, + rtl_digest_updateHMAC_MD5, + rtl_digest_getHMAC_MD5 +}; + +/* + * __rtl_digest_initHMAC_MD5. + */ +static void __rtl_digest_initHMAC_MD5 (ContextHMAC_MD5 * ctx) +{ + DigestMD5_Impl *pImpl = &(ctx->m_hash); + + pImpl->m_digest = __rtl_digest_MD5; + __rtl_digest_initMD5 (&(pImpl->m_context)); + + rtl_zeroMemory (ctx->m_opad, DIGEST_CBLOCK_HMAC_MD5); +} + +/* + * __rtl_digest_ipadHMAC_MD5. + */ +static void __rtl_digest_ipadHMAC_MD5 (ContextHMAC_MD5 * ctx) +{ + register sal_uInt32 i; + + for (i = 0; i < DIGEST_CBLOCK_HMAC_MD5; i++) + ctx->m_opad[i] ^= 0x36; + rtl_digest_updateMD5 ( + &(ctx->m_hash), ctx->m_opad, DIGEST_CBLOCK_HMAC_MD5); + for (i = 0; i < DIGEST_CBLOCK_HMAC_MD5; i++) + ctx->m_opad[i] ^= 0x36; +} + +/* + * __rtl_digest_opadHMAC_MD5. + */ +static void __rtl_digest_opadHMAC_MD5 (ContextHMAC_MD5 * ctx) +{ + register sal_uInt32 i; + + for (i = 0; i < DIGEST_CBLOCK_HMAC_MD5; i++) + ctx->m_opad[i] ^= 0x5c; +} + +/*======================================================================== + * + * rtl_digest_HMAC_MD5 implementation. + * + *======================================================================*/ +/* + * rtl_digest_HMAC_MD5. + */ +rtlDigestError SAL_CALL rtl_digest_HMAC_MD5 ( + const sal_uInt8 *pKeyData, sal_uInt32 nKeyLen, + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestHMAC_MD5_Impl digest; + rtlDigestError result; + + digest.m_digest = __rtl_digest_HMAC_MD5; + + result = rtl_digest_initHMAC_MD5 (&digest, pKeyData, nKeyLen); + if (result == rtl_Digest_E_None) + { + result = rtl_digest_updateHMAC_MD5 (&digest, pData, nDatLen); + if (result == rtl_Digest_E_None) + result = rtl_digest_getHMAC_MD5 (&digest, pBuffer, nBufLen); + } + + rtl_zeroMemory (&digest, sizeof (digest)); + return (result); +} + +/* + * rtl_digest_createHMAC_MD5. + */ +rtlDigest SAL_CALL rtl_digest_createHMAC_MD5 (void) +{ + DigestHMAC_MD5_Impl *pImpl = (DigestHMAC_MD5_Impl*)NULL; + pImpl = RTL_DIGEST_CREATE(DigestHMAC_MD5_Impl); + if (pImpl) + { + pImpl->m_digest = __rtl_digest_HMAC_MD5; + __rtl_digest_initHMAC_MD5 (&(pImpl->m_context)); + } + return ((rtlDigest)pImpl); +} + +/* + * rtl_digest_initHMAC_MD5. + */ +rtlDigestError SAL_CALL rtl_digest_initHMAC_MD5 ( + rtlDigest Digest, const sal_uInt8 *pKeyData, sal_uInt32 nKeyLen) +{ + DigestHMAC_MD5_Impl *pImpl = (DigestHMAC_MD5_Impl*)Digest; + ContextHMAC_MD5 *ctx; + + if ((pImpl == NULL) || (pKeyData == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmHMAC_MD5)) + return rtl_Digest_E_Algorithm; + + ctx = &(pImpl->m_context); + __rtl_digest_initHMAC_MD5 (ctx); + + if (nKeyLen > DIGEST_CBLOCK_HMAC_MD5) + { + /* Initialize 'opad' with hashed 'KeyData' */ + rtl_digest_updateMD5 ( + &(ctx->m_hash), pKeyData, nKeyLen); + rtl_digest_getMD5 ( + &(ctx->m_hash), ctx->m_opad, RTL_DIGEST_LENGTH_MD5); + } + else + { + /* Initialize 'opad' with plain 'KeyData' */ + rtl_copyMemory (ctx->m_opad, pKeyData, nKeyLen); + } + + __rtl_digest_ipadHMAC_MD5 (ctx); + __rtl_digest_opadHMAC_MD5 (ctx); + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_updateHMAC_MD5. + */ +rtlDigestError SAL_CALL rtl_digest_updateHMAC_MD5 ( + rtlDigest Digest, const void *pData, sal_uInt32 nDatLen) +{ + DigestHMAC_MD5_Impl *pImpl = (DigestHMAC_MD5_Impl*)Digest; + ContextHMAC_MD5 *ctx; + + if ((pImpl == NULL) || (pData == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmHMAC_MD5)) + return rtl_Digest_E_Algorithm; + + ctx = &(pImpl->m_context); + rtl_digest_updateMD5 (&(ctx->m_hash), pData, nDatLen); + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_getHMAC_MD5. + */ +rtlDigestError SAL_CALL rtl_digest_getHMAC_MD5 ( + rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestHMAC_MD5_Impl *pImpl = (DigestHMAC_MD5_Impl*)Digest; + ContextHMAC_MD5 *ctx; + + if ((pImpl == NULL) || (pBuffer == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmHMAC_MD5)) + return rtl_Digest_E_Algorithm; + + if (!(pImpl->m_digest.m_length <= nBufLen)) + return rtl_Digest_E_BufferSize; + + nBufLen = pImpl->m_digest.m_length; + + ctx = &(pImpl->m_context); + rtl_digest_getMD5 (&(ctx->m_hash), pBuffer, nBufLen); + + rtl_digest_updateMD5 (&(ctx->m_hash), ctx->m_opad, 64); + rtl_digest_updateMD5 (&(ctx->m_hash), pBuffer, nBufLen); + rtl_digest_getMD5 (&(ctx->m_hash), pBuffer, nBufLen); + + __rtl_digest_opadHMAC_MD5 (ctx); + __rtl_digest_ipadHMAC_MD5 (ctx); + __rtl_digest_opadHMAC_MD5 (ctx); + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_destroyHMAC_MD5. + */ +void SAL_CALL rtl_digest_destroyHMAC_MD5 (rtlDigest Digest) +{ + DigestHMAC_MD5_Impl *pImpl = (DigestHMAC_MD5_Impl*)Digest; + if (pImpl) + { + if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmHMAC_MD5) + rtl_freeZeroMemory (pImpl, sizeof (DigestHMAC_MD5_Impl)); + else + rtl_freeMemory (pImpl); + } +} + +/*======================================================================== + * + * rtl_digest_HMAC_SHA1 internals. + * + *======================================================================*/ +#define DIGEST_CBLOCK_HMAC_SHA1 64 + +typedef struct _contextHMAC_SHA1_st +{ + DigestSHA_Impl m_hash; + sal_uInt8 m_opad[DIGEST_CBLOCK_HMAC_SHA1]; +} ContextHMAC_SHA1; + +typedef struct _digestHMAC_SHA1_impl_st +{ + Digest_Impl m_digest; + ContextHMAC_SHA1 m_context; +} DigestHMAC_SHA1_Impl; + +static void __rtl_digest_initHMAC_SHA1 (ContextHMAC_SHA1 * ctx); +static void __rtl_digest_ipadHMAC_SHA1 (ContextHMAC_SHA1 * ctx); +static void __rtl_digest_opadHMAC_SHA1 (ContextHMAC_SHA1 * ctx); + +/* + * __rtl_digest_HMAC_SHA1. + */ +static const Digest_Impl __rtl_digest_HMAC_SHA1 = +{ + rtl_Digest_AlgorithmHMAC_SHA1, + RTL_DIGEST_LENGTH_SHA1, + + rtl_digest_initHMAC_SHA1, + rtl_digest_destroyHMAC_SHA1, + rtl_digest_updateHMAC_SHA1, + rtl_digest_getHMAC_SHA1 +}; + +/* + * __rtl_digest_initHMAC_SHA1. + */ +static void __rtl_digest_initHMAC_SHA1 (ContextHMAC_SHA1 * ctx) +{ + DigestSHA_Impl *pImpl = &(ctx->m_hash); + + pImpl->m_digest = __rtl_digest_SHA_1; + __rtl_digest_initSHA (&(pImpl->m_context), __rtl_digest_updateSHA_1); + + rtl_zeroMemory (ctx->m_opad, DIGEST_CBLOCK_HMAC_SHA1); +} + +/* + * __rtl_digest_ipadHMAC_SHA1. + */ +static void __rtl_digest_ipadHMAC_SHA1 (ContextHMAC_SHA1 * ctx) +{ + register sal_uInt32 i; + + for (i = 0; i < DIGEST_CBLOCK_HMAC_SHA1; i++) + ctx->m_opad[i] ^= 0x36; + rtl_digest_updateSHA1 ( + &(ctx->m_hash), ctx->m_opad, DIGEST_CBLOCK_HMAC_SHA1); + for (i = 0; i < DIGEST_CBLOCK_HMAC_SHA1; i++) + ctx->m_opad[i] ^= 0x36; +} + +/* + * __rtl_digest_opadHMAC_SHA1. + */ +static void __rtl_digest_opadHMAC_SHA1 (ContextHMAC_SHA1 * ctx) +{ + register sal_uInt32 i; + + for (i = 0; i < DIGEST_CBLOCK_HMAC_SHA1; i++) + ctx->m_opad[i] ^= 0x5c; +} + +/*======================================================================== + * + * rtl_digest_HMAC_SHA1 implementation. + * + *======================================================================*/ +/* + * rtl_digest_HMAC_SHA1. + */ +rtlDigestError SAL_CALL rtl_digest_HMAC_SHA1 ( + const sal_uInt8 *pKeyData, sal_uInt32 nKeyLen, + const void *pData, sal_uInt32 nDatLen, + sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestHMAC_SHA1_Impl digest; + rtlDigestError result; + + digest.m_digest = __rtl_digest_HMAC_SHA1; + + result = rtl_digest_initHMAC_SHA1 (&digest, pKeyData, nKeyLen); + if (result == rtl_Digest_E_None) + { + result = rtl_digest_updateHMAC_SHA1 (&digest, pData, nDatLen); + if (result == rtl_Digest_E_None) + result = rtl_digest_getHMAC_SHA1 (&digest, pBuffer, nBufLen); + } + + rtl_zeroMemory (&digest, sizeof (digest)); + return (result); +} + +/* + * rtl_digest_createHMAC_SHA1. + */ +rtlDigest SAL_CALL rtl_digest_createHMAC_SHA1 (void) +{ + DigestHMAC_SHA1_Impl *pImpl = (DigestHMAC_SHA1_Impl*)NULL; + pImpl = RTL_DIGEST_CREATE(DigestHMAC_SHA1_Impl); + if (pImpl) + { + pImpl->m_digest = __rtl_digest_HMAC_SHA1; + __rtl_digest_initHMAC_SHA1 (&(pImpl->m_context)); + } + return ((rtlDigest)pImpl); +} + +/* + * rtl_digest_initHMAC_SHA1. + */ +rtlDigestError SAL_CALL rtl_digest_initHMAC_SHA1 ( + rtlDigest Digest, const sal_uInt8 *pKeyData, sal_uInt32 nKeyLen) +{ + DigestHMAC_SHA1_Impl *pImpl = (DigestHMAC_SHA1_Impl*)Digest; + ContextHMAC_SHA1 *ctx; + + if ((pImpl == NULL) || (pKeyData == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmHMAC_SHA1)) + return rtl_Digest_E_Algorithm; + + ctx = &(pImpl->m_context); + __rtl_digest_initHMAC_SHA1 (ctx); + + if (nKeyLen > DIGEST_CBLOCK_HMAC_SHA1) + { + /* Initialize 'opad' with hashed 'KeyData' */ + rtl_digest_updateSHA1 ( + &(ctx->m_hash), pKeyData, nKeyLen); + rtl_digest_getSHA1 ( + &(ctx->m_hash), ctx->m_opad, RTL_DIGEST_LENGTH_SHA1); + } + else + { + /* Initialize 'opad' with plain 'KeyData' */ + rtl_copyMemory (ctx->m_opad, pKeyData, nKeyLen); + } + + __rtl_digest_ipadHMAC_SHA1 (ctx); + __rtl_digest_opadHMAC_SHA1 (ctx); + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_updateHMAC_SHA1. + */ +rtlDigestError SAL_CALL rtl_digest_updateHMAC_SHA1 ( + rtlDigest Digest, const void *pData, sal_uInt32 nDatLen) +{ + DigestHMAC_SHA1_Impl *pImpl = (DigestHMAC_SHA1_Impl*)Digest; + ContextHMAC_SHA1 *ctx; + + if ((pImpl == NULL) || (pData == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmHMAC_SHA1)) + return rtl_Digest_E_Algorithm; + + ctx = &(pImpl->m_context); + rtl_digest_updateSHA1 (&(ctx->m_hash), pData, nDatLen); + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_getHMAC_SHA1. + */ +rtlDigestError SAL_CALL rtl_digest_getHMAC_SHA1 ( + rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen) +{ + DigestHMAC_SHA1_Impl *pImpl = (DigestHMAC_SHA1_Impl*)Digest; + ContextHMAC_SHA1 *ctx; + + if ((pImpl == NULL) || (pBuffer == NULL)) + return rtl_Digest_E_Argument; + + if (!(pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmHMAC_SHA1)) + return rtl_Digest_E_Algorithm; + + if (!(pImpl->m_digest.m_length <= nBufLen)) + return rtl_Digest_E_BufferSize; + + nBufLen = pImpl->m_digest.m_length; + + ctx = &(pImpl->m_context); + rtl_digest_getSHA1 (&(ctx->m_hash), pBuffer, nBufLen); + + rtl_digest_updateSHA1 (&(ctx->m_hash), ctx->m_opad, sizeof(ctx->m_opad)); + rtl_digest_updateSHA1 (&(ctx->m_hash), pBuffer, nBufLen); + rtl_digest_getSHA1 (&(ctx->m_hash), pBuffer, nBufLen); + + __rtl_digest_opadHMAC_SHA1 (ctx); + __rtl_digest_ipadHMAC_SHA1 (ctx); + __rtl_digest_opadHMAC_SHA1 (ctx); + + return rtl_Digest_E_None; +} + +/* + * rtl_digest_destroyHMAC_SHA1. + */ +void SAL_CALL rtl_digest_destroyHMAC_SHA1 (rtlDigest Digest) +{ + DigestHMAC_SHA1_Impl *pImpl = (DigestHMAC_SHA1_Impl*)Digest; + if (pImpl) + { + if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmHMAC_SHA1) + rtl_freeZeroMemory (pImpl, sizeof (DigestHMAC_SHA1_Impl)); + else + rtl_freeMemory (pImpl); + } +} + +/*======================================================================== + * + * rtl_digest_PBKDF2 internals. + * + *======================================================================*/ +#define DIGEST_CBLOCK_PBKDF2 RTL_DIGEST_LENGTH_HMAC_SHA1 + +/* + * __rtl_digest_updatePBKDF2. + */ +static void __rtl_digest_updatePBKDF2 ( + rtlDigest hDigest, + sal_uInt8 T[DIGEST_CBLOCK_PBKDF2], + const sal_uInt8 *pSaltData, sal_uInt32 nSaltLen, + sal_uInt32 nCount, sal_uInt32 nIndex) +{ + /* T_i = F (P, S, c, i) */ + sal_uInt8 U[DIGEST_CBLOCK_PBKDF2]; + register sal_uInt32 i, k; + + /* U_(1) = PRF (P, S || INDEX) */ + rtl_digest_updateHMAC_SHA1 (hDigest, pSaltData, nSaltLen); + rtl_digest_updateHMAC_SHA1 (hDigest, &nIndex, sizeof(nIndex)); + rtl_digest_getHMAC_SHA1 (hDigest, U, DIGEST_CBLOCK_PBKDF2); + + /* T = U_(1) */ + for (k = 0; k < DIGEST_CBLOCK_PBKDF2; k++) T[k] = U[k]; + + /* T ^= U_(2) ^ ... ^ U_(c) */ + for (i = 1; i < nCount; i++) + { + /* U_(i) = PRF (P, U_(i-1)) */ + rtl_digest_updateHMAC_SHA1 (hDigest, U, DIGEST_CBLOCK_PBKDF2); + rtl_digest_getHMAC_SHA1 (hDigest, U, DIGEST_CBLOCK_PBKDF2); + + /* T ^= U_(i) */ + for (k = 0; k < DIGEST_CBLOCK_PBKDF2; k++) T[k] ^= U[k]; + } + + rtl_zeroMemory (U, DIGEST_CBLOCK_PBKDF2); +} + +/*======================================================================== + * + * rtl_digest_PBKDF2 implementation. + * + *======================================================================*/ +/* + * rtl_digest_PBKDF2. + */ +rtlDigestError SAL_CALL rtl_digest_PBKDF2 ( + sal_uInt8 *pKeyData , sal_uInt32 nKeyLen, + const sal_uInt8 *pPassData, sal_uInt32 nPassLen, + const sal_uInt8 *pSaltData, sal_uInt32 nSaltLen, + sal_uInt32 nCount) +{ + DigestHMAC_SHA1_Impl digest; + sal_uInt32 i = 1; + + if ((pKeyData == NULL) || (pPassData == NULL) || (pSaltData == NULL)) + return rtl_Digest_E_Argument; + + digest.m_digest = __rtl_digest_HMAC_SHA1; + rtl_digest_initHMAC_SHA1 (&digest, pPassData, nPassLen); + + /* DK = T_(1) || T_(2) || ... || T_(l) */ + while (nKeyLen >= DIGEST_CBLOCK_PBKDF2) + { + /* T_(i) = F (P, S, c, i); DK ||= T_(i) */ + __rtl_digest_updatePBKDF2 ( + &digest, pKeyData, + pSaltData, nSaltLen, + nCount, OSL_NETDWORD(i)); + + /* Next 'KeyData' block */ + pKeyData += DIGEST_CBLOCK_PBKDF2; + nKeyLen -= DIGEST_CBLOCK_PBKDF2; + i += 1; + } + if (nKeyLen > 0) + { + /* Last 'KeyData' block */ + sal_uInt8 T[DIGEST_CBLOCK_PBKDF2]; + + /* T_i = F (P, S, c, i) */ + __rtl_digest_updatePBKDF2 ( + &digest, T, + pSaltData, nSaltLen, + nCount, OSL_NETDWORD(i)); + + /* DK ||= T_(i) */ + rtl_copyMemory (pKeyData, T, nKeyLen); + rtl_zeroMemory (T, DIGEST_CBLOCK_PBKDF2); + } + + rtl_zeroMemory (&digest, sizeof (digest)); + return rtl_Digest_E_None; +} + +/*======================================================================== + * + * The End. + * + *======================================================================*/ diff --git a/sal/rtl/source/gen_makefile.cxx b/sal/rtl/source/gen_makefile.cxx new file mode 100644 index 000000000000..0b11c11d06c9 --- /dev/null +++ b/sal/rtl/source/gen_makefile.cxx @@ -0,0 +1,41 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "macro.hxx" +#include <stdio.h> + +int main() +{ + printf( "RTL_OS:=%s\n", THIS_OS ); + printf( "RTL_ARCH:=%s\n", THIS_ARCH ); + return 0; +} + + diff --git a/sal/rtl/source/hash.cxx b/sal/rtl/source/hash.cxx new file mode 100644 index 000000000000..7caa2341ca11 --- /dev/null +++ b/sal/rtl/source/hash.cxx @@ -0,0 +1,113 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" +#include "rtl/allocator.hxx" + +#include "hash.h" +#include "strimp.h" + + +#include <hash_set> + +namespace { + +struct UStringHash +{ + size_t operator()(rtl_uString * const &rString) const + { return (size_t)rtl_ustr_hashCode_WithLength( rString->buffer, rString->length ); } +}; + +struct UStringEqual +{ + sal_Bool operator() ( rtl_uString * const &pStringA, + rtl_uString * const &pStringB) const + { + if (pStringA == pStringB) + return true; + if (pStringA->length != pStringB->length) + return false; + return !rtl_ustr_compare_WithLength( pStringA->buffer, pStringA->length, + pStringB->buffer, pStringB->length); + } +}; + +typedef std::hash_set< rtl_uString *, UStringHash, UStringEqual, + rtl::Allocator<rtl_uString *> > StringHashTable; + +StringHashTable * +getHashTable () +{ + static StringHashTable *pInternPool = NULL; + if (pInternPool == NULL) { + static StringHashTable aImpl(1024); + pInternPool = &aImpl; + } + return pInternPool; +} + +} + +extern "C" { + +rtl_uString * +rtl_str_hash_intern (rtl_uString *pString, + int can_return) +{ + StringHashTable *pHash = getHashTable(); + StringHashTable::iterator aIter; + aIter = pHash->find(pString); + if (aIter != pHash->end()) + { + rtl_uString *pHashStr = *aIter; + rtl_uString_acquire (pHashStr); + return pHashStr; + } + if (!can_return) + { + rtl_uString *pCopy = NULL; + rtl_uString_newFromString( &pCopy, pString ); + pString = pCopy; + if (!pString) + return NULL; + } + + if (!SAL_STRING_IS_STATIC (pString)) + pString->refCount |= SAL_STRING_INTERN_FLAG; + pHash->insert(pString); + + return pString; +} + +void +rtl_str_hash_remove (rtl_uString *pString) +{ + getHashTable()->erase(pString); +} + +} diff --git a/sal/rtl/source/hash.h b/sal/rtl/source/hash.h new file mode 100644 index 000000000000..2aadfb33efcd --- /dev/null +++ b/sal/rtl/source/hash.h @@ -0,0 +1,21 @@ +#ifndef INCLUDED_RTL_SOURCE_HASH_H +#define INCLUDED_RTL_SOURCE_HASH_H + +#include <sal/types.h> +#include <rtl/ustring.h> + +#if defined __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* These functions are not multi-thread safe: */ + +rtl_uString *rtl_str_hash_intern (rtl_uString *pString, + int can_return); +void rtl_str_hash_remove (rtl_uString *pString); + +#if defined __cplusplus +} +#endif /* __cplusplus */ + +#endif /* INCLUDED_RTL_SOURCE_HASH_H */ diff --git a/sal/rtl/source/locale.c b/sal/rtl/source/locale.c new file mode 100644 index 000000000000..89a8568f8478 --- /dev/null +++ b/sal/rtl/source/locale.c @@ -0,0 +1,362 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "rtl/locale.h" + +#include "osl/diagnose.h" +#include "rtl/alloc.h" + +#include "internal/once.h" + +static sal_Int32 RTL_HASHTABLE_SIZE[] = +{ + 7, 31, 127, 251, 509, 1021, 2039, 4093 +}; + +typedef struct rtl_hashentry RTL_HASHENTRY; + +struct rtl_hashentry +{ + rtl_Locale* Entry; + RTL_HASHENTRY* Next; +}; + +typedef struct rtl_hashtable +{ + sal_Int8 iSize; + sal_Int32 Size; + sal_Int32 Elements; + RTL_HASHENTRY** Table; +} RTL_HASHTABLE; + +static RTL_HASHTABLE* g_pLocaleTable = NULL; + +static rtl_Locale* g_pDefaultLocale = NULL; + +static int rtl_locale_init (void); + +/************************************************************************* + */ +void rtl_hashentry_destroy(RTL_HASHENTRY* entry) +{ + rtl_uString_release(entry->Entry->Language); + rtl_uString_release(entry->Entry->Country); + rtl_uString_release(entry->Entry->Variant); + if (entry->Next) + rtl_hashentry_destroy(entry->Next); + + rtl_freeMemory(entry->Entry); + rtl_freeMemory(entry); +} + +void rtl_hashtable_destroy(RTL_HASHTABLE* table) +{ + sal_Int32 size = 0; + + if (!table) + return; + + size = table->Size; + + while (size) + { + if (table->Table[size - 1]) + rtl_hashentry_destroy(table->Table[size - 1]); + size--; + } + + rtl_freeMemory(table->Table); + rtl_freeMemory(table); +} + +void rtl_hashtable_init(RTL_HASHTABLE** table, sal_Int8 sizeIndex) +{ + sal_Int32 nSize = RTL_HASHTABLE_SIZE[sizeIndex]; + + if (*table) + rtl_hashtable_destroy(*table); + + *table = (RTL_HASHTABLE*)rtl_allocateMemory( sizeof(RTL_HASHTABLE) ); + + (*table)->iSize = sizeIndex; + (*table)->Size = nSize; + (*table)->Elements = 0; + (*table)->Table = (RTL_HASHENTRY**)rtl_allocateMemory( (*table)->Size * sizeof(RTL_HASHENTRY*) ); + + while (nSize) + { + (*table)->Table[nSize - 1] = NULL; + nSize--; + } +} + +sal_Int32 rtl_hashfunc(RTL_HASHTABLE* table, sal_Int32 key) +{ + return ( (sal_uInt32) key % table->Size); +} + +sal_Bool rtl_hashtable_grow(RTL_HASHTABLE** table); + +rtl_Locale* rtl_hashtable_add(RTL_HASHTABLE** table, rtl_Locale* value) +{ + sal_Int32 key = 0; + + if (!(*table)) + return NULL; + + if ((*table)->Elements > ((*table)->Size / 2)) + rtl_hashtable_grow(table); + + key = rtl_hashfunc(*table, value->HashCode); + + if (!(*table)->Table[key]) + { + RTL_HASHENTRY *newEntry = (RTL_HASHENTRY*)rtl_allocateMemory( sizeof(RTL_HASHENTRY) ); + newEntry->Entry = value; + newEntry->Next = NULL; + (*table)->Table[key] = newEntry; + (*table)->Elements++; + return NULL; + } else + { + RTL_HASHENTRY *pEntry = (*table)->Table[key]; + RTL_HASHENTRY *newEntry = NULL; + + while (pEntry) + { + if (value->HashCode == pEntry->Entry->HashCode) + return pEntry->Entry; + + if (!pEntry->Next) + break; + + pEntry = pEntry->Next; + } + + newEntry = (RTL_HASHENTRY*)rtl_allocateMemory( sizeof(RTL_HASHENTRY) ); + newEntry->Entry = value; + newEntry->Next = NULL; + pEntry->Next = newEntry; + (*table)->Elements++; + return NULL; + } +} + +sal_Bool rtl_hashtable_grow(RTL_HASHTABLE** table) +{ + RTL_HASHTABLE* pNewTable = NULL; + sal_Int32 i = 0; + + rtl_hashtable_init(&pNewTable, (sal_Int8)((*table)->iSize + 1)); + + while (i < (*table)->Size) + { + if ((*table)->Table[i]) + { + RTL_HASHENTRY *pNext; + RTL_HASHENTRY *pEntry = (*table)->Table[i]; + + rtl_hashtable_add(&pNewTable, pEntry->Entry); + + while (pEntry->Next) + { + rtl_hashtable_add(&pNewTable, pEntry->Next->Entry); + pNext = pEntry->Next; + rtl_freeMemory(pEntry); + pEntry = pNext; + } + + rtl_freeMemory(pEntry); + } + i++; + } + + rtl_freeMemory((*table)->Table); + rtl_freeMemory((*table)); + (*table) = pNewTable; + + return sal_True; +} + +sal_Bool rtl_hashtable_find(RTL_HASHTABLE * table, sal_Int32 key, sal_Int32 hashCode, rtl_Locale** pValue) +{ + if (!table) + return sal_False; + + if (table->Table[key]) + { + RTL_HASHENTRY *pEntry = table->Table[key]; + + while (pEntry && hashCode != pEntry->Entry->HashCode) + pEntry = pEntry->Next; + + if (pEntry) + *pValue = pEntry->Entry; + else + return sal_False; + } else + return sal_False; + + return sal_True; +} + +/************************************************************************* + * rtl_locale_init + */ +static void rtl_locale_once_init (void) +{ + OSL_ASSERT(g_pLocaleTable == 0); + rtl_hashtable_init(&g_pLocaleTable, 1); +} + +static int rtl_locale_init (void) +{ + static sal_once_type g_once = SAL_ONCE_INIT; + SAL_ONCE(&g_once, rtl_locale_once_init); + return (g_pLocaleTable != 0); +} + +/************************************************************************* + * rtl_locale_fini + */ +#if defined(__GNUC__) +static void rtl_locale_fini (void) __attribute__((destructor)); +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma fini(rtl_locale_fini) +static void rtl_locale_fini (void); +#endif /* __GNUC__ || __SUNPRO_C */ + +void rtl_locale_fini (void) +{ + if (g_pLocaleTable != 0) + { + rtl_hashtable_destroy (g_pLocaleTable); + g_pLocaleTable = 0; + } +} + +/************************************************************************* + * rtl_locale_register + */ +rtl_Locale * SAL_CALL rtl_locale_register( const sal_Unicode * language, const sal_Unicode * country, const sal_Unicode * variant ) +{ + sal_Unicode c = 0; + rtl_uString* sLanguage = NULL; + rtl_uString* sCountry = NULL; + rtl_uString* sVariant = NULL; + rtl_Locale *newLocale = NULL; + sal_Int32 hashCode = -1; + sal_Int32 key = 0; + + if ( !country ) + country = &c; + if ( !variant ) + variant = &c; + + if (!rtl_locale_init()) + return NULL; + + hashCode = rtl_ustr_hashCode(language) ^ rtl_ustr_hashCode(country) ^ rtl_ustr_hashCode(variant); + key = rtl_hashfunc(g_pLocaleTable, hashCode); + + if (rtl_hashtable_find(g_pLocaleTable, key, hashCode, &newLocale)) + return newLocale; + + rtl_uString_newFromStr(&sLanguage, language); + rtl_uString_newFromStr(&sCountry, country); + rtl_uString_newFromStr(&sVariant, variant); + + newLocale = (rtl_Locale*)rtl_allocateMemory( sizeof(rtl_Locale) ); + + newLocale->Language = sLanguage; + newLocale->Country = sCountry; + newLocale->Variant = sVariant; + newLocale->HashCode = hashCode; + + rtl_hashtable_add(&g_pLocaleTable, newLocale); + + return newLocale; +} + +/************************************************************************* + * rtl_locale_getDefault + */ +rtl_Locale * SAL_CALL rtl_locale_getDefault() +{ + return g_pDefaultLocale; +} + +/************************************************************************* + * rtl_locale_setDefault + */ +void SAL_CALL rtl_locale_setDefault( const sal_Unicode * language, const sal_Unicode * country, const sal_Unicode * variant ) +{ + g_pDefaultLocale = rtl_locale_register(language, country, variant); +} + +/************************************************************************* + * rtl_locale_getLanguage + */ +rtl_uString * SAL_CALL rtl_locale_getLanguage( rtl_Locale * This ) +{ + rtl_uString_acquire(This->Language); + return This->Language; +} + +/************************************************************************* + * rtl_locale_getCountry + */ +rtl_uString * SAL_CALL rtl_locale_getCountry( rtl_Locale * This ) +{ + rtl_uString_acquire(This->Country); + return This->Country; +} + +/************************************************************************* + * rtl_locale_getVariant + */ +rtl_uString * SAL_CALL rtl_locale_getVariant( rtl_Locale * This ) +{ + rtl_uString_acquire(This->Variant); + return This->Variant; +} + +/************************************************************************* + * rtl_locale_hashCode + */ +sal_Int32 SAL_CALL rtl_locale_hashCode( rtl_Locale * This ) +{ + return This->HashCode; +} + +/************************************************************************* + * rtl_locale_equals + */ +sal_Int32 SAL_CALL rtl_locale_equals( rtl_Locale * This, rtl_Locale * obj ) +{ + return This == obj; +} diff --git a/sal/rtl/source/logfile.cxx b/sal/rtl/source/logfile.cxx new file mode 100644 index 000000000000..56d5e5d5d68e --- /dev/null +++ b/sal/rtl/source/logfile.cxx @@ -0,0 +1,254 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" +#include <cstdarg> +#include <cstdio> +#include <stdio.h> +#include <stdarg.h> + +#include <rtl/logfile.h> +#include <osl/process.h> +#ifndef _OSL_FILE_H_ +#include <osl/time.h> +#endif +#include <osl/time.h> +#include <osl/mutex.hxx> +#include <rtl/bootstrap.h> +#include <rtl/ustring.hxx> +#ifndef _RTL_STRBUF_HXX_ +#include <rtl/ustrbuf.hxx> +#endif +#include <rtl/alloc.h> +#include "osl/thread.h" + +#include <algorithm> + +#ifdef _MSC_VER +#define vsnprintf _vsnprintf +#endif + +using namespace rtl; +using namespace osl; +using namespace std; + +namespace { + +static oslFileHandle g_aFile = 0; +static sal_Bool g_bHasBeenCalled = sal_False; +static const sal_Int32 g_BUFFERSIZE = 4096; +static sal_Char *g_buffer = 0; + +class LoggerGuard +{ +public: + ~LoggerGuard(); +}; + +LoggerGuard::~LoggerGuard() +{ + if( g_buffer ) + { + sal_Int64 nWritten, nConverted = + sprintf( g_buffer, "closing log file at %06" SAL_PRIuUINT32, osl_getGlobalTimer() ); + if( nConverted > 0 ) + osl_writeFile( g_aFile, g_buffer, nConverted, (sal_uInt64 *)&nWritten ); + osl_closeFile( g_aFile ); + g_aFile = 0; + + rtl_freeMemory( g_buffer ); + g_buffer = 0; + g_bHasBeenCalled = sal_False; + } +} + +// The destructor of this static LoggerGuard is "activated" by the assignment to +// g_buffer in init(): +LoggerGuard loggerGuard; + +Mutex & getLogMutex() +{ + static Mutex *pMutex = 0; + if( !pMutex ) + { + MutexGuard guard( Mutex::getGlobalMutex() ); + if( ! pMutex ) + { + static Mutex mutex; + pMutex = &mutex; + } + } + return *pMutex; +} + +OUString getFileUrl( const OUString &name ) +{ + OUString aRet; + if ( osl_getFileURLFromSystemPath( name.pData, &aRet.pData ) + != osl_File_E_None ) + { + OSL_ASSERT( false ); + } + + OUString aWorkingDirectory; + osl_getProcessWorkingDir( &(aWorkingDirectory.pData) ); + osl_getAbsoluteFileURL( aWorkingDirectory.pData, aRet.pData, &(aRet.pData) ); + + return aRet; +} + +void init() { + if( !g_bHasBeenCalled ) + { + MutexGuard guard( getLogMutex() ); + if( ! g_bHasBeenCalled ) + { + OUString name( RTL_CONSTASCII_USTRINGPARAM( "RTL_LOGFILE" ) ); + OUString value; + if( rtl_bootstrap_get( name.pData, &value.pData, 0 ) ) + { + // Obtain process id. + oslProcessIdentifier aProcessId = 0; + oslProcessInfo info; + info.Size = sizeof (oslProcessInfo); + if (osl_getProcessInfo (0, osl_Process_IDENTIFIER, &info) == osl_Process_E_None) + aProcessId = info.Ident; + + // Construct name of log file and open the file. + OUStringBuffer buf( 128 ); + buf.append( value ); + + // if the filename ends with .nopid, the incoming filename is not modified + if( value.getLength() < 6 /* ".nopid" */ || + rtl_ustr_ascii_compare_WithLength( + value.getStr() + (value.getLength()-6) , 6 , ".nopid" ) ) + { + buf.appendAscii( "_" ); + buf.append( (sal_Int32) aProcessId ); + buf.appendAscii( ".log" ); + } + + OUString o = getFileUrl( buf.makeStringAndClear() ); + oslFileError e = osl_openFile( + o.pData, &g_aFile, osl_File_OpenFlag_Write|osl_File_OpenFlag_Create); + + if( osl_File_E_None == e ) + { + TimeValue aCurrentTime; + g_buffer = ( sal_Char * ) rtl_allocateMemory( g_BUFFERSIZE ); + sal_Int64 nConverted = 0; + if (osl_getSystemTime (&aCurrentTime)) + { + nConverted = (sal_Int64 ) sprintf ( + g_buffer, + "opening log file %f seconds past January 1st 1970\n" + "corresponding to %" SAL_PRIuUINT32 " ms after timer start\n", + aCurrentTime.Seconds + 1e-9 * aCurrentTime.Nanosec, + osl_getGlobalTimer()); + + if( nConverted > 0 ) + { + sal_Int64 nWritten; + osl_writeFile( g_aFile, g_buffer, nConverted , (sal_uInt64 *)&nWritten ); + } + } + + nConverted = sprintf (g_buffer, "Process id is %" SAL_PRIuUINT32 "\n", aProcessId); + if( nConverted ) + { + sal_Int64 nWritten; + osl_writeFile( g_aFile, g_buffer, nConverted, (sal_uInt64 *)&nWritten ); + } + } + else + { + OSL_TRACE( "Couldn't open logfile %s(%d)" , o.getStr(), e ); + } + } + g_bHasBeenCalled = sal_True; + } + } +} + +} + +extern "C" void SAL_CALL rtl_logfile_trace ( const char *pszFormat, ... ) +{ + init(); + if( g_buffer ) + { + va_list args; + va_start(args, pszFormat); + { + sal_Int64 nConverted, nWritten; + MutexGuard guard( getLogMutex() ); + nConverted = vsnprintf( g_buffer , g_BUFFERSIZE, pszFormat, args ); + nConverted = (nConverted > g_BUFFERSIZE ? g_BUFFERSIZE : nConverted ); + if( nConverted > 0 ) + osl_writeFile( g_aFile, g_buffer, nConverted, (sal_uInt64*)&nWritten ); + } + va_end(args); + } +} + +extern "C" void SAL_CALL rtl_logfile_longTrace(char const * format, ...) { + init(); + if (g_buffer != 0) { + sal_uInt32 time = osl_getGlobalTimer(); + oslThreadIdentifier threadId = osl_getThreadIdentifier(0); + va_list args; + va_start(args, format); + { + MutexGuard g(getLogMutex()); + int n1 = snprintf( + g_buffer, g_BUFFERSIZE, "%06" SAL_PRIuUINT32 " %" SAL_PRIuUINT32 " ", time, threadId); + if (n1 >= 0) { + sal_uInt64 n2; + osl_writeFile( + g_aFile, g_buffer, + static_cast< sal_uInt64 >( + std::min(n1, static_cast< int >(g_BUFFERSIZE))), + &n2); + n1 = vsnprintf(g_buffer, g_BUFFERSIZE, format, args); + if (n1 > 0) { + osl_writeFile( + g_aFile, g_buffer, + static_cast< sal_uInt64 >( + std::min(n1, static_cast< int >(g_BUFFERSIZE))), + &n2); + } + } + } + va_end(args); + } +} + +extern "C" sal_Bool SAL_CALL rtl_logfile_hasLogFile( void ) { + init(); + return g_buffer != 0; +} diff --git a/sal/rtl/source/macro.hxx b/sal/rtl/source/macro.hxx new file mode 100644 index 000000000000..3fa0fbe58f42 --- /dev/null +++ b/sal/rtl/source/macro.hxx @@ -0,0 +1,110 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _RTL_MACRO_HXX +#define _RTL_MACRO_HXX + +#include <rtl/bootstrap.h> +#include <rtl/ustring.hxx> +#include <osl/endian.h> + +#if defined WIN32 +#define THIS_OS "Windows" +#elif defined OS2 +#define THIS_OS "OS2" +#elif defined SOLARIS +#define THIS_OS "Solaris" +#elif defined LINUX +#ifdef __FreeBSD_kernel__ +#define THIS_OS "kFreeBSD" +#else +#define THIS_OS "Linux" +#endif +#elif defined MACOSX +#define THIS_OS "MacOSX" +#elif defined NETBSD +#define THIS_OS "NetBSD" +#elif defined FREEBSD +#define THIS_OS "FreeBSD" +#endif + +#if ! defined THIS_OS +#error "unknown OS -- insert your OS identifier above" +this is inserted for the case that the preprocessor ignores error +#endif + +#if defined X86_64 +# define THIS_ARCH "X86_64" +#elif defined INTEL +# define THIS_ARCH "x86" +#elif defined POWERPC64 +# define THIS_ARCH "PowerPC_64" +#elif defined POWERPC +# define THIS_ARCH "PowerPC" +#elif defined S390X +# define THIS_ARCH "S390x" +#elif defined S390 +# define THIS_ARCH "S390" +#elif defined SPARC +#if defined IS_LP64 +# define THIS_ARCH "SPARC64" +#else +# define THIS_ARCH "SPARC" +#endif +#elif defined MIPS +# ifdef OSL_BIGENDIAN +# define THIS_ARCH "MIPS_EB" +# else +# define THIS_ARCH "MIPS_EL" +# endif +#elif defined ARM +# ifdef __ARM_EABI__ +# define THIS_ARCH "ARM_EABI" +# else +# define THIS_ARCH "ARM_OABI" +# endif +#elif defined IA64 +# define THIS_ARCH "IA64" +#elif defined M68K +# define THIS_ARCH "M68K" +#elif defined HPPA +# define THIS_ARCH "HPPA" +#elif defined AXP +# define THIS_ARCH "ALPHA" +#endif + +#if ! defined THIS_ARCH +#error "unknown ARCH -- insert your ARCH identifier above" +this is inserted for the case that the preprocessor ignores error +#endif + +#endif + + + + + diff --git a/sal/rtl/source/makefile.mk b/sal/rtl/source/makefile.mk new file mode 100644 index 000000000000..9968d8992be4 --- /dev/null +++ b/sal/rtl/source/makefile.mk @@ -0,0 +1,198 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=sal +TARGET=cpprtl +ENABLE_EXCEPTIONS=TRUE +USE_LDUMP2=TRUE + +PROJECTPCH4DLL=TRUE +PROJECTPCH=cont_pch +PROJECTPCHSOURCE=cont_pch + +.IF "$(GUI)" == "OS2" +STL_OS2_BUILDING=1 +.ENDIF + +TARGETTYPE=CUI + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +.IF "$(ALLOC)" == "SYS_ALLOC" || "$(ALLOC)" == "TCMALLOC" || "$(ALLOC)" == "JEMALLOC" +CDEFS+= -DFORCE_SYSALLOC +.ENDIF + +CFLAGS+= $(LFS_CFLAGS) +CXXFLAGS+= $(LFS_CFLAGS) + +# --- Files -------------------------------------------------------- + +# safe that way: gen_makefile doesn't want it, +# no other link target here +UWINAPILIB:= + +.IF "$(header)" == "" + +ALWAYSDBGFILES=$(SLO)$/debugprint.obj + +.IF "$(ALWAYSDBGFILES)" != "" +ALWAYSDBGTARGET=do_it_alwaysdebug +.ENDIF + +SLOFILES= \ + $(SLO)$/memory.obj \ + $(SLO)$/cipher.obj \ + $(SLO)$/crc.obj \ + $(SLO)$/digest.obj \ + $(SLO)$/random.obj \ + $(SLO)$/locale.obj \ + $(SLO)$/strimp.obj \ + $(SLO)$/hash.obj \ + $(SLO)$/string.obj \ + $(SLO)$/ustring.obj \ + $(SLO)$/strbuf.obj \ + $(SLO)$/ustrbuf.obj \ + $(SLO)$/uuid.obj \ + $(SLO)$/rtl_process.obj \ + $(SLO)$/byteseq.obj \ + $(SLO)$/uri.obj \ + $(SLO)$/bootstrap.obj \ + $(SLO)$/cmdargs.obj \ + $(SLO)$/unload.obj \ + $(SLO)$/logfile.obj \ + $(SLO)$/tres.obj \ + $(SLO)$/debugprint.obj \ + $(SLO)$/math.obj \ + $(SLO)$/alloc_global.obj\ + $(SLO)$/alloc_cache.obj \ + $(SLO)$/alloc_arena.obj + +.IF "$(OS)"=="MACOSX" +SLOFILES+=$(SLO)$/memory_fini.obj +.ENDIF + + +#.IF "$(UPDATER)"=="YES" +OBJFILES= \ + $(OBJ)$/memory.obj \ + $(OBJ)$/cipher.obj \ + $(OBJ)$/crc.obj \ + $(OBJ)$/digest.obj \ + $(OBJ)$/random.obj \ + $(OBJ)$/locale.obj \ + $(OBJ)$/strimp.obj \ + $(OBJ)$/hash.obj \ + $(OBJ)$/string.obj \ + $(OBJ)$/ustring.obj \ + $(OBJ)$/strbuf.obj \ + $(OBJ)$/ustrbuf.obj \ + $(OBJ)$/uuid.obj \ + $(OBJ)$/rtl_process.obj \ + $(OBJ)$/byteseq.obj \ + $(OBJ)$/uri.obj \ + $(OBJ)$/bootstrap.obj \ + $(OBJ)$/cmdargs.obj \ + $(OBJ)$/unload.obj \ + $(OBJ)$/logfile.obj \ + $(OBJ)$/tres.obj \ + $(OBJ)$/math.obj \ + $(OBJ)$/alloc_global.obj\ + $(OBJ)$/alloc_cache.obj \ + $(OBJ)$/alloc_arena.obj + +.IF "$(OS)"=="MACOSX" +OBJFILES+=$(OBJ)$/memory_fini.obj +.ENDIF + + +APP1TARGET=gen_makefile +APP1OBJS=$(SLO)$/gen_makefile.obj +APP1LIBSALCPPRT= +APP1RPATH=NONE + +# --- Extra objs ---------------------------------------------------- + +.IF "$(OS)"=="LINUX" || "$(OS)"=="OS2" + +# +# This part builds a second version of alloc.c, with +# FORCE_SYSALLOC defined. Is later used in util/makefile.mk +# to build a tiny replacement lib to LD_PRELOAD into the +# office, enabling e.g. proper valgrinding. +# + +SECOND_BUILD=SYSALLOC +SYSALLOC_SLOFILES= $(SLO)$/alloc_global.obj +SYSALLOCCDEFS+=-DFORCE_SYSALLOC + +.ENDIF # .IF "$(OS)"=="LINUX" + +#.ENDIF + +.ENDIF + +# --- Makefile snippet -------------------------------------------- + +# used by e.g. update info file +BOOTSTRAPMK = $(OUT)$/inc$/rtlbootstrap.mk + +# --- Targets ------------------------------------------------------ + +.IF "$(ALWAYSDBG_FLAG)"=="" +TARGETDEPS+=$(ALWAYSDBGTARGET) +.ENDIF + +.INCLUDE : target.mk + +.IF "$(ALWAYSDBGTARGET)" != "" +.IF "$(ALWAYSDBG_FLAG)" == "" +# -------------------------------------------------- +# - ALWAYSDBG - files always compiled with debugging +# -------------------------------------------------- +$(ALWAYSDBGTARGET): + @echo --- ALWAYSDBGFILES --- + @dmake $(MFLAGS) $(MAKEFILE) debug=true $(ALWAYSDBGFILES) ALWAYSDBG_FLAG=TRUE $(CALLMACROS) + @echo --- ALWAYSDBGFILES OVER --- + +$(ALWAYSDBGFILES): + @echo --- ALWAYSDBG --- + @dmake $(MFLAGS) $(MAKEFILE) debug=true ALWAYSDBG_FLAG=TRUE $(CALLMACROS) $@ + @echo --- ALWAYSDBG OVER --- + +.ENDIF +.ENDIF + + +ALLTAR : $(BOOTSTRAPMK) + +$(BOOTSTRAPMK) : $(APP1TARGETN) + $(AUGMENT_LIBRARY_PATH) $< > $@ + diff --git a/sal/rtl/source/math.cxx b/sal/rtl/source/math.cxx new file mode 100644 index 000000000000..34b940a301c9 --- /dev/null +++ b/sal/rtl/source/math.cxx @@ -0,0 +1,1265 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "rtl/math.h" + +#include "osl/diagnose.h" +#include "rtl/alloc.h" +#include "rtl/math.hxx" +#include "rtl/strbuf.h" +#include "rtl/string.h" +#include "rtl/ustrbuf.h" +#include "rtl/ustring.h" +#include "sal/mathconf.h" +#include "sal/types.h" + +#include <algorithm> +#include <float.h> +#include <limits.h> +#include <math.h> +#include <stdlib.h> + + +static int const n10Count = 16; +static double const n10s[2][n10Count] = { + { 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, + 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16 }, + { 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, + 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16 } +}; + +// return pow(10.0,nExp) optimized for exponents in the interval [-16,16] +static double getN10Exp( int nExp ) +{ + if ( nExp < 0 ) + { + if ( -nExp <= n10Count ) + return n10s[1][-nExp-1]; + else + return pow( 10.0, static_cast<double>( nExp ) ); + } + else if ( nExp > 0 ) + { + if ( nExp <= n10Count ) + return n10s[0][nExp-1]; + else + return pow( 10.0, static_cast<double>( nExp ) ); + } + else // ( nExp == 0 ) + return 1.0; +} + +/** Approximation algorithm for erf for 0 < x < 0.65. */ +void lcl_Erf0065( double x, double& fVal ) +{ + static const double pn[] = { + 1.12837916709551256, + 1.35894887627277916E-1, + 4.03259488531795274E-2, + 1.20339380863079457E-3, + 6.49254556481904354E-5 + }; + static const double qn[] = { + 1.00000000000000000, + 4.53767041780002545E-1, + 8.69936222615385890E-2, + 8.49717371168693357E-3, + 3.64915280629351082E-4 + }; + double fPSum = 0.0; + double fQSum = 0.0; + double fXPow = 1.0; + for ( unsigned int i = 0; i <= 4; ++i ) + { + fPSum += pn[i]*fXPow; + fQSum += qn[i]*fXPow; + fXPow *= x*x; + } + fVal = x * fPSum / fQSum; +} + +/** Approximation algorithm for erfc for 0.65 < x < 6.0. */ +void lcl_Erfc0600( double x, double& fVal ) +{ + double fPSum = 0.0; + double fQSum = 0.0; + double fXPow = 1.0; + const double *pn; + const double *qn; + + if ( x < 2.2 ) + { + static const double pn22[] = { + 9.99999992049799098E-1, + 1.33154163936765307, + 8.78115804155881782E-1, + 3.31899559578213215E-1, + 7.14193832506776067E-2, + 7.06940843763253131E-3 + }; + static const double qn22[] = { + 1.00000000000000000, + 2.45992070144245533, + 2.65383972869775752, + 1.61876655543871376, + 5.94651311286481502E-1, + 1.26579413030177940E-1, + 1.25304936549413393E-2 + }; + pn = pn22; + qn = qn22; + } + else /* if ( x < 6.0 ) this is true, but the compiler does not know */ + { + static const double pn60[] = { + 9.99921140009714409E-1, + 1.62356584489366647, + 1.26739901455873222, + 5.81528574177741135E-1, + 1.57289620742838702E-1, + 2.25716982919217555E-2 + }; + static const double qn60[] = { + 1.00000000000000000, + 2.75143870676376208, + 3.37367334657284535, + 2.38574194785344389, + 1.05074004614827206, + 2.78788439273628983E-1, + 4.00072964526861362E-2 + }; + pn = pn60; + qn = qn60; + } + + for ( unsigned int i = 0; i < 6; ++i ) + { + fPSum += pn[i]*fXPow; + fQSum += qn[i]*fXPow; + fXPow *= x; + } + fQSum += qn[6]*fXPow; + fVal = exp( -1.0*x*x )* fPSum / fQSum; +} + +/** Approximation algorithm for erfc for 6.0 < x < 26.54 (but used for all + x > 6.0). */ +void lcl_Erfc2654( double x, double& fVal ) +{ + static const double pn[] = { + 5.64189583547756078E-1, + 8.80253746105525775, + 3.84683103716117320E1, + 4.77209965874436377E1, + 8.08040729052301677 + }; + static const double qn[] = { + 1.00000000000000000, + 1.61020914205869003E1, + 7.54843505665954743E1, + 1.12123870801026015E2, + 3.73997570145040850E1 + }; + + double fPSum = 0.0; + double fQSum = 0.0; + double fXPow = 1.0; + + for ( unsigned int i = 0; i <= 4; ++i ) + { + fPSum += pn[i]*fXPow; + fQSum += qn[i]*fXPow; + fXPow /= x*x; + } + fVal = exp(-1.0*x*x)*fPSum / (x*fQSum); +} + +namespace { + +double const nKorrVal[] = { + 0, 9e-1, 9e-2, 9e-3, 9e-4, 9e-5, 9e-6, 9e-7, 9e-8, + 9e-9, 9e-10, 9e-11, 9e-12, 9e-13, 9e-14, 9e-15 +}; + +struct StringTraits +{ + typedef sal_Char Char; + + typedef rtl_String String; + + static inline void createString(rtl_String ** pString, + sal_Char const * pChars, sal_Int32 nLen) + { + rtl_string_newFromStr_WithLength(pString, pChars, nLen); + } + + static inline void createBuffer(rtl_String ** pBuffer, + sal_Int32 * pCapacity) + { + rtl_string_new_WithLength(pBuffer, *pCapacity); + } + + static inline void appendChar(rtl_String ** pBuffer, sal_Int32 * pCapacity, + sal_Int32 * pOffset, sal_Char cChar) + { + rtl_stringbuffer_insert(pBuffer, pCapacity, *pOffset, &cChar, 1); + ++*pOffset; + } + + static inline void appendChars(rtl_String ** pBuffer, sal_Int32 * pCapacity, + sal_Int32 * pOffset, sal_Char const * pChars, + sal_Int32 nLen) + { + rtl_stringbuffer_insert(pBuffer, pCapacity, *pOffset, pChars, nLen); + *pOffset += nLen; + } + + static inline void appendAscii(rtl_String ** pBuffer, sal_Int32 * pCapacity, + sal_Int32 * pOffset, sal_Char const * pStr, + sal_Int32 nLen) + { + rtl_stringbuffer_insert(pBuffer, pCapacity, *pOffset, pStr, nLen); + *pOffset += nLen; + } +}; + +struct UStringTraits +{ + typedef sal_Unicode Char; + + typedef rtl_uString String; + + static inline void createString(rtl_uString ** pString, + sal_Unicode const * pChars, sal_Int32 nLen) + { + rtl_uString_newFromStr_WithLength(pString, pChars, nLen); + } + + static inline void createBuffer(rtl_uString ** pBuffer, + sal_Int32 * pCapacity) + { + rtl_uString_new_WithLength(pBuffer, *pCapacity); + } + + static inline void appendChar(rtl_uString ** pBuffer, sal_Int32 * pCapacity, + sal_Int32 * pOffset, sal_Unicode cChar) + { + rtl_uStringbuffer_insert(pBuffer, pCapacity, *pOffset, &cChar, 1); + ++*pOffset; + } + + static inline void appendChars(rtl_uString ** pBuffer, + sal_Int32 * pCapacity, sal_Int32 * pOffset, + sal_Unicode const * pChars, sal_Int32 nLen) + { + rtl_uStringbuffer_insert(pBuffer, pCapacity, *pOffset, pChars, nLen); + *pOffset += nLen; + } + + static inline void appendAscii(rtl_uString ** pBuffer, + sal_Int32 * pCapacity, sal_Int32 * pOffset, + sal_Char const * pStr, sal_Int32 nLen) + { + rtl_uStringbuffer_insert_ascii(pBuffer, pCapacity, *pOffset, pStr, + nLen); + *pOffset += nLen; + } +}; + + +// Solaris C++ 5.2 compiler has problems when "StringT ** pResult" is +// "typename T::String ** pResult" instead: +template< typename T, typename StringT > +inline void doubleToString(StringT ** pResult, + sal_Int32 * pResultCapacity, sal_Int32 nResultOffset, + double fValue, rtl_math_StringFormat eFormat, + sal_Int32 nDecPlaces, typename T::Char cDecSeparator, + sal_Int32 const * pGroups, + typename T::Char cGroupSeparator, + bool bEraseTrailingDecZeros) +{ + static double const nRoundVal[] = { + 5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6, + 0.5e-7, 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14 + }; + + // sign adjustment, instead of testing for fValue<0.0 this will also fetch + // -0.0 + bool bSign = rtl::math::isSignBitSet( fValue ); + if( bSign ) + fValue = -fValue; + + if ( rtl::math::isNan( fValue ) ) + { + // #i112652# XMLSchema-2 + sal_Int32 nCapacity = RTL_CONSTASCII_LENGTH("NaN"); + if (pResultCapacity == 0) + { + pResultCapacity = &nCapacity; + T::createBuffer(pResult, pResultCapacity); + nResultOffset = 0; + } + T::appendAscii(pResult, pResultCapacity, &nResultOffset, + RTL_CONSTASCII_STRINGPARAM("NaN")); + + return; + } + + bool bHuge = fValue == HUGE_VAL; // g++ 3.0.1 requires it this way... + if ( bHuge || rtl::math::isInf( fValue ) ) + { + // #i112652# XMLSchema-2 + sal_Int32 nCapacity = RTL_CONSTASCII_LENGTH("-INF"); + if (pResultCapacity == 0) + { + pResultCapacity = &nCapacity; + T::createBuffer(pResult, pResultCapacity); + nResultOffset = 0; + } + if ( bSign ) + T::appendAscii(pResult, pResultCapacity, &nResultOffset, + RTL_CONSTASCII_STRINGPARAM("-")); + T::appendAscii(pResult, pResultCapacity, &nResultOffset, + RTL_CONSTASCII_STRINGPARAM("INF")); + + return; + } + + // find the exponent + int nExp = 0; + if ( fValue > 0.0 ) + { + nExp = static_cast< int >( floor( log10( fValue ) ) ); + fValue /= getN10Exp( nExp ); + } + + switch ( eFormat ) + { + case rtl_math_StringFormat_Automatic : + { // E or F depending on exponent magnitude + int nPrec; + if ( nExp <= -15 || nExp >= 15 ) // #58531# was <-16, >16 + { + nPrec = 14; + eFormat = rtl_math_StringFormat_E; + } + else + { + if ( nExp < 14 ) + { + nPrec = 15 - nExp - 1; + eFormat = rtl_math_StringFormat_F; + } + else + { + nPrec = 15; + eFormat = rtl_math_StringFormat_F; + } + } + if ( nDecPlaces == rtl_math_DecimalPlaces_Max ) + nDecPlaces = nPrec; + } + break; + case rtl_math_StringFormat_G : + { // G-Point, similar to sprintf %G + if ( nDecPlaces == rtl_math_DecimalPlaces_DefaultSignificance ) + nDecPlaces = 6; + if ( nExp < -4 || nExp >= nDecPlaces ) + { + nDecPlaces = std::max< sal_Int32 >( 1, nDecPlaces - 1 ); + eFormat = rtl_math_StringFormat_E; + } + else + { + nDecPlaces = std::max< sal_Int32 >( 0, nDecPlaces - nExp - 1 ); + eFormat = rtl_math_StringFormat_F; + } + } + break; + default: + break; + } + + sal_Int32 nDigits = nDecPlaces + 1; + + if( eFormat == rtl_math_StringFormat_F ) + nDigits += nExp; + + // Round the number + if( nDigits >= 0 ) + { + if( ( fValue += nRoundVal[ nDigits > 15 ? 15 : nDigits ] ) >= 10 ) + { + fValue = 1.0; + nExp++; + if( eFormat == rtl_math_StringFormat_F ) + nDigits++; + } + } + + static sal_Int32 const nBufMax = 256; + typename T::Char aBuf[nBufMax]; + typename T::Char * pBuf; + sal_Int32 nBuf = static_cast< sal_Int32 > + ( nDigits <= 0 ? std::max< sal_Int32 >( nDecPlaces, abs(nExp) ) + : nDigits + nDecPlaces ) + 10 + (pGroups ? abs(nDigits) * 2 : 0); + if ( nBuf > nBufMax ) + { + pBuf = reinterpret_cast< typename T::Char * >( + rtl_allocateMemory(nBuf * sizeof (typename T::Char))); + OSL_ENSURE(pBuf != 0, "Out of memory"); + } + else + pBuf = aBuf; + typename T::Char * p = pBuf; + if ( bSign ) + *p++ = static_cast< typename T::Char >('-'); + + bool bHasDec = false; + + int nDecPos; + // Check for F format and number < 1 + if( eFormat == rtl_math_StringFormat_F ) + { + if( nExp < 0 ) + { + *p++ = static_cast< typename T::Char >('0'); + if ( nDecPlaces > 0 ) + { + *p++ = cDecSeparator; + bHasDec = true; + } + sal_Int32 i = ( nDigits <= 0 ? nDecPlaces : -nExp - 1 ); + while( (i--) > 0 ) + *p++ = static_cast< typename T::Char >('0'); + nDecPos = 0; + } + else + nDecPos = nExp + 1; + } + else + nDecPos = 1; + + int nGrouping = 0, nGroupSelector = 0, nGroupExceed = 0; + if ( nDecPos > 1 && pGroups && pGroups[0] && cGroupSeparator ) + { + while ( nGrouping + pGroups[nGroupSelector] < nDecPos ) + { + nGrouping += pGroups[ nGroupSelector ]; + if ( pGroups[nGroupSelector+1] ) + { + if ( nGrouping + pGroups[nGroupSelector+1] >= nDecPos ) + break; // while + ++nGroupSelector; + } + else if ( !nGroupExceed ) + nGroupExceed = nGrouping; + } + } + + // print the number + if( nDigits > 0 ) + { + for ( int i = 0; ; i++ ) + { + if( i < 15 ) + { + int nDigit; + if (nDigits-1 == 0 && i > 0 && i < 14) + nDigit = static_cast< int >( floor( fValue + + nKorrVal[15-i] ) ); + else + nDigit = static_cast< int >( fValue + 1E-15 ); + if (nDigit >= 10) + { // after-treatment of up-rounding to the next decade + sal_Int32 sLen = static_cast< long >(p-pBuf)-1; + if (sLen == -1) + { + p = pBuf; + if ( eFormat == rtl_math_StringFormat_F ) + { + *p++ = static_cast< typename T::Char >('1'); + *p++ = static_cast< typename T::Char >('0'); + } + else + { + *p++ = static_cast< typename T::Char >('1'); + *p++ = cDecSeparator; + *p++ = static_cast< typename T::Char >('0'); + nExp++; + bHasDec = true; + } + } + else + { + for (sal_Int32 j = sLen; j >= 0; j--) + { + typename T::Char cS = pBuf[j]; + if (cS != cDecSeparator) + { + if ( cS != static_cast< typename T::Char >('9')) + { + pBuf[j] = ++cS; + j = -1; // break loop + } + else + { + pBuf[j] + = static_cast< typename T::Char >('0'); + if (j == 0) + { + if ( eFormat == rtl_math_StringFormat_F) + { // insert '1' + typename T::Char * px = p++; + while ( pBuf < px ) + { + *px = *(px-1); + px--; + } + pBuf[0] = static_cast< + typename T::Char >('1'); + } + else + { + pBuf[j] = static_cast< + typename T::Char >('1'); + nExp++; + } + } + } + } + } + *p++ = static_cast< typename T::Char >('0'); + } + fValue = 0.0; + } + else + { + *p++ = static_cast< typename T::Char >( + nDigit + static_cast< typename T::Char >('0') ); + fValue = ( fValue - nDigit ) * 10.0; + } + } + else + *p++ = static_cast< typename T::Char >('0'); + if( !--nDigits ) + break; // for + if( nDecPos ) + { + if( !--nDecPos ) + { + *p++ = cDecSeparator; + bHasDec = true; + } + else if ( nDecPos == nGrouping ) + { + *p++ = cGroupSeparator; + nGrouping -= pGroups[ nGroupSelector ]; + if ( nGroupSelector && nGrouping < nGroupExceed ) + --nGroupSelector; + } + } + } + } + + if ( !bHasDec && eFormat == rtl_math_StringFormat_F ) + { // nDecPlaces < 0 did round the value + while ( --nDecPos > 0 ) + { // fill before decimal point + if ( nDecPos == nGrouping ) + { + *p++ = cGroupSeparator; + nGrouping -= pGroups[ nGroupSelector ]; + if ( nGroupSelector && nGrouping < nGroupExceed ) + --nGroupSelector; + } + *p++ = static_cast< typename T::Char >('0'); + } + } + + if ( bEraseTrailingDecZeros && bHasDec && p > pBuf ) + { + while ( *(p-1) == static_cast< typename T::Char >('0') ) + p--; + if ( *(p-1) == cDecSeparator ) + p--; + } + + // Print the exponent ('E', followed by '+' or '-', followed by exactly + // three digits). The code in rtl_[u]str_valueOf{Float|Double} relies on + // this format. + if( eFormat == rtl_math_StringFormat_E ) + { + if ( p == pBuf ) + *p++ = static_cast< typename T::Char >('1'); + // maybe no nDigits if nDecPlaces < 0 + *p++ = static_cast< typename T::Char >('E'); + if( nExp < 0 ) + { + nExp = -nExp; + *p++ = static_cast< typename T::Char >('-'); + } + else + *p++ = static_cast< typename T::Char >('+'); +// if (nExp >= 100 ) + *p++ = static_cast< typename T::Char >( + nExp / 100 + static_cast< typename T::Char >('0') ); + nExp %= 100; + *p++ = static_cast< typename T::Char >( + nExp / 10 + static_cast< typename T::Char >('0') ); + *p++ = static_cast< typename T::Char >( + nExp % 10 + static_cast< typename T::Char >('0') ); + } + + if (pResultCapacity == 0) + T::createString(pResult, pBuf, p - pBuf); + else + T::appendChars(pResult, pResultCapacity, &nResultOffset, pBuf, + p - pBuf); + + if ( pBuf != &aBuf[0] ) + rtl_freeMemory(pBuf); +} + +} + +void SAL_CALL rtl_math_doubleToString(rtl_String ** pResult, + sal_Int32 * pResultCapacity, + sal_Int32 nResultOffset, double fValue, + rtl_math_StringFormat eFormat, + sal_Int32 nDecPlaces, + sal_Char cDecSeparator, + sal_Int32 const * pGroups, + sal_Char cGroupSeparator, + sal_Bool bEraseTrailingDecZeros) + SAL_THROW_EXTERN_C() +{ + doubleToString< StringTraits, StringTraits::String >( + pResult, pResultCapacity, nResultOffset, fValue, eFormat, nDecPlaces, + cDecSeparator, pGroups, cGroupSeparator, bEraseTrailingDecZeros); +} + +void SAL_CALL rtl_math_doubleToUString(rtl_uString ** pResult, + sal_Int32 * pResultCapacity, + sal_Int32 nResultOffset, double fValue, + rtl_math_StringFormat eFormat, + sal_Int32 nDecPlaces, + sal_Unicode cDecSeparator, + sal_Int32 const * pGroups, + sal_Unicode cGroupSeparator, + sal_Bool bEraseTrailingDecZeros) + SAL_THROW_EXTERN_C() +{ + doubleToString< UStringTraits, UStringTraits::String >( + pResult, pResultCapacity, nResultOffset, fValue, eFormat, nDecPlaces, + cDecSeparator, pGroups, cGroupSeparator, bEraseTrailingDecZeros); +} + + +namespace { + +// if nExp * 10 + nAdd would result in overflow +inline bool long10Overflow( long& nExp, int nAdd ) +{ + if ( nExp > (LONG_MAX/10) + || (nExp == (LONG_MAX/10) && nAdd > (LONG_MAX%10)) ) + { + nExp = LONG_MAX; + return true; + } + return false; +} + +// We are only concerned about ASCII arabic numerical digits here +template< typename CharT > +inline bool isDigit( CharT c ) +{ + return 0x30 <= c && c <= 0x39; +} + +template< typename CharT > +inline double stringToDouble(CharT const * pBegin, CharT const * pEnd, + CharT cDecSeparator, CharT cGroupSeparator, + rtl_math_ConversionStatus * pStatus, + CharT const ** pParsedEnd) +{ + double fVal = 0.0; + rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; + + CharT const * p0 = pBegin; + while (p0 != pEnd && (*p0 == CharT(' ') || *p0 == CharT('\t'))) + ++p0; + bool bSign; + if (p0 != pEnd && *p0 == CharT('-')) + { + bSign = true; + ++p0; + } + else + { + bSign = false; + if (p0 != pEnd && *p0 == CharT('+')) + ++p0; + } + CharT const * p = p0; + bool bDone = false; + + // #i112652# XMLSchema-2 + if (3 >= (pEnd - p)) + { + if ((CharT('N') == p[0]) && (CharT('a') == p[1]) + && (CharT('N') == p[2])) + { + p += 3; + rtl::math::setNan( &fVal ); + bDone = true; + } + else if ((CharT('I') == p[0]) && (CharT('N') == p[1]) + && (CharT('F') == p[2])) + { + p += 3; + fVal = HUGE_VAL; + eStatus = rtl_math_ConversionStatus_OutOfRange; + bDone = true; + } + } + + if (!bDone) // do not recognize e.g. NaN1.23 + { + // leading zeros and group separators may be safely ignored + while (p != pEnd && (*p == CharT('0') || *p == cGroupSeparator)) + ++p; + + long nValExp = 0; // carry along exponent of mantissa + + // integer part of mantissa + for (; p != pEnd; ++p) + { + CharT c = *p; + if (isDigit(c)) + { + fVal = fVal * 10.0 + static_cast< double >( c - CharT('0') ); + ++nValExp; + } + else if (c != cGroupSeparator) + break; + } + + // fraction part of mantissa + if (p != pEnd && *p == cDecSeparator) + { + ++p; + double fFrac = 0.0; + long nFracExp = 0; + while (p != pEnd && *p == CharT('0')) + { + --nFracExp; + ++p; + } + if ( nValExp == 0 ) + nValExp = nFracExp - 1; // no integer part => fraction exponent + // one decimal digit needs ld(10) ~= 3.32 bits + static const int nSigs = (DBL_MANT_DIG / 3) + 1; + int nDigs = 0; + for (; p != pEnd; ++p) + { + CharT c = *p; + if (!isDigit(c)) + break; + if ( nDigs < nSigs ) + { // further digits (more than nSigs) don't have any + // significance + fFrac = fFrac * 10.0 + static_cast<double>(c - CharT('0')); + --nFracExp; + ++nDigs; + } + } + if ( fFrac != 0.0 ) + fVal += rtl::math::pow10Exp( fFrac, nFracExp ); + else if ( nValExp < 0 ) + nValExp = 0; // no digit other than 0 after decimal point + } + + if ( nValExp > 0 ) + --nValExp; // started with offset +1 at the first mantissa digit + + // Exponent + if (p != p0 && p != pEnd && (*p == CharT('E') || *p == CharT('e'))) + { + ++p; + bool bExpSign; + if (p != pEnd && *p == CharT('-')) + { + bExpSign = true; + ++p; + } + else + { + bExpSign = false; + if (p != pEnd && *p == CharT('+')) + ++p; + } + if ( fVal == 0.0 ) + { // no matter what follows, zero stays zero, but carry on the + // offset + while (p != pEnd && isDigit(*p)) + ++p; + } + else + { + bool bOverFlow = false; + long nExp = 0; + for (; p != pEnd; ++p) + { + CharT c = *p; + if (!isDigit(c)) + break; + int i = c - CharT('0'); + if ( long10Overflow( nExp, i ) ) + bOverFlow = true; + else + nExp = nExp * 10 + i; + } + if ( nExp ) + { + if ( bExpSign ) + nExp = -nExp; + long nAllExp = ( bOverFlow ? 0 : nExp + nValExp ); + if ( nAllExp > DBL_MAX_10_EXP || (bOverFlow && !bExpSign) ) + { // overflow + fVal = HUGE_VAL; + eStatus = rtl_math_ConversionStatus_OutOfRange; + } + else if ((nAllExp < DBL_MIN_10_EXP) || + (bOverFlow && bExpSign) ) + { // underflow + fVal = 0.0; + eStatus = rtl_math_ConversionStatus_OutOfRange; + } + else if ( nExp > DBL_MAX_10_EXP || nExp < DBL_MIN_10_EXP ) + { // compensate exponents + fVal = rtl::math::pow10Exp( fVal, -nValExp ); + fVal = rtl::math::pow10Exp( fVal, nAllExp ); + } + else + fVal = rtl::math::pow10Exp( fVal, nExp ); // normal + } + } + } + else if (p - p0 == 2 && p != pEnd && p[0] == CharT('#') + && p[-1] == cDecSeparator && p[-2] == CharT('1')) + { + if (pEnd - p >= 4 && p[1] == CharT('I') && p[2] == CharT('N') + && p[3] == CharT('F')) + { + // "1.#INF", "+1.#INF", "-1.#INF" + p += 4; + fVal = HUGE_VAL; + eStatus = rtl_math_ConversionStatus_OutOfRange; + // Eat any further digits: + while (p != pEnd && isDigit(*p)) + ++p; + } + else if (pEnd - p >= 4 && p[1] == CharT('N') && p[2] == CharT('A') + && p[3] == CharT('N')) + { + // "1.#NAN", "+1.#NAN", "-1.#NAN" + p += 4; + rtl::math::setNan( &fVal ); + if (bSign) + { + union { + double sd; + sal_math_Double md; + } m; + m.sd = fVal; + m.md.w32_parts.msw |= 0x80000000; // create negative NaN + fVal = m.sd; + bSign = false; // don't negate again + } + // Eat any further digits: + while (p != pEnd && isDigit(*p)) + ++p; + } + } + } + + // overflow also if more than DBL_MAX_10_EXP digits without decimal + // separator, or 0. and more than DBL_MIN_10_EXP digits, ... + bool bHuge = fVal == HUGE_VAL; // g++ 3.0.1 requires it this way... + if ( bHuge ) + eStatus = rtl_math_ConversionStatus_OutOfRange; + + if ( bSign ) + fVal = -fVal; + + if (pStatus != 0) + *pStatus = eStatus; + if (pParsedEnd != 0) + *pParsedEnd = p == p0 ? pBegin : p; + + return fVal; +} + +} + +double SAL_CALL rtl_math_stringToDouble(sal_Char const * pBegin, + sal_Char const * pEnd, + sal_Char cDecSeparator, + sal_Char cGroupSeparator, + rtl_math_ConversionStatus * pStatus, + sal_Char const ** pParsedEnd) + SAL_THROW_EXTERN_C() +{ + return stringToDouble(pBegin, pEnd, cDecSeparator, cGroupSeparator, pStatus, + pParsedEnd); +} + +double SAL_CALL rtl_math_uStringToDouble(sal_Unicode const * pBegin, + sal_Unicode const * pEnd, + sal_Unicode cDecSeparator, + sal_Unicode cGroupSeparator, + rtl_math_ConversionStatus * pStatus, + sal_Unicode const ** pParsedEnd) + SAL_THROW_EXTERN_C() +{ + return stringToDouble(pBegin, pEnd, cDecSeparator, cGroupSeparator, pStatus, + pParsedEnd); +} + +double SAL_CALL rtl_math_round(double fValue, int nDecPlaces, + enum rtl_math_RoundingMode eMode) + SAL_THROW_EXTERN_C() +{ + OSL_ASSERT(nDecPlaces >= -20 && nDecPlaces <= 20); + + if ( fValue == 0.0 ) + return fValue; + + // sign adjustment + bool bSign = rtl::math::isSignBitSet( fValue ); + if ( bSign ) + fValue = -fValue; + + double fFac = 0; + if ( nDecPlaces != 0 ) + { + // max 20 decimals, we don't have unlimited precision + // #38810# and no overflow on fValue*=fFac + if ( nDecPlaces < -20 || 20 < nDecPlaces || fValue > (DBL_MAX / 1e20) ) + return bSign ? -fValue : fValue; + + fFac = getN10Exp( nDecPlaces ); + fValue *= fFac; + } + //else //! uninitialized fFac, not needed + + switch ( eMode ) + { + case rtl_math_RoundingMode_Corrected : + { + int nExp; // exponent for correction + if ( fValue > 0.0 ) + nExp = static_cast<int>( floor( log10( fValue ) ) ); + else + nExp = 0; + int nIndex = 15 - nExp; + if ( nIndex > 15 ) + nIndex = 15; + else if ( nIndex <= 1 ) + nIndex = 0; + fValue = floor( fValue + 0.5 + nKorrVal[nIndex] ); + } + break; + case rtl_math_RoundingMode_Down : + fValue = rtl::math::approxFloor( fValue ); + break; + case rtl_math_RoundingMode_Up : + fValue = rtl::math::approxCeil( fValue ); + break; + case rtl_math_RoundingMode_Floor : + fValue = bSign ? rtl::math::approxCeil( fValue ) + : rtl::math::approxFloor( fValue ); + break; + case rtl_math_RoundingMode_Ceiling : + fValue = bSign ? rtl::math::approxFloor( fValue ) + : rtl::math::approxCeil( fValue ); + break; + case rtl_math_RoundingMode_HalfDown : + { + double f = floor( fValue ); + fValue = ((fValue - f) <= 0.5) ? f : ceil( fValue ); + } + break; + case rtl_math_RoundingMode_HalfUp : + { + double f = floor( fValue ); + fValue = ((fValue - f) < 0.5) ? f : ceil( fValue ); + } + break; + case rtl_math_RoundingMode_HalfEven : +#if defined FLT_ROUNDS +/* + Use fast version. FLT_ROUNDS may be defined to a function by some compilers! + + DBL_EPSILON is the smallest fractional number which can be represented, + its reciprocal is therefore the smallest number that cannot have a + fractional part. Once you add this reciprocal to `x', its fractional part + is stripped off. Simply subtracting the reciprocal back out returns `x' + without its fractional component. + Simple, clever, and elegant - thanks to Ross Cottrell, the original author, + who placed it into public domain. + + volatile: prevent compiler from being too smart +*/ + if ( FLT_ROUNDS == 1 ) + { + volatile double x = fValue + 1.0 / DBL_EPSILON; + fValue = x - 1.0 / DBL_EPSILON; + } + else +#endif // FLT_ROUNDS + { + double f = floor( fValue ); + if ( (fValue - f) != 0.5 ) + fValue = floor( fValue + 0.5 ); + else + { + double g = f / 2.0; + fValue = (g == floor( g )) ? f : (f + 1.0); + } + } + break; + default: + OSL_ASSERT(false); + break; + } + + if ( nDecPlaces != 0 ) + fValue /= fFac; + + return bSign ? -fValue : fValue; +} + + +double SAL_CALL rtl_math_pow10Exp(double fValue, int nExp) SAL_THROW_EXTERN_C() +{ + return fValue * getN10Exp( nExp ); +} + + +double SAL_CALL rtl_math_approxValue( double fValue ) SAL_THROW_EXTERN_C() +{ + if (fValue == 0.0 || fValue == HUGE_VAL || !::rtl::math::isFinite( fValue)) + // We don't handle these conditions. Bail out. + return fValue; + + double fOrigValue = fValue; + + bool bSign = ::rtl::math::isSignBitSet( fValue); + if (bSign) + fValue = -fValue; + + int nExp = static_cast<int>( floor( log10( fValue))); + nExp = 14 - nExp; + double fExpValue = getN10Exp( nExp); + + fValue *= fExpValue; + // If the original value was near DBL_MIN we got an overflow. Restore and + // bail out. + if (!rtl::math::isFinite( fValue)) + return fOrigValue; + fValue = rtl_math_round( fValue, 0, rtl_math_RoundingMode_Corrected); + fValue /= fExpValue; + // If the original value was near DBL_MAX we got an overflow. Restore and + // bail out. + if (!rtl::math::isFinite( fValue)) + return fOrigValue; + + return bSign ? -fValue : fValue; +} + + +double SAL_CALL rtl_math_expm1( double fValue ) SAL_THROW_EXTERN_C() +{ + double fe = exp( fValue ); + if (fe == 1.0) + return fValue; + if (fe-1.0 == -1.0) + return -1.0; + return (fe-1.0) * fValue / log(fe); +} + + +double SAL_CALL rtl_math_log1p( double fValue ) SAL_THROW_EXTERN_C() +{ + // Use volatile because a compiler may be too smart "optimizing" the + // condition such that in certain cases the else path was called even if + // (fp==1.0) was true, where the term (fp-1.0) then resulted in 0.0 and + // hence the entire expression resulted in NaN. + // Happened with g++ 3.4.1 and an input value of 9.87E-18 + volatile double fp = 1.0 + fValue; + if (fp == 1.0) + return fValue; + else + return log(fp) * fValue / (fp-1.0); +} + + +double SAL_CALL rtl_math_atanh( double fValue ) SAL_THROW_EXTERN_C() +{ + return 0.5 * rtl_math_log1p( 2.0 * fValue / (1.0-fValue) ); +} + + +/** Parent error function (erf) that calls different algorithms based on the + value of x. It takes care of cases where x is negative as erf is an odd + function i.e. erf(-x) = -erf(x). + + Kramer, W., and Blomquist, F., 2000, Algorithms with Guaranteed Error Bounds + for the Error Function and the Complementary Error Function + + http://www.math.uni-wuppertal.de/wrswt/literatur_en.html + + @author Kohei Yoshida <kohei@openoffice.org> + + @see #i55735# + */ +double SAL_CALL rtl_math_erf( double x ) SAL_THROW_EXTERN_C() +{ + if( x == 0.0 ) + return 0.0; + + bool bNegative = false; + if ( x < 0.0 ) + { + x = fabs( x ); + bNegative = true; + } + + double fErf = 1.0; + if ( x < 1.0e-10 ) + fErf = (double) (x*1.1283791670955125738961589031215452L); + else if ( x < 0.65 ) + lcl_Erf0065( x, fErf ); + else + fErf = 1.0 - rtl_math_erfc( x ); + + if ( bNegative ) + fErf *= -1.0; + + return fErf; +} + + +/** Parent complementary error function (erfc) that calls different algorithms + based on the value of x. It takes care of cases where x is negative as erfc + satisfies relationship erfc(-x) = 2 - erfc(x). See the comment for Erf(x) + for the source publication. + + @author Kohei Yoshida <kohei@openoffice.org> + + @see #i55735#, moved from module scaddins (#i97091#) + + */ +double SAL_CALL rtl_math_erfc( double x ) SAL_THROW_EXTERN_C() +{ + if ( x == 0.0 ) + return 1.0; + + bool bNegative = false; + if ( x < 0.0 ) + { + x = fabs( x ); + bNegative = true; + } + + double fErfc = 0.0; + if ( x >= 0.65 ) + { + if ( x < 6.0 ) + lcl_Erfc0600( x, fErfc ); + else + lcl_Erfc2654( x, fErfc ); + } + else + fErfc = 1.0 - rtl_math_erf( x ); + + if ( bNegative ) + fErfc = 2.0 - fErfc; + + return fErfc; +} + +/** improved accuracy of asinh for |x| large and for x near zero + @see #i97605# + */ +double SAL_CALL rtl_math_asinh( double fX ) SAL_THROW_EXTERN_C() +{ + double fSign = 1.0; + if ( fX == 0.0 ) + return 0.0; + else + { + if ( fX < 0.0 ) + { + fX = - fX; + fSign = -1.0; + } + if ( fX < 0.125 ) + return fSign * rtl_math_log1p( fX + fX*fX / (1.0 + sqrt( 1.0 + fX*fX))); + else if ( fX < 1.25e7 ) + return fSign * log( fX + sqrt( 1.0 + fX*fX)); + else + return fSign * log( 2.0*fX); + } +} + +/** improved accuracy of acosh for x large and for x near 1 + @see #i97605# + */ +double SAL_CALL rtl_math_acosh( double fX ) SAL_THROW_EXTERN_C() +{ + volatile double fZ = fX - 1.0; + if ( fX < 1.0 ) + { + double fResult; + ::rtl::math::setNan( &fResult ); + return fResult; + } + else if ( fX == 1.0 ) + return 0.0; + else if ( fX < 1.1 ) + return rtl_math_log1p( fZ + sqrt( fZ*fZ + 2.0*fZ)); + else if ( fX < 1.25e7 ) + return log( fX + sqrt( fX*fX - 1.0)); + else + return log( 2.0*fX); +} diff --git a/sal/rtl/source/memory.c b/sal/rtl/source/memory.c new file mode 100644 index 000000000000..a92d4201bd32 --- /dev/null +++ b/sal/rtl/source/memory.c @@ -0,0 +1,62 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include <string.h> +#include <rtl/memory.h> + +void SAL_CALL rtl_zeroMemory(void *Ptr, sal_Size Bytes) +{ + memset(Ptr, 0, Bytes); +} + +void SAL_CALL rtl_fillMemory(void *Ptr, sal_Size Bytes, sal_uInt8 Fill) +{ + memset(Ptr, Fill, Bytes); +} + +void SAL_CALL rtl_copyMemory(void *Dst, const void *Src, sal_Size Bytes) +{ + memcpy(Dst, Src, Bytes); +} + +void SAL_CALL rtl_moveMemory(void *Dst, const void *Src, sal_Size Bytes) +{ + memmove(Dst, Src, Bytes); +} + +sal_Int32 SAL_CALL rtl_compareMemory(const void *MemA, const void *MemB, sal_Size Bytes) +{ + return memcmp(MemA, MemB, Bytes); +} + +void* SAL_CALL rtl_findInMemory(const void *MemA, sal_uInt8 ch, sal_Size Bytes) +{ + return memchr(MemA, ch, Bytes); +} + + diff --git a/sal/rtl/source/memory_fini.cxx b/sal/rtl/source/memory_fini.cxx new file mode 100755 index 000000000000..f88f09887595 --- /dev/null +++ b/sal/rtl/source/memory_fini.cxx @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/* + Issue http://udk.openoffice.org/issues/show_bug.cgi?id=92388 + + Mac OS X does not seem to support "__cxa__atexit", thus leading + to the situation that "__attribute__((destructor))__" functions + (in particular "rtl_memory_fini") become called _before_ global + C++ object d'tors. + + Using a C++ dummy object instead. +*/ + +#include <stdio.h> + +extern "C" void rtl_memory_fini (void); + + +struct RTL_Memory_Fini { + ~RTL_Memory_Fini() ; +}; + +RTL_Memory_Fini::~RTL_Memory_Fini() { + rtl_memory_fini(); +} + + +static RTL_Memory_Fini rtl_Memory_Fini; diff --git a/sal/rtl/source/random.c b/sal/rtl/source/random.c new file mode 100644 index 000000000000..3ee911942684 --- /dev/null +++ b/sal/rtl/source/random.c @@ -0,0 +1,338 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define _RTL_RANDOM_C_ "$Revision: 1.6 $" + +#include <sal/types.h> +#include <osl/thread.h> +#include <osl/time.h> +#include <rtl/alloc.h> +#include <rtl/digest.h> +#include <rtl/random.h> +#include <osl/time.h> + +/*======================================================================== + * + * rtlRandom internals. + * + *======================================================================*/ +#define RTL_RANDOM_RNG_1(a) ((a) * 16807L) +#define RTL_RANDOM_RNG_2(a) ((a) * 65539L) + +#define RTL_RANDOM_RNG(x, y, z) \ +{ \ + (x) = 170 * ((x) % 178) - 63 * ((x) / 178); \ + if ((x) < 0) (x) += 30328L; \ + \ + (y) = 171 * ((y) % 177) - 2 * ((y) / 177); \ + if ((y) < 0) (y) += 30269L; \ + \ + (z) = 172 * ((z) % 176) - 35 * ((z) / 176); \ + if ((z) < 0) (z) += 30307L; \ +} + +/** RandomData_Impl. + */ +typedef struct random_data_impl_st +{ + sal_Int16 m_nX; + sal_Int16 m_nY; + sal_Int16 m_nZ; +} RandomData_Impl; + +/** __rtl_random_data. + */ +static double __rtl_random_data (RandomData_Impl *pImpl); + +/** RandomPool_Impl. + */ +#define RTL_RANDOM_DIGEST rtl_Digest_AlgorithmMD5 +#define RTL_RANDOM_SIZE_DIGEST RTL_DIGEST_LENGTH_MD5 +#define RTL_RANDOM_SIZE_POOL 1023 + +typedef struct random_pool_impl_st +{ + rtlDigest m_hDigest; + sal_uInt8 m_pDigest[RTL_RANDOM_SIZE_DIGEST]; + sal_uInt8 m_pData[RTL_RANDOM_SIZE_POOL + 1]; + sal_uInt32 m_nData; + sal_uInt32 m_nIndex; + sal_uInt32 m_nCount; +} RandomPool_Impl; + +/** __rtl_random_initPool. + */ +static sal_Bool __rtl_random_initPool ( + RandomPool_Impl *pImpl); + +/** __rtl_random_seedPool. + */ +static void __rtl_random_seedPool ( + RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen); + +/** __rtl_random_readPool. + */ +static void __rtl_random_readPool ( + RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen); + +/* + * __rtl_random_data. + */ +static double __rtl_random_data (RandomData_Impl *pImpl) +{ + register double random; + + RTL_RANDOM_RNG (pImpl->m_nX, pImpl->m_nY, pImpl->m_nZ); + random = (((double)(pImpl->m_nX) / 30328.0) + + ((double)(pImpl->m_nY) / 30269.0) + + ((double)(pImpl->m_nZ) / 30307.0) ); + + random -= ((double)((sal_uInt32)(random))); + return (random); +} + +/* + * __rtl_random_initPool. + */ +static sal_Bool __rtl_random_initPool (RandomPool_Impl *pImpl) +{ + pImpl->m_hDigest = rtl_digest_create (RTL_RANDOM_DIGEST); + if (pImpl->m_hDigest) + { + oslThreadIdentifier id; + TimeValue tv; + RandomData_Impl rd; + double seed; + + /* The use of uninitialized stack variables as a way to + * enhance the entropy of the random pool triggers + * memory checkers like purify and valgrind. + */ + + /* + __rtl_random_seedPool (pImpl, (sal_uInt8*)&id, sizeof(id)); + __rtl_random_seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv)); + __rtl_random_seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd)); + */ + + id = osl_getThreadIdentifier (NULL); + id = RTL_RANDOM_RNG_2(RTL_RANDOM_RNG_1(id)); + __rtl_random_seedPool (pImpl, (sal_uInt8*)&id, sizeof(id)); + + osl_getSystemTime (&tv); + tv.Seconds = RTL_RANDOM_RNG_2(tv.Seconds); + tv.Nanosec = RTL_RANDOM_RNG_2(tv.Nanosec); + __rtl_random_seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv)); + + rd.m_nX = (sal_Int16)(((id >> 1) << 1) + 1); + rd.m_nY = (sal_Int16)(((tv.Seconds >> 1) << 1) + 1); + rd.m_nZ = (sal_Int16)(((tv.Nanosec >> 1) << 1) + 1); + __rtl_random_seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd)); + + while (pImpl->m_nData < RTL_RANDOM_SIZE_POOL) + { + seed = __rtl_random_data (&rd); + __rtl_random_seedPool (pImpl, (sal_uInt8*)&seed, sizeof(seed)); + } + return sal_True; + } + return sal_False; +} + +/* + * __rtl_random_seedPool. + */ +static void __rtl_random_seedPool ( + RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen) +{ + sal_Size i; + sal_sSize j, k; + + for (i = 0; i < nBufLen; i += RTL_RANDOM_SIZE_DIGEST) + { + j = nBufLen - i; + if (j > RTL_RANDOM_SIZE_DIGEST) + j = RTL_RANDOM_SIZE_DIGEST; + + rtl_digest_update ( + pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST); + + k = (pImpl->m_nIndex + j) - RTL_RANDOM_SIZE_POOL; + if (k > 0) + { + rtl_digest_update ( + pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k); + rtl_digest_update ( + pImpl->m_hDigest, &(pImpl->m_pData[0]), k); + } + else + { + rtl_digest_update ( + pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j); + } + + rtl_digest_update (pImpl->m_hDigest, pBuffer, j); + pBuffer += j; + + rtl_digest_get ( + pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST); + for (k = 0; k < j; k++) + { + pImpl->m_pData[pImpl->m_nIndex++] ^= pImpl->m_pDigest[k]; + if (pImpl->m_nIndex >= RTL_RANDOM_SIZE_POOL) + { + pImpl->m_nData = RTL_RANDOM_SIZE_POOL; + pImpl->m_nIndex = 0; + } + } + } + + if (pImpl->m_nIndex > pImpl->m_nData) + pImpl->m_nData = pImpl->m_nIndex; +} + +/* + * __rtl_random_readPool. + */ +static void __rtl_random_readPool ( + RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen) +{ + sal_Int32 j, k; + + while (nBufLen > 0) + { + j = nBufLen; + if (j > RTL_RANDOM_SIZE_DIGEST/2) + j = RTL_RANDOM_SIZE_DIGEST/2; + nBufLen -= j; + + rtl_digest_update ( + pImpl->m_hDigest, + &(pImpl->m_pDigest[RTL_RANDOM_SIZE_DIGEST/2]), + RTL_RANDOM_SIZE_DIGEST/2); + + k = (pImpl->m_nIndex + j) - pImpl->m_nData; + if (k > 0) + { + rtl_digest_update ( + pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k); + rtl_digest_update ( + pImpl->m_hDigest, &(pImpl->m_pData[0]), k); + } + else + { + rtl_digest_update ( + pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j); + } + + rtl_digest_get ( + pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST); + for (k = 0; k < j; k++) + { + if (pImpl->m_nIndex >= pImpl->m_nData) pImpl->m_nIndex = 0; + pImpl->m_pData[pImpl->m_nIndex++] ^= pImpl->m_pDigest[k]; + *pBuffer++ = pImpl->m_pDigest[k + RTL_RANDOM_SIZE_DIGEST/2]; + } + } + + pImpl->m_nCount++; + rtl_digest_update ( + pImpl->m_hDigest, &(pImpl->m_nCount), sizeof(pImpl->m_nCount)); + rtl_digest_update ( + pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST); + rtl_digest_get ( + pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST); +} + +/*======================================================================== + * + * rtlRandom implementation. + * + *======================================================================*/ +/* + * rtl_random_createPool. + */ +rtlRandomPool SAL_CALL rtl_random_createPool (void) +{ + RandomPool_Impl *pImpl = (RandomPool_Impl*)NULL; + pImpl = (RandomPool_Impl*)rtl_allocateZeroMemory (sizeof(RandomPool_Impl)); + if (pImpl) + { + if (!__rtl_random_initPool (pImpl)) + { + rtl_freeZeroMemory (pImpl, sizeof(RandomPool_Impl)); + pImpl = (RandomPool_Impl*)NULL; + } + } + return ((rtlRandomPool)pImpl); +} + +/* + * rtl_random_destroyPool. + */ +void SAL_CALL rtl_random_destroyPool (rtlRandomPool Pool) +{ + RandomPool_Impl *pImpl = (RandomPool_Impl *)Pool; + if (pImpl) + { + rtl_digest_destroy (pImpl->m_hDigest); + rtl_freeZeroMemory (pImpl, sizeof (RandomPool_Impl)); + } +} + +/* + * rtl_random_addBytes. + */ +rtlRandomError SAL_CALL rtl_random_addBytes ( + rtlRandomPool Pool, const void *Buffer, sal_Size Bytes) +{ + RandomPool_Impl *pImpl = (RandomPool_Impl *)Pool; + const sal_uInt8 *pBuffer = (const sal_uInt8 *)Buffer; + + if ((pImpl == NULL) || (pBuffer == NULL)) + return rtl_Random_E_Argument; + + __rtl_random_seedPool (pImpl, pBuffer, Bytes); + return rtl_Random_E_None; +} + +/* + * rtl_random_getBytes. + */ +rtlRandomError SAL_CALL rtl_random_getBytes ( + rtlRandomPool Pool, void *Buffer, sal_Size Bytes) +{ + RandomPool_Impl *pImpl = (RandomPool_Impl *)Pool; + sal_uInt8 *pBuffer = (sal_uInt8 *)Buffer; + + if ((pImpl == NULL) || (pBuffer == NULL)) + return rtl_Random_E_Argument; + + __rtl_random_readPool (pImpl, pBuffer, Bytes); + return rtl_Random_E_None; +} + diff --git a/sal/rtl/source/rtl_process.c b/sal/rtl/source/rtl_process.c new file mode 100644 index 000000000000..d70c92c17cee --- /dev/null +++ b/sal/rtl/source/rtl_process.c @@ -0,0 +1,49 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <string.h> +#include <osl/mutex.h> +#include <rtl/uuid.h> + +/* rtl_getCommandArg, rtl_getCommandArgCount see cmdargs.cxx */ + +void SAL_CALL rtl_getGlobalProcessId( sal_uInt8 *pTargetUUID ) +{ + static sal_uInt8 *pUuid = 0; + if( ! pUuid ) + { + osl_acquireMutex( * osl_getGlobalMutex() ); + if( ! pUuid ) + { + static sal_uInt8 aUuid[16]; + rtl_createUuid( aUuid , 0 , sal_False ); + pUuid = aUuid; + } + osl_releaseMutex( * osl_getGlobalMutex() ); + } + memcpy( pTargetUUID , pUuid , 16 ); +} + diff --git a/sal/rtl/source/strbuf.c b/sal/rtl/source/strbuf.c new file mode 100644 index 000000000000..09dd83f8b32f --- /dev/null +++ b/sal/rtl/source/strbuf.c @@ -0,0 +1,147 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <osl/interlck.h> + +#ifndef _RTL_STRING_HXX_ +#include <rtl/strbuf.hxx> +#endif +#include <rtl/memory.h> + +/* +#include <rtl/alloc.h> +*/ + + + +/************************************************************************* + * rtl_stringbuffer_newFromStr_WithLength + */ +void SAL_CALL rtl_stringbuffer_newFromStr_WithLength( rtl_String ** newStr, + const sal_Char * value, + sal_Int32 count ) +{ + if (!value) + { + rtl_string_new_WithLength( newStr, 16 ); + return; + } + + rtl_string_new_WithLength( newStr, count + 16 ); + (*newStr)->length = count; + rtl_copyMemory( (*newStr)->buffer, value, count ); + return; +} + +/************************************************************************* + * rtl_stringbuffer_newFromStringBuffer + */ +sal_Int32 SAL_CALL rtl_stringbuffer_newFromStringBuffer( rtl_String ** newStr, + sal_Int32 capacity, + rtl_String * oldStr ) +{ + sal_Int32 newCapacity = capacity; + + if (newCapacity < oldStr->length) + newCapacity = oldStr->length; + + rtl_string_new_WithLength( newStr, newCapacity ); + if (oldStr->length > 0) { + (*newStr)->length = oldStr->length; + rtl_copyMemory( (*newStr)->buffer, oldStr->buffer, oldStr->length ); + } + return newCapacity; +} + +/************************************************************************* + * rtl_stringbuffer_ensureCapacity + */ +void SAL_CALL rtl_stringbuffer_ensureCapacity + (rtl_String ** This, sal_Int32* capacity, sal_Int32 minimumCapacity) +{ + if (minimumCapacity > *capacity) + { + rtl_String * pTmp = *This; + rtl_String * pNew = NULL; + *capacity = ((*This)->length + 1) * 2; + if (minimumCapacity > *capacity) + /* still lower, set to the minimum capacity */ + *capacity = minimumCapacity; + + rtl_string_new_WithLength(&pNew, *capacity); + pNew->length = (*This)->length; + *This = pNew; + + rtl_copyMemory( (*This)->buffer, pTmp->buffer, pTmp->length ); + rtl_string_release( pTmp ); + } +} + +/************************************************************************* + * rtl_stringbuffer_insert + */ +void SAL_CALL rtl_stringbuffer_insert( rtl_String ** This, + sal_Int32 * capacity, + sal_Int32 offset, + const sal_Char * str, + sal_Int32 len ) +{ + sal_Int32 nOldLen; + sal_Char * pBuf; + sal_Int32 n; + if( len != 0 ) + { + if (*capacity < (*This)->length + len) + rtl_stringbuffer_ensureCapacity( This, capacity, (*This)->length + len ); + + /* + if( len == 1 ) + This->buffer + */ + nOldLen = (*This)->length; + pBuf = (*This)->buffer; + + /* copy the tail */ + n = (nOldLen - offset); + if( n == 1 ) + /* optimized for 1 character */ + pBuf[offset + len] = pBuf[offset]; + else if( n > 1 ) + rtl_moveMemory( pBuf + offset + len, pBuf + offset, n * sizeof(sal_Char) ); + + /* insert the new characters */ + n = len; + if( len == 1 ) + /* optimized for 1 character */ + pBuf[offset] = *str; + else if( n > 1 ) + rtl_copyMemory( pBuf + offset, str, len * sizeof(sal_Char) ); + (*This)->length = nOldLen + len; + pBuf[ nOldLen + len ] = 0; + } +} + diff --git a/sal/rtl/source/strimp.c b/sal/rtl/source/strimp.c new file mode 100644 index 000000000000..993969700a88 --- /dev/null +++ b/sal/rtl/source/strimp.c @@ -0,0 +1,58 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "strimp.h" + +sal_Int16 rtl_ImplGetDigit( sal_Unicode ch, sal_Int16 nRadix ) +{ + sal_Int16 n = -1; + if ( (ch >= '0') && (ch <= '9') ) + n = ch-'0'; + else if ( (ch >= 'a') && (ch <= 'z') ) + n = ch-'a'+10; + else if ( (ch >= 'A') && (ch <= 'Z') ) + n = ch-'A'+10; + return (n < nRadix) ? n : -1; +} + +sal_Bool rtl_ImplIsWhitespace( sal_Unicode c ) +{ + /* Space or Control character? */ + if ( (c <= 32) && c ) + return sal_True; + + /* Only in the General Punctuation area Space or Control characters are included? */ + if ( (c < 0x2000) || (c > 0x206F) ) + return sal_False; + + if ( ((c >= 0x2000) && (c <= 0x200B)) || /* All Spaces */ + (c == 0x2028) || /* LINE SEPARATOR */ + (c == 0x2029) ) /* PARAGRAPH SEPARATOR */ + return sal_True; + + return sal_False; +} diff --git a/sal/rtl/source/strimp.h b/sal/rtl/source/strimp.h new file mode 100644 index 000000000000..533b7087a652 --- /dev/null +++ b/sal/rtl/source/strimp.h @@ -0,0 +1,64 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_RTL_SOURCE_STRIMP_H +#define INCLUDED_RTL_SOURCE_STRIMP_H + +#include <osl/interlck.h> + +#include "sal/types.h" + +/* ======================================================================= */ +/* Help functions for String and UString */ +/* ======================================================================= */ + +#if defined __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * refCount is opaqueincludes 2 bit-fields; + * MSB: 'interned' - is stored in the intern hash + * MSB-1: 'static' - is a const / static string, + * do no ref counting + */ +#define SAL_STRING_INTERN_FLAG 0x80000000 +#define SAL_STRING_STATIC_FLAG 0x40000000 +#define SAL_STRING_REFCOUNT(a) ((a) & 0x3fffffff) + +#define SAL_STRING_IS_INTERN(a) ((a)->refCount & SAL_STRING_INTERN_FLAG) +#define SAL_STRING_IS_STATIC(a) ((a)->refCount & SAL_STRING_STATIC_FLAG) + +sal_Int16 rtl_ImplGetDigit( sal_Unicode ch, sal_Int16 nRadix ); + +sal_Bool rtl_ImplIsWhitespace( sal_Unicode c ); + +#if defined __cplusplus +} +#endif /* __cplusplus */ + +#endif /* INCLUDED_RTL_SOURCE_STRIMP_H */ diff --git a/sal/rtl/source/string.c b/sal/rtl/source/string.c new file mode 100644 index 000000000000..c0f9a33c218b --- /dev/null +++ b/sal/rtl/source/string.c @@ -0,0 +1,320 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#pragma warning(disable:4738) // storing 32-bit float result in memory, possible loss of performance +#endif + +#include <rtl/memory.h> +#include <osl/interlck.h> +#include <rtl/alloc.h> +#include <osl/diagnose.h> +#include <rtl/tencinfo.h> + +#include "strimp.h" +#include "surrogates.h" +#include <rtl/string.h> + +#include "rtl/math.h" +#include "rtl/tencinfo.h" + +/* ======================================================================= */ + +/* static data to be referenced by all empty strings + * the refCount is predefined to 1 and must never become 0 ! + */ +static rtl_String const aImplEmpty_rtl_String = +{ + SAL_STRING_STATIC_FLAG|1, + /* sal_Int32 refCount; */ + 0, /* sal_Int32 length; */ + { 0 } /* sal_Char buffer[1]; */ +}; + +/* ======================================================================= */ + +#define IMPL_RTL_STRCODE sal_Char +#define IMPL_RTL_USTRCODE( c ) ((unsigned char)c) +#define IMPL_RTL_STRNAME( n ) rtl_str_ ## n + +#define IMPL_RTL_STRINGNAME( n ) rtl_string_ ## n +#define IMPL_RTL_STRINGDATA rtl_String +#define IMPL_RTL_EMPTYSTRING aImplEmpty_rtl_String + +/* ======================================================================= */ + +/* Include String/UString template code */ + +#include "strtmpl.c" + +sal_Int32 SAL_CALL rtl_str_valueOfFloat(sal_Char * pStr, float f) +{ + rtl_String * pResult = NULL; + sal_Int32 nLen; + rtl_math_doubleToString( + &pResult, 0, 0, f, rtl_math_StringFormat_G, + RTL_STR_MAX_VALUEOFFLOAT - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', 0, 0, + sal_True); + nLen = pResult->length; + OSL_ASSERT(nLen < RTL_STR_MAX_VALUEOFFLOAT); + rtl_copyMemory(pStr, pResult->buffer, (nLen + 1) * sizeof(sal_Char)); + rtl_string_release(pResult); + return nLen; +} + +sal_Int32 SAL_CALL rtl_str_valueOfDouble(sal_Char * pStr, double d) +{ + rtl_String * pResult = NULL; + sal_Int32 nLen; + rtl_math_doubleToString( + &pResult, 0, 0, d, rtl_math_StringFormat_G, + RTL_STR_MAX_VALUEOFDOUBLE - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', 0, + 0, sal_True); + nLen = pResult->length; + OSL_ASSERT(nLen < RTL_STR_MAX_VALUEOFDOUBLE); + rtl_copyMemory(pStr, pResult->buffer, (nLen + 1) * sizeof(sal_Char)); + rtl_string_release(pResult); + return nLen; +} + +float SAL_CALL rtl_str_toFloat(sal_Char const * pStr) +{ + return (float) rtl_math_stringToDouble(pStr, pStr + rtl_str_getLength(pStr), + '.', 0, 0, 0); +} + +double SAL_CALL rtl_str_toDouble(sal_Char const * pStr) +{ + return rtl_math_stringToDouble(pStr, pStr + rtl_str_getLength(pStr), '.', 0, + 0, 0); +} + +/* ======================================================================= */ + +static int rtl_ImplGetFastUTF8ByteLen( const sal_Unicode* pStr, sal_Int32 nLen ) +{ + int n; + sal_Unicode c; + sal_uInt32 nUCS4Char; + const sal_Unicode* pEndStr; + + n = 0; + pEndStr = pStr+nLen; + while ( pStr < pEndStr ) + { + c = *pStr; + + if ( c < 0x80 ) + n++; + else if ( c < 0x800 ) + n += 2; + else + { + if ( !SAL_RTL_IS_HIGH_SURROGATE(c) ) + n += 3; + else + { + nUCS4Char = c; + + if ( pStr+1 < pEndStr ) + { + c = *(pStr+1); + if ( SAL_RTL_IS_LOW_SURROGATE(c) ) + { + nUCS4Char = SAL_RTL_COMBINE_SURROGATES(nUCS4Char, c); + pStr++; + } + } + + if ( nUCS4Char < 0x10000 ) + n += 3; + else if ( nUCS4Char < 0x200000 ) + n += 4; + else if ( nUCS4Char < 0x4000000 ) + n += 5; + else + n += 6; + } + } + + pStr++; + } + + return n; +} + +/* ----------------------------------------------------------------------- */ + +sal_Bool SAL_CALL rtl_impl_convertUStringToString(rtl_String ** pTarget, + sal_Unicode const * pSource, + sal_Int32 nLength, + rtl_TextEncoding nEncoding, + sal_uInt32 nFlags, + sal_Bool bCheckErrors) +{ + OSL_ASSERT(pTarget != NULL + && (pSource != NULL || nLength == 0) + && nLength >= 0 + && rtl_isOctetTextEncoding(nEncoding)); + + if ( !nLength ) + rtl_string_new( pTarget ); + else + { + rtl_String* pTemp; + rtl_UnicodeToTextConverter hConverter; + sal_uInt32 nInfo; + sal_Size nSrcChars; + sal_Size nDestBytes; + sal_Size nNewLen; + sal_Size nNotConvertedChars; + sal_Size nMaxCharLen; + + /* Optimization for UTF-8 - we try to calculate the exact length */ + /* For all other encoding we try an good estimation */ + if ( nEncoding == RTL_TEXTENCODING_UTF8 ) + { + nNewLen = rtl_ImplGetFastUTF8ByteLen( pSource, nLength ); + /* Includes the string only ASCII, then we could copy + the buffer faster */ + if ( nNewLen == (sal_Size)nLength ) + { + IMPL_RTL_STRCODE* pBuffer; + if ( *pTarget ) + IMPL_RTL_STRINGNAME( release )( *pTarget ); + *pTarget = IMPL_RTL_STRINGNAME( ImplAlloc )( nLength ); + OSL_ASSERT(*pTarget != NULL); + pBuffer = (*pTarget)->buffer; + do + { + /* Check ASCII range */ + OSL_ENSURE( *pSource <= 127, + "rtl_uString2String() - UTF8 test is encoding is wrong" ); + + *pBuffer = (IMPL_RTL_STRCODE)(unsigned char)*pSource; + pBuffer++; + pSource++; + nLength--; + } + while ( nLength ); + return sal_True; + } + + nMaxCharLen = 4; + } + else + { + rtl_TextEncodingInfo aTextEncInfo; + aTextEncInfo.StructSize = sizeof( aTextEncInfo ); + if ( !rtl_getTextEncodingInfo( nEncoding, &aTextEncInfo ) ) + { + aTextEncInfo.AverageCharSize = 1; + aTextEncInfo.MaximumCharSize = 8; + } + + nNewLen = nLength*aTextEncInfo.AverageCharSize; + nMaxCharLen = aTextEncInfo.MaximumCharSize; + } + + nFlags |= RTL_UNICODETOTEXT_FLAGS_FLUSH; + hConverter = rtl_createUnicodeToTextConverter( nEncoding ); + + for (;;) + { + pTemp = IMPL_RTL_STRINGNAME( ImplAlloc )( nNewLen ); + OSL_ASSERT(pTemp != NULL); + nDestBytes = rtl_convertUnicodeToText( hConverter, 0, + pSource, nLength, + pTemp->buffer, nNewLen, + nFlags, + &nInfo, &nSrcChars ); + if (bCheckErrors && (nInfo & RTL_UNICODETOTEXT_INFO_ERROR) != 0) + { + rtl_freeMemory(pTemp); + rtl_destroyUnicodeToTextConverter(hConverter); + return sal_False; + } + + if ((nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL) == 0) + break; + + /* Buffer not big enough, try again with enough space */ + rtl_freeMemory( pTemp ); + + /* Try with the max. count of characters with + additional overhead for replacing functionality */ + nNotConvertedChars = nLength-nSrcChars; + nNewLen = nDestBytes+(nNotConvertedChars*nMaxCharLen)+nNotConvertedChars+4; + } + + /* Set the buffer to the correct size or is there to + much overhead, reallocate to the correct size */ + if ( nNewLen > nDestBytes+8 ) + { + rtl_String* pTemp2 = IMPL_RTL_STRINGNAME( ImplAlloc )( nDestBytes ); + OSL_ASSERT(pTemp2 != NULL); + rtl_str_ImplCopy( pTemp2->buffer, pTemp->buffer, nDestBytes ); + rtl_freeMemory( pTemp ); + pTemp = pTemp2; + } + else + { + pTemp->length = nDestBytes; + pTemp->buffer[nDestBytes] = 0; + } + + rtl_destroyUnicodeToTextConverter( hConverter ); + if ( *pTarget ) + IMPL_RTL_STRINGNAME( release )( *pTarget ); + *pTarget = pTemp; + + /* Results the conversion in an empty buffer - + create an empty string */ + if ( pTemp && !nDestBytes ) + rtl_string_new( pTarget ); + } + return sal_True; +} + +void SAL_CALL rtl_uString2String( rtl_String** ppThis, + const sal_Unicode* pUStr, + sal_Int32 nULen, + rtl_TextEncoding eTextEncoding, + sal_uInt32 nCvtFlags ) +{ + rtl_impl_convertUStringToString(ppThis, pUStr, nULen, eTextEncoding, + nCvtFlags, sal_False); +} + +sal_Bool SAL_CALL rtl_convertUStringToString(rtl_String ** pTarget, + sal_Unicode const * pSource, + sal_Int32 nLength, + rtl_TextEncoding nEncoding, + sal_uInt32 nFlags) +{ + return rtl_impl_convertUStringToString(pTarget, pSource, nLength, nEncoding, + nFlags, sal_True); +} diff --git a/sal/rtl/source/strtmpl.c b/sal/rtl/source/strtmpl.c new file mode 100644 index 000000000000..8c60583b14cc --- /dev/null +++ b/sal/rtl/source/strtmpl.c @@ -0,0 +1,1567 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/* ======================================================================= */ +/* Internal C-String help functions which could be used without the */ +/* String-Class */ +/* ======================================================================= */ + +/* +inline void rtl_str_ImplCopy( IMPL_RTL_STRCODE* pDest, + const IMPL_RTL_STRCODE* pSrc, + sal_Int32 nCount ) +{ + while ( nCount > 0 ) + { + *pDest = *pSrc; + pDest++; + pSrc++; + nCount--; + } +} +*/ + +#define rtl_str_ImplCopy( _pDest, _pSrc, _nCount ) \ +{ \ + IMPL_RTL_STRCODE* __mm_pDest = _pDest; \ + const IMPL_RTL_STRCODE* __mm_pSrc = _pSrc; \ + sal_Int32 __mm_nCount = _nCount; \ + while ( __mm_nCount > 0 ) \ + { \ + *__mm_pDest = *__mm_pSrc; \ + __mm_pDest++; \ + __mm_pSrc++; \ + __mm_nCount--; \ + } \ +} + +/* ======================================================================= */ +/* C-String functions which could be used without the String-Class */ +/* ======================================================================= */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( getLength )( const IMPL_RTL_STRCODE* pStr ) +{ + const IMPL_RTL_STRCODE* pTempStr = pStr; + while( *pTempStr ) + pTempStr++; + return pTempStr-pStr; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( compare )( const IMPL_RTL_STRCODE* pStr1, + const IMPL_RTL_STRCODE* pStr2 ) +{ + sal_Int32 nRet; + while ( ((nRet = ((sal_Int32)(IMPL_RTL_USTRCODE(*pStr1)))- + ((sal_Int32)(IMPL_RTL_USTRCODE(*pStr2)))) == 0) && + *pStr2 ) + { + pStr1++; + pStr2++; + } + + return nRet; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( compare_WithLength )( const IMPL_RTL_STRCODE* pStr1, + sal_Int32 nStr1Len, + const IMPL_RTL_STRCODE* pStr2, + sal_Int32 nStr2Len ) +{ + sal_Int32 nRet = nStr1Len - nStr2Len; + int nCount = (nRet <= 0) ? nStr1Len : nStr2Len; + + --pStr1; + --pStr2; + while( (--nCount >= 0) && (*++pStr1 == *++pStr2) ); + + if( nCount >= 0 ) + nRet = ((sal_Int32)(IMPL_RTL_USTRCODE( *pStr1 ))) + - ((sal_Int32)(IMPL_RTL_USTRCODE( *pStr2 ))); + + return nRet; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( shortenedCompare_WithLength )( const IMPL_RTL_STRCODE* pStr1, + sal_Int32 nStr1Len, + const IMPL_RTL_STRCODE* pStr2, + sal_Int32 nStr2Len, + sal_Int32 nShortenedLength ) +{ + const IMPL_RTL_STRCODE* pStr1End = pStr1 + nStr1Len; + const IMPL_RTL_STRCODE* pStr2End = pStr2 + nStr2Len; + sal_Int32 nRet; + while ( (nShortenedLength > 0) && + (pStr1 < pStr1End) && (pStr2 < pStr2End) ) + { + nRet = ((sal_Int32)(IMPL_RTL_USTRCODE( *pStr1 )))- + ((sal_Int32)(IMPL_RTL_USTRCODE( *pStr2 ))); + if ( nRet ) + return nRet; + + nShortenedLength--; + pStr1++; + pStr2++; + } + + if ( nShortenedLength <= 0 ) + return 0; + return nStr1Len - nStr2Len; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( reverseCompare_WithLength )( const IMPL_RTL_STRCODE* pStr1, + sal_Int32 nStr1Len, + const IMPL_RTL_STRCODE* pStr2, + sal_Int32 nStr2Len ) +{ + const IMPL_RTL_STRCODE* pStr1Run = pStr1+nStr1Len; + const IMPL_RTL_STRCODE* pStr2Run = pStr2+nStr2Len; + sal_Int32 nRet; + while ( (pStr1 < pStr1Run) && (pStr2 < pStr2Run) ) + { + pStr1Run--; + pStr2Run--; + nRet = ((sal_Int32)(IMPL_RTL_USTRCODE( *pStr1Run )))- + ((sal_Int32)(IMPL_RTL_USTRCODE( *pStr2Run ))); + if ( nRet ) + return nRet; + } + + return nStr1Len - nStr2Len; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( compareIgnoreAsciiCase )( const IMPL_RTL_STRCODE* pStr1, + const IMPL_RTL_STRCODE* pStr2 ) +{ + sal_Int32 nRet; + sal_Int32 c1; + sal_Int32 c2; + do + { + /* If character between 'A' and 'Z', than convert it to lowercase */ + c1 = (sal_Int32)IMPL_RTL_USTRCODE( *pStr1 ); + c2 = (sal_Int32)IMPL_RTL_USTRCODE( *pStr2 ); + if ( (c1 >= 65) && (c1 <= 90) ) + c1 += 32; + if ( (c2 >= 65) && (c2 <= 90) ) + c2 += 32; + nRet = c1-c2; + if ( nRet != 0 ) + return nRet; + + pStr1++; + pStr2++; + } + while ( c2 ); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( compareIgnoreAsciiCase_WithLength )( const IMPL_RTL_STRCODE* pStr1, + sal_Int32 nStr1Len, + const IMPL_RTL_STRCODE* pStr2, + sal_Int32 nStr2Len ) +{ + const IMPL_RTL_STRCODE* pStr1End = pStr1 + nStr1Len; + const IMPL_RTL_STRCODE* pStr2End = pStr2 + nStr2Len; + sal_Int32 nRet; + sal_Int32 c1; + sal_Int32 c2; + while ( (pStr1 < pStr1End) && (pStr2 < pStr2End) ) + { + /* If character between 'A' and 'Z', than convert it to lowercase */ + c1 = (sal_Int32)IMPL_RTL_USTRCODE( *pStr1 ); + c2 = (sal_Int32)IMPL_RTL_USTRCODE( *pStr2 ); + if ( (c1 >= 65) && (c1 <= 90) ) + c1 += 32; + if ( (c2 >= 65) && (c2 <= 90) ) + c2 += 32; + nRet = c1-c2; + if ( nRet != 0 ) + return nRet; + + pStr1++; + pStr2++; + } + + return nStr1Len - nStr2Len; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( shortenedCompareIgnoreAsciiCase_WithLength )( const IMPL_RTL_STRCODE* pStr1, + sal_Int32 nStr1Len, + const IMPL_RTL_STRCODE* pStr2, + sal_Int32 nStr2Len, + sal_Int32 nShortenedLength ) +{ + const IMPL_RTL_STRCODE* pStr1End = pStr1 + nStr1Len; + const IMPL_RTL_STRCODE* pStr2End = pStr2 + nStr2Len; + sal_Int32 nRet; + sal_Int32 c1; + sal_Int32 c2; + while ( (nShortenedLength > 0) && + (pStr1 < pStr1End) && (pStr2 < pStr2End) ) + { + /* If character between 'A' and 'Z', than convert it to lowercase */ + c1 = (sal_Int32)IMPL_RTL_USTRCODE( *pStr1 ); + c2 = (sal_Int32)IMPL_RTL_USTRCODE( *pStr2 ); + if ( (c1 >= 65) && (c1 <= 90) ) + c1 += 32; + if ( (c2 >= 65) && (c2 <= 90) ) + c2 += 32; + nRet = c1-c2; + if ( nRet != 0 ) + return nRet; + + nShortenedLength--; + pStr1++; + pStr2++; + } + + if ( nShortenedLength <= 0 ) + return 0; + return nStr1Len - nStr2Len; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( hashCode )( const IMPL_RTL_STRCODE* pStr ) +{ + return IMPL_RTL_STRNAME( hashCode_WithLength )( pStr, IMPL_RTL_STRNAME( getLength )( pStr ) ); +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( hashCode_WithLength )( const IMPL_RTL_STRCODE* pStr, + sal_Int32 nLen ) +{ + sal_Int32 h = nLen; + + if ( nLen < 256 ) + { + while ( nLen > 0 ) + { + h = (h*37) + IMPL_RTL_USTRCODE( *pStr ); + pStr++; + nLen--; + } + } + else + { + sal_Int32 nSkip; + const IMPL_RTL_STRCODE* pEndStr = pStr+nLen-5; + + /* only sample some characters */ + /* the first 3, some characters between, and the last 5 */ + h = (h*39) + IMPL_RTL_USTRCODE( *pStr ); + pStr++; + h = (h*39) + IMPL_RTL_USTRCODE( *pStr ); + pStr++; + h = (h*39) + IMPL_RTL_USTRCODE( *pStr ); + pStr++; + + if ( nLen < 32 ) + nSkip = nLen / 4; + else + nSkip = nLen / 8; + nLen -= 8; + while ( nLen > 0 ) + { + h = (h*39) + IMPL_RTL_USTRCODE( *pStr ); + pStr += nSkip; + nLen -= nSkip; + } + + h = (h*39) + IMPL_RTL_USTRCODE( *pEndStr ); + pEndStr++; + h = (h*39) + IMPL_RTL_USTRCODE( *pEndStr ); + pEndStr++; + h = (h*39) + IMPL_RTL_USTRCODE( *pEndStr ); + pEndStr++; + h = (h*39) + IMPL_RTL_USTRCODE( *pEndStr ); + pEndStr++; + h = (h*39) + IMPL_RTL_USTRCODE( *pEndStr ); + } + + return h; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( indexOfChar )( const IMPL_RTL_STRCODE* pStr, + IMPL_RTL_STRCODE c ) +{ + const IMPL_RTL_STRCODE* pTempStr = pStr; + while ( *pTempStr ) + { + if ( *pTempStr == c ) + return pTempStr-pStr; + + pTempStr++; + } + + return -1; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( indexOfChar_WithLength )( const IMPL_RTL_STRCODE* pStr, + sal_Int32 nLen, + IMPL_RTL_STRCODE c ) +{ + const IMPL_RTL_STRCODE* pTempStr = pStr; + while ( nLen > 0 ) + { + if ( *pTempStr == c ) + return pTempStr-pStr; + + pTempStr++; + nLen--; + } + + return -1; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( lastIndexOfChar )( const IMPL_RTL_STRCODE* pStr, + IMPL_RTL_STRCODE c ) +{ + return IMPL_RTL_STRNAME( lastIndexOfChar_WithLength )( pStr, IMPL_RTL_STRNAME( getLength )( pStr ), c ); +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( lastIndexOfChar_WithLength )( const IMPL_RTL_STRCODE* pStr, + sal_Int32 nLen, + IMPL_RTL_STRCODE c ) +{ + pStr += nLen; + while ( nLen > 0 ) + { + nLen--; + pStr--; + + if ( *pStr == c ) + return nLen; + } + + return -1; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( indexOfStr )( const IMPL_RTL_STRCODE* pStr, + const IMPL_RTL_STRCODE* pSubStr ) +{ + return IMPL_RTL_STRNAME( indexOfStr_WithLength )( pStr, IMPL_RTL_STRNAME( getLength )( pStr ), + pSubStr, IMPL_RTL_STRNAME( getLength )( pSubStr ) ); +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( indexOfStr_WithLength )( const IMPL_RTL_STRCODE* pStr, + sal_Int32 nStrLen, + const IMPL_RTL_STRCODE* pSubStr, + sal_Int32 nSubLen ) +{ + /* faster search for a single character */ + if ( nSubLen < 2 ) + { + /* an empty SubString is always not foundable */ + if ( nSubLen == 1 ) + { + IMPL_RTL_STRCODE c = *pSubStr; + const IMPL_RTL_STRCODE* pTempStr = pStr; + while ( nStrLen > 0 ) + { + if ( *pTempStr == c ) + return pTempStr-pStr; + + pTempStr++; + nStrLen--; + } + } + } + else + { + const IMPL_RTL_STRCODE* pTempStr = pStr; + while ( nStrLen > 0 ) + { + if ( *pTempStr == *pSubStr ) + { + /* Compare SubString */ + if ( nSubLen <= nStrLen ) + { + const IMPL_RTL_STRCODE* pTempStr1 = pTempStr; + const IMPL_RTL_STRCODE* pTempStr2 = pSubStr; + sal_Int32 nTempLen = nSubLen; + while ( nTempLen ) + { + if ( *pTempStr1 != *pTempStr2 ) + break; + + pTempStr1++; + pTempStr2++; + nTempLen--; + } + + if ( !nTempLen ) + return pTempStr-pStr; + } + else + break; + } + + nStrLen--; + pTempStr++; + } + } + + return -1; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( lastIndexOfStr )( const IMPL_RTL_STRCODE* pStr, + const IMPL_RTL_STRCODE* pSubStr ) +{ + return IMPL_RTL_STRNAME( lastIndexOfStr_WithLength )( pStr, IMPL_RTL_STRNAME( getLength )( pStr ), + pSubStr, IMPL_RTL_STRNAME( getLength )( pSubStr ) ); +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( lastIndexOfStr_WithLength )( const IMPL_RTL_STRCODE* pStr, + sal_Int32 nStrLen, + const IMPL_RTL_STRCODE* pSubStr, + sal_Int32 nSubLen ) +{ + /* faster search for a single character */ + if ( nSubLen < 2 ) + { + /* an empty SubString is always not foundable */ + if ( nSubLen == 1 ) + { + IMPL_RTL_STRCODE c = *pSubStr; + pStr += nStrLen; + while ( nStrLen > 0 ) + { + nStrLen--; + pStr--; + + if ( *pStr == c ) + return nStrLen; + } + } + } + else + { + pStr += nStrLen; + nStrLen -= nSubLen; + pStr -= nSubLen; + while ( nStrLen >= 0 ) + { + const IMPL_RTL_STRCODE* pTempStr1 = pStr; + const IMPL_RTL_STRCODE* pTempStr2 = pSubStr; + sal_Int32 nTempLen = nSubLen; + while ( nTempLen ) + { + if ( *pTempStr1 != *pTempStr2 ) + break; + + pTempStr1++; + pTempStr2++; + nTempLen--; + } + + if ( !nTempLen ) + return nStrLen; + + nStrLen--; + pStr--; + } + } + + return -1; +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRNAME( replaceChar )( IMPL_RTL_STRCODE* pStr, + IMPL_RTL_STRCODE cOld, + IMPL_RTL_STRCODE cNew ) +{ + while ( *pStr ) + { + if ( *pStr == cOld ) + *pStr = cNew; + + pStr++; + } +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRNAME( replaceChar_WithLength )( IMPL_RTL_STRCODE* pStr, + sal_Int32 nLen, + IMPL_RTL_STRCODE cOld, + IMPL_RTL_STRCODE cNew ) +{ + while ( nLen > 0 ) + { + if ( *pStr == cOld ) + *pStr = cNew; + + pStr++; + nLen--; + } +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRNAME( toAsciiLowerCase )( IMPL_RTL_STRCODE* pStr ) +{ + while ( *pStr ) + { + /* Between A-Z (65-90), than to lowercase (+32) */ + if ( (*pStr >= 65) && (*pStr <= 90) ) + *pStr += 32; + + pStr++; + } +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRNAME( toAsciiLowerCase_WithLength )( IMPL_RTL_STRCODE* pStr, + sal_Int32 nLen ) +{ + while ( nLen > 0 ) + { + /* Between A-Z (65-90), than to lowercase (+32) */ + if ( (*pStr >= 65) && (*pStr <= 90) ) + *pStr += 32; + + pStr++; + nLen--; + } +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRNAME( toAsciiUpperCase )( IMPL_RTL_STRCODE* pStr ) +{ + while ( *pStr ) + { + /* Between a-z (97-122), than to uppercase (-32) */ + if ( (*pStr >= 97) && (*pStr <= 122) ) + *pStr -= 32; + + pStr++; + } +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRNAME( toAsciiUpperCase_WithLength )( IMPL_RTL_STRCODE* pStr, + sal_Int32 nLen ) +{ + while ( nLen > 0 ) + { + /* Between a-z (97-122), than to uppercase (-32) */ + if ( (*pStr >= 97) && (*pStr <= 122) ) + *pStr -= 32; + + pStr++; + nLen--; + } +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( trim )( IMPL_RTL_STRCODE* pStr ) +{ + return IMPL_RTL_STRNAME( trim_WithLength )( pStr, IMPL_RTL_STRNAME( getLength )( pStr ) ); +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( trim_WithLength )( IMPL_RTL_STRCODE* pStr, sal_Int32 nLen ) +{ + sal_Int32 nPreSpaces = 0; + sal_Int32 nPostSpaces = 0; + sal_Int32 nIndex = nLen-1; + + while ( (nPreSpaces < nLen) && rtl_ImplIsWhitespace( IMPL_RTL_USTRCODE(*(pStr+nPreSpaces)) ) ) + nPreSpaces++; + + while ( (nIndex > nPreSpaces) && rtl_ImplIsWhitespace( IMPL_RTL_USTRCODE(*(pStr+nIndex)) ) ) + { + nPostSpaces++; + nIndex--; + } + + if ( nPostSpaces ) + { + nLen -= nPostSpaces; + *(pStr+nLen) = 0; + } + + if ( nPreSpaces ) + { + IMPL_RTL_STRCODE* pNewStr = pStr+nPreSpaces; + + nLen -= nPreSpaces; + nIndex = nLen; + + while ( nIndex ) + { + *pStr = *pNewStr; + pStr++; + pNewStr++; + nIndex--; + } + *pStr = 0; + } + + return nLen; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( valueOfBoolean )( IMPL_RTL_STRCODE* pStr, sal_Bool b ) +{ + if ( b ) + { + *pStr = 't'; + pStr++; + *pStr = 'r'; + pStr++; + *pStr = 'u'; + pStr++; + *pStr = 'e'; + pStr++; + *pStr = 0; + return 4; + } + else + { + *pStr = 'f'; + pStr++; + *pStr = 'a'; + pStr++; + *pStr = 'l'; + pStr++; + *pStr = 's'; + pStr++; + *pStr = 'e'; + pStr++; + *pStr = 0; + return 5; + } +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( valueOfChar )( IMPL_RTL_STRCODE* pStr, + IMPL_RTL_STRCODE c ) +{ + *pStr++ = c; + *pStr = 0; + return 1; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( valueOfInt32 )( IMPL_RTL_STRCODE* pStr, + sal_Int32 n, + sal_Int16 nRadix ) +{ + sal_Char aBuf[RTL_STR_MAX_VALUEOFINT32]; + sal_Char* pBuf = aBuf; + sal_Int32 nLen = 0; + sal_uInt32 nValue; + + /* Radix must be valid */ + if ( (nRadix < RTL_STR_MIN_RADIX) || (nRadix > RTL_STR_MAX_RADIX) ) + nRadix = 10; + + /* is value negativ */ + if ( n < 0 ) + { + *pStr = '-'; + pStr++; + nLen++; + nValue = -n; /* FIXME this code is not portable for n == -2147483648 + (smallest negative value for sal_Int32) */ + } + else + nValue = n; + + /* create a recursive buffer with all values, except the last one */ + do + { + sal_Char nDigit = (sal_Char)(nValue % nRadix); + nValue /= nRadix; + if ( nDigit > 9 ) + *pBuf = (nDigit-10) + 'a'; + else + *pBuf = (nDigit + '0' ); + pBuf++; + } + while ( nValue > 0 ); + + /* copy the values in the right direction into the destination buffer */ + do + { + pBuf--; + *pStr = *pBuf; + pStr++; + nLen++; + } + while ( pBuf != aBuf ); + *pStr = 0; + + return nLen; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( valueOfInt64 )( IMPL_RTL_STRCODE* pStr, + sal_Int64 n, + sal_Int16 nRadix ) +{ + sal_Char aBuf[RTL_STR_MAX_VALUEOFINT64]; + sal_Char* pBuf = aBuf; + sal_Int32 nLen = 0; + sal_uInt64 nValue; + + /* Radix must be valid */ + if ( (nRadix < RTL_STR_MIN_RADIX) || (nRadix > RTL_STR_MAX_RADIX) ) + nRadix = 10; + + /* is value negativ */ + if ( n < 0 ) + { + *pStr = '-'; + pStr++; + nLen++; + nValue = -n; /* FIXME this code is not portable for + n == -9223372036854775808 (smallest negative value for + sal_Int64) */ + } + else + nValue = n; + + /* create a recursive buffer with all values, except the last one */ + do + { + sal_Char nDigit = (sal_Char)(nValue % nRadix); + nValue /= nRadix; + if ( nDigit > 9 ) + *pBuf = (nDigit-10) + 'a'; + else + *pBuf = (nDigit + '0' ); + pBuf++; + } + while ( nValue > 0 ); + + /* copy the values in the right direction into the destination buffer */ + do + { + pBuf--; + *pStr = *pBuf; + pStr++; + nLen++; + } + while ( pBuf != aBuf ); + *pStr = 0; + + return nLen; +} + +/* ----------------------------------------------------------------------- */ + +sal_Bool SAL_CALL IMPL_RTL_STRNAME( toBoolean )( const IMPL_RTL_STRCODE* pStr ) +{ + if ( *pStr == '1' ) + return sal_True; + + if ( (*pStr == 'T') || (*pStr == 't') ) + { + pStr++; + if ( (*pStr == 'R') || (*pStr == 'r') ) + { + pStr++; + if ( (*pStr == 'U') || (*pStr == 'u') ) + { + pStr++; + if ( (*pStr == 'E') || (*pStr == 'e') ) + return sal_True; + } + } + } + + return sal_False; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRNAME( toInt32 )( const IMPL_RTL_STRCODE* pStr, + sal_Int16 nRadix ) +{ + sal_Bool bNeg; + sal_Int16 nDigit; + sal_Int32 n = 0; + + if ( (nRadix < RTL_STR_MIN_RADIX) || (nRadix > RTL_STR_MAX_RADIX) ) + nRadix = 10; + + /* Skip whitespaces */ + while ( *pStr && rtl_ImplIsWhitespace( IMPL_RTL_USTRCODE( *pStr ) ) ) + pStr++; + + if ( *pStr == '-' ) + { + bNeg = sal_True; + pStr++; + } + else + { + if ( *pStr == '+' ) + pStr++; + bNeg = sal_False; + } + + while ( *pStr ) + { + nDigit = rtl_ImplGetDigit( IMPL_RTL_USTRCODE( *pStr ), nRadix ); + if ( nDigit < 0 ) + break; + + n *= nRadix; + n += nDigit; + + pStr++; + } + + if ( bNeg ) + return -n; + else + return n; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int64 SAL_CALL IMPL_RTL_STRNAME( toInt64 )( const IMPL_RTL_STRCODE* pStr, + sal_Int16 nRadix ) +{ + sal_Bool bNeg; + sal_Int16 nDigit; + sal_Int64 n = 0; + + if ( (nRadix < RTL_STR_MIN_RADIX) || (nRadix > RTL_STR_MAX_RADIX) ) + nRadix = 10; + + /* Skip whitespaces */ + while ( *pStr && rtl_ImplIsWhitespace( IMPL_RTL_USTRCODE( *pStr ) ) ) + pStr++; + + if ( *pStr == '-' ) + { + bNeg = sal_True; + pStr++; + } + else + { + if ( *pStr == '+' ) + pStr++; + bNeg = sal_False; + } + + while ( *pStr ) + { + nDigit = rtl_ImplGetDigit( IMPL_RTL_USTRCODE( *pStr ), nRadix ); + if ( nDigit < 0 ) + break; + + n *= nRadix; + n += nDigit; + + pStr++; + } + + if ( bNeg ) + return -n; + else + return n; +} + +/* ======================================================================= */ +/* Internal String-Class help functions */ +/* ======================================================================= */ + +static IMPL_RTL_STRINGDATA* IMPL_RTL_STRINGNAME( ImplAlloc )( sal_Int32 nLen ) +{ + IMPL_RTL_STRINGDATA * pData + = (SAL_INT_CAST(sal_uInt32, nLen) + <= ((SAL_MAX_UINT32 - sizeof (IMPL_RTL_STRINGDATA)) + / sizeof (IMPL_RTL_STRCODE))) + ? (IMPL_RTL_STRINGDATA *) rtl_allocateMemory( + sizeof (IMPL_RTL_STRINGDATA) + nLen * sizeof (IMPL_RTL_STRCODE)) + : NULL; + if (pData != NULL) { + pData->refCount = 1; + pData->length = nLen; + pData->buffer[nLen] = 0; + } + return pData; +} + +/* ----------------------------------------------------------------------- */ + +static IMPL_RTL_STRCODE* IMPL_RTL_STRINGNAME( ImplNewCopy )( IMPL_RTL_STRINGDATA** ppThis, + IMPL_RTL_STRINGDATA* pStr, + sal_Int32 nCount ) +{ + IMPL_RTL_STRCODE* pDest; + const IMPL_RTL_STRCODE* pSrc; + IMPL_RTL_STRINGDATA* pData = IMPL_RTL_STRINGNAME( ImplAlloc )( pStr->length ); + OSL_ASSERT(pData != NULL); + + pDest = pData->buffer; + pSrc = pStr->buffer; + while ( nCount > 0 ) + { + *pDest = *pSrc; + pDest++; + pSrc++; + nCount--; + } + + *ppThis = pData; + return pDest; +} + +/* ======================================================================= */ +/* String-Class functions */ +/* ======================================================================= */ + +#define IMPL_RTL_AQUIRE( pThis ) \ +{ \ + if (!SAL_STRING_IS_STATIC (pThis)) \ + osl_incrementInterlockedCount( &((pThis)->refCount) ); \ +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( acquire )( IMPL_RTL_STRINGDATA* pThis ) +{ + IMPL_RTL_AQUIRE( pThis ); +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( release )( IMPL_RTL_STRINGDATA* pThis ) +{ + if (SAL_STRING_IS_STATIC (pThis)) + return; + +/* OString doesn't have an 'intern' */ +#ifdef IMPL_RTL_INTERN + if (SAL_STRING_IS_INTERN (pThis)) + { + internRelease (pThis); + return; + } +#endif + + if ( pThis->refCount == 1 || + !osl_decrementInterlockedCount( &(pThis->refCount) ) ) + { + rtl_freeMemory( pThis ); + } +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( new )( IMPL_RTL_STRINGDATA** ppThis ) +{ + if ( *ppThis) + IMPL_RTL_STRINGNAME( release )( *ppThis ); + + *ppThis = (IMPL_RTL_STRINGDATA*) (&IMPL_RTL_EMPTYSTRING); + IMPL_RTL_AQUIRE( *ppThis ); +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( new_WithLength )( IMPL_RTL_STRINGDATA** ppThis, sal_Int32 nLen ) +{ + if ( nLen <= 0 ) + IMPL_RTL_STRINGNAME( new )( ppThis ); + else + { + if ( *ppThis) + IMPL_RTL_STRINGNAME( release )( *ppThis ); + + *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen ); + OSL_ASSERT(*ppThis != NULL); + (*ppThis)->length = 0; + + { + IMPL_RTL_STRCODE* pTempStr = (*ppThis)->buffer; + while ( nLen >= 0 ) + { + *pTempStr = 0; + pTempStr++; + nLen--; + } + } + } +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( newFromString )( IMPL_RTL_STRINGDATA** ppThis, + const IMPL_RTL_STRINGDATA* pStr ) +{ + IMPL_RTL_STRINGDATA* pOrg; + + if ( !pStr->length ) + { + IMPL_RTL_STRINGNAME( new )( ppThis ); + return; + } + + pOrg = *ppThis; + *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( pStr->length ); + OSL_ASSERT(*ppThis != NULL); + rtl_str_ImplCopy( (*ppThis)->buffer, pStr->buffer, pStr->length ); + + /* must be done at least, if pStr == *ppThis */ + if ( pOrg ) + IMPL_RTL_STRINGNAME( release )( pOrg ); +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( newFromStr )( IMPL_RTL_STRINGDATA** ppThis, + const IMPL_RTL_STRCODE* pCharStr ) +{ + IMPL_RTL_STRCODE* pBuffer; + IMPL_RTL_STRINGDATA* pOrg; + sal_Int32 nLen; + + if ( pCharStr ) + { + const IMPL_RTL_STRCODE* pTempStr = pCharStr; + while( *pTempStr ) + pTempStr++; + nLen = pTempStr-pCharStr; + } + else + nLen = 0; + + if ( !nLen ) + { + IMPL_RTL_STRINGNAME( new )( ppThis ); + return; + } + + pOrg = *ppThis; + *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen ); + OSL_ASSERT(*ppThis != NULL); + pBuffer = (*ppThis)->buffer; + do + { + *pBuffer = *pCharStr; + pBuffer++; + pCharStr++; + } + while ( *pCharStr ); + + /* must be done at least, if pCharStr == *ppThis */ + if ( pOrg ) + IMPL_RTL_STRINGNAME( release )( pOrg ); +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( newFromStr_WithLength )( IMPL_RTL_STRINGDATA** ppThis, + const IMPL_RTL_STRCODE* pCharStr, + sal_Int32 nLen ) +{ + IMPL_RTL_STRINGDATA* pOrg; + + if ( !pCharStr || (nLen <= 0) ) + { + IMPL_RTL_STRINGNAME( new )( ppThis ); + return; + } + + pOrg = *ppThis; + *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen ); + OSL_ASSERT(*ppThis != NULL); + rtl_str_ImplCopy( (*ppThis)->buffer, pCharStr, nLen ); + + /* must be done at least, if pCharStr == *ppThis */ + if ( pOrg ) + IMPL_RTL_STRINGNAME( release )( pOrg ); +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( assign )( IMPL_RTL_STRINGDATA** ppThis, + IMPL_RTL_STRINGDATA* pStr ) +{ + /* must be done at first, if pStr == *ppThis */ + IMPL_RTL_AQUIRE( pStr ); + + if ( *ppThis ) + IMPL_RTL_STRINGNAME( release )( *ppThis ); + + *ppThis = pStr; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRINGNAME( getLength )( const IMPL_RTL_STRINGDATA* pThis ) +{ + return pThis->length; +} + +/* ----------------------------------------------------------------------- */ + +IMPL_RTL_STRCODE* SAL_CALL IMPL_RTL_STRINGNAME( getStr )( IMPL_RTL_STRINGDATA * pThis ) +{ + return pThis->buffer; +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( newConcat )( IMPL_RTL_STRINGDATA** ppThis, + IMPL_RTL_STRINGDATA* pLeft, + IMPL_RTL_STRINGDATA* pRight ) +{ + IMPL_RTL_STRINGDATA* pOrg = *ppThis; + + /* Test for 0-Pointer - if not, change newReplaceStrAt! */ + if ( !pRight || !pRight->length ) + { + *ppThis = pLeft; + IMPL_RTL_AQUIRE( pLeft ); + } + else if ( !pLeft || !pLeft->length ) + { + *ppThis = pRight; + IMPL_RTL_AQUIRE( pRight ); + } + else + { + IMPL_RTL_STRINGDATA* pTempStr = IMPL_RTL_STRINGNAME( ImplAlloc )( pLeft->length + pRight->length ); + OSL_ASSERT(pTempStr != NULL); + rtl_str_ImplCopy( pTempStr->buffer, pLeft->buffer, pLeft->length ); + rtl_str_ImplCopy( pTempStr->buffer+pLeft->length, pRight->buffer, pRight->length ); + *ppThis = pTempStr; + } + + /* must be done at least, if left or right == *ppThis */ + if ( pOrg ) + IMPL_RTL_STRINGNAME( release )( pOrg ); +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( newReplaceStrAt )( IMPL_RTL_STRINGDATA** ppThis, + IMPL_RTL_STRINGDATA* pStr, + sal_Int32 nIndex, + sal_Int32 nCount, + IMPL_RTL_STRINGDATA* pNewSubStr ) +{ + /* Append? */ + if ( nIndex >= pStr->length ) + { + /* newConcat test, if pNewSubStr is 0 */ + IMPL_RTL_STRINGNAME( newConcat )( ppThis, pStr, pNewSubStr ); + return; + } + + /* negativ index? */ + if ( nIndex < 0 ) + { + nCount -= nIndex; + nIndex = 0; + } + + /* not more than the String length could be deleted */ + if ( nCount >= pStr->length-nIndex ) + { + nCount = pStr->length-nIndex; + + /* Assign of NewSubStr? */ + if ( !nIndex && (nCount >= pStr->length) ) + { + if ( !pNewSubStr ) + IMPL_RTL_STRINGNAME( new )( ppThis ); + else + IMPL_RTL_STRINGNAME( assign )( ppThis, pNewSubStr ); + return; + } + } + + /* Assign of Str? */ + if ( !nCount && (!pNewSubStr || !pNewSubStr->length) ) + { + IMPL_RTL_STRINGNAME( assign )( ppThis, pStr ); + return; + } + + { + IMPL_RTL_STRINGDATA* pOrg = *ppThis; + IMPL_RTL_STRCODE* pBuffer; + sal_Int32 nNewLen; + + /* Calculate length of the new string */ + nNewLen = pStr->length-nCount; + if ( pNewSubStr ) + nNewLen += pNewSubStr->length; + + /* Alloc New Buffer */ + *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nNewLen ); + OSL_ASSERT(*ppThis != NULL); + pBuffer = (*ppThis)->buffer; + if ( nIndex ) + { + rtl_str_ImplCopy( pBuffer, pStr->buffer, nIndex ); + pBuffer += nIndex; + } + if ( pNewSubStr && pNewSubStr->length ) + { + rtl_str_ImplCopy( pBuffer, pNewSubStr->buffer, pNewSubStr->length ); + pBuffer += pNewSubStr->length; + } + rtl_str_ImplCopy( pBuffer, pStr->buffer+nIndex+nCount, pStr->length-nIndex-nCount ); + + /* must be done at least, if pStr or pNewSubStr == *ppThis */ + if ( pOrg ) + IMPL_RTL_STRINGNAME( release )( pOrg ); + } +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( newReplace )( IMPL_RTL_STRINGDATA** ppThis, + IMPL_RTL_STRINGDATA* pStr, + IMPL_RTL_STRCODE cOld, + IMPL_RTL_STRCODE cNew ) +{ + IMPL_RTL_STRINGDATA* pOrg = *ppThis; + int bChanged = 0; + sal_Int32 nLen = pStr->length; + const IMPL_RTL_STRCODE* pCharStr = pStr->buffer; + + while ( nLen > 0 ) + { + if ( *pCharStr == cOld ) + { + /* Copy String */ + IMPL_RTL_STRCODE* pNewCharStr = IMPL_RTL_STRINGNAME( ImplNewCopy )( ppThis, pStr, pCharStr-pStr->buffer ); + + /* replace/copy rest of the string */ + if ( pNewCharStr ) + { + *pNewCharStr = cNew; + pNewCharStr++; + pCharStr++; + nLen--; + + while ( nLen > 0 ) + { + if ( *pCharStr == cOld ) + *pNewCharStr = cNew; + else + *pNewCharStr = *pCharStr; + + pNewCharStr++; + pCharStr++; + nLen--; + } + } + + bChanged = 1; + break; + } + + pCharStr++; + nLen--; + } + + if ( !bChanged ) + { + *ppThis = pStr; + IMPL_RTL_AQUIRE( pStr ); + } + + /* must be done at least, if pStr == *ppThis */ + if ( pOrg ) + IMPL_RTL_STRINGNAME( release )( pOrg ); +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( newToAsciiLowerCase )( IMPL_RTL_STRINGDATA** ppThis, + IMPL_RTL_STRINGDATA* pStr ) +{ + IMPL_RTL_STRINGDATA* pOrg = *ppThis; + int bChanged = 0; + sal_Int32 nLen = pStr->length; + const IMPL_RTL_STRCODE* pCharStr = pStr->buffer; + + while ( nLen > 0 ) + { + /* Between A-Z (65-90), than to lowercase (+32) */ + if ( (*pCharStr >= 65) && (*pCharStr <= 90) ) + { + /* Copy String */ + IMPL_RTL_STRCODE* pNewCharStr = IMPL_RTL_STRINGNAME( ImplNewCopy )( ppThis, pStr, pCharStr-pStr->buffer ); + + /* replace/copy rest of the string */ + if ( pNewCharStr ) + { + /* to lowercase (+32) */ + *pNewCharStr = *pCharStr+32; + pNewCharStr++; + pCharStr++; + nLen--; + + while ( nLen > 0 ) + { + /* Between A-Z (65-90), than to lowercase (+32) */ + if ( (*pCharStr >= 65) && (*pCharStr <= 90) ) + *pNewCharStr = *pCharStr+32; + else + *pNewCharStr = *pCharStr; + + pNewCharStr++; + pCharStr++; + nLen--; + } + } + + bChanged = 1; + break; + } + + pCharStr++; + nLen--; + } + + if ( !bChanged ) + { + *ppThis = pStr; + IMPL_RTL_AQUIRE( pStr ); + } + + /* must be done at least, if pStr == *ppThis */ + if ( pOrg ) + IMPL_RTL_STRINGNAME( release )( pOrg ); +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( newToAsciiUpperCase )( IMPL_RTL_STRINGDATA** ppThis, + IMPL_RTL_STRINGDATA* pStr ) +{ + IMPL_RTL_STRINGDATA* pOrg = *ppThis; + int bChanged = 0; + sal_Int32 nLen = pStr->length; + const IMPL_RTL_STRCODE* pCharStr = pStr->buffer; + + while ( nLen > 0 ) + { + /* Between a-z (97-122), than to uppercase (-32) */ + if ( (*pCharStr >= 97) && (*pCharStr <= 122) ) + { + /* Copy String */ + IMPL_RTL_STRCODE* pNewCharStr = IMPL_RTL_STRINGNAME( ImplNewCopy )( ppThis, pStr, pCharStr-pStr->buffer ); + + /* replace/copy rest of the string */ + if ( pNewCharStr ) + { + /* to uppercase (-32) */ + *pNewCharStr = *pCharStr-32; + pNewCharStr++; + pCharStr++; + nLen--; + + while ( nLen > 0 ) + { + /* Between a-z (97-122), than to uppercase (-32) */ + if ( (*pCharStr >= 97) && (*pCharStr <= 122) ) + *pNewCharStr = *pCharStr-32; + else + *pNewCharStr = *pCharStr; + + pNewCharStr++; + pCharStr++; + nLen--; + } + } + + bChanged = 1; + break; + } + + pCharStr++; + nLen--; + } + + if ( !bChanged ) + { + *ppThis = pStr; + IMPL_RTL_AQUIRE( pStr ); + } + + /* must be done at least, if pStr == *ppThis */ + if ( pOrg ) + IMPL_RTL_STRINGNAME( release )( pOrg ); +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL IMPL_RTL_STRINGNAME( newTrim )( IMPL_RTL_STRINGDATA** ppThis, + IMPL_RTL_STRINGDATA* pStr ) +{ + IMPL_RTL_STRINGDATA* pOrg = *ppThis; + const IMPL_RTL_STRCODE* pCharStr = pStr->buffer; + sal_Int32 nPreSpaces = 0; + sal_Int32 nPostSpaces = 0; + sal_Int32 nLen = pStr->length; + sal_Int32 nIndex = nLen-1; + + while ( (nPreSpaces < nLen) && rtl_ImplIsWhitespace( IMPL_RTL_USTRCODE(*(pCharStr+nPreSpaces)) ) ) + nPreSpaces++; + + while ( (nIndex > nPreSpaces) && rtl_ImplIsWhitespace( IMPL_RTL_USTRCODE(*(pCharStr+nIndex)) ) ) + { + nPostSpaces++; + nIndex--; + } + + if ( !nPreSpaces && !nPostSpaces ) + { + *ppThis = pStr; + IMPL_RTL_AQUIRE( pStr ); + } + else + { + nLen -= nPostSpaces+nPreSpaces; + *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen ); + OSL_ASSERT(*ppThis != NULL); + if ( *ppThis ) + rtl_str_ImplCopy( (*ppThis)->buffer, pStr->buffer+nPreSpaces, nLen ); + } + + /* must be done at least, if pStr == *ppThis */ + if ( pOrg ) + IMPL_RTL_STRINGNAME( release )( pOrg ); +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL IMPL_RTL_STRINGNAME( getToken )( IMPL_RTL_STRINGDATA** ppThis, + IMPL_RTL_STRINGDATA* pStr, + sal_Int32 nToken, + IMPL_RTL_STRCODE cTok, + sal_Int32 nIndex ) +{ + const IMPL_RTL_STRCODE* pCharStr = pStr->buffer; + const IMPL_RTL_STRCODE* pCharStrStart; + const IMPL_RTL_STRCODE* pOrgCharStr; + sal_Int32 nLen = pStr->length-nIndex; + sal_Int32 nTokCount = 0; + + // Set ppThis to an empty string and return -1 if either nToken or nIndex is + // negative: + if (nIndex < 0) { + nToken = -1; + } + + pCharStr += nIndex; + pOrgCharStr = pCharStr; + pCharStrStart = pCharStr; + while ( nLen > 0 ) + { + if ( *pCharStr == cTok ) + { + nTokCount++; + + if ( nTokCount == nToken ) + pCharStrStart = pCharStr+1; + else + { + if ( nTokCount > nToken ) + break; + } + } + + pCharStr++; + nLen--; + } + + if ( (nToken < 0) || (nTokCount < nToken) || (pCharStr == pCharStrStart) ) + { + IMPL_RTL_STRINGNAME( new )( ppThis ); + if( (nToken < 0) || (nTokCount < nToken ) ) + return -1; + else if( nLen > 0 ) + return nIndex+(pCharStr-pOrgCharStr)+1; + else return -1; + } + else + { + IMPL_RTL_STRINGNAME( newFromStr_WithLength )( ppThis, pCharStrStart, pCharStr-pCharStrStart ); + if ( nLen ) + return nIndex+(pCharStr-pOrgCharStr)+1; + else + return -1; + } +} diff --git a/sal/rtl/source/surrogates.h b/sal/rtl/source/surrogates.h new file mode 100644 index 000000000000..48fe4182ad46 --- /dev/null +++ b/sal/rtl/source/surrogates.h @@ -0,0 +1,50 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_SAL_RTL_SOURCE_SURROGATES_H +#define INCLUDED_SAL_RTL_SOURCE_SURROGATES_H + +#include "sal/config.h" + +#define SAL_RTL_FIRST_HIGH_SURROGATE 0xD800 +#define SAL_RTL_LAST_HIGH_SURROGATE 0xDBFF +#define SAL_RTL_FIRST_LOW_SURROGATE 0xDC00 +#define SAL_RTL_LAST_LOW_SURROGATE 0xDFFF + +#define SAL_RTL_IS_HIGH_SURROGATE(utf16) \ + ((utf16) >= SAL_RTL_FIRST_HIGH_SURROGATE && \ + (utf16) <= SAL_RTL_LAST_HIGH_SURROGATE) + +#define SAL_RTL_IS_LOW_SURROGATE(utf16) \ + ((utf16) >= SAL_RTL_FIRST_LOW_SURROGATE && \ + (utf16) <= SAL_RTL_LAST_LOW_SURROGATE) + +#define SAL_RTL_COMBINE_SURROGATES(high, low) \ + ((((high) - SAL_RTL_FIRST_HIGH_SURROGATE) << 10) + \ + ((low) - SAL_RTL_FIRST_LOW_SURROGATE) + 0x10000) + +#endif diff --git a/sal/rtl/source/tres.c b/sal/rtl/source/tres.c new file mode 100644 index 000000000000..85e5c4367066 --- /dev/null +++ b/sal/rtl/source/tres.c @@ -0,0 +1,686 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <stdio.h> +#include <rtl/tres.h> +#include <osl/diagnose.h> +#include <osl/time.h> + + /* force an assertion on false state */ +#define TST_BOOM(c, m) OSL_ENSURE(c, m) + + +typedef struct _rtl_CmpState +{ + struct _rtl_CmpState* m_next; + struct _rtl_CmpState* m_prev; + + sal_Bool m_stat; + rtl_String* m_msg; + +} rtl_CmpState; + +typedef struct _rtl_FuncState +{ + struct _rtl_FuncState* m_next; + struct _rtl_FuncState* m_prev; + rtl_String* m_name; + sal_uInt32 m_flags; + sal_uInt32 m_start; + sal_uInt32 m_stop; + struct _rtl_CmpState* m_cmp; + +} rtl_FuncState; + + + +typedef struct _rtl_TestResult_Data +{ + rtl_TestResult_vtable* m_funcs; + void* m_externaldata; + + rtl_FuncState* m_state; + +} rtl_TestResult_Data; + + + /** + * internal helper functions + */ + + /* ...to create, link, unlink and destroy allocated memory */ +rtl_FuncState* SAL_CALL rtl_tres_create_funcstate( const sal_Char* meth ); +rtl_FuncState* SAL_CALL rtl_tres_link_funcstate( rtl_FuncState* ptr, + rtl_FuncState* plink ); +rtl_FuncState* SAL_CALL rtl_tres_unlink_funcstate( rtl_FuncState* plink ); +rtl_CmpState* SAL_CALL rtl_tres_create_cmpstate( + sal_Bool state, + const sal_Char* msg + ); +rtl_CmpState* SAL_CALL rtl_tres_link_cmpstate( rtl_CmpState* ptr, + rtl_CmpState* plink ); +rtl_CmpState* SAL_CALL rtl_tres_unlink_cmpstate( rtl_CmpState* plink ); +sal_uInt32 SAL_CALL rtl_tres_timer(); +void SAL_CALL rtl_tres_destroy_funcstate( rtl_FuncState* pState_ ); +void SAL_CALL rtl_tres_destroy_funcstates( rtl_FuncState* pState_ ); +void SAL_CALL rtl_tres_destroy_cmpstates( rtl_CmpState* pState_ ); +void SAL_CALL rtl_tres_destroy_cmpstate( rtl_CmpState* pState_ ); + + + /* set and clear single bits */ +static void SAL_CALL rtl_tres_setbit( rtl_FuncState* pState_, + sal_uInt32 flag ); +static void SAL_CALL rtl_tres_clearbit( rtl_FuncState* pState_, + sal_uInt32 flag ); + + /** + * forward declarations of concrete function implementations overloadable + * and accessible via vtable + */ +static sal_Bool SAL_CALL rtl_tres_state( + rtl_TestResult* pThis_, + sal_Bool state, + const sal_Char* msg, + const sal_Char* sub, + sal_Bool v + ); + +static void SAL_CALL rtl_tres_end( rtl_TestResult* pThis_, + const sal_Char* msg ); + +static rtl_funcstate SAL_CALL rtl_tres_funcstate( rtl_TestResult* pThis_ ); + +static sal_Bool SAL_CALL rtl_tres_ispassed( rtl_TestResult* pThis_ ); +static sal_Bool SAL_CALL rtl_tres_isok( rtl_TestResult* pThis_ ); + +static sal_Bool SAL_CALL rtl_tres_isbit( rtl_TestResult* pThis_, + sal_uInt32 flag ); + +static rtl_funcstate SAL_CALL rtl_tres_getnextfuncstate( rtl_funcstate ); +static rtl_funcstate SAL_CALL rtl_tres_getprevfuncstate( rtl_funcstate ); +static sal_uInt32 SAL_CALL rtl_tres_getflags( rtl_funcstate ); +sal_uInt32 SAL_CALL rtl_tres_getstarttime( rtl_funcstate ); +sal_uInt32 SAL_CALL rtl_tres_getstoptime( rtl_funcstate ); +static rtl_cmpstate SAL_CALL rtl_tres_getcmpstate( rtl_funcstate ); + +static sal_Bool SAL_CALL rtl_tres_getstat( rtl_cmpstate ); +rtl_String* SAL_CALL rtl_tres_getname( rtl_funcstate ); +rtl_String* SAL_CALL rtl_tres_getmsg( rtl_cmpstate ); +static rtl_cmpstate SAL_CALL rtl_tres_getnextcmpstate( rtl_cmpstate ); + + + /** + * initialize vtable with function pointers + */ +static rtl_TestResult_vtable trVTable = +{ + sizeof(rtl_TestResult_vtable), + rtl_tres_state, + rtl_tres_end, + rtl_tres_ispassed, + rtl_tres_isok, + rtl_tres_funcstate, + rtl_tres_isbit, + rtl_tres_getnextfuncstate, + rtl_tres_getprevfuncstate, + rtl_tres_getflags, + rtl_tres_getname, + rtl_tres_getstarttime, + rtl_tres_getstoptime, + rtl_tres_getcmpstate, + rtl_tres_getstat, + rtl_tres_getmsg, + rtl_tres_getnextcmpstate +}; + + /** + * rtl_tres_create + * create and initialize data struct for TestResult + * + * @param const sal_Char* meth = name of the method (entryname) + * @param sal_uInt32 flags = bitmap of comandline and status flags + * + * @return rtl_TestResult* = pointer to a new allocated testresult struct + */ +rtl_TestResult* rtl_tres_create( const sal_Char* meth, sal_uInt32 flags ) +{ + /* allocate memory for testresult data structure */ + rtl_TestResult_Data* pData = (rtl_TestResult_Data*) malloc( sizeof( + rtl_TestResult_Data ) ); + /* initialize members... */ + pData->m_funcs = &trVTable; /* ...vtableptr to vtbladr */ + pData->m_externaldata = 0; /* ...external data pointer */ + + /* allocate memory for state structure and initialize members */ + pData->m_state = rtl_tres_create_funcstate( meth ); + pData->m_state->m_flags = flags; /* ...option Bitmap */ + + /* set OK flag initial */ + rtl_tres_setbit( pData->m_state, rtl_tres_Flag_OK ); + + return (rtl_TestResult*)pData ; +} + +/** + * rtl_tres_create_funcstate + * allocates and initializes a structure to represent the status of a test + * entry or its substates + * + * @param const sal_Char* meth = the name of the method (entry or sub entry) + * + * @return rtl_FuncState* = pointer to a new allocated funcstate struct + */ +rtl_FuncState* SAL_CALL rtl_tres_create_funcstate( const sal_Char* meth ) +{ + rtl_FuncState* pStat = 0; /* status structure */ + + /* allocate memory for status structure */ + pStat = (rtl_FuncState*) malloc( sizeof( struct _rtl_FuncState ) ); + + if ( pStat ) + { + pStat->m_next = pStat; /* init ptr to next struct */ + pStat->m_prev = pStat; /* init ptr to prev struct */ + + pStat->m_name = 0; /* init name */ + pStat->m_flags = 0; /* init flags */ + pStat->m_start = rtl_tres_timer(); /* init start milliseconds */ + pStat->m_stop = 0; /* init stop milliseconds */ + pStat->m_cmp = 0; /* init ptr to msg struct */ + rtl_string_newFromStr( &pStat->m_name, meth );/* copy meth to name */ + + /* set ok flag initially */ + rtl_tres_setbit(pStat, rtl_tres_Flag_OK); + } + + return ( pStat ); +} + /** + * rtl_tres_link_funcstate + * link initialized funcstate structure to a circular double linked list + * + * @param rtl_FuncState* ptr = pointer to a funcstate where to link in new + * @param rtl_FuncState* plink = pointer to a funcstate to link in list + * + * @return rtl_FuncState* = pointer to structure linked in new + */ +rtl_FuncState* SAL_CALL rtl_tres_link_funcstate( rtl_FuncState* ptr, + rtl_FuncState* plink ) +{ + ptr->m_next->m_prev = plink; + ptr->m_next->m_prev->m_next = ptr->m_next; + ptr->m_next->m_prev->m_prev = ptr; + ptr->m_next = plink; + return ( plink ); +} + + /** + * rtl_tres_unlink_funcstate + * unlink funcstate structure from a circular double linked list + * + * @param rtl_FuncState* plink = pointer to a funcstate to unlink from list + * + * @return rtl_FuncState* = pointer to funcstate struct unlinked from + * list + */ +rtl_FuncState* SAL_CALL rtl_tres_unlink_funcstate( rtl_FuncState* plink ) +{ + plink->m_next->m_prev = plink->m_prev; + plink->m_prev->m_next = plink->m_next; + plink->m_next = plink; + plink->m_prev = plink; + return ( plink ); +} + + /** + * rtl_tres_link_cmpstate + * link initialized cmpstate structure to a circular double linked list + * + * @param rtl_CmpState* ptr = pointer to a cmpstate where to link in new + * @param rtl_CmpState* plink = pointer to a cmpstate to link in list + * + * @return rtl_CmpState* = pointer to cmpstate struct linked in new + */ +rtl_CmpState* SAL_CALL rtl_tres_link_cmpstate( rtl_CmpState* ptr, + rtl_CmpState* plink ) +{ + ptr->m_next->m_prev = plink; + ptr->m_next->m_prev->m_next = ptr->m_next; + ptr->m_next->m_prev->m_prev = ptr; + ptr->m_next = plink; + return ( plink ); +} + /** + * rtl_tres_unlink_cmpstate + * unlink cmpstate structure from a circular double linked list + * + * @param rtl_CmpState* plink = pointer to a cmpstate to unlink from list + * + * @return rtl_CmpState* = pointer to cmpstate struct unlinked from list + */ +rtl_CmpState* SAL_CALL rtl_tres_unlink_cmpstate( rtl_CmpState* plink ) +{ + plink->m_next->m_prev = plink->m_prev; + plink->m_prev->m_next = plink->m_next; + plink->m_next = plink; + plink->m_prev = plink; + return ( plink ); +} + + /** + * rtl_tres_create_cmpstate + * allocates and initializes a structure to represent the status of a test + * comparison + * + * @param sal_Bool state = compare state + * @param sal_Char* msg = message for logging and debug purposes + * + * @return rtl_CmpState* = pointer to the new allocated struct + */ +rtl_CmpState* SAL_CALL rtl_tres_create_cmpstate( + sal_Bool state, + const sal_Char* msg + ) +{ + /* allocate memory for cmpstate struct */ + rtl_CmpState* pStat = (rtl_CmpState*) malloc( sizeof( rtl_CmpState ) ); + + /* initialize if memory could be allocated */ + if ( pStat ) + { + pStat->m_next = pStat; /* init next with this */ + pStat->m_prev = pStat; /* init prev with this */ + pStat->m_msg = 0; + pStat->m_stat = state; /* boolean state */ + rtl_string_newFromStr( &pStat->m_msg, msg ); /* copy message */ + } + return ( pStat ); +} + + /** + * rtl_tres_destroy + * free allocated memory of testresult data struct + * + * @param rtl_TestResult* pThis_ = ponter to a valid testresult struct + */ +void SAL_CALL rtl_tres_destroy( rtl_TestResult* pThis_ ) +{ + /* cast to implementation representation structure */ + rtl_TestResult_Data* pData = (rtl_TestResult_Data*) pThis_; + + /* destroy all funcstates */ + if ( pData->m_state ) + rtl_tres_destroy_funcstates( pData->m_state ); + + /* free allocted memory and reinitialize to zero */ + /* to be able to prevent dangling pointer access*/ + free( pData ); pData = 0; +} + + /** + * rtl_tres_destroy_funcstates + * free allocated memory occupied by the list of funcstate data structs + * (iterates through next pointers) + * + * @param rtl_FuncState* pState_ = pointer to a valid funcstate struct + */ +void SAL_CALL rtl_tres_destroy_funcstates( rtl_FuncState* pState_ ) +{ + rtl_FuncState* plink = pState_->m_next; + while ( plink != plink->m_next ) + { + rtl_tres_destroy_funcstate( rtl_tres_unlink_funcstate( plink ) ); + plink = pState_->m_next; + } + rtl_tres_destroy_funcstate( plink ); +} + + /** + * rtl_tres_destroy_cmpstates + * free allocated memory occupied by the list of cmpstate data structs + * (iterates through next pointers) + * + * @param rtl_CmpState* pState_ = pointer to a valid cmpstate struct + */ +void SAL_CALL rtl_tres_destroy_cmpstates( rtl_CmpState* pState_ ) +{ + rtl_CmpState* plink = pState_->m_next; + while ( plink != plink->m_next ) + { + rtl_tres_destroy_cmpstate( rtl_tres_unlink_cmpstate( plink ) ); + plink = pState_->m_next; + } + rtl_tres_destroy_cmpstate( plink ); +} + + + /** + * rtl_tres_destroy_funcstate + * free allocated memory occupied by one funcstate and it's list + * of cmpstate data structs + * + * @param rtl_FuncState* pState_ = pointer to a valid funcstate struct + */ +void SAL_CALL rtl_tres_destroy_funcstate( rtl_FuncState* pState_ ) +{ + rtl_FuncState* plink = pState_; + + if ( plink->m_cmp ) + rtl_tres_destroy_cmpstates( plink->m_cmp ); + + if ( plink->m_name ) + { + rtl_string_release( plink->m_name ); + plink->m_name = 0; + } + plink->m_flags = 0; + free( plink ); + plink = 0; +} + + /** + * rtl_tres_destroy_cmpstate + * free allocated memory of a cmpstate data struct + * + * @param rtl_CmpState* pState_ = pointer to cmpstate struct to destroy + */ +void SAL_CALL rtl_tres_destroy_cmpstate( rtl_CmpState* pState_ ) +{ + + rtl_CmpState* plink = pState_; + + if ( plink->m_msg ) + { + rtl_string_release( plink->m_msg ); + plink->m_msg = 0; + } + free( plink ); + plink = 0; +} + /** + * central function to call in tests + * + * @param rtl_TestResult* pThis_ = self pointer to TestResult structure + * @param sal_Bool state = boolean result of statement comparison + * @param const sal_Char* msg = message for actual statementcomparison + * @param const sal_Char* sub = name of sub testfunction + * @param sal_Bool v = boolean verbose parameter + * + * @return sal_Bool = determines if statement comparison + * was positive or not + */ +static sal_Bool SAL_CALL rtl_tres_state( + rtl_TestResult* pThis_, + sal_Bool state, + const sal_Char* msg, + const sal_Char* sub, + sal_Bool v + ) +{ + + /* cast pointer to testresult data implementation struct*/ + rtl_TestResult_Data* pData = (rtl_TestResult_Data*)pThis_; + + /* initialize funcstate pointer with masterstate */ + rtl_FuncState* pFunc = pData->m_state; + + /* if substate required */ + if ( sub ) + { + /* link new created function state to last item */ + pFunc = rtl_tres_link_funcstate( pFunc->m_prev, + rtl_tres_create_funcstate( sub ) ); + + /* indicate this state as substate */ + rtl_tres_setbit( pFunc, rtl_tres_Flag_SUB ); + + /* indicate prvious state as passed if no masterstate */ + if ( pFunc->m_prev != pData->m_state ) + rtl_tres_setbit( pFunc->m_prev, rtl_tres_Flag_PASSED ); + } + + + /* test failed */ + if( ! state ) + { + /* determine if assertion should be thrown */ + if ( rtl_tres_isbit( pThis_, rtl_tres_Flag_BOOM ) ) + { + /* if message available */ + if ( msg ) + TST_BOOM( state, msg ); + else + TST_BOOM( state, "no msg available" ); + } + + /* clear this state ok flag and masterstate ok flag */ + rtl_tres_clearbit( pFunc, rtl_tres_Flag_OK ); + rtl_tres_clearbit( pData->m_state, rtl_tres_Flag_OK ); + } + /* message available */ + if( msg ) + { + /* append a new comparison state */ + if (! pFunc->m_cmp ) + pFunc->m_cmp = rtl_tres_create_cmpstate( state, msg ); + else + rtl_tres_link_cmpstate( pFunc->m_cmp, + rtl_tres_create_cmpstate(state, msg ) ); + + /* message to stderr required ? */ + if ( v || ( pFunc->m_next->m_flags & rtl_tres_Flag_VERBOSE ) ) + fprintf( stderr, "%s\n", msg ); + } + + pFunc->m_stop = rtl_tres_timer(); + return ( state ); +} + + /** + * rtl_tres_timer + * function to get actual timevalue + * this has to be replaced by a high resolution timer + */ +sal_uInt32 SAL_CALL rtl_tres_timer() +{ + sal_uInt32 val = 0; + TimeValue* tmv = (TimeValue*)malloc( sizeof( TimeValue ) ); + osl_getSystemTime( tmv ); + val = tmv->Nanosec/1000L; + free( tmv ); + return ( val ); +} + + +static void SAL_CALL rtl_tres_end( rtl_TestResult* pThis_, + const sal_Char* msg ) +{ + rtl_TestResult_Data* pData = (rtl_TestResult_Data*) pThis_; + + if( msg ) + { + if (! pData->m_state->m_cmp ) + pData->m_state->m_cmp = rtl_tres_create_cmpstate( sal_True, msg ); + else + rtl_tres_link_cmpstate( pData->m_state->m_cmp, + rtl_tres_create_cmpstate( sal_True, msg ) ); + } + pData->m_state->m_prev->m_flags |= rtl_tres_Flag_PASSED; + pData->m_state->m_flags |= rtl_tres_Flag_PASSED; + pData->m_state->m_stop = rtl_tres_timer(); +} + + +static sal_Bool SAL_CALL rtl_tres_ispassed( rtl_TestResult* pThis_ ) +{ + return rtl_tres_isbit( pThis_, rtl_tres_Flag_PASSED ); +} + +static sal_Bool SAL_CALL rtl_tres_isok( rtl_TestResult* pThis_ ) +{ + return rtl_tres_isbit( pThis_, rtl_tres_Flag_OK ); +} + /** + * return pointer to funcstate structure + */ +static rtl_funcstate SAL_CALL rtl_tres_funcstate( rtl_TestResult* pThis_ ) +{ + + rtl_TestResult_Data* pThis = (rtl_TestResult_Data*) pThis_; + return (rtl_funcstate)pThis->m_state; +} + + /** + * determine if a flag is set or not + */ +static sal_Bool SAL_CALL rtl_tres_isbit( rtl_TestResult* pThis_, + sal_uInt32 flag ) +{ + return (sal_Bool) + ((((rtl_TestResult_Data *) pThis_)->m_state->m_flags & flag) == flag); +} + /** + * set one single bit + */ +static void SAL_CALL rtl_tres_setbit( rtl_FuncState* pState_, + sal_uInt32 flag ) +{ + pState_->m_flags |= flag; +} + /** + * clear one single bit + */ +static void SAL_CALL rtl_tres_clearbit( rtl_FuncState* pState_, + sal_uInt32 flag ) +{ + pState_->m_flags = pState_->m_flags & ( ~flag ); +} + + /** + * returns next pointer of passed funcstate structure + */ +rtl_funcstate SAL_CALL rtl_tres_getnextfuncstate( rtl_funcstate fstate ) +{ + rtl_FuncState* fs = (rtl_FuncState*)fstate; + return( (rtl_funcstate)fs->m_next ); + +} + /** + * returns previous pointer of passed funcstate structure + */ +rtl_funcstate SAL_CALL rtl_tres_getprevfuncstate( rtl_funcstate fstate ) +{ + rtl_FuncState* fs = (rtl_FuncState*)fstate; + return( (rtl_funcstate)fs->m_prev ); + +} + /** + * returns flag value of passed funcstate structure + */ +sal_uInt32 SAL_CALL rtl_tres_getflags( rtl_funcstate fstate ) +{ + rtl_FuncState* fs = (rtl_FuncState*)fstate; + return( fs->m_flags ); +} + /** + * returns name of passed funcstate structure + */ +rtl_String* SAL_CALL rtl_tres_getname( rtl_funcstate fstate ) +{ + rtl_FuncState* fs = (rtl_FuncState*)fstate; + return( fs->m_name ); +} + /** + * returns starttime of passed funcstate structure + */ +sal_uInt32 SAL_CALL rtl_tres_getstarttime( rtl_funcstate fstate ) +{ + rtl_FuncState* fs = (rtl_FuncState*)fstate; + return( fs->m_start ); +} + + /** + * returns stoptime of passed funcstate structure + */ +sal_uInt32 SAL_CALL rtl_tres_getstoptime( rtl_funcstate fstate ) +{ + rtl_FuncState* fs = (rtl_FuncState*)fstate; + return( fs->m_stop ); +} + + /** + * returns pointer to cmpstate of passed funcstate structure + */ +rtl_cmpstate SAL_CALL rtl_tres_getcmpstate( rtl_funcstate fstate) +{ + rtl_FuncState* fs = (rtl_FuncState*)fstate; + return( (rtl_cmpstate)fs->m_cmp ); + +} + /** + * returns boolean state of passed cmpstate structure + */ +sal_Bool SAL_CALL rtl_tres_getstat( rtl_cmpstate cstate) +{ + rtl_CmpState* cs = (rtl_CmpState*)cstate; + return( cs->m_stat ); +} + /** + * returns message of passed cmpstate structure + */ +rtl_String* SAL_CALL rtl_tres_getmsg( rtl_cmpstate cstate) +{ + rtl_CmpState* cs = (rtl_CmpState*)cstate; + return( cs->m_msg ); +} + /** + * returns next pointer of passed cmpstate structure + */ +rtl_cmpstate SAL_CALL rtl_tres_getnextcmpstate( rtl_cmpstate cstate) +{ + rtl_CmpState* cs = (rtl_CmpState*)cstate; + return( (rtl_cmpstate)cs->m_next ); +} + +/* +// <method_logPrintf> +//inline void logPrintf ( const sal_Bool bTestCaseState, +// const char *pFormatStr, ... +// ) +//{ +// if( m_pFunctions && m_pFunctions->pLogPrintf ) +// { +// va_list vArgumentList; +// va_start ( vArgumentList, pFormatStr ); + +// m_pFunctions->pLogPrintf( this, bTestCaseState, pFormatStr, vArgumentList ); + +// va_end ( vArgumentList ); +// } +//} // </method_logPrintf> + */ + diff --git a/sal/rtl/source/unload.cxx b/sal/rtl/source/unload.cxx new file mode 100644 index 000000000000..ba31bd9c86f9 --- /dev/null +++ b/sal/rtl/source/unload.cxx @@ -0,0 +1,417 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" +#include <rtl/unload.h> +#include <rtl/alloc.h> +#include <rtl/ustring.hxx> +#include <osl/mutex.hxx> +#include <hash_map> +#include "rtl/allocator.hxx" + +#include <functional> +#include <list> +#include <deque> + +using osl::MutexGuard; + +//---------------------------------------------------------------------------- + +static void rtl_notifyUnloadingListeners(); + +static sal_Bool isEqualTimeValue ( const TimeValue* time1, const TimeValue* time2) +{ + if( time1->Seconds == time2->Seconds && + time1->Nanosec == time2->Nanosec) + return sal_True; + else + return sal_False; +} + +static sal_Bool isGreaterTimeValue( const TimeValue* time1, const TimeValue* time2) +{ + sal_Bool retval= sal_False; + if ( time1->Seconds > time2->Seconds) + retval= sal_True; + else if ( time1->Seconds == time2->Seconds) + { + if( time1->Nanosec > time2->Nanosec) + retval= sal_True; + } + return retval; +} + +static sal_Bool isGreaterEqualTimeValue( const TimeValue* time1, const TimeValue* time2) +{ + if( isEqualTimeValue( time1, time2) ) + return sal_True; + else if( isGreaterTimeValue( time1, time2)) + return sal_True; + else + return sal_False; +} + +static void addTimeValue( const TimeValue* value1, const TimeValue* value2, TimeValue* result) +{ + sal_uInt64 sum; + result->Nanosec=0; + result->Seconds=0; + + sum= value1->Nanosec + value2->Nanosec; + if( sum >= 1000000000 ) + { + result->Seconds=1; + sum -= 1000000000; + } + result->Nanosec= (sal_uInt32)sum; + result->Seconds += value1->Seconds + value2->Seconds; +} + + +static sal_Bool hasEnoughTimePassed( const TimeValue* unusedSince, const TimeValue* timespan) +{ + sal_Bool retval= sal_False; + TimeValue currentTime; + if( osl_getSystemTime( ¤tTime)) + { + TimeValue addedTime; + addTimeValue( unusedSince, timespan, &addedTime); + if( isGreaterEqualTimeValue( ¤tTime, &addedTime)) + retval= sal_True; + } + + return retval; +} + +static osl::Mutex* getUnloadingMutex() +{ + static osl::Mutex * g_pMutex= NULL; + if (!g_pMutex) + { + MutexGuard guard( osl::Mutex::getGlobalMutex() ); + if (!g_pMutex) + { + static osl::Mutex g_aMutex; + g_pMutex= &g_aMutex; + } + } + return g_pMutex; +} + +extern "C" void rtl_moduleCount_acquire(rtl_ModuleCount * that ) +{ + rtl_StandardModuleCount* pMod= (rtl_StandardModuleCount*)that; + osl_incrementInterlockedCount( &pMod->counter); +} + +extern "C" void rtl_moduleCount_release( rtl_ModuleCount * that ) +{ + rtl_StandardModuleCount* pMod= (rtl_StandardModuleCount*)that; + OSL_ENSURE( pMod->counter >0 , "library counter incorrect" ); + osl_decrementInterlockedCount( &pMod->counter); + if( pMod->counter == 0) + { + MutexGuard guard( getUnloadingMutex()); + + if( sal_False == osl_getSystemTime( &pMod->unusedSince) ) + { + // set the time to 0 if we could not get the time + pMod->unusedSince.Seconds= 0; + pMod->unusedSince.Nanosec= 0; + } + } +} + + +struct hashModule +{ + size_t operator()( const oslModule& rkey) const + { + return (size_t)rkey; + } +}; + +typedef std::hash_map< + oslModule, + std::pair<sal_uInt32, component_canUnloadFunc>, + hashModule, + std::equal_to<oslModule>, + rtl::Allocator<oslModule> +> ModuleMap; + +typedef ModuleMap::iterator Mod_IT; + +static ModuleMap& getModuleMap() +{ + static ModuleMap * g_pMap= NULL; + if (!g_pMap) + { + MutexGuard guard( getUnloadingMutex() ); + if (!g_pMap) + { + static ModuleMap g_aModuleMap; + g_pMap= &g_aModuleMap; + } + } + return *g_pMap; +} + +extern "C" sal_Bool rtl_moduleCount_canUnload( rtl_StandardModuleCount * that, TimeValue * libUnused) +{ + if (that->counter == 0) + { + MutexGuard guard( getUnloadingMutex()); + if (libUnused && (that->counter == 0)) + { + rtl_copyMemory(libUnused, &that->unusedSince, sizeof(TimeValue)); + } + } + return (that->counter == 0); +} + + +extern "C" sal_Bool SAL_CALL rtl_registerModuleForUnloading( oslModule module) +{ + MutexGuard guard( getUnloadingMutex()); + ModuleMap& moduleMap= getModuleMap(); + sal_Bool ret= sal_True; + + // If the module has been registered before, then find it and increment + // its reference cout + Mod_IT it= moduleMap.find( module); + if( it != moduleMap.end()) + { + //module already registered, increment ref count + it->second.first++; + } + else + { + // Test if the module supports unloading (exports component_canUnload) + rtl::OUString name(RTL_CONSTASCII_USTRINGPARAM( COMPONENT_CANUNLOAD)); + component_canUnloadFunc pFunc= + (component_canUnloadFunc)osl_getFunctionSymbol( module, name.pData); + if (pFunc) + { + //register module for the first time, set ref count to 1 + moduleMap[module]= std::make_pair((sal_uInt32)1, pFunc); + } + else + ret= sal_False; + } + return ret; +} + +extern "C" void SAL_CALL rtl_unregisterModuleForUnloading( oslModule module) +{ + MutexGuard guard( getUnloadingMutex()); + + ModuleMap& moduleMap= getModuleMap(); + Mod_IT it= moduleMap.find( module); + if( it != moduleMap.end() ) + { + // The module is registered, decrement ref count. + it->second.first --; + + // If the refcount == 0 then remove the module from the map + if( it->second.first == 0) + moduleMap.erase( it); + } +} + +extern "C" void SAL_CALL rtl_unloadUnusedModules( TimeValue* libUnused) +{ + MutexGuard guard( getUnloadingMutex()); + + typedef std::list< oslModule, rtl::Allocator<oslModule> > list_type; + list_type unloadedModulesList; + + ModuleMap& moduleMap= getModuleMap(); + Mod_IT it_e= moduleMap.end(); + + // notify all listeners + rtl_notifyUnloadingListeners(); + + // prepare default TimeValue if argumetn is NULL + TimeValue nullTime={0,0}; + TimeValue* pLibUnused= libUnused? libUnused : &nullTime; + + Mod_IT it= moduleMap.begin(); + for (; it != it_e; ++it) + { + //can the module be unloaded? + component_canUnloadFunc func= it->second.second; + TimeValue unusedSince= {0, 0}; + + if( func( &unusedSince) ) + { + // module can be unloaded if it has not been used at least for the time + // specified by the argument libUnused + if( hasEnoughTimePassed( &unusedSince, pLibUnused)) + { + // get the reference count and unload the module as many times + sal_uInt32 refCount= it->second.first; + + for ( sal_uInt32 i=0; i < refCount; i++) + osl_unloadModule( it->first); + + // mark the module for later removal + unloadedModulesList.push_front( it->first); + } + } + } + + // remove all entries containing invalid (unloaded) modules + list_type::const_iterator un_it= unloadedModulesList.begin(); + for (; un_it != unloadedModulesList.end(); ++un_it) + { + moduleMap.erase( *un_it); + } +} + + +// ============================================================================== +// Unloading Listener Administration +//=============================================================================== +struct hashListener +{ + size_t operator()( const sal_Int32& rkey) const + { + return (size_t)rkey; + } +}; + +typedef std::hash_map< + sal_Int32, + std::pair<rtl_unloadingListenerFunc, void*>, + hashListener, + std::equal_to<sal_Int32>, + rtl::Allocator<sal_Int32> +> ListenerMap; + +typedef ListenerMap::iterator Lis_IT; + +static ListenerMap& getListenerMap() +{ + static ListenerMap * g_pListeners= NULL; + if (!g_pListeners) + { + MutexGuard guard( getUnloadingMutex() ); + if (!g_pListeners) + { + static ListenerMap g_aListenerMap; + g_pListeners= &g_aListenerMap; + } + } + return *g_pListeners; +} + + +// This queue contains cookies which have been passed out by rtl_addUnloadingListener and +// which have been regainded by rtl_removeUnloadingListener. When rtl_addUnloadingListener +// is called then a cookie has to be returned. First we look into the set if there is one +// availabe. Otherwise a new cookie will be provided. +// not a new value is returned. + +typedef std::deque< + sal_Int32, + rtl::Allocator<sal_Int32> +> queue_type; + +static queue_type& getCookieQueue() +{ + static queue_type * g_pCookies= NULL; + if (!g_pCookies) + { + MutexGuard guard( getUnloadingMutex() ); + if (!g_pCookies) + { + static queue_type g_aCookieQueue; + g_pCookies= &g_aCookieQueue; + } + } + return *g_pCookies; +} + +static sal_Int32 getCookie() +{ + static sal_Int32 cookieValue= 1; + + sal_Int32 retval; + queue_type& regainedCookies= getCookieQueue(); + if( regainedCookies.empty() ) + retval= cookieValue++; + else + { + retval= regainedCookies.front(); + regainedCookies.pop_front(); + } + return retval; +} + +static inline void recycleCookie( sal_Int32 i) +{ + getCookieQueue().push_back(i); +} + + +// calling the function twice with the same arguments will return tow different cookies. +// The listener will then notified twice. + +extern "C" +sal_Int32 SAL_CALL rtl_addUnloadingListener( rtl_unloadingListenerFunc callback, void* _this) +{ + MutexGuard guard( getUnloadingMutex()); + + sal_Int32 cookie= getCookie(); + ListenerMap& listenerMap= getListenerMap(); + listenerMap[ cookie]= std::make_pair( callback, _this); + return cookie; +} + + +extern "C" +void SAL_CALL rtl_removeUnloadingListener( sal_Int32 cookie ) +{ + MutexGuard guard( getUnloadingMutex()); + + ListenerMap& listenerMap= getListenerMap(); + size_t removedElements= listenerMap.erase( cookie); + if( removedElements ) + recycleCookie( cookie); +} + + +static void rtl_notifyUnloadingListeners() +{ + ListenerMap& listenerMap= getListenerMap(); + for( Lis_IT it= listenerMap.begin(); it != listenerMap.end(); ++it) + { + rtl_unloadingListenerFunc callbackFunc= it->second.first; + callbackFunc( it->second.second); + } +} diff --git a/sal/rtl/source/uri.cxx b/sal/rtl/source/uri.cxx new file mode 100644 index 000000000000..551c4f199251 --- /dev/null +++ b/sal/rtl/source/uri.cxx @@ -0,0 +1,799 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include "rtl/uri.h" + +#include "surrogates.h" + +#include "osl/diagnose.h" +#include "rtl/strbuf.hxx" +#include "rtl/textenc.h" +#include "rtl/textcvt.h" +#include "rtl/uri.h" +#include "rtl/ustrbuf.h" +#include "rtl/ustrbuf.hxx" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" + +#include <cstddef> + +namespace { + +std::size_t const nCharClassSize = 128; + +sal_Unicode const cEscapePrefix = 0x25; // '%' + +inline bool isDigit(sal_uInt32 nUtf32) +{ + return nUtf32 >= 0x30 && nUtf32 <= 0x39; // '0'--'9' +} + +inline bool isAlpha(sal_uInt32 nUtf32) +{ + // 'A'--'Z', 'a'--'z' + return ( + (nUtf32 >= 0x41 && nUtf32 <= 0x5A) || + (nUtf32 >= 0x61 && nUtf32 <= 0x7A) + ); +} + +inline bool isHighSurrogate(sal_uInt32 nUtf16) +{ + return SAL_RTL_IS_HIGH_SURROGATE(nUtf16); +} + +inline bool isLowSurrogate(sal_uInt32 nUtf16) +{ + return SAL_RTL_IS_LOW_SURROGATE(nUtf16); +} + +inline sal_uInt32 combineSurrogates(sal_uInt32 high, sal_uInt32 low) +{ + return SAL_RTL_COMBINE_SURROGATES(high, low); +} + +inline int getHexWeight(sal_uInt32 nUtf32) +{ + return nUtf32 >= 0x30 && nUtf32 <= 0x39 ? // '0'--'9' + static_cast< int >(nUtf32 - 0x30) : + nUtf32 >= 0x41 && nUtf32 <= 0x46 ? // 'A'--'F' + static_cast< int >(nUtf32 - 0x41 + 10) : + nUtf32 >= 0x61 && nUtf32 <= 0x66 ? // 'a'--'f' + static_cast< int >(nUtf32 - 0x61 + 10) : + -1; // not a hex digit +} + +inline bool isValid(sal_Bool const * pCharClass, sal_uInt32 nUtf32) +{ + return nUtf32 < nCharClassSize && pCharClass[nUtf32]; +} + +inline void writeUnicode(rtl_uString ** pBuffer, sal_Int32 * pCapacity, + sal_Unicode cChar) +{ + rtl_uStringbuffer_insert(pBuffer, pCapacity, (*pBuffer)->length, &cChar, 1); +} + +enum EscapeType +{ + EscapeNo, + EscapeChar, + EscapeOctet +}; + +/* Read any of the following: + + - sequence of escape sequences representing character from eCharset, + translated to single UCS4 character; or + + - pair of UTF-16 surrogates, translated to single UCS4 character; or + + _ single UTF-16 character, extended to UCS4 character. + */ +sal_uInt32 readUcs4(sal_Unicode const ** pBegin, sal_Unicode const * pEnd, + bool bEncoded, rtl_TextEncoding eCharset, + EscapeType * pType) +{ + sal_uInt32 nChar = *(*pBegin)++; + int nWeight1; + int nWeight2; + if (nChar == cEscapePrefix && bEncoded && pEnd - *pBegin >= 2 + && (nWeight1 = getHexWeight((*pBegin)[0])) >= 0 + && (nWeight2 = getHexWeight((*pBegin)[1])) >= 0) + { + *pBegin += 2; + nChar = static_cast< sal_uInt32 >(nWeight1 << 4 | nWeight2); + if (nChar <= 0x7F) + *pType = EscapeChar; + else if (eCharset == RTL_TEXTENCODING_UTF8) + { + if (nChar >= 0xC0 && nChar <= 0xF4) + { + sal_uInt32 nEncoded; + int nShift; + sal_uInt32 nMin; + if (nChar <= 0xDF) + { + nEncoded = (nChar & 0x1F) << 6; + nShift = 0; + nMin = 0x80; + } + else if (nChar <= 0xEF) + { + nEncoded = (nChar & 0x0F) << 12; + nShift = 6; + nMin = 0x800; + } + else + { + nEncoded = (nChar & 0x07) << 18; + nShift = 12; + nMin = 0x10000; + } + sal_Unicode const * p = *pBegin; + bool bUTF8 = true; + for (; nShift >= 0; nShift -= 6) + { + if (pEnd - p < 3 || p[0] != cEscapePrefix + || (nWeight1 = getHexWeight(p[1])) < 8 + || nWeight1 > 11 + || (nWeight2 = getHexWeight(p[2])) < 0) + { + bUTF8 = sal_False; + break; + } + p += 3; + nEncoded |= ((nWeight1 & 3) << 4 | nWeight2) << nShift; + } + if (bUTF8 && nEncoded >= nMin && !isHighSurrogate(nEncoded) + && !isLowSurrogate(nEncoded) && nEncoded <= 0x10FFFF) + { + *pBegin = p; + *pType = EscapeChar; + return nEncoded; + } + } + *pType = EscapeOctet; + } + else + { + rtl::OStringBuffer aBuf; + aBuf.append(static_cast< char >(nChar)); + rtl_TextToUnicodeConverter aConverter + = rtl_createTextToUnicodeConverter(eCharset); + sal_Unicode const * p = *pBegin; + for (;;) + { + sal_Unicode aDst[2]; + sal_uInt32 nInfo; + sal_Size nConverted; + sal_Size nDstSize = rtl_convertTextToUnicode( + aConverter, 0, aBuf.getStr(), aBuf.getLength(), aDst, + sizeof aDst / sizeof aDst[0], + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR), + &nInfo, &nConverted); + if (nInfo == 0) + { + OSL_ASSERT( + nConverted + == sal::static_int_cast< sal_uInt32 >( + aBuf.getLength())); + rtl_destroyTextToUnicodeConverter(aConverter); + *pBegin = p; + *pType = EscapeChar; + OSL_ASSERT( + nDstSize == 1 + || (nDstSize == 2 && isHighSurrogate(aDst[0]) + && isLowSurrogate(aDst[1]))); + return nDstSize == 1 + ? aDst[0] : combineSurrogates(aDst[0], aDst[1]); + } + else if (nInfo == RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL + && pEnd - p >= 3 && p[0] == cEscapePrefix + && (nWeight1 = getHexWeight(p[1])) >= 0 + && (nWeight2 = getHexWeight(p[2])) >= 0) + { + p += 3; + aBuf.append(static_cast< char >(nWeight1 << 4 | nWeight2)); + } + else if (nInfo == RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL + && p != pEnd && *p <= 0x7F) + { + aBuf.append(static_cast< char >(*p++)); + } + else + { + OSL_ASSERT( + (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL) + == 0); + break; + } + } + rtl_destroyTextToUnicodeConverter(aConverter); + *pType = EscapeOctet; + } + return nChar; + } + else + { + *pType = EscapeNo; + return isHighSurrogate(nChar) && *pBegin < pEnd + && isLowSurrogate(**pBegin) ? + combineSurrogates(nChar, *(*pBegin)++) : nChar; + } +} + +void writeUcs4(rtl_uString ** pBuffer, sal_Int32 * pCapacity, sal_uInt32 nUtf32) +{ + OSL_ENSURE(nUtf32 <= 0x10FFFF, "bad UTF-32 char"); + if (nUtf32 <= 0xFFFF) { + writeUnicode( + pBuffer, pCapacity, static_cast< sal_Unicode >(nUtf32)); + } else { + nUtf32 -= 0x10000; + writeUnicode( + pBuffer, pCapacity, + static_cast< sal_Unicode >(nUtf32 >> 10 | 0xD800)); + writeUnicode( + pBuffer, pCapacity, + static_cast< sal_Unicode >((nUtf32 & 0x3FF) | 0xDC00)); + } +} + +void writeEscapeOctet(rtl_uString ** pBuffer, sal_Int32 * pCapacity, + sal_uInt32 nOctet) +{ + OSL_ENSURE(nOctet <= 0xFF, "bad octet"); + + static sal_Unicode const aHex[16] + = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }; /* '0'--'9', 'A'--'F' */ + + writeUnicode(pBuffer, pCapacity, cEscapePrefix); + writeUnicode(pBuffer, pCapacity, aHex[nOctet >> 4]); + writeUnicode(pBuffer, pCapacity, aHex[nOctet & 15]); +} + +bool writeEscapeChar(rtl_uString ** pBuffer, sal_Int32 * pCapacity, + sal_uInt32 nUtf32, rtl_TextEncoding eCharset, bool bStrict) +{ + OSL_ENSURE(nUtf32 <= 0x10FFFF, "bad UTF-32 char"); + if (eCharset == RTL_TEXTENCODING_UTF8) { + if (nUtf32 < 0x80) + writeEscapeOctet(pBuffer, pCapacity, nUtf32); + else if (nUtf32 < 0x800) + { + writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 6 | 0xC0); + writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80); + } + else if (nUtf32 < 0x10000) + { + writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 12 | 0xE0); + writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 6 & 0x3F) | 0x80); + writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80); + } + else + { + writeEscapeOctet(pBuffer, pCapacity, nUtf32 >> 18 | 0xF0); + writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 12 & 0x3F) | 0x80); + writeEscapeOctet(pBuffer, pCapacity, (nUtf32 >> 6 & 0x3F) | 0x80); + writeEscapeOctet(pBuffer, pCapacity, (nUtf32 & 0x3F) | 0x80); + } + } else { + rtl_UnicodeToTextConverter aConverter + = rtl_createUnicodeToTextConverter(eCharset); + sal_Unicode aSrc[2]; + sal_Size nSrcSize; + if (nUtf32 <= 0xFFFF) + { + aSrc[0] = static_cast< sal_Unicode >(nUtf32); + nSrcSize = 1; + } + else + { + aSrc[0] = static_cast< sal_Unicode >( + ((nUtf32 - 0x10000) >> 10) | 0xD800); + aSrc[1] = static_cast< sal_Unicode >( + ((nUtf32 - 0x10000) & 0x3FF) | 0xDC00); + nSrcSize = 2; + } + sal_Char aDst[32]; // FIXME random value + sal_uInt32 nInfo; + sal_Size nConverted; + sal_Size nDstSize = rtl_convertUnicodeToText( + aConverter, 0, aSrc, nSrcSize, aDst, sizeof aDst, + RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR + | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR + | RTL_UNICODETOTEXT_FLAGS_FLUSH, + &nInfo, &nConverted); + OSL_ASSERT((nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL) == 0); + rtl_destroyUnicodeToTextConverter(aConverter); + if (nInfo == 0) { + OSL_ENSURE(nConverted == nSrcSize, "bad rtl_convertUnicodeToText"); + for (sal_Size i = 0; i < nDstSize; ++i) + writeEscapeOctet(pBuffer, pCapacity, + static_cast< unsigned char >(aDst[i])); + // FIXME all octets are escaped, even if there is no need + } else { + if (bStrict) { + return false; + } else { + writeUcs4(pBuffer, pCapacity, nUtf32); + } + } + } + return true; +} + +struct Component +{ + sal_Unicode const * pBegin; + sal_Unicode const * pEnd; + + inline Component(): pBegin(0) {} + + inline bool isPresent() const { return pBegin != 0; } + + inline sal_Int32 getLength() const; +}; + +inline sal_Int32 Component::getLength() const +{ + OSL_ENSURE(isPresent(), "taking length of non-present component"); + return static_cast< sal_Int32 >(pEnd - pBegin); +} + +struct Components +{ + Component aScheme; + Component aAuthority; + Component aPath; + Component aQuery; + Component aFragment; +}; + +void parseUriRef(rtl_uString const * pUriRef, Components * pComponents) +{ + // This algorithm is liberal and accepts various forms of illegal input. + + sal_Unicode const * pBegin = pUriRef->buffer; + sal_Unicode const * pEnd = pBegin + pUriRef->length; + sal_Unicode const * pPos = pBegin; + + if (pPos != pEnd && isAlpha(*pPos)) + for (sal_Unicode const * p = pPos + 1; p != pEnd; ++p) + if (*p == ':') + { + pComponents->aScheme.pBegin = pBegin; + pComponents->aScheme.pEnd = ++p; + pPos = p; + break; + } + else if (!isAlpha(*p) && !isDigit(*p) && *p != '+' && *p != '-' + && *p != '.') + break; + + if (pEnd - pPos >= 2 && pPos[0] == '/' && pPos[1] == '/') + { + pComponents->aAuthority.pBegin = pPos; + pPos += 2; + while (pPos != pEnd && *pPos != '/' && *pPos != '?' && *pPos != '#') + ++pPos; + pComponents->aAuthority.pEnd = pPos; + } + + pComponents->aPath.pBegin = pPos; + while (pPos != pEnd && *pPos != '?' && * pPos != '#') + ++pPos; + pComponents->aPath.pEnd = pPos; + + if (pPos != pEnd && *pPos == '?') + { + pComponents->aQuery.pBegin = pPos++; + while (pPos != pEnd && * pPos != '#') + ++pPos; + pComponents->aQuery.pEnd = pPos; + } + + if (pPos != pEnd) + { + OSL_ASSERT(*pPos == '#'); + pComponents->aFragment.pBegin = pPos; + pComponents->aFragment.pEnd = pEnd; + } +} + +rtl::OUString joinPaths(Component const & rBasePath, Component const & rRelPath) +{ + OSL_ASSERT(rBasePath.isPresent() && *rBasePath.pBegin == '/'); + OSL_ASSERT(rRelPath.isPresent()); + + // The invariant of aBuffer is that it always starts and ends with a slash + // (until probably right at the end of the algorithm, when the last segment + // of rRelPath is added, which does not necessarily end in a slash): + rtl::OUStringBuffer aBuffer(rBasePath.getLength() + rRelPath.getLength()); + // XXX numeric overflow + + // Segments "." and ".." within rBasePath are not conisdered special (but + // are also not removed by ".." segments within rRelPath), RFC 2396 seems a + // bit unclear about this point: + sal_Int32 nFixed = 1; + sal_Unicode const * p = rBasePath.pBegin + 1; + for (sal_Unicode const * q = p; q != rBasePath.pEnd; ++q) + if (*q == '/') + { + if ( + (q - p == 1 && p[0] == '.') || + (q - p == 2 && p[0] == '.' && p[1] == '.') + ) + { + nFixed = q + 1 - rBasePath.pBegin; + } + p = q + 1; + } + aBuffer.append(rBasePath.pBegin, p - rBasePath.pBegin); + + p = rRelPath.pBegin; + if (p != rRelPath.pEnd) + for (;;) + { + sal_Unicode const * q = p; + sal_Unicode const * r; + for (;;) + { + if (q == rRelPath.pEnd) + { + r = q; + break; + } + if (*q == '/') + { + r = q + 1; + break; + } + ++q; + } + if (q - p == 2 && p[0] == '.' && p[1] == '.') + { + // Erroneous excess segments ".." within rRelPath are left + // intact, as the examples in RFC 2396, section C.2, suggest: + sal_Int32 i = aBuffer.getLength() - 1; + if (i < nFixed) + { + aBuffer.append(p, r - p); + nFixed += 3; + } + else + { + while (aBuffer.charAt(i - 1) != '/') + --i; + aBuffer.setLength(i); + } + } + else if (q - p != 1 || *p != '.') + aBuffer.append(p, r - p); + if (q == rRelPath.pEnd) + break; + p = q + 1; + } + + return aBuffer.makeStringAndClear(); +} + +} + +sal_Bool const * SAL_CALL rtl_getUriCharClass(rtl_UriCharClass eCharClass) + SAL_THROW_EXTERN_C() +{ + static sal_Bool const aCharClass[][nCharClassSize] + = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* None */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* !"#$%&'()*+,-./*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*0123456789:;<=>?*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*@ABCDEFGHIJKLMNO*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*PQRSTUVWXYZ[\]^_*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*`abcdefghijklmno*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /*pqrstuvwxyz{|}~ */ + }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Uric */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, /*0123456789:;<=>?*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, /*PQRSTUVWXYZ[\]^_*/ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */ + }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* UricNoSlash */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, /*0123456789:;<=>?*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */ + }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* RelSegment */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, /*0123456789:;<=>?*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */ + }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* RegName */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, /*0123456789:;<=>?*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */ + }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Userinfo */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, /*0123456789:;<=>?*/ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */ + }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /*0123456789:;<=>?*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */ + }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* UnoParamValue */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* !"#$%&'()*+,-./*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*0123456789:;<=>?*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /*PQRSTUVWXYZ[\]^_*/ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */ + }}; + OSL_ENSURE( + (eCharClass >= 0 + && (sal::static_int_cast< std::size_t >(eCharClass) + < sizeof aCharClass / sizeof aCharClass[0])), + "bad eCharClass"); + return aCharClass[eCharClass]; +} + +void SAL_CALL rtl_uriEncode(rtl_uString * pText, sal_Bool const * pCharClass, + rtl_UriEncodeMechanism eMechanism, + rtl_TextEncoding eCharset, rtl_uString ** pResult) + SAL_THROW_EXTERN_C() +{ + OSL_ENSURE(!pCharClass[0x25], "bad pCharClass"); + // make sure the percent sign is encoded... + + sal_Unicode const * p = pText->buffer; + sal_Unicode const * pEnd = p + pText->length; + sal_Int32 nCapacity = 0; + rtl_uString_new(pResult); + while (p < pEnd) + { + EscapeType eType; + sal_uInt32 nUtf32 = readUcs4( + &p, pEnd, + (eMechanism == rtl_UriEncodeKeepEscapes + || eMechanism == rtl_UriEncodeCheckEscapes + || eMechanism == rtl_UriEncodeStrictKeepEscapes), + eCharset, &eType); + switch (eType) + { + case EscapeNo: + if (isValid(pCharClass, nUtf32)) // implies nUtf32 <= 0x7F + writeUnicode(pResult, &nCapacity, + static_cast< sal_Unicode >(nUtf32)); + else if (!writeEscapeChar( + pResult, &nCapacity, nUtf32, eCharset, + (eMechanism == rtl_UriEncodeStrict + || eMechanism == rtl_UriEncodeStrictKeepEscapes))) + { + rtl_uString_new(pResult); + return; + } + break; + + case EscapeChar: + if (eMechanism == rtl_UriEncodeCheckEscapes + && isValid(pCharClass, nUtf32)) // implies nUtf32 <= 0x7F + writeUnicode(pResult, &nCapacity, + static_cast< sal_Unicode >(nUtf32)); + else if (!writeEscapeChar( + pResult, &nCapacity, nUtf32, eCharset, + (eMechanism == rtl_UriEncodeStrict + || eMechanism == rtl_UriEncodeStrictKeepEscapes))) + { + rtl_uString_new(pResult); + return; + } + break; + + case EscapeOctet: + writeEscapeOctet(pResult, &nCapacity, nUtf32); + break; + } + } +} + +void SAL_CALL rtl_uriDecode(rtl_uString * pText, + rtl_UriDecodeMechanism eMechanism, + rtl_TextEncoding eCharset, rtl_uString ** pResult) + SAL_THROW_EXTERN_C() +{ + switch (eMechanism) + { + case rtl_UriDecodeNone: + rtl_uString_assign(pResult, pText); + break; + + case rtl_UriDecodeToIuri: + eCharset = RTL_TEXTENCODING_UTF8; + default: // rtl_UriDecodeWithCharset, rtl_UriDecodeStrict + { + sal_Unicode const * p = pText->buffer; + sal_Unicode const * pEnd = p + pText->length; + sal_Int32 nCapacity = 0; + rtl_uString_new(pResult); + while (p < pEnd) + { + EscapeType eType; + sal_uInt32 nUtf32 = readUcs4(&p, pEnd, true, eCharset, &eType); + switch (eType) + { + case EscapeChar: + if (nUtf32 <= 0x7F && eMechanism == rtl_UriDecodeToIuri) + { + writeEscapeOctet(pResult, &nCapacity, nUtf32); + break; + } + case EscapeNo: + writeUcs4(pResult, &nCapacity, nUtf32); + break; + + case EscapeOctet: + if (eMechanism == rtl_UriDecodeStrict) { + rtl_uString_new(pResult); + return; + } + writeEscapeOctet(pResult, &nCapacity, nUtf32); + break; + } + } + } + break; + } +} + +sal_Bool SAL_CALL rtl_uriConvertRelToAbs(rtl_uString * pBaseUriRef, + rtl_uString * pRelUriRef, + rtl_uString ** pResult, + rtl_uString ** pException) + SAL_THROW_EXTERN_C() +{ + // If pRelUriRef starts with a scheme component it is an absolute URI + // reference, and we are done (i.e., this algorithm does not support + // backwards-compatible relative URIs starting with a scheme component, see + // RFC 2396, section 5.2, step 3): + Components aRelComponents; + parseUriRef(pRelUriRef, &aRelComponents); + if (aRelComponents.aScheme.isPresent()) + { + rtl_uString_assign(pResult, pRelUriRef); + return true; + } + + // Parse pBaseUriRef; if the scheme component is not present or not valid, + // or the path component is not empty and starts with anything but a slash, + // an exception is raised: + Components aBaseComponents; + parseUriRef(pBaseUriRef, &aBaseComponents); + if (!aBaseComponents.aScheme.isPresent()) + { + rtl::OUString aMessage(pBaseUriRef); + aMessage += rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + " does not start with a scheme component")); + rtl_uString_assign(pException, + const_cast< rtl::OUString & >(aMessage).pData); + return false; + } + if (aBaseComponents.aPath.pBegin != aBaseComponents.aPath.pEnd + && *aBaseComponents.aPath.pBegin != '/') + { + rtl::OUString aMessage(pBaseUriRef); + aMessage += rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "path component does not start with slash")); + rtl_uString_assign(pException, aMessage.pData); + return false; + } + + // Use the algorithm from RFC 2396, section 5.2, to turn the relative URI + // into an absolute one (if the relative URI is a reference to the "current + // document," the "current document" is here taken to be the base URI): + rtl::OUStringBuffer aBuffer; + aBuffer.append(aBaseComponents.aScheme.pBegin, + aBaseComponents.aScheme.getLength()); + if (aRelComponents.aAuthority.isPresent()) + { + aBuffer.append(aRelComponents.aAuthority.pBegin, + aRelComponents.aAuthority.getLength()); + aBuffer.append(aRelComponents.aPath.pBegin, + aRelComponents.aPath.getLength()); + if (aRelComponents.aQuery.isPresent()) + aBuffer.append(aRelComponents.aQuery.pBegin, + aRelComponents.aQuery.getLength()); + } + else + { + if (aBaseComponents.aAuthority.isPresent()) + aBuffer.append(aBaseComponents.aAuthority.pBegin, + aBaseComponents.aAuthority.getLength()); + if (aRelComponents.aPath.pBegin == aRelComponents.aPath.pEnd + && !aRelComponents.aQuery.isPresent()) + { + aBuffer.append(aBaseComponents.aPath.pBegin, + aBaseComponents.aPath.getLength()); + if (aBaseComponents.aQuery.isPresent()) + aBuffer.append(aBaseComponents.aQuery.pBegin, + aBaseComponents.aQuery.getLength()); + } + else + { + if (*aRelComponents.aPath.pBegin == '/') + aBuffer.append(aRelComponents.aPath.pBegin, + aRelComponents.aPath.getLength()); + else + aBuffer.append(joinPaths(aBaseComponents.aPath, + aRelComponents.aPath)); + if (aRelComponents.aQuery.isPresent()) + aBuffer.append(aRelComponents.aQuery.pBegin, + aRelComponents.aQuery.getLength()); + } + } + if (aRelComponents.aFragment.isPresent()) + aBuffer.append(aRelComponents.aFragment.pBegin, + aRelComponents.aFragment.getLength()); + rtl_uString_assign(pResult, aBuffer.makeStringAndClear().pData); + return true; +} diff --git a/sal/rtl/source/ustrbuf.c b/sal/rtl/source/ustrbuf.c new file mode 100644 index 000000000000..d9fdb9983fb1 --- /dev/null +++ b/sal/rtl/source/ustrbuf.c @@ -0,0 +1,208 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <osl/interlck.h> + +#ifndef _RTL_STRING_HXX_ +#include <rtl/ustrbuf.hxx> +#endif +#include <rtl/memory.h> + +/* +#include <rtl/alloc.h> +*/ + + + +/************************************************************************* + * rtl_uStringbuffer_newFromStr_WithLength + */ +void SAL_CALL rtl_uStringbuffer_newFromStr_WithLength( rtl_uString ** newStr, + const sal_Unicode * value, + sal_Int32 count) +{ + if (!value) + { + rtl_uString_new_WithLength( newStr, 16 ); + return; + } + + rtl_uString_new_WithLength( newStr, count + 16 ); + (*newStr)->length = count; + rtl_copyMemory( (*newStr)->buffer, value, count * sizeof(sal_Unicode)); + return; +} + +/************************************************************************* + * rtl_uStringbuffer_newFromStringBuffer + */ +sal_Int32 SAL_CALL rtl_uStringbuffer_newFromStringBuffer( rtl_uString ** newStr, + sal_Int32 capacity, + rtl_uString * oldStr ) +{ + sal_Int32 newCapacity = capacity; + + if (newCapacity < oldStr->length) + newCapacity = oldStr->length; + + rtl_uString_new_WithLength( newStr, newCapacity ); + + if (oldStr->length > 0) { + (*newStr)->length = oldStr->length; + rtl_copyMemory( (*newStr)->buffer, oldStr->buffer, oldStr->length * sizeof(sal_Unicode)); + } + return newCapacity; +} + +/************************************************************************* + * rtl_uStringbuffer_ensureCapacity + */ +void SAL_CALL rtl_uStringbuffer_ensureCapacity + (rtl_uString ** This, sal_Int32* capacity, sal_Int32 minimumCapacity) +{ + if (minimumCapacity > *capacity) + { + rtl_uString * pTmp = *This; + rtl_uString * pNew = NULL; + *capacity = ((*This)->length + 1) * 2; + if (minimumCapacity > *capacity) + /* still lower, set to the minimum capacity */ + *capacity = minimumCapacity; + + rtl_uString_new_WithLength(&pNew, *capacity); + pNew->length = (*This)->length; + *This = pNew; + + rtl_copyMemory( (*This)->buffer, pTmp->buffer, pTmp->length * sizeof(sal_Unicode) ); + rtl_uString_release( pTmp ); + } +} + +/************************************************************************* + * rtl_uStringbuffer_insert + */ +void SAL_CALL rtl_uStringbuffer_insert( rtl_uString ** This, + sal_Int32 * capacity, + sal_Int32 offset, + const sal_Unicode * str, + sal_Int32 len) +{ + sal_Int32 nOldLen; + sal_Unicode * pBuf; + sal_Int32 n; + if( len != 0 ) + { + if (*capacity < (*This)->length + len) + rtl_uStringbuffer_ensureCapacity( This, capacity, (*This)->length + len ); + + /* + if( len == 1 ) + This->buffer + */ + nOldLen = (*This)->length; + pBuf = (*This)->buffer; + + /* copy the tail */ + n = (nOldLen - offset); + if( n == 1 ) + /* optimized for 1 character */ + pBuf[offset + len] = pBuf[offset]; + else if( n > 1 ) + rtl_moveMemory( pBuf + offset + len, pBuf + offset, n * sizeof(sal_Unicode) ); + + /* insert the new characters */ + if( len == 1 ) + /* optimized for 1 character */ + pBuf[offset] = *str; + else if( len > 1 ) + rtl_copyMemory( pBuf + offset, str, len * sizeof(sal_Unicode) ); + (*This)->length = nOldLen + len; + pBuf[ nOldLen + len ] = 0; + } +} + +void rtl_uStringbuffer_insertUtf32( + rtl_uString ** pThis, sal_Int32 * capacity, sal_Int32 offset, sal_uInt32 c) +{ + sal_Unicode buf[2]; + sal_Int32 len; + OSL_ASSERT(c <= 0x10FFFF && !(c >= 0xD800 && c <= 0xDFFF)); + if (c <= 0xFFFF) { + buf[0] = (sal_Unicode) c; + len = 1; + } else { + c -= 0x10000; + buf[0] = (sal_Unicode) ((c >> 10) | 0xD800); + buf[1] = (sal_Unicode) ((c & 0x3FF) | 0xDC00); + len = 2; + } + rtl_uStringbuffer_insert(pThis, capacity, offset, buf, len); +} + +/************************************************************************* + * rtl_uStringbuffer_insert_ascii + */ +void SAL_CALL rtl_uStringbuffer_insert_ascii( /*inout*/rtl_uString ** This, + /*inout*/sal_Int32 * capacity, + sal_Int32 offset, + const sal_Char * str, + sal_Int32 len) +{ + sal_Int32 nOldLen; + sal_Unicode * pBuf; + sal_Int32 n; + if( len != 0 ) + { + if (*capacity < (*This)->length + len) + rtl_uStringbuffer_ensureCapacity( This, capacity, (*This)->length + len ); + + nOldLen = (*This)->length; + pBuf = (*This)->buffer; + + /* copy the tail */ + n = (nOldLen - offset); + if( n == 1 ) + /* optimized for 1 character */ + pBuf[offset + len] = pBuf[offset]; + else if( n > 1 ) + rtl_moveMemory( pBuf + offset + len, pBuf + offset, n * sizeof(sal_Unicode) ); + + /* insert the new characters */ + for( n = 0; n < len; n++ ) + { + /* Check ASCII range */ + OSL_ENSURE( (*str & 0x80) == 0, "Found ASCII char > 127"); + + pBuf[offset + n] = (sal_Unicode)*(str++); + } + + (*This)->length = nOldLen + len; + pBuf[ nOldLen + len ] = 0; + } +} + + diff --git a/sal/rtl/source/ustring.c b/sal/rtl/source/ustring.c new file mode 100644 index 000000000000..b0bdd2d98e73 --- /dev/null +++ b/sal/rtl/source/ustring.c @@ -0,0 +1,934 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#pragma warning(disable:4738) // storing 32-bit float result in memory, possible loss of performance +#endif + +#include <rtl/memory.h> +#include <osl/diagnose.h> +#include <osl/interlck.h> +#include <rtl/alloc.h> +#include <osl/mutex.h> +#include <osl/doublecheckedlocking.h> +#include <rtl/tencinfo.h> + +#include <string.h> +#include <sal/alloca.h> + +#include "hash.h" +#include "strimp.h" +#include "surrogates.h" +#include <rtl/ustring.h> + +#include "rtl/math.h" +#include "rtl/tencinfo.h" + +/* ======================================================================= */ + +/* static data to be referenced by all empty strings + * the refCount is predefined to 1 and must never become 0 ! + */ +static rtl_uString const aImplEmpty_rtl_uString = +{ + (sal_Int32) (SAL_STRING_INTERN_FLAG|SAL_STRING_STATIC_FLAG|1), /*sal_Int32 refCount; */ + 0, /*sal_Int32 length; */ + { 0 } /*sal_Unicode buffer[1];*/ +}; + +/* ======================================================================= */ + +#define IMPL_RTL_STRCODE sal_Unicode +#define IMPL_RTL_USTRCODE( c ) (c) +#define IMPL_RTL_STRNAME( n ) rtl_ustr_ ## n + +#define IMPL_RTL_STRINGNAME( n ) rtl_uString_ ## n +#define IMPL_RTL_STRINGDATA rtl_uString +#define IMPL_RTL_EMPTYSTRING aImplEmpty_rtl_uString +#define IMPL_RTL_INTERN +static void internRelease (rtl_uString *pThis); + +/* ======================================================================= */ + +/* Include String/UString template code */ + +#include "strtmpl.c" + +sal_Int32 rtl_ustr_indexOfAscii_WithLength( + sal_Unicode const * str, sal_Int32 len, + char const * subStr, sal_Int32 subLen) +{ + if (subLen > 0 && subLen <= len) { + sal_Int32 i; + for (i = 0; i <= len - subLen; ++i) { + if (rtl_ustr_asciil_reverseEquals_WithLength( + str + i, subStr, subLen)) + { + return i; + } + } + } + return -1; +} + +sal_Int32 rtl_ustr_lastIndexOfAscii_WithLength( + sal_Unicode const * str, sal_Int32 len, + char const * subStr, sal_Int32 subLen) +{ + if (subLen > 0 && subLen <= len) { + sal_Int32 i; + for (i = len - subLen; i >= 0; --i) { + if (rtl_ustr_asciil_reverseEquals_WithLength( + str + i, subStr, subLen)) + { + return i; + } + } + } + return -1; +} + +sal_Int32 SAL_CALL rtl_ustr_valueOfFloat(sal_Unicode * pStr, float f) +{ + rtl_uString * pResult = NULL; + sal_Int32 nLen; + rtl_math_doubleToUString( + &pResult, 0, 0, f, rtl_math_StringFormat_G, + RTL_USTR_MAX_VALUEOFFLOAT - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', 0, + 0, sal_True); + nLen = pResult->length; + OSL_ASSERT(nLen < RTL_USTR_MAX_VALUEOFFLOAT); + rtl_copyMemory(pStr, pResult->buffer, (nLen + 1) * sizeof(sal_Unicode)); + rtl_uString_release(pResult); + return nLen; +} + +sal_Int32 SAL_CALL rtl_ustr_valueOfDouble(sal_Unicode * pStr, double d) +{ + rtl_uString * pResult = NULL; + sal_Int32 nLen; + rtl_math_doubleToUString( + &pResult, 0, 0, d, rtl_math_StringFormat_G, + RTL_USTR_MAX_VALUEOFDOUBLE - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', 0, + 0, sal_True); + nLen = pResult->length; + OSL_ASSERT(nLen < RTL_USTR_MAX_VALUEOFDOUBLE); + rtl_copyMemory(pStr, pResult->buffer, (nLen + 1) * sizeof(sal_Unicode)); + rtl_uString_release(pResult); + return nLen; +} + +float SAL_CALL rtl_ustr_toFloat(sal_Unicode const * pStr) +{ + return (float) rtl_math_uStringToDouble(pStr, + pStr + rtl_ustr_getLength(pStr), + '.', 0, 0, 0); +} + +double SAL_CALL rtl_ustr_toDouble(sal_Unicode const * pStr) +{ + return rtl_math_uStringToDouble(pStr, pStr + rtl_ustr_getLength(pStr), '.', + 0, 0, 0); +} + +/* ======================================================================= */ + +sal_Int32 SAL_CALL rtl_ustr_ascii_compare( const sal_Unicode* pStr1, + const sal_Char* pStr2 ) +{ + sal_Int32 nRet; + while ( ((nRet = ((sal_Int32)(*pStr1))- + ((sal_Int32)((unsigned char)(*pStr2)))) == 0) && + *pStr2 ) + { + pStr1++; + pStr2++; + } + + return nRet; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL rtl_ustr_ascii_compare_WithLength( const sal_Unicode* pStr1, + sal_Int32 nStr1Len, + const sal_Char* pStr2 ) +{ + sal_Int32 nRet = 0; + while( ((nRet = (nStr1Len ? (sal_Int32)(*pStr1) : 0)- + ((sal_Int32)((unsigned char)(*pStr2)))) == 0) && + nStr1Len && *pStr2 ) + { + pStr1++; + pStr2++; + nStr1Len--; + } + + return nRet; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL rtl_ustr_ascii_shortenedCompare_WithLength( const sal_Unicode* pStr1, + sal_Int32 nStr1Len, + const sal_Char* pStr2, + sal_Int32 nShortenedLength ) +{ + const sal_Unicode* pStr1End = pStr1 + nStr1Len; + sal_Int32 nRet; + while ( (nShortenedLength > 0) && + (pStr1 < pStr1End) && *pStr2 ) + { + /* Check ASCII range */ + OSL_ENSURE( (*pStr2 & 0x80) == 0, "Found ASCII char > 127"); + + nRet = ((sal_Int32)*pStr1)- + ((sal_Int32)(unsigned char)*pStr2); + if ( nRet != 0 ) + return nRet; + + nShortenedLength--; + pStr1++; + pStr2++; + } + + if ( nShortenedLength <= 0 ) + return 0; + + if ( *pStr2 ) + { + OSL_ENSURE( pStr1 == pStr1End, "pStr1 == pStr1End failed" ); + // first is a substring of the second string => less (negative value) + nRet = -1; + } + else + { + // greater or equal + nRet = pStr1End - pStr1; + } + + return nRet; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL rtl_ustr_asciil_reverseCompare_WithLength( const sal_Unicode* pStr1, + sal_Int32 nStr1Len, + const sal_Char* pStr2, + sal_Int32 nStr2Len ) +{ + const sal_Unicode* pStr1Run = pStr1+nStr1Len; + const sal_Char* pStr2Run = pStr2+nStr2Len; + sal_Int32 nRet; + while ( (pStr1 < pStr1Run) && (pStr2 < pStr2Run) ) + { + pStr1Run--; + pStr2Run--; + nRet = ((sal_Int32)*pStr1Run)-((sal_Int32)*pStr2Run); + if ( nRet ) + return nRet; + } + + return nStr1Len - nStr2Len; +} + +/* ----------------------------------------------------------------------- */ + +sal_Bool SAL_CALL rtl_ustr_asciil_reverseEquals_WithLength( const sal_Unicode* pStr1, + const sal_Char* pStr2, + sal_Int32 nStrLen ) +{ + const sal_Unicode* pStr1Run = pStr1+nStrLen; + const sal_Char* pStr2Run = pStr2+nStrLen; + while ( pStr1 < pStr1Run ) + { + pStr1Run--; + pStr2Run--; + if( *pStr1Run != (sal_Unicode)*pStr2Run ) + return sal_False; + } + + return sal_True; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL rtl_ustr_ascii_compareIgnoreAsciiCase( const sal_Unicode* pStr1, + const sal_Char* pStr2 ) +{ + sal_Int32 nRet; + sal_Int32 c1; + sal_Int32 c2; + do + { + /* If character between 'A' and 'Z', than convert it to lowercase */ + c1 = (sal_Int32)*pStr1; + c2 = (sal_Int32)((unsigned char)*pStr2); + if ( (c1 >= 65) && (c1 <= 90) ) + c1 += 32; + if ( (c2 >= 65) && (c2 <= 90) ) + c2 += 32; + nRet = c1-c2; + if ( nRet != 0 ) + return nRet; + + pStr1++; + pStr2++; + } + while ( c2 ); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( const sal_Unicode* pStr1, + sal_Int32 nStr1Len, + const sal_Char* pStr2 ) +{ + sal_Int32 nRet; + sal_Int32 c1; + sal_Int32 c2; + do + { + if ( !nStr1Len ) + return *pStr2 == '\0' ? 0 : -1; + + /* If character between 'A' and 'Z', than convert it to lowercase */ + c1 = (sal_Int32)*pStr1; + c2 = (sal_Int32)((unsigned char)*pStr2); + if ( (c1 >= 65) && (c1 <= 90) ) + c1 += 32; + if ( (c2 >= 65) && (c2 <= 90) ) + c2 += 32; + nRet = c1-c2; + if ( nRet != 0 ) + return nRet; + + pStr1++; + pStr2++; + nStr1Len--; + } + while( c2 ); + + return 0; +} + +sal_Int32 rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths( + sal_Unicode const * first, sal_Int32 firstLen, + char const * second, sal_Int32 secondLen) +{ + sal_Int32 i; + sal_Int32 len = firstLen < secondLen ? firstLen : secondLen; + for (i = 0; i < len; ++i) { + sal_Int32 c1 = *first++; + sal_Int32 c2 = (unsigned char) *second++; + sal_Int32 d; + if (c1 >= 65 && c1 <= 90) { + c1 += 32; + } + if (c2 >= 65 && c2 <= 90) { + c2 += 32; + } + d = c1 - c2; + if (d != 0) { + return d; + } + } + return firstLen - secondLen; +} + +/* ----------------------------------------------------------------------- */ + +sal_Int32 SAL_CALL rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( const sal_Unicode* pStr1, + sal_Int32 nStr1Len, + const sal_Char* pStr2, + sal_Int32 nShortenedLength ) +{ + const sal_Unicode* pStr1End = pStr1 + nStr1Len; + sal_Int32 nRet; + sal_Int32 c1; + sal_Int32 c2; + while ( (nShortenedLength > 0) && + (pStr1 < pStr1End) && *pStr2 ) + { + /* Check ASCII range */ + OSL_ENSURE( (*pStr2 & 0x80) == 0, "Found ASCII char > 127"); + + /* If character between 'A' and 'Z', than convert it to lowercase */ + c1 = (sal_Int32)*pStr1; + c2 = (sal_Int32)((unsigned char)*pStr2); + if ( (c1 >= 65) && (c1 <= 90) ) + c1 += 32; + if ( (c2 >= 65) && (c2 <= 90) ) + c2 += 32; + nRet = c1-c2; + if ( nRet != 0 ) + return nRet; + + nShortenedLength--; + pStr1++; + pStr2++; + } + + if ( nShortenedLength <= 0 ) + return 0; + + if ( *pStr2 ) + { + OSL_ENSURE( pStr1 == pStr1End, "pStr1 == pStr1End failed" ); + // first is a substring of the second string => less (negative value) + nRet = -1; + } + else + { + // greater or equal + nRet = pStr1End - pStr1; + } + + return nRet; +} + +/* ----------------------------------------------------------------------- */ + +void SAL_CALL rtl_uString_newFromAscii( rtl_uString** ppThis, + const sal_Char* pCharStr ) +{ + sal_Int32 nLen; + + if ( pCharStr ) + { + const sal_Char* pTempStr = pCharStr; + while( *pTempStr ) + pTempStr++; + nLen = pTempStr-pCharStr; + } + else + nLen = 0; + + if ( !nLen ) + { + IMPL_RTL_STRINGNAME( new )( ppThis ); + return; + } + + if ( *ppThis ) + IMPL_RTL_STRINGNAME( release )( *ppThis ); + + *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen ); + OSL_ASSERT(*ppThis != NULL); + if ( (*ppThis) ) + { + IMPL_RTL_STRCODE* pBuffer = (*ppThis)->buffer; + do + { + /* Check ASCII range */ + OSL_ENSURE( ((unsigned char)*pCharStr) <= 127, + "rtl_uString_newFromAscii() - Found ASCII char > 127" ); + + *pBuffer = *pCharStr; + pBuffer++; + pCharStr++; + } + while ( *pCharStr ); + } +} + +void SAL_CALL rtl_uString_newFromCodePoints( + rtl_uString ** newString, sal_uInt32 const * codePoints, + sal_Int32 codePointCount) +{ + sal_Int32 n; + sal_Int32 i; + sal_Unicode * p; + OSL_ASSERT( + newString != NULL && + (codePoints != NULL || codePointCount == 0) && + codePointCount >= 0); + if (codePointCount == 0) { + rtl_uString_new(newString); + return; + } + if (*newString != NULL) { + rtl_uString_release(*newString); + } + n = codePointCount; + for (i = 0; i < codePointCount; ++i) { + OSL_ASSERT(codePoints[i] <= 0x10FFFF); + if (codePoints[i] >= 0x10000) { + ++n; + } + } + /* Builds on the assumption that sal_Int32 uses 32 bit two's complement + representation with wrap around (the necessary number of UTF-16 code + units will be no larger than 2 * SAL_MAX_INT32, represented as + sal_Int32 -2): */ + if (n < 0) { + *newString = NULL; + return; + } + *newString = rtl_uString_ImplAlloc(n); + if (*newString == NULL) { + return; + } + p = (*newString)->buffer; + for (i = 0; i < codePointCount; ++i) { + sal_uInt32 c = codePoints[i]; + if (c < 0x10000) { + *p++ = (sal_Unicode) c; + } else { + c -= 0x10000; + *p++ = (sal_Unicode) ((c >> 10) | SAL_RTL_FIRST_HIGH_SURROGATE); + *p++ = (sal_Unicode) ((c & 0x3FF) | SAL_RTL_FIRST_LOW_SURROGATE); + } + } +} + +/* ======================================================================= */ + +static int rtl_ImplGetFastUTF8UnicodeLen( const sal_Char* pStr, sal_Int32 nLen ) +{ + int n; + sal_uChar c; + const sal_Char* pEndStr; + + n = 0; + pEndStr = pStr+nLen; + while ( pStr < pEndStr ) + { + c = (sal_uChar)*pStr; + + if ( !(c & 0x80) ) + pStr++; + else if ( (c & 0xE0) == 0xC0 ) + pStr += 2; + else if ( (c & 0xF0) == 0xE0 ) + pStr += 3; + else if ( (c & 0xF8) == 0xF0 ) + pStr += 4; + else if ( (c & 0xFC) == 0xF8 ) + pStr += 5; + else if ( (c & 0xFE) == 0xFC ) + pStr += 6; + else + pStr++; + + n++; + } + + return n; +} + +/* ----------------------------------------------------------------------- */ + +static void rtl_string2UString_status( rtl_uString** ppThis, + const sal_Char* pStr, + sal_Int32 nLen, + rtl_TextEncoding eTextEncoding, + sal_uInt32 nCvtFlags, + sal_uInt32 *pInfo ) +{ + OSL_ENSURE(rtl_isOctetTextEncoding(eTextEncoding), + "rtl_string2UString_status() - Wrong TextEncoding" ); + + if ( !nLen ) + { + rtl_uString_new( ppThis ); + if (pInfo != NULL) { + *pInfo = 0; + } + } + else + { + if ( *ppThis ) + IMPL_RTL_STRINGNAME( release )( *ppThis ); + + /* Optimization for US-ASCII */ + if ( eTextEncoding == RTL_TEXTENCODING_ASCII_US ) + { + IMPL_RTL_STRCODE* pBuffer; + *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen ); + if (*ppThis == NULL) { + if (pInfo != NULL) { + *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR | + RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL; + } + return; + } + pBuffer = (*ppThis)->buffer; + do + { + /* Check ASCII range */ + OSL_ENSURE( ((unsigned char)*pStr) <= 127, + "rtl_string2UString_status() - Found char > 127 and RTL_TEXTENCODING_ASCII_US is specified" ); + + *pBuffer = *pStr; + pBuffer++; + pStr++; + nLen--; + } + while ( nLen ); + if (pInfo != NULL) { + *pInfo = 0; + } + } + else + { + rtl_uString* pTemp; + rtl_uString* pTemp2 = NULL; + rtl_TextToUnicodeConverter hConverter; + sal_uInt32 nInfo; + sal_Size nSrcBytes; + sal_Size nDestChars; + sal_Size nNewLen; + + /* Optimization for UTF-8 - we try to calculate the exact length */ + /* For all other encoding we try the maximum - and reallocate + the buffer if needed */ + if ( eTextEncoding == RTL_TEXTENCODING_UTF8 ) + { + nNewLen = rtl_ImplGetFastUTF8UnicodeLen( pStr, nLen ); + /* Includes the string only ASCII, then we could copy + the buffer faster */ + if ( nNewLen == (sal_Size)nLen ) + { + IMPL_RTL_STRCODE* pBuffer; + *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen ); + if (*ppThis == NULL) + { + if (pInfo != NULL) { + *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR | + RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL; + } + return; + } + pBuffer = (*ppThis)->buffer; + do + { + /* Check ASCII range */ + OSL_ENSURE( ((unsigned char)*pStr) <= 127, + "rtl_string2UString_status() - UTF8 test encoding is wrong" ); + + *pBuffer = *pStr; + pBuffer++; + pStr++; + nLen--; + } + while ( nLen ); + if (pInfo != NULL) { + *pInfo = 0; + } + return; + } + } + else + nNewLen = nLen; + + nCvtFlags |= RTL_TEXTTOUNICODE_FLAGS_FLUSH; + hConverter = rtl_createTextToUnicodeConverter( eTextEncoding ); + + pTemp = IMPL_RTL_STRINGNAME( ImplAlloc )( nNewLen ); + if (pTemp == NULL) { + if (pInfo != NULL) { + *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR | + RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL; + } + return; + } + nDestChars = rtl_convertTextToUnicode( hConverter, 0, + pStr, nLen, + pTemp->buffer, nNewLen, + nCvtFlags, + &nInfo, &nSrcBytes ); + + /* Buffer not big enough, try again with enough space */ + /* Shouldn't be the case, but if we get textencoding which + could results in more unicode characters we have this + code here. Could be the case for apple encodings */ + while ( nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL ) + { + rtl_freeMemory( pTemp ); + nNewLen += 8; + pTemp = IMPL_RTL_STRINGNAME( ImplAlloc )( nNewLen ); + if (pTemp == NULL) { + if (pInfo != NULL) { + *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR | + RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL; + } + return; + } + nDestChars = rtl_convertTextToUnicode( hConverter, 0, + pStr, nLen, + pTemp->buffer, nNewLen, + nCvtFlags, + &nInfo, &nSrcBytes ); + } + + if (pInfo) + *pInfo = nInfo; + + /* Set the buffer to the correct size or if there is too + much overhead, reallocate to the correct size */ + if ( nNewLen > nDestChars+8 ) + { + pTemp2 = IMPL_RTL_STRINGNAME( ImplAlloc )( nDestChars ); + } + if (pTemp2 != NULL) + { + rtl_str_ImplCopy(pTemp2->buffer, pTemp->buffer, nDestChars); + rtl_freeMemory(pTemp); + pTemp = pTemp2; + } + else + { + pTemp->length = nDestChars; + pTemp->buffer[nDestChars] = 0; + } + + rtl_destroyTextToUnicodeConverter( hConverter ); + *ppThis = pTemp; + + /* Results the conversion in an empty buffer - + create an empty string */ + if ( pTemp && !nDestChars ) + rtl_uString_new( ppThis ); + } + } +} + +void SAL_CALL rtl_string2UString( rtl_uString** ppThis, + const sal_Char* pStr, + sal_Int32 nLen, + rtl_TextEncoding eTextEncoding, + sal_uInt32 nCvtFlags ) +{ + rtl_string2UString_status( ppThis, pStr, nLen, eTextEncoding, + nCvtFlags, NULL ); +} + +/* ----------------------------------------------------------------------- */ + +typedef enum { + CANNOT_RETURN, + CAN_RETURN = 1 +} StrLifecycle; + +static oslMutex +getInternMutex() +{ + static oslMutex pPoolGuard = NULL; + if( !pPoolGuard ) + { + oslMutex pGlobalGuard; + pGlobalGuard = *osl_getGlobalMutex(); + osl_acquireMutex( pGlobalGuard ); + if( !pPoolGuard ) + { + oslMutex p = osl_createMutex(); + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + pPoolGuard = p; + } + osl_releaseMutex( pGlobalGuard ); + } + else + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + + return pPoolGuard; +} + +/* returns true if we found a dup in the pool */ +static void rtl_ustring_intern_internal( rtl_uString ** newStr, + rtl_uString * str, + StrLifecycle can_return ) +{ + oslMutex pPoolMutex; + + pPoolMutex = getInternMutex(); + + osl_acquireMutex( pPoolMutex ); + + *newStr = rtl_str_hash_intern (str, can_return); + + osl_releaseMutex( pPoolMutex ); + + if( can_return && *newStr != str ) + { /* we dupped, then found a match */ + rtl_freeMemory( str ); + } +} + +void SAL_CALL rtl_uString_intern( rtl_uString ** newStr, + rtl_uString * str) +{ + if (SAL_STRING_IS_INTERN(str)) + { + IMPL_RTL_AQUIRE( str ); + *newStr = str; + } + else + { + rtl_uString *pOrg = *newStr; + *newStr = NULL; + rtl_ustring_intern_internal( newStr, str, CANNOT_RETURN ); + if (pOrg) + rtl_uString_release (pOrg); + } +} + +void SAL_CALL rtl_uString_internConvert( rtl_uString ** newStr, + const sal_Char * str, + sal_Int32 len, + rtl_TextEncoding eTextEncoding, + sal_uInt32 convertFlags, + sal_uInt32 * pInfo ) +{ + rtl_uString *scratch; + + if (*newStr) + { + rtl_uString_release (*newStr); + *newStr = NULL; + } + + if ( len < 256 ) + { // try various optimisations + if ( len < 0 ) + len = strlen( str ); + if ( eTextEncoding == RTL_TEXTENCODING_ASCII_US ) + { + int i; + rtl_uString *pScratch; + pScratch = alloca( sizeof( rtl_uString ) + + len * sizeof (IMPL_RTL_STRCODE ) ); + for (i = 0; i < len; i++) + { + /* Check ASCII range */ + OSL_ENSURE( ((unsigned char)str[i]) <= 127, + "rtl_ustring_internConvert() - Found char > 127 and RTL_TEXTENCODING_ASCII_US is specified" ); + pScratch->buffer[i] = str[i]; + } + pScratch->length = len; + rtl_ustring_intern_internal( newStr, pScratch, CANNOT_RETURN ); + return; + } + /* FIXME: we want a nice UTF-8 / alloca shortcut here */ + } + + scratch = NULL; + rtl_string2UString_status( &scratch, str, len, eTextEncoding, convertFlags, + pInfo ); + if (!scratch) { + return; + } + rtl_ustring_intern_internal( newStr, scratch, CAN_RETURN ); +} + +static void +internRelease (rtl_uString *pThis) +{ + oslMutex pPoolMutex; + + rtl_uString *pFree = NULL; + if ( SAL_STRING_REFCOUNT( + osl_decrementInterlockedCount( &(pThis->refCount) ) ) == 0) + { + pPoolMutex = getInternMutex(); + osl_acquireMutex( pPoolMutex ); + + rtl_str_hash_remove (pThis); + + /* May have been separately acquired */ + if ( SAL_STRING_REFCOUNT( + osl_incrementInterlockedCount( &(pThis->refCount) ) ) == 1 ) + { + /* we got the last ref */ + pFree = pThis; + } + else /* very unusual */ + { + internRelease (pThis); + } + + osl_releaseMutex( pPoolMutex ); + } + if (pFree) + rtl_freeMemory (pFree); +} + +sal_uInt32 SAL_CALL rtl_uString_iterateCodePoints( + rtl_uString const * string, sal_Int32 * indexUtf16, + sal_Int32 incrementCodePoints) +{ + sal_Int32 n; + sal_Unicode cu; + sal_uInt32 cp; + OSL_ASSERT(string != NULL && indexUtf16 != NULL); + n = *indexUtf16; + OSL_ASSERT(n >= 0 && n <= string->length); + while (incrementCodePoints < 0) { + OSL_ASSERT(n > 0); + cu = string->buffer[--n]; + if (SAL_RTL_IS_LOW_SURROGATE(cu) && n != 0 && + SAL_RTL_IS_HIGH_SURROGATE(string->buffer[n - 1])) + { + --n; + } + ++incrementCodePoints; + } + OSL_ASSERT(n >= 0 && n < string->length); + cu = string->buffer[n]; + if (SAL_RTL_IS_HIGH_SURROGATE(cu) && string->length - n >= 2 && + SAL_RTL_IS_LOW_SURROGATE(string->buffer[n + 1])) + { + cp = SAL_RTL_COMBINE_SURROGATES(cu, string->buffer[n + 1]); + } else { + cp = cu; + } + while (incrementCodePoints > 0) { + OSL_ASSERT(n < string->length); + cu = string->buffer[n++]; + if (SAL_RTL_IS_HIGH_SURROGATE(cu) && n != string->length && + SAL_RTL_IS_LOW_SURROGATE(string->buffer[n])) + { + ++n; + } + --incrementCodePoints; + } + OSL_ASSERT(n >= 0 && n <= string->length); + *indexUtf16 = n; + return cp; +} + +sal_Bool rtl_convertStringToUString( + rtl_uString ** target, char const * source, sal_Int32 length, + rtl_TextEncoding encoding, sal_uInt32 flags) SAL_THROW_EXTERN_C() +{ + sal_uInt32 info; + rtl_string2UString_status(target, source, length, encoding, flags, &info); + return (sal_Bool) ((info & RTL_TEXTTOUNICODE_INFO_ERROR) == 0); +} diff --git a/sal/rtl/source/uuid.cxx b/sal/rtl/source/uuid.cxx new file mode 100644 index 000000000000..79790c99887e --- /dev/null +++ b/sal/rtl/source/uuid.cxx @@ -0,0 +1,180 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sal.hxx" + +#include <string.h> +#include <stdlib.h> + +#include <osl/mutex.hxx> +#include <rtl/random.h> +#include <rtl/uuid.h> +#include <rtl/digest.h> + +#define SWAP_INT32_TO_NETWORK(x)\ + { sal_uInt32 y = x;\ + sal_uInt8 *p = (sal_uInt8 * )&(x); \ + p[0] = (sal_uInt8) ( ( y >> 24 ) & 0xff );\ + p[1] = (sal_uInt8) ( ( y >> 16 ) & 0xff );\ + p[2] = (sal_uInt8) ( ( y >> 8 ) & 0xff );\ + p[3] = (sal_uInt8) ( ( y ) & 0xff);\ + } +#define SWAP_INT16_TO_NETWORK(x)\ + { sal_uInt16 y = x;\ + sal_uInt8 *p = (sal_uInt8 * )&(x); \ + p[0] = (sal_uInt8) ( ( y >> 8 ) & 0xff );\ + p[1] = (sal_uInt8) ( ( y ) & 0xff);\ + } + +#define SWAP_NETWORK_TO_INT16(x)\ + { sal_uInt16 y = x;\ + sal_uInt8 *p = (sal_uInt8 * )&(y);\ + x = ( ( ((sal_uInt16)p[0]) & 0xff) << 8 ) |\ + ( ( (sal_uInt16)p[1]) & 0xff);\ + } +#define SWAP_NETWORK_TO_INT32(x)\ + { sal_uInt32 y = x;\ + sal_uInt8 *p = (sal_uInt8 * )&(y); \ + x = ( ( ((sal_uInt32)p[0]) & 0xff) << 24 ) |\ + ( ( ((sal_uInt32)p[1]) & 0xff) << 16 ) |\ + ( ( ((sal_uInt32)p[2]) & 0xff) << 8 ) |\ + ( ( (sal_uInt32)p[3]) & 0xff);\ + } + +typedef struct _UUID +{ + sal_uInt32 time_low; + sal_uInt16 time_mid; + sal_uInt16 time_hi_and_version; + sal_uInt8 clock_seq_hi_and_reserved; + sal_uInt8 clock_seq_low; + sal_uInt8 node[6]; +} UUID; + +static void write_v3( sal_uInt8 *pUuid ) +{ + UUID uuid; + // copy to avoid alignment problems + memcpy( &uuid , pUuid , 16 ); + + SWAP_NETWORK_TO_INT32( uuid.time_low ); + SWAP_NETWORK_TO_INT16( uuid.time_mid ); + SWAP_NETWORK_TO_INT16( uuid.time_hi_and_version ); + + /* put in the variant and version bits */ + uuid.time_hi_and_version &= 0x0FFF; + uuid.time_hi_and_version |= (3 << 12); + uuid.clock_seq_hi_and_reserved &= 0x3F; + uuid.clock_seq_hi_and_reserved |= 0x80; + + SWAP_INT32_TO_NETWORK( uuid.time_low ); + SWAP_INT16_TO_NETWORK( uuid.time_mid ); + SWAP_INT16_TO_NETWORK( uuid.time_hi_and_version ); + + memcpy( pUuid , &uuid , 16 ); +} + + +extern "C" void SAL_CALL rtl_createUuid( sal_uInt8 *pTargetUUID , + const sal_uInt8 *, sal_Bool ) +{ + { + osl::MutexGuard g(osl::Mutex::getGlobalMutex()); + static rtlRandomPool pool = NULL; + if (pool == NULL) { + pool = rtl_random_createPool(); + if (pool == NULL) { + abort(); + // only possible way to signal failure here (rtl_createUuid + // being part of a fixed C API) + } + } + if (rtl_random_getBytes(pool, pTargetUUID, 16) != rtl_Random_E_None) { + abort(); + // only possible way to signal failure here (rtl_createUuid + // being part of a fixed C API) + } + } + // See ITU-T Recommendation X.667: + pTargetUUID[6] &= 0x0F; + pTargetUUID[6] |= 0x40; + pTargetUUID[8] &= 0x3F; + pTargetUUID[8] |= 0x80; +} + + +extern "C" void SAL_CALL rtl_createNamedUuid( sal_uInt8 *pTargetUUID, + const sal_uInt8 *pNameSpaceUUID, + const rtl_String *pName ) +{ + rtlDigest digest = rtl_digest_createMD5 (); + + rtl_digest_updateMD5( digest, pNameSpaceUUID , 16 ); + rtl_digest_updateMD5( digest, pName->buffer , pName->length ); + + rtl_digest_getMD5( digest, pTargetUUID , 16 ); + rtl_digest_destroyMD5 (digest); + + write_v3(pTargetUUID); +} + + + +extern "C" sal_Int32 SAL_CALL rtl_compareUuid( const sal_uInt8 *pUUID1 , const sal_uInt8 *pUUID2 ) +{ + int i; + UUID u1; + UUID u2; + memcpy( &u1 , pUUID1 , 16 ); + memcpy( &u2 , pUUID2 , 16 ); + + SWAP_NETWORK_TO_INT32( u1.time_low ); + SWAP_NETWORK_TO_INT16( u1.time_mid ); + SWAP_NETWORK_TO_INT16( u1.time_hi_and_version ); + + SWAP_NETWORK_TO_INT32( u2.time_low ); + SWAP_NETWORK_TO_INT16( u2.time_mid ); + SWAP_NETWORK_TO_INT16( u2.time_hi_and_version ); + +#define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1; + CHECK(u1.time_low, u2.time_low); + CHECK(u1.time_mid, u2.time_mid); + CHECK(u1.time_hi_and_version, u2.time_hi_and_version); + CHECK(u1.clock_seq_hi_and_reserved, u2.clock_seq_hi_and_reserved); + CHECK(u1.clock_seq_low, u2.clock_seq_low); + for (i = 0; i < 6; i++) + { + if (u1.node[i] < u2.node[i]) + return -1; + if (u1.node[i] > u2.node[i]) + return 1; + } + return 0; + +} + |