summaryrefslogtreecommitdiffstats
path: root/sal/rtl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sal/rtl
parentInitial commit. (diff)
downloadlibreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.tar.xz
libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sal/rtl')
-rw-r--r--sal/rtl/alloc_arena.cxx1112
-rw-r--r--sal/rtl/alloc_arena.hxx118
-rw-r--r--sal/rtl/alloc_cache.cxx225
-rw-r--r--sal/rtl/alloc_cache.hxx40
-rw-r--r--sal/rtl/alloc_fini.cxx90
-rw-r--r--sal/rtl/alloc_global.cxx81
-rw-r--r--sal/rtl/alloc_impl.hxx217
-rw-r--r--sal/rtl/bootstrap.cxx1014
-rw-r--r--sal/rtl/byteseq.cxx245
-rw-r--r--sal/rtl/cipher.cxx1433
-rw-r--r--sal/rtl/cmdargs.cxx101
-rw-r--r--sal/rtl/crc.cxx149
-rw-r--r--sal/rtl/digest.cxx1897
-rw-r--r--sal/rtl/hash.cxx241
-rw-r--r--sal/rtl/hash.hxx33
-rw-r--r--sal/rtl/locale.cxx142
-rw-r--r--sal/rtl/math.cxx1410
-rw-r--r--sal/rtl/random.cxx310
-rw-r--r--sal/rtl/rtl_process.cxx58
-rw-r--r--sal/rtl/strbuf.cxx182
-rw-r--r--sal/rtl/strimp.cxx120
-rw-r--r--sal/rtl/strimp.hxx96
-rw-r--r--sal/rtl/string.cxx394
-rw-r--r--sal/rtl/strtmpl.cxx1911
-rw-r--r--sal/rtl/unload.cxx35
-rw-r--r--sal/rtl/uri.cxx893
-rw-r--r--sal/rtl/ustrbuf.cxx268
-rw-r--r--sal/rtl/ustring.cxx1562
-rw-r--r--sal/rtl/uuid.cxx173
29 files changed, 14550 insertions, 0 deletions
diff --git a/sal/rtl/alloc_arena.cxx b/sal/rtl/alloc_arena.cxx
new file mode 100644
index 000000000..f126efdab
--- /dev/null
+++ b/sal/rtl/alloc_arena.cxx
@@ -0,0 +1,1112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include "alloc_arena.hxx"
+
+#include "alloc_impl.hxx"
+#include <rtllifecycle.h>
+#include <sal/macros.h>
+
+#include <cassert>
+#include <string.h>
+#include <stdio.h>
+
+namespace {
+
+/**
+ @internal
+*/
+struct rtl_arena_list_st
+{
+ rtl_memory_lock_type m_lock;
+ rtl_arena_type m_arena_head;
+};
+
+}
+
+static rtl_arena_list_st g_arena_list;
+
+/**
+ provided for arena_type allocations, and hash_table resizing.
+
+ @internal
+*/
+static rtl_arena_type * gp_arena_arena = nullptr;
+
+/**
+ Low level virtual memory (pseudo) arena
+ (platform dependent implementation)
+
+ @internal
+ */
+static rtl_arena_type * gp_machdep_arena = nullptr;
+
+rtl_arena_type * gp_default_arena = nullptr;
+
+namespace
+{
+
+void * rtl_machdep_alloc(
+ rtl_arena_type * pArena,
+ sal_Size * pSize
+);
+
+void rtl_machdep_free(
+ rtl_arena_type * pArena,
+ void * pAddr,
+ sal_Size nSize
+);
+
+sal_Size rtl_machdep_pagesize();
+
+void rtl_arena_segment_constructor(void * obj)
+{
+ rtl_arena_segment_type * segment = static_cast<rtl_arena_segment_type*>(obj);
+
+ QUEUE_START_NAMED(segment, s);
+ QUEUE_START_NAMED(segment, f);
+}
+
+void rtl_arena_segment_destructor(void * obj)
+{
+ rtl_arena_segment_type * segment = static_cast< rtl_arena_segment_type * >(
+ obj);
+ assert(QUEUE_STARTED_NAMED(segment, s));
+ assert(QUEUE_STARTED_NAMED(segment, f));
+ (void) segment; // avoid warnings
+}
+
+/**
+ @precond arena->m_lock acquired.
+ */
+bool rtl_arena_segment_populate(rtl_arena_type * arena)
+{
+ rtl_arena_segment_type *span;
+ sal_Size size = rtl_machdep_pagesize();
+
+ span = static_cast< rtl_arena_segment_type * >(
+ rtl_machdep_alloc(gp_machdep_arena, &size));
+ if (span)
+ {
+ 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 = reinterpret_cast<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 != nullptr);
+}
+
+/**
+ @precond arena->m_lock acquired.
+ @precond (*ppSegment == 0)
+*/
+void rtl_arena_segment_get(
+ rtl_arena_type * arena,
+ rtl_arena_segment_type ** ppSegment
+)
+{
+ rtl_arena_segment_type * head;
+
+ assert(!*ppSegment);
+
+ 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);
+ }
+}
+
+/**
+ @precond arena->m_lock acquired.
+ @postcond (*ppSegment == 0)
+ */
+void rtl_arena_segment_put(
+ rtl_arena_type * arena,
+ rtl_arena_segment_type ** ppSegment
+)
+{
+ rtl_arena_segment_type * head;
+
+ assert(QUEUE_STARTED_NAMED(*ppSegment, s));
+ assert(QUEUE_STARTED_NAMED(*ppSegment, f));
+
+ (*ppSegment)->m_addr = 0;
+ (*ppSegment)->m_size = 0;
+
+ 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) = nullptr;
+}
+
+/**
+ @precond arena->m_lock acquired.
+*/
+void rtl_arena_freelist_insert (
+ rtl_arena_type * arena,
+ rtl_arena_segment_type * segment
+)
+{
+ rtl_arena_segment_type * head;
+ const auto bit = highbit(segment->m_size);
+ assert(bit > 0);
+ head = &(arena->m_freelist_head[bit - 1]);
+ QUEUE_INSERT_TAIL_NAMED(head, segment, f);
+
+ arena->m_freelist_bitmap |= head->m_size;
+}
+
+/**
+ @precond arena->m_lock acquired.
+*/
+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;
+ assert(arena->m_freelist_bitmap & head->m_size);
+ arena->m_freelist_bitmap ^= head->m_size;
+ }
+ QUEUE_REMOVE_NAMED(segment, f);
+}
+
+#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))
+
+/**
+ @precond arena->m_lock released.
+*/
+void rtl_arena_hash_rescale(
+ rtl_arena_type * arena,
+ sal_Size new_size
+)
+{
+ assert(new_size != 0);
+
+ rtl_arena_segment_type ** new_table;
+ sal_Size new_bytes;
+
+ new_bytes = new_size * sizeof(rtl_arena_segment_type*);
+ new_table = static_cast<rtl_arena_segment_type **>(rtl_arena_alloc (gp_arena_arena, &new_bytes));
+
+ if (new_table)
+ {
+ 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;
+
+ 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)
+ {
+ rtl_arena_segment_type * next = curr->m_fnext;
+ rtl_arena_segment_type ** head;
+
+ // coverity[negative_shift] - bogus
+ head = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, curr->m_addr)]);
+ curr->m_fnext = (*head);
+ (*head) = curr;
+
+ curr = next;
+ }
+ old_table[i] = nullptr;
+ }
+
+ 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);
+ }
+ }
+}
+
+/**
+ Insert arena hash, and update stats.
+*/
+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;
+}
+
+/**
+ Remove arena hash, and update stats.
+*/
+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;
+
+ segpp = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, addr)]);
+ while ((segment = *segpp))
+ {
+ 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);
+ }
+
+ assert(segment); // bad free
+ if (segment)
+ {
+ assert(segment->m_size == size);
+ (void) size; // avoid warnings
+
+ arena->m_stats.m_free += 1;
+ arena->m_stats.m_mem_alloc -= segment->m_size;
+
+ if (lookups > 1)
+ {
+ sal_Size nseg = static_cast<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;
+ assert(ave != 0);
+ 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;
+}
+
+/**
+ allocate (and remove) segment from freelist
+
+ @precond arena->m_lock acquired
+ @precond (*ppSegment == 0)
+*/
+bool rtl_arena_segment_alloc(
+ rtl_arena_type * arena,
+ sal_Size size,
+ rtl_arena_segment_type ** ppSegment
+)
+{
+ int index = 0;
+
+ assert(!*ppSegment);
+ if (!RTL_MEMORY_ISP2(size))
+ {
+ unsigned int msb = highbit(size);
+ if (RTL_ARENA_FREELIST_SIZE == 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 = ((sal_Size(1)) << 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;
+ assert((*ppSegment) != head);
+ }
+
+dequeue_and_leave:
+ if (*ppSegment)
+ {
+ /* remove from freelist */
+ rtl_arena_freelist_remove (arena, (*ppSegment));
+ }
+ return (*ppSegment != nullptr);
+}
+
+/**
+ import new (span) segment from source arena
+
+ @precond arena->m_lock acquired
+ @precond (*ppSegment == 0)
+*/
+bool rtl_arena_segment_create(
+ rtl_arena_type * arena,
+ sal_Size size,
+ rtl_arena_segment_type ** ppSegment
+)
+{
+ assert(!*ppSegment);
+ if (arena->m_source_alloc)
+ {
+ rtl_arena_segment_get (arena, ppSegment);
+ if (*ppSegment)
+ {
+ rtl_arena_segment_type * span = nullptr;
+ rtl_arena_segment_get (arena, &span);
+ if (span)
+ {
+ /* import new span from source arena */
+ RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
+
+ span->m_size = size;
+ span->m_addr = reinterpret_cast<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 true;
+ }
+ rtl_arena_segment_put (arena, &span);
+ }
+ rtl_arena_segment_put (arena, ppSegment);
+ }
+ }
+ return false; // failure
+}
+
+/**
+ mark as free and join with adjacent free segment(s)
+
+ @precond arena->m_lock acquired
+ @precond segment marked 'used'
+*/
+void rtl_arena_segment_coalesce(
+ rtl_arena_type * arena,
+ rtl_arena_segment_type * segment
+)
+{
+ rtl_arena_segment_type *next, *prev;
+
+ /* mark segment free */
+ 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)
+ {
+ 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)
+ {
+ 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);
+ }
+}
+
+void rtl_arena_constructor(void * obj)
+{
+ rtl_arena_type * arena = static_cast<rtl_arena_type*>(obj);
+ rtl_arena_segment_type * head;
+ size_t i;
+
+ memset (arena, 0, sizeof(rtl_arena_type));
+
+ QUEUE_START_NAMED(arena, arena_);
+
+ 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 = ((sal_Size(1)) << 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;
+}
+
+void rtl_arena_destructor(void * obj)
+{
+ rtl_arena_type * arena = static_cast<rtl_arena_type*>(obj);
+ rtl_arena_segment_type * head;
+ size_t i;
+
+ assert(QUEUE_STARTED_NAMED(arena, arena_));
+
+ RTL_MEMORY_LOCK_DESTROY(&(arena->m_lock));
+
+ head = &(arena->m_segment_reserve_span_head);
+ assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD);
+ rtl_arena_segment_destructor (head);
+
+ head = &(arena->m_segment_reserve_head);
+ assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD);
+ rtl_arena_segment_destructor (head);
+
+ head = &(arena->m_segment_head);
+ 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]);
+
+ assert(head->m_size == ((sal_Size(1)) << i));
+ assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD);
+
+ rtl_arena_segment_destructor (head);
+ }
+
+ assert(arena->m_hash_table == arena->m_hash_table_0);
+ assert(arena->m_hash_size == RTL_ARENA_HASH_SIZE);
+ assert(arena->m_hash_shift == highbit(arena->m_hash_size) - 1);
+}
+
+rtl_arena_type * rtl_arena_activate(
+ rtl_arena_type * arena,
+ const char * name,
+ sal_Size quantum,
+ 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)
+)
+{
+ assert(arena);
+ if (arena)
+ {
+ (void) snprintf (arena->m_name, sizeof(arena->m_name), "%s", name);
+
+ if (!RTL_MEMORY_ISP2(quantum))
+ {
+ /* roundup to next power of 2 */
+ quantum = ((sal_Size(1)) << highbit(quantum));
+ }
+
+ arena->m_quantum = quantum;
+ arena->m_quantum_shift = highbit(arena->m_quantum) - 1;
+
+ arena->m_source_arena = source_arena;
+ arena->m_source_alloc = source_alloc;
+ arena->m_source_free = source_free;
+
+ /* 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;
+}
+
+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));
+
+ /* check for leaked segments */
+ if (arena->m_stats.m_alloc > arena->m_stats.m_free)
+ {
+ sal_Size i, n;
+
+ /* cleanup still used segment(s) */
+ for (i = 0, n = arena->m_hash_size; i < n; i++)
+ {
+ while ((segment = arena->m_hash_table[i]))
+ {
+ /* 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 */
+ 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 */
+ 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, reinterpret_cast<void*>(segment->m_addr), segment->m_size);
+ }
+}
+
+} // namespace
+
+rtl_arena_type * SAL_CALL rtl_arena_create(
+ const char * name,
+ sal_Size quantum,
+ sal_Size,
+ 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),
+ SAL_UNUSED_PARAMETER int
+) SAL_THROW_EXTERN_C()
+{
+ rtl_arena_type * result = nullptr;
+ sal_Size size = sizeof(rtl_arena_type);
+
+try_alloc:
+ result = static_cast<rtl_arena_type*>(rtl_arena_alloc (gp_arena_arena, &size));
+ if (result)
+ {
+ rtl_arena_type * arena = result;
+ rtl_arena_constructor (arena);
+
+ if (!source_arena)
+ {
+ assert(gp_default_arena);
+ source_arena = gp_default_arena;
+ }
+
+ result = rtl_arena_activate (
+ arena,
+ name,
+ quantum,
+ source_arena,
+ source_alloc,
+ source_free
+ );
+
+ if (!result)
+ {
+ rtl_arena_deactivate (arena);
+ rtl_arena_destructor (arena);
+ rtl_arena_free (gp_arena_arena, arena, size);
+ }
+ }
+ else if (!gp_arena_arena)
+ {
+ ensureArenaSingleton();
+ if (gp_arena_arena)
+ {
+ /* try again */
+ goto try_alloc;
+ }
+ }
+ return result;
+}
+
+void SAL_CALL rtl_arena_destroy(rtl_arena_type * arena) SAL_THROW_EXTERN_C()
+{
+ if (arena)
+ {
+ rtl_arena_deactivate (arena);
+ rtl_arena_destructor (arena);
+ rtl_arena_free (gp_arena_arena, arena, sizeof(rtl_arena_type));
+ }
+}
+
+void * SAL_CALL rtl_arena_alloc(
+ rtl_arena_type * arena,
+ sal_Size * pSize
+) SAL_THROW_EXTERN_C()
+{
+ void * addr = nullptr;
+
+ if (arena && pSize)
+ {
+ sal_Size size;
+
+ size = RTL_MEMORY_ALIGN(*pSize, arena->m_quantum);
+ if (size > 0)
+ {
+ /* allocate from segment list */
+ rtl_arena_segment_type *segment = nullptr;
+
+ 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 */
+ assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE);
+ segment->m_type = RTL_ARENA_SEGMENT_TYPE_USED;
+
+ /* resize */
+ assert(segment->m_size >= size);
+ oversize = segment->m_size - size;
+ if (oversize >= arena->m_quantum)
+ {
+ rtl_arena_segment_type * remainder = nullptr;
+ rtl_arena_segment_get (arena, &remainder);
+ if (remainder)
+ {
+ 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 = reinterpret_cast<void*>(segment->m_addr);
+ }
+ RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock));
+ }
+ }
+ return addr;
+}
+
+void SAL_CALL rtl_arena_free (
+ rtl_arena_type * arena,
+ void * addr,
+ sal_Size size
+) SAL_THROW_EXTERN_C()
+{
+ if (arena)
+ {
+ size = RTL_MEMORY_ALIGN(size, arena->m_quantum);
+ if (size > 0)
+ {
+ /* free to segment list */
+ rtl_arena_segment_type * segment;
+
+ RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock));
+
+ segment = rtl_arena_hash_remove (arena, reinterpret_cast<sal_uIntPtr>(addr), size);
+ if (segment)
+ {
+ 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)))
+ {
+ assert(
+ prev->m_addr == segment->m_addr
+ && prev->m_size == segment->m_size);
+
+ if (arena->m_source_free)
+ {
+ addr = reinterpret_cast<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));
+ }
+ }
+}
+
+void rtl_arena_foreach (rtl_arena_type *arena, ArenaForeachFn foreachFn)
+{
+ /* used segments */
+ for (int i = 0, n = arena->m_hash_size; i < n; i++)
+ {
+ for (rtl_arena_segment_type *segment = arena->m_hash_table[i];
+ segment != nullptr; segment = segment->m_fnext)
+ {
+ foreachFn(reinterpret_cast<void *>(segment->m_addr),
+ segment->m_size);
+ }
+ }
+}
+
+#if defined(SAL_UNX)
+#include <sys/mman.h>
+#elif defined(_WIN32)
+#define MAP_FAILED nullptr
+#endif /* SAL_UNX || _WIN32 */
+
+namespace
+{
+
+void * rtl_machdep_alloc(
+ rtl_arena_type * pArena,
+ sal_Size * pSize
+)
+{
+ void * addr;
+ sal_Size size = *pSize;
+
+ assert(pArena == gp_machdep_arena);
+
+#if defined(__sun) && 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 */
+ if (pArena->m_quantum < (64 << 10))
+ {
+ size = RTL_MEMORY_P2ROUNDUP(size, (64 << 10));
+ }
+ else
+ {
+ size = RTL_MEMORY_P2ROUNDUP(size, pArena->m_quantum);
+ }
+#endif
+
+#if defined(SAL_UNX)
+ addr = mmap (nullptr, static_cast<size_t>(size), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+#elif defined(_WIN32)
+ addr = VirtualAlloc (nullptr, static_cast<SIZE_T>(size), MEM_COMMIT, PAGE_READWRITE);
+#endif /* (SAL_UNX || _WIN32) */
+
+ 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 nullptr;
+}
+
+void rtl_machdep_free(
+ rtl_arena_type * pArena,
+ void * pAddr,
+ sal_Size nSize
+)
+{
+ assert(pArena == gp_machdep_arena);
+
+ 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(_WIN32)
+ (void) VirtualFree (pAddr, SIZE_T(0), MEM_RELEASE);
+#endif /* (SAL_UNX || _WIN32) */
+}
+
+sal_Size rtl_machdep_pagesize()
+{
+#if defined(SAL_UNX)
+#if defined(FREEBSD) || defined(NETBSD) || defined(DRAGONFLY)
+ return (sal_Size)getpagesize();
+#else /* POSIX */
+ return static_cast<sal_Size>(sysconf(_SC_PAGESIZE));
+#endif /* xBSD || POSIX */
+#elif defined(_WIN32)
+ SYSTEM_INFO info;
+ GetSystemInfo (&info);
+ return static_cast<sal_Size>(info.dwPageSize);
+#endif /* (SAL_UNX || _WIN32) */
+}
+
+} //namespace
+
+void rtl_arena_init()
+{
+ {
+ /* 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;
+
+ assert(!gp_machdep_arena);
+ rtl_arena_constructor (&g_machdep_arena);
+
+ gp_machdep_arena = rtl_arena_activate (
+ &g_machdep_arena,
+ "rtl_machdep_arena",
+ rtl_machdep_pagesize(),
+ nullptr, nullptr, nullptr /* no source */
+ );
+ assert(gp_machdep_arena);
+ }
+ {
+ /* default arena */
+ static rtl_arena_type g_default_arena;
+
+ assert(!gp_default_arena);
+ rtl_arena_constructor (&g_default_arena);
+
+ gp_default_arena = rtl_arena_activate (
+ &g_default_arena,
+ "rtl_default_arena",
+ rtl_machdep_pagesize(),
+ gp_machdep_arena, /* source */
+ rtl_machdep_alloc,
+ rtl_machdep_free
+ );
+ assert(gp_default_arena);
+ }
+ {
+ /* arena internal arena */
+ static rtl_arena_type g_arena_arena;
+
+ assert(!gp_arena_arena);
+ rtl_arena_constructor (&g_arena_arena);
+
+ gp_arena_arena = rtl_arena_activate(
+ &g_arena_arena,
+ "rtl_arena_internal_arena",
+ 64, /* quantum */
+ gp_default_arena, /* source */
+ rtl_arena_alloc,
+ rtl_arena_free
+ );
+ assert(gp_arena_arena);
+ }
+}
+
+void rtl_arena_fini()
+{
+ if (gp_arena_arena)
+ {
+ 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)
+ {
+ // noop
+ }
+ RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock));
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/alloc_arena.hxx b/sal/rtl/alloc_arena.hxx
new file mode 100644
index 000000000..7226ef3f1
--- /dev/null
+++ b/sal/rtl/alloc_arena.hxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SAL_RTL_ALLOC_ARENA_HXX
+#define INCLUDED_SAL_RTL_ALLOC_ARENA_HXX
+
+#include <sal/types.h>
+#include <rtl/alloc.h>
+#include "alloc_impl.hxx"
+
+/** rtl_arena_stat_type
+ * @internal
+ */
+struct rtl_arena_stat_type
+{
+ sal_uInt64 m_alloc;
+ sal_uInt64 m_free;
+
+ sal_Size m_mem_total;
+ sal_Size m_mem_alloc;
+};
+
+/** rtl_arena_segment_type
+ * @internal
+ */
+constexpr sal_Size RTL_ARENA_SEGMENT_TYPE_HEAD = 0x01;
+constexpr sal_Size RTL_ARENA_SEGMENT_TYPE_SPAN = 0x02;
+constexpr sal_Size RTL_ARENA_SEGMENT_TYPE_FREE = 0x04;
+constexpr sal_Size RTL_ARENA_SEGMENT_TYPE_USED = 0x08;
+
+struct rtl_arena_segment_type
+{
+ /* 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
+ */
+constexpr auto RTL_ARENA_FREELIST_SIZE = sizeof(void*) * 8;
+constexpr auto RTL_ARENA_HASH_SIZE = 64;
+
+constexpr auto 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) */
+};
+
+/** gp_default_arena
+ * default arena with pagesize quantum
+ *
+ * @internal
+ */
+extern rtl_arena_type * gp_default_arena;
+
+typedef void (*ArenaForeachFn)(void *addr, sal_Size size);
+
+void rtl_arena_foreach(rtl_arena_type *arena, ArenaForeachFn fn);
+
+#endif // INCLUDED_SAL_RTL_ALLOC_ARENA_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/alloc_cache.cxx b/sal/rtl/alloc_cache.cxx
new file mode 100644
index 000000000..1f165cca1
--- /dev/null
+++ b/sal/rtl/alloc_cache.cxx
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "alloc_cache.hxx"
+#include "alloc_impl.hxx"
+#include "alloc_arena.hxx"
+#include <rtllifecycle.h>
+
+#include <cassert>
+#include <cstdlib>
+#include <string.h>
+#include <stdio.h>
+
+/**
+ provided for cache_type allocations, and hash_table resizing.
+
+ @internal
+*/
+static rtl_arena_type * gp_cache_arena = nullptr;
+
+namespace
+{
+
+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 * userarg
+)
+{
+ assert(cache);
+
+ snprintf (cache->m_name, sizeof(cache->m_name), "%s", name);
+
+ 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 */
+ if(objalign < RTL_MEMORY_ALIGNMENT_4)
+ {
+ objalign = RTL_MEMORY_ALIGNMENT_4;
+ }
+ }
+ assert(RTL_MEMORY_ISP2(objalign));
+
+ cache->m_type_size = RTL_MEMORY_P2ROUNDUP(objsize, objalign);
+
+ cache->m_constructor = constructor;
+ cache->m_destructor = destructor;
+ cache->m_userarg = userarg;
+
+ return cache;
+}
+
+} //namespace
+
+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 *,
+ int
+) SAL_THROW_EXTERN_C()
+{
+ rtl_cache_type * result = nullptr;
+ sal_Size size = sizeof(rtl_cache_type);
+
+try_alloc:
+ result = static_cast<rtl_cache_type*>(rtl_arena_alloc (gp_cache_arena, &size));
+ if (result)
+ {
+ rtl_cache_type * cache = result;
+ memset (cache, 0, sizeof(rtl_cache_type));
+
+ result = rtl_cache_activate (
+ cache,
+ name,
+ objsize,
+ objalign,
+ constructor,
+ destructor,
+ userarg
+ );
+
+ if (!result)
+ {
+ /* activation failed */
+ rtl_arena_free (gp_cache_arena, cache, size);
+ }
+ }
+ else if (!gp_cache_arena)
+ {
+ ensureCacheSingleton();
+ if (gp_cache_arena)
+ {
+ /* try again */
+ goto try_alloc;
+ }
+ }
+ return result;
+}
+
+void SAL_CALL rtl_cache_destroy(rtl_cache_type * cache) SAL_THROW_EXTERN_C()
+{
+ if (cache)
+ {
+ rtl_arena_free (gp_cache_arena, cache, sizeof(rtl_cache_type));
+ }
+}
+
+void * SAL_CALL rtl_cache_alloc(rtl_cache_type * cache) SAL_THROW_EXTERN_C()
+{
+ void * obj = nullptr;
+
+ if (!cache)
+ return nullptr;
+
+ obj = std::malloc(cache->m_type_size);
+ if (obj && cache->m_constructor)
+ {
+ if (!(cache->m_constructor)(obj, cache->m_userarg))
+ {
+ /* construction failure */
+ std::free(obj);
+ obj = nullptr;
+ }
+ }
+ return obj;
+}
+
+void SAL_CALL rtl_cache_free(
+ rtl_cache_type * cache,
+ void * obj
+) SAL_THROW_EXTERN_C()
+{
+ if (obj && cache)
+ {
+ if (cache->m_destructor)
+ {
+ /* destruct object */
+ (cache->m_destructor)(obj, cache->m_userarg);
+ }
+ std::free(obj);
+ }
+}
+
+#if defined(SAL_UNX)
+
+void SAL_CALL rtl_secureZeroMemory(void *Ptr, sal_Size Bytes) SAL_THROW_EXTERN_C()
+{
+ //currently glibc doesn't implement memset_s
+ volatile char *p = static_cast<volatile char*>(Ptr);
+ while (Bytes--)
+ *p++ = 0;
+}
+
+#elif defined(_WIN32)
+
+void SAL_CALL rtl_secureZeroMemory(void *Ptr, sal_Size Bytes) SAL_THROW_EXTERN_C()
+{
+ RtlSecureZeroMemory(Ptr, Bytes);
+}
+
+#endif /* SAL_UNX || _WIN32 */
+
+void rtl_cache_init()
+{
+ /* cache: internal arena */
+ assert(!gp_cache_arena);
+
+ gp_cache_arena = rtl_arena_create (
+ "rtl_cache_internal_arena",
+ 64, /* quantum */
+ 0, /* no quantum caching */
+ nullptr, /* default source */
+ rtl_arena_alloc,
+ rtl_arena_free,
+ 0 /* flags */
+ );
+ assert(gp_cache_arena);
+
+ /* check 'gp_default_arena' initialization */
+ assert(gp_default_arena);
+}
+
+void rtl_cache_fini()
+{
+ if (gp_cache_arena)
+ {
+ rtl_arena_destroy (gp_cache_arena);
+ gp_cache_arena = nullptr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/alloc_cache.hxx b/sal/rtl/alloc_cache.hxx
new file mode 100644
index 000000000..501d5770b
--- /dev/null
+++ b/sal/rtl/alloc_cache.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SAL_RTL_ALLOC_CACHE_HXX
+#define INCLUDED_SAL_RTL_ALLOC_CACHE_HXX
+
+#include <sal/types.h>
+#include <rtl/alloc.h>
+
+struct rtl_cache_st
+{
+ /* properties */
+ char m_name[RTL_CACHE_NAME_LENGTH + 1];
+
+ sal_Size 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 * m_userarg;
+};
+
+#endif // INCLUDED_SAL_RTL_ALLOC_CACHE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/alloc_fini.cxx b/sal/rtl/alloc_fini.cxx
new file mode 100644
index 000000000..3745e900c
--- /dev/null
+++ b/sal/rtl/alloc_fini.cxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rtl/instance.hxx>
+
+#include <rtllifecycle.h>
+
+namespace
+{
+ struct rtlCacheSingleton
+ {
+ rtlCacheSingleton()
+ {
+ rtl_cache_init();
+ }
+ ~rtlCacheSingleton()
+ {
+ rtl_cache_fini();
+ }
+ };
+ class theCacheSingleton
+ : public rtl::Static<rtlCacheSingleton, theCacheSingleton>{};
+}
+
+void ensureCacheSingleton()
+{
+ theCacheSingleton::get();
+}
+
+namespace
+{
+ struct rtlArenaSingleton
+ {
+ rtlArenaSingleton()
+ {
+ rtl_arena_init();
+ }
+ ~rtlArenaSingleton()
+ {
+ rtl_arena_fini();
+ }
+ };
+ class theArenaSingleton
+ : public rtl::Static<rtlArenaSingleton, theArenaSingleton>{};
+}
+
+void ensureArenaSingleton()
+{
+ theArenaSingleton::get();
+}
+
+namespace
+{
+ struct rtlLocaleSingleton
+ {
+ rtlLocaleSingleton()
+ {
+ rtl_locale_init();
+ }
+ ~rtlLocaleSingleton()
+ {
+ rtl_locale_fini();
+ }
+ };
+ class theLocaleSingleton
+ : public rtl::Static<rtlLocaleSingleton, theLocaleSingleton>{};
+}
+
+void ensureLocaleSingleton()
+{
+ theLocaleSingleton::get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/alloc_global.cxx b/sal/rtl/alloc_global.cxx
new file mode 100644
index 000000000..9ceba4f41
--- /dev/null
+++ b/sal/rtl/alloc_global.cxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "alloc_impl.hxx"
+#include <rtl/alloc.h>
+#include <sal/log.hxx>
+#include <sal/macros.h>
+
+#include <algorithm>
+#include <cassert>
+#include <string.h>
+#include <stdio.h>
+
+#include <rtllifecycle.h>
+#include <oslmemory.h>
+
+void* SAL_CALL rtl_allocateMemory(sal_Size n) SAL_THROW_EXTERN_C()
+{
+ SAL_WARN_IF(
+ n >= SAL_MAX_INT32, "sal.rtl",
+ "suspicious massive alloc " << n);
+ return malloc (n);
+}
+
+void* SAL_CALL rtl_reallocateMemory(void * p, sal_Size n) SAL_THROW_EXTERN_C()
+{
+ SAL_WARN_IF(
+ n >= SAL_MAX_INT32, "sal.rtl",
+ "suspicious massive alloc " << n);
+ return realloc (p, n);
+}
+
+void SAL_CALL rtl_freeMemory(void * p) SAL_THROW_EXTERN_C()
+{
+ free (p);
+}
+
+void * SAL_CALL rtl_allocateZeroMemory(sal_Size n) SAL_THROW_EXTERN_C()
+{
+ void * p = rtl_allocateMemory (n);
+ if (p)
+ memset (p, 0, n);
+ return p;
+}
+
+void SAL_CALL rtl_freeZeroMemory(void * p, sal_Size n) SAL_THROW_EXTERN_C()
+{
+ if (p)
+ {
+ rtl_secureZeroMemory (p, n);
+ rtl_freeMemory (p);
+ }
+}
+
+void* SAL_CALL rtl_allocateAlignedMemory(sal_Size Alignment, sal_Size Bytes) SAL_THROW_EXTERN_C()
+{
+ return osl_aligned_alloc(Alignment, Bytes);
+}
+
+void SAL_CALL rtl_freeAlignedMemory(void* Ptr) SAL_THROW_EXTERN_C()
+{
+ osl_aligned_free(Ptr);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/alloc_impl.hxx b/sal/rtl/alloc_impl.hxx
new file mode 100644
index 000000000..bdacba04a
--- /dev/null
+++ b/sal/rtl/alloc_impl.hxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SAL_RTL_ALLOC_IMPL_HXX
+#define INCLUDED_SAL_RTL_ALLOC_IMPL_HXX
+
+#include <sal/types.h>
+
+/** 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) & -static_cast<sal_IntPtr>(align))
+
+#define RTL_MEMORY_P2ROUNDUP(value, align) \
+ (-(-static_cast<sal_IntPtr>(value) & -static_cast<sal_IntPtr>(align)))
+#define RTL_MEMORY_P2END(value, align) \
+ (-(~static_cast<sal_IntPtr>(value) & -static_cast<sal_IntPtr>(align)))
+
+/** highbit(): log2() + 1
+ (complexity O(1))
+*/
+static inline unsigned int highbit(sal_Size n)
+{
+ unsigned 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;
+}
+
+/** find first bit set
+ (complexity O(1))
+*/
+static inline unsigned int lowbit(sal_Size n)
+{
+ unsigned 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;
+}
+
+/** 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); \
+}
+
+#if defined(SAL_UNX)
+
+#include <unistd.h>
+#include <pthread.h>
+
+typedef pthread_mutex_t rtl_memory_lock_type;
+
+#define RTL_MEMORY_LOCK_INIT(lock) pthread_mutex_init((lock), nullptr)
+#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(_WIN32)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+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 | _WIN32 */
+
+/** Cache creation flags.
+ @internal
+*/
+#define RTL_CACHE_FLAG_NOMAGAZINE (1 << 13) /* w/o magazine layer */
+
+#endif // INCLUDED_SAL_RTL_ALLOC_IMPL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/bootstrap.cxx b/sal/rtl/bootstrap.cxx
new file mode 100644
index 000000000..460786c77
--- /dev/null
+++ b/sal/rtl/bootstrap.cxx
@@ -0,0 +1,1014 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <config_features.h>
+#include <config_folders.h>
+
+#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 <sal/log.hxx>
+
+#include <vector>
+#include <algorithm>
+#include <unordered_map>
+
+#ifdef ANDROID
+#include <osl/detail/android-bootstrap.h>
+#endif
+
+#ifdef IOS
+#include <premac.h>
+#import <Foundation/Foundation.h>
+#include <postmac.h>
+#endif
+
+using osl::DirectoryItem;
+using osl::FileStatus;
+
+namespace
+{
+
+struct Bootstrap_Impl;
+
+static char const VND_SUN_STAR_PATHNAME[] = "vnd.sun.star.pathname:";
+
+bool isPathnameUrl(OUString const & url)
+{
+ return url.matchIgnoreAsciiCase(VND_SUN_STAR_PATHNAME);
+}
+
+bool resolvePathnameUrl(OUString * url)
+{
+ OSL_ASSERT(url);
+ if (!isPathnameUrl(*url) ||
+ (osl::FileBase::getFileURLFromSystemPath(
+ url->copy(RTL_CONSTASCII_LENGTH(VND_SUN_STAR_PATHNAME)), *url) ==
+ osl::FileBase::E_None))
+ {
+ return true;
+ }
+ *url = 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;
+ OUString key;
+};
+
+OUString expandMacros(
+ Bootstrap_Impl const * file, OUString const & text, LookupMode mode,
+ ExpandRequestLink const * requestStack);
+
+OUString recursivelyExpandMacros(
+ Bootstrap_Impl const * file, OUString const & text, LookupMode mode,
+ Bootstrap_Impl const * requestFile, OUString const & requestKey,
+ ExpandRequestLink const * requestStack)
+{
+ for (; requestStack; requestStack = requestStack->next) {
+ if (requestStack->file == requestFile &&
+ requestStack->key == requestKey)
+ {
+ return "***RECURSION DETECTED***";
+ }
+ }
+ ExpandRequestLink link = { requestStack, requestFile, requestKey };
+ return expandMacros(file, text, mode, &link);
+}
+
+struct rtl_bootstrap_NameValue
+{
+ OUString sName;
+ OUString sValue;
+
+ rtl_bootstrap_NameValue()
+ {}
+ rtl_bootstrap_NameValue(OUString const & name, OUString const & value )
+ : sName( name ),
+ sValue( value )
+ {}
+};
+
+} // end namespace
+
+typedef std::vector<rtl_bootstrap_NameValue> NameValueVector;
+
+static bool find(
+ NameValueVector const & vector, OUString const & key,
+ OUString * value)
+{
+ OSL_ASSERT(value);
+ auto i = std::find_if(vector.begin(), vector.end(),
+ [&key](const rtl_bootstrap_NameValue& rNameValue) { return rNameValue.sName == key; });
+ if (i != vector.end())
+ {
+ *value = i->sValue;
+ return true;
+ }
+ return false;
+}
+
+namespace
+{
+ struct rtl_bootstrap_set_vector :
+ public rtl::Static< NameValueVector, rtl_bootstrap_set_vector > {};
+}
+
+static bool getFromCommandLineArgs(
+ OUString const & key, OUString * value )
+{
+ OSL_ASSERT(value);
+
+ static NameValueVector nameValueVector = [&]()
+ {
+ NameValueVector tmp;
+
+ sal_Int32 nArgCount = osl_getCommandArgCount();
+ for(sal_Int32 i = 0; i < nArgCount; ++ i)
+ {
+ rtl_uString *pArg = nullptr;
+ osl_getCommandArg( i, &pArg );
+ if( (pArg->buffer[0] == '-' || pArg->buffer[0] == '/' ) &&
+ pArg->buffer[1] == 'e' &&
+ pArg->buffer[2] == 'n' &&
+ pArg->buffer[3] == 'v' &&
+ 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);
+ }
+
+ tmp.push_back( nameValue );
+ }
+ }
+ rtl_uString_release( pArg );
+ };
+ return tmp;
+ }();
+
+ return find(nameValueVector, key, value);
+}
+
+static void getExecutableDirectory_Impl(rtl_uString ** ppDirURL)
+{
+ OUString fileName;
+ osl_getExecutableFile(&(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 aStaticName = []() {
+ OUString fileName;
+
+#if defined IOS
+ // On iOS hardcode the inifile as "rc" in the .app
+ // directory. Apps are self-contained anyway, there is no
+ // possibility to have several "applications" in the same
+ // installation location with different inifiles.
+ const char *inifile = [[@"vnd.sun.star.pathname:" stringByAppendingString: [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent: @"rc"]] UTF8String];
+ fileName = OUString(inifile, strlen(inifile), RTL_TEXTENCODING_UTF8);
+ resolvePathnameUrl(&fileName);
+#elif defined ANDROID
+ // Apps are self-contained on Android, too, can as well hardcode
+ // it as "rc" in the "/assets" directory, i.e. inside the app's
+ // .apk (zip) archive as the /assets/rc file.
+ fileName = OUString("vnd.sun.star.pathname:/assets/rc");
+ resolvePathnameUrl(&fileName);
+#else
+ if (getFromCommandLineArgs("INIFILENAME", &fileName))
+ {
+ resolvePathnameUrl(&fileName);
+ }
+ else
+ {
+ osl_getExecutableFile(&(fileName.pData));
+
+ // get rid of a potential executable extension
+ OUString progExt = ".bin";
+ if (fileName.getLength() > progExt.getLength()
+ && fileName.copy(fileName.getLength() - progExt.getLength()).equalsIgnoreAsciiCase(progExt))
+ {
+ fileName = fileName.copy(0, fileName.getLength() - progExt.getLength());
+ }
+
+ progExt = ".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 += SAL_CONFIGFILE("");
+
+#ifdef MACOSX
+ // We keep only executables in the MacOS folder, and all
+ // rc files in LIBO_ETC_FOLDER (typically "Resources").
+ sal_Int32 off = fileName.lastIndexOf( "/MacOS/" );
+ if (off != -1)
+ fileName = fileName.replaceAt(off + 1, strlen("MacOS"), LIBO_ETC_FOLDER);
+#endif
+ }
+#endif
+
+ return fileName;
+ }();
+
+ return aStaticName;
+}
+
+// ensure the given file url has no final slash
+
+static void EnsureNoFinalSlash (OUString & url)
+{
+ sal_Int32 i = url.getLength();
+
+ if (i > 0 && url[i - 1] == '/')
+ url = url.copy(0, i - 1);
+}
+
+namespace {
+
+struct Bootstrap_Impl
+{
+ sal_Int32 _nRefCount;
+ Bootstrap_Impl * _base_ini;
+
+ NameValueVector _nameValueVector;
+ OUString _iniName;
+
+ explicit Bootstrap_Impl (OUString const & rIniName);
+ ~Bootstrap_Impl();
+
+ static void * operator new (std::size_t n)
+ { return malloc (sal_uInt32(n)); }
+ static void operator delete (void * p , std::size_t)
+ { free (p); }
+
+ bool getValue(
+ OUString const & key, rtl_uString ** value,
+ rtl_uString * defaultValue, LookupMode mode, bool override,
+ ExpandRequestLink const * requestStack) const;
+ bool getDirectValue(
+ OUString const & key, rtl_uString ** value, LookupMode mode,
+ ExpandRequestLink const * requestStack) const;
+ bool getAmbienceValue(
+ OUString const & key, rtl_uString ** value, LookupMode mode,
+ ExpandRequestLink const * requestStack) const;
+ void expandValue(
+ rtl_uString ** value, OUString const & text, LookupMode mode,
+ Bootstrap_Impl const * requestFile, OUString const & requestKey,
+ ExpandRequestLink const * requestStack) const;
+};
+
+}
+
+Bootstrap_Impl::Bootstrap_Impl( OUString const & rIniName )
+ : _nRefCount( 0 ),
+ _base_ini( nullptr ),
+ _iniName (rIniName)
+{
+ OUString base_ini(getIniFileName_Impl());
+ // normalize path
+ FileStatus status( osl_FileStatus_Mask_FileURL );
+ DirectoryItem dirItem;
+ if (DirectoryItem::get(base_ini, dirItem) == DirectoryItem::E_None &&
+ dirItem.getFileStatus(status) == DirectoryItem::E_None)
+ {
+ base_ini = status.getFileURL();
+ if (rIniName != base_ini)
+ {
+ _base_ini = static_cast< Bootstrap_Impl * >(
+ rtl_bootstrap_args_open(base_ini.pData));
+ }
+ }
+ SAL_INFO("sal.bootstrap", "Bootstrap_Impl(): sFile=" << _iniName);
+ oslFileHandle handle;
+ if (!_iniName.isEmpty() &&
+ osl_openFile(_iniName.pData, &handle, osl_File_OpenFlag_Read) == osl_File_E_None)
+ {
+ rtl::ByteSequence seq;
+
+ while (osl_readLine(handle , reinterpret_cast<sal_Sequence **>(&seq)) == osl_File_E_None)
+ {
+ OString line(reinterpret_cast<const 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);
+
+ SAL_INFO("sal.bootstrap", "pushing: name=" << nameValue.sName << " value=" << nameValue.sValue);
+
+ _nameValueVector.push_back(nameValue);
+ }
+ }
+ osl_closeFile(handle);
+ }
+ else
+ {
+ SAL_INFO( "sal.bootstrap", "couldn't open file: " << _iniName );
+ }
+}
+
+Bootstrap_Impl::~Bootstrap_Impl()
+{
+ if (_base_ini)
+ rtl_bootstrap_args_close( _base_ini );
+}
+
+namespace {
+
+Bootstrap_Impl * get_static_bootstrap_handle()
+{
+ static Bootstrap_Impl* s_handle = []() {
+ OUString iniName(getIniFileName_Impl());
+ Bootstrap_Impl* that = static_cast<Bootstrap_Impl*>(rtl_bootstrap_args_open(iniName.pData));
+ if (!that)
+ {
+ that = new Bootstrap_Impl(iniName);
+ ++that->_nRefCount;
+ }
+ return that;
+ }();
+
+ return s_handle;
+}
+
+struct FundamentalIniData
+{
+ rtlBootstrapHandle ini;
+
+ FundamentalIniData()
+ {
+ OUString uri;
+ ini =
+ (get_static_bootstrap_handle()->getValue(
+ "URE_BOOTSTRAP", &uri.pData, nullptr, LOOKUP_MODE_NORMAL, false,
+ nullptr)
+ && resolvePathnameUrl(&uri))
+ ? rtl_bootstrap_args_open(uri.pData) : nullptr;
+ }
+
+ ~FundamentalIniData() { rtl_bootstrap_args_close(ini); }
+
+ FundamentalIniData(const FundamentalIniData&) = delete;
+ FundamentalIniData& operator=(const FundamentalIniData&) = delete;
+};
+
+struct FundamentalIni: public rtl::Static< FundamentalIniData, FundamentalIni >
+{};
+
+}
+
+bool Bootstrap_Impl::getValue(
+ OUString const & key, rtl_uString ** value, rtl_uString * defaultValue,
+ LookupMode mode, bool override, ExpandRequestLink const * requestStack)
+ const
+{
+ if (mode == LOOKUP_MODE_NORMAL && key == "URE_BOOTSTRAP")
+ mode = LOOKUP_MODE_URE_BOOTSTRAP;
+
+ if (override && getDirectValue(key, value, mode, requestStack))
+ return true;
+
+ if (key == "_OS")
+ {
+ rtl_uString_assign(
+ value, OUString(RTL_OS).pData);
+ return true;
+ }
+
+ if (key == "_ARCH")
+ {
+ rtl_uString_assign(
+ value, OUString(RTL_ARCH).pData);
+ return true;
+ }
+
+ if (key == "_CPPU_ENV")
+ {
+ rtl_uString_assign(
+ value,
+ (OUString(
+ SAL_STRINGIFY(CPPU_ENV)).
+ pData));
+ return true;
+ }
+
+#ifdef ANDROID
+ if (key == "APP_DATA_DIR")
+ {
+ const char *app_data_dir = lo_get_app_data_dir();
+ rtl_uString_assign(
+ value, OUString(app_data_dir, strlen(app_data_dir), RTL_TEXTENCODING_UTF8).pData);
+ return true;
+ }
+#endif
+
+#ifdef IOS
+ if (key == "APP_DATA_DIR")
+ {
+ const char *app_data_dir = [[[[NSBundle mainBundle] bundlePath] stringByAddingPercentEncodingWithAllowedCharacters: [NSCharacterSet URLPathAllowedCharacterSet]] UTF8String];
+ rtl_uString_assign(
+ value, OUString(app_data_dir, strlen(app_data_dir), RTL_TEXTENCODING_UTF8).pData);
+ return true;
+ }
+#endif
+
+ if (key == "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 == "SYSUSERCONFIG")
+ {
+ OUString v;
+ bool b = osl::Security().getConfigDir(v);
+ EnsureNoFinalSlash(v);
+ rtl_uString_assign(value, v.pData);
+ return b;
+ }
+
+ if (key == "SYSUSERHOME")
+ {
+ OUString v;
+ bool b = osl::Security().getHomeDir(v);
+ EnsureNoFinalSlash(v);
+ rtl_uString_assign(value, v.pData);
+ return b;
+ }
+
+ if (key == "SYSBINDIR")
+ {
+ getExecutableDirectory_Impl(value);
+ return true;
+ }
+
+ if (_base_ini != nullptr && _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 != nullptr && b != this && b->getDirectValue(key, value, mode, requestStack))
+ return true;
+ }
+
+ if (defaultValue != nullptr)
+ {
+ rtl_uString_assign(value, defaultValue);
+ return true;
+ }
+
+ rtl_uString_new(value);
+ return false;
+}
+
+bool Bootstrap_Impl::getDirectValue(
+ OUString const & key, rtl_uString ** value, LookupMode mode,
+ ExpandRequestLink const * requestStack) const
+{
+ OUString v;
+ if (find(_nameValueVector, key, &v))
+ {
+ expandValue(value, v, mode, this, key, requestStack);
+ return true;
+ }
+
+ return false;
+}
+
+bool Bootstrap_Impl::getAmbienceValue(
+ OUString const & key, rtl_uString ** value, LookupMode mode,
+ ExpandRequestLink const * requestStack) const
+{
+ OUString v;
+ bool f;
+
+ {
+ osl::MutexGuard g(osl::Mutex::getGlobalMutex());
+ f = find(rtl_bootstrap_set_vector::get(), key, &v);
+ }
+
+ if (f || getFromCommandLineArgs(key, &v) ||
+ osl_getEnvironment(key.pData, &v.pData) == osl_Process_E_None)
+ {
+ expandValue(value, v, mode, nullptr, key, requestStack);
+ return true;
+ }
+
+ return false;
+}
+
+void Bootstrap_Impl::expandValue(
+ rtl_uString ** value, OUString const & text, LookupMode mode,
+ Bootstrap_Impl const * requestFile, 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 {
+ typedef std::unordered_map<
+ OUString, Bootstrap_Impl * > t;
+
+ bootstrap_map(const bootstrap_map&) = delete;
+ bootstrap_map& operator=(const bootstrap_map&) = delete;
+
+ // get and release must only be called properly synchronized via some mutex
+ // (e.g., osl::Mutex::getGlobalMutex()):
+
+ static t * get()
+ {
+ if (!m_map)
+ m_map = new t;
+
+ return m_map;
+ }
+
+ static void release()
+ {
+ if (m_map != nullptr && m_map->empty())
+ {
+ delete m_map;
+ m_map = nullptr;
+ }
+ }
+
+private:
+ static t * m_map;
+};
+
+bootstrap_map::t * bootstrap_map::m_map = nullptr;
+
+}
+
+rtlBootstrapHandle SAL_CALL rtl_bootstrap_args_open(rtl_uString * pIniName)
+{
+ OUString iniName( pIniName );
+
+ // normalize path
+ FileStatus status(osl_FileStatus_Mask_FileURL);
+ DirectoryItem dirItem;
+ if (DirectoryItem::get(iniName, dirItem) != DirectoryItem::E_None ||
+ dirItem.getFileStatus(status) != DirectoryItem::E_None)
+ {
+ return nullptr;
+ }
+
+ 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->emplace(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)
+ 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)
+ return;
+
+ std::size_t const nLeaking = 8; // only hold up to 8 files statically
+ 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
+)
+{
+ osl::MutexGuard guard(osl::Mutex::getGlobalMutex());
+
+ bool found = false;
+ if(ppValue && pName)
+ {
+ if (!handle)
+ handle = get_static_bootstrap_handle();
+
+ found = static_cast< Bootstrap_Impl * >(handle)->getValue(
+ pName, ppValue, pDefault, LOOKUP_MODE_NORMAL, false, nullptr );
+ }
+
+ return found;
+}
+
+void SAL_CALL rtl_bootstrap_get_iniName_from_handle (
+ rtlBootstrapHandle handle,
+ rtl_uString ** ppIniName
+)
+{
+ if(!ppIniName)
+ return;
+
+ 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
+)
+{
+ 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
+)
+{
+ return rtl_bootstrap_get_from_handle(nullptr, pName, ppValue, pDefault);
+}
+
+void SAL_CALL rtl_bootstrap_set (
+ rtl_uString * pName,
+ rtl_uString * pValue
+)
+{
+ const OUString name(pName);
+ const OUString value(pValue);
+
+ osl::MutexGuard guard(osl::Mutex::getGlobalMutex());
+
+ NameValueVector& r_rtl_bootstrap_set_vector= rtl_bootstrap_set_vector::get();
+ for (auto & item : r_rtl_bootstrap_set_vector)
+ {
+ if (item.sName == name)
+ {
+ item.sValue = value;
+ return;
+ }
+ }
+
+ SAL_INFO("sal.bootstrap", "explicitly getting: name=" << name << " value=" <<value);
+
+ r_rtl_bootstrap_set_vector.emplace_back(name, value);
+}
+
+void SAL_CALL rtl_bootstrap_expandMacros_from_handle(
+ rtlBootstrapHandle handle,
+ rtl_uString ** macro)
+{
+ if (!handle)
+ handle = get_static_bootstrap_handle();
+
+ OUString expanded(expandMacros(static_cast< Bootstrap_Impl * >(handle),
+ OUString::unacquired(macro),
+ LOOKUP_MODE_NORMAL, nullptr));
+ rtl_uString_assign(macro, expanded.pData);
+}
+
+void SAL_CALL rtl_bootstrap_expandMacros(rtl_uString ** macro)
+{
+ rtl_bootstrap_expandMacros_from_handle(nullptr, macro);
+}
+
+void rtl_bootstrap_encode(rtl_uString const * value, rtl_uString ** encoded)
+{
+ OSL_ASSERT(value);
+ OUStringBuffer b(value->length+5);
+ for (sal_Int32 i = 0; i < value->length; ++i)
+ {
+ sal_Unicode c = value->buffer[i];
+ if (c == '$' || c == '\\')
+ b.append('\\');
+
+ 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(OUString const & text, sal_Int32 * pos, bool * escaped)
+{
+ OSL_ASSERT(pos && *pos >= 0 && *pos < text.getLength() && escaped);
+ 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);
+ }
+
+ if (*pos < text.getLength())
+ {
+ *escaped = true;
+ return text[(*pos)++];
+ }
+ }
+
+ *escaped = false;
+ return c;
+}
+
+OUString lookup(
+ Bootstrap_Impl const * file, LookupMode mode, bool override,
+ OUString const & key, ExpandRequestLink const * requestStack)
+{
+ OUString v;
+ (file == nullptr ? get_static_bootstrap_handle() : file)->getValue(
+ key, &v.pData, nullptr, mode, override, requestStack);
+ return v;
+}
+
+OUString expandMacros(
+ Bootstrap_Impl const * file, OUString const & text, LookupMode mode,
+ ExpandRequestLink const * requestStack)
+{
+ SAL_INFO("sal.bootstrap", "expandMacros called with: " << text);
+ OUStringBuffer buf(2048);
+
+ 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;
+ 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 == 1)
+ {
+ buf.append(lookup(file, mode, false, seg[0], requestStack));
+ }
+ else if (n == 3 && seg[0] == ".override")
+ {
+ rtl::Bootstrap b(seg[1]);
+ Bootstrap_Impl * f = static_cast< Bootstrap_Impl * >(b.getHandle());
+ buf.append(lookup(f, mode, f != nullptr, seg[2], requestStack));
+ }
+ else
+ {
+ if (n == 3 && seg[1].isEmpty())
+ {
+ // For backward compatibility, treat ${file::key} the
+ // same as just ${file:key}:
+ seg[1] = seg[2];
+ n = 2;
+ }
+
+ if (n == 2)
+ {
+ buf.append(
+ lookup(
+ static_cast< Bootstrap_Impl * >(
+ rtl::Bootstrap(seg[0]).getHandle()),
+ mode, false, seg[1], 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(
+ OStringToOUString(
+ osl::Profile(seg[0]).readString(
+ OUStringToOString(
+ seg[1], RTL_TEXTENCODING_UTF8),
+ OUStringToOString(
+ seg[2], RTL_TEXTENCODING_UTF8),
+ OString()),
+ RTL_TEXTENCODING_UTF8));
+ }
+ }
+ }
+ else
+ {
+ OUStringBuffer kbuf(text.getLength());
+ 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));
+ }
+ }
+ }
+
+ OUString result(buf.makeStringAndClear());
+ SAL_INFO("sal.bootstrap", "expandMacros result: " << result);
+
+ return result;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/byteseq.cxx b/sal/rtl/byteseq.cxx
new file mode 100644
index 000000000..c78a1e22f
--- /dev/null
+++ b/sal/rtl/byteseq.cxx
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <osl/diagnose.h>
+#include <osl/interlck.h>
+
+#include <rtl/byteseq.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_THROW_EXTERN_C()
+{
+ sal_Sequence * pSequence, * pNew;
+
+ OSL_ENSURE( ppSequence, "### null ptr!" );
+ pSequence = *ppSequence;
+
+ if (pSequence->nRefCount > 1)
+ {
+ sal_Int32 nElements = pSequence->nElements;
+ if (nElements)
+ {
+ pNew = static_cast<sal_Sequence *>(malloc( SAL_SEQUENCE_HEADER_SIZE + nElements ));
+
+ if ( pNew != nullptr )
+ memcpy( pNew->elements, pSequence->elements, nElements );
+
+ if (! osl_atomic_decrement( &pSequence->nRefCount ))
+ free( pSequence );
+ }
+ else
+ {
+ pNew = static_cast<sal_Sequence *>(malloc( SAL_SEQUENCE_HEADER_SIZE ));
+ }
+
+ if ( pNew != nullptr )
+ {
+ pNew->nRefCount = 1;
+ pNew->nElements = nElements;
+ }
+
+ *ppSequence = pNew;
+ }
+}
+
+void SAL_CALL rtl_byte_sequence_realloc(
+ sal_Sequence ** ppSequence, sal_Int32 nSize ) SAL_THROW_EXTERN_C()
+{
+ sal_Sequence * pSequence, * pNew;
+ sal_Int32 nElements;
+
+ assert(ppSequence && "### null ptr!");
+ pSequence = *ppSequence;
+ nElements = pSequence->nElements;
+
+ if (nElements == nSize)
+ return;
+
+ if (pSequence->nRefCount > 1) // split
+ {
+ pNew = static_cast<sal_Sequence *>(malloc( SAL_SEQUENCE_HEADER_SIZE + nSize ));
+
+ if ( pNew != nullptr )
+ {
+ if (nSize > nElements)
+ {
+ memcpy( pNew->elements, pSequence->elements, nElements );
+ memset( pNew->elements + nElements, 0, nSize - nElements );
+ }
+ else
+ {
+ memcpy( pNew->elements, pSequence->elements, nSize );
+ }
+ }
+
+ if (! osl_atomic_decrement( &pSequence->nRefCount ))
+ free( pSequence );
+ pSequence = pNew;
+ }
+ else
+ {
+ pSequence = static_cast<sal_Sequence *>(realloc(
+ pSequence, SAL_SEQUENCE_HEADER_SIZE + nSize ));
+ }
+
+ if ( pSequence != nullptr )
+ {
+ pSequence->nRefCount = 1;
+ pSequence->nElements = nSize;
+ }
+
+ *ppSequence = pSequence;
+}
+
+void SAL_CALL rtl_byte_sequence_acquire( sal_Sequence *pSequence )
+ SAL_THROW_EXTERN_C()
+{
+ OSL_ASSERT( pSequence );
+ osl_atomic_increment( &(pSequence->nRefCount) );
+}
+
+void SAL_CALL rtl_byte_sequence_release( sal_Sequence *pSequence )
+ SAL_THROW_EXTERN_C()
+{
+ if ( pSequence != nullptr )
+ {
+ if (! osl_atomic_decrement( &(pSequence->nRefCount )) )
+ {
+ free( pSequence );
+ }
+ }
+}
+
+void SAL_CALL rtl_byte_sequence_construct( sal_Sequence **ppSequence , sal_Int32 nLength )
+ SAL_THROW_EXTERN_C()
+{
+ OSL_ASSERT( ppSequence );
+ if( *ppSequence )
+ {
+ rtl_byte_sequence_release( *ppSequence );
+ *ppSequence = nullptr;
+ }
+
+ if( nLength )
+ {
+ *ppSequence = static_cast<sal_Sequence *>(rtl_allocateZeroMemory( SAL_SEQUENCE_HEADER_SIZE + nLength ));
+
+ if ( *ppSequence != nullptr )
+ {
+ (*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 )
+ SAL_THROW_EXTERN_C()
+{
+ OSL_ASSERT( ppSequence );
+ if( *ppSequence )
+ {
+ rtl_byte_sequence_release( *ppSequence );
+ *ppSequence = nullptr;
+ }
+
+ *ppSequence = static_cast<sal_Sequence *>(malloc( SAL_SEQUENCE_HEADER_SIZE + nLength ));
+
+ if ( *ppSequence != nullptr )
+ {
+ (*ppSequence)->nRefCount = 1;
+ (*ppSequence)->nElements = nLength;
+ }
+}
+
+void SAL_CALL rtl_byte_sequence_constructFromArray(
+ sal_Sequence **ppSequence, const sal_Int8 *pData , sal_Int32 nLength )
+ SAL_THROW_EXTERN_C()
+{
+ rtl_byte_sequence_constructNoDefault( ppSequence , nLength );
+ if ( *ppSequence != nullptr && nLength != 0 )
+ memcpy( (*ppSequence)->elements, pData, nLength );
+}
+
+void SAL_CALL rtl_byte_sequence_assign( sal_Sequence **ppSequence , sal_Sequence *pSequence )
+ SAL_THROW_EXTERN_C()
+{
+ 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pSequence1 && pSequence2);
+ if (pSequence1 == pSequence2)
+ {
+ return true;
+ }
+ if (pSequence1->nElements != pSequence2->nElements)
+ {
+ return false;
+ }
+ return
+ memcmp(
+ pSequence1->elements, pSequence2->elements, pSequence1->nElements )
+ == 0;
+}
+
+const sal_Int8 *SAL_CALL rtl_byte_sequence_getConstArray( sal_Sequence *pSequence )
+ SAL_THROW_EXTERN_C()
+{
+ return reinterpret_cast<sal_Int8*>(pSequence->elements);
+}
+
+sal_Int32 SAL_CALL rtl_byte_sequence_getLength( sal_Sequence *pSequence )
+ SAL_THROW_EXTERN_C()
+{
+ return pSequence->nElements;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/cipher.cxx b/sal/rtl/cipher.cxx
new file mode 100644
index 000000000..344286549
--- /dev/null
+++ b/sal/rtl/cipher.cxx
@@ -0,0 +1,1433 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+
+#include <o3tl/safeint.hxx>
+#include <sal/types.h>
+#include <rtl/alloc.h>
+#include <rtl/cipher.h>
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <limits>
+
+#if defined LIBO_CIPHER_OPENSSL_BACKEND
+#include <openssl/evp.h>
+#endif
+
+#if !defined LIBO_CIPHER_OPENSSL_BACKEND
+#define RTL_CIPHER_NTOHL(c, l) \
+ ((l) = (static_cast<sal_uInt32>(*((c)++))) << 24, \
+ (l) |= (static_cast<sal_uInt32>(*((c)++))) << 16, \
+ (l) |= (static_cast<sal_uInt32>(*((c)++))) << 8, \
+ (l) |= (static_cast<sal_uInt32>(*((c)++))))
+
+#define RTL_CIPHER_HTONL(l, c) \
+ (*((c)++) = static_cast<sal_uInt8>(((l) >> 24) & 0xff), \
+ *((c)++) = static_cast<sal_uInt8>(((l) >> 16) & 0xff), \
+ *((c)++) = static_cast<sal_uInt8>(((l) >> 8) & 0xff), \
+ *((c)++) = static_cast<sal_uInt8>(((l) ) & 0xff))
+
+#define RTL_CIPHER_NTOHL64(c, xl, xr, n) \
+{ \
+ (xl) = (xr) = 0; \
+ (c) += (n); \
+ switch ((n)) \
+ { \
+ case 8: (xr) = (static_cast<sal_uInt32>(*(--(c)))); \
+ [[fallthrough]]; \
+ case 7: (xr) |= (static_cast<sal_uInt32>(*(--(c)))) << 8; \
+ [[fallthrough]]; \
+ case 6: (xr) |= (static_cast<sal_uInt32>(*(--(c)))) << 16; \
+ [[fallthrough]]; \
+ case 5: (xr) |= (static_cast<sal_uInt32>(*(--(c)))) << 24; \
+ [[fallthrough]]; \
+ case 4: (xl) = (static_cast<sal_uInt32>(*(--(c)))); \
+ [[fallthrough]]; \
+ case 3: (xl) |= (static_cast<sal_uInt32>(*(--(c)))) << 8; \
+ [[fallthrough]]; \
+ case 2: (xl) |= (static_cast<sal_uInt32>(*(--(c)))) << 16; \
+ [[fallthrough]]; \
+ case 1: (xl) |= (static_cast<sal_uInt32>(*(--(c)))) << 24; \
+ } \
+}
+
+#define RTL_CIPHER_HTONL64(xl, xr, c, n) \
+{ \
+ (c) += (n); \
+ switch ((n)) \
+ { \
+ case 8: *(--(c)) = static_cast<sal_uInt8>(((xr) ) & 0xff); \
+ [[fallthrough]]; \
+ case 7: *(--(c)) = static_cast<sal_uInt8>(((xr) >> 8) & 0xff); \
+ [[fallthrough]]; \
+ case 6: *(--(c)) = static_cast<sal_uInt8>(((xr) >> 16) & 0xff); \
+ [[fallthrough]]; \
+ case 5: *(--(c)) = static_cast<sal_uInt8>(((xr) >> 24) & 0xff); \
+ [[fallthrough]]; \
+ case 4: *(--(c)) = static_cast<sal_uInt8>(((xl) ) & 0xff); \
+ [[fallthrough]]; \
+ case 3: *(--(c)) = static_cast<sal_uInt8>(((xl) >> 8) & 0xff); \
+ [[fallthrough]]; \
+ case 2: *(--(c)) = static_cast<sal_uInt8>(((xl) >> 16) & 0xff); \
+ [[fallthrough]]; \
+ case 1: *(--(c)) = static_cast<sal_uInt8>(((xl) >> 24) & 0xff); \
+ } \
+}
+#endif
+
+typedef rtlCipherError(cipher_init_t) (
+ rtlCipher Cipher,
+ rtlCipherDirection Direction,
+ const sal_uInt8 *pKeyData, sal_Size nKeyLen,
+ const sal_uInt8 *pArgData, sal_Size nArgLen);
+
+typedef rtlCipherError(cipher_update_t) (
+ rtlCipher Cipher,
+ const void *pData, sal_Size nDatLen,
+ sal_uInt8 *pBuffer, sal_Size nBufLen);
+
+typedef void (cipher_delete_t) (rtlCipher Cipher);
+
+namespace {
+
+struct Cipher_Impl
+{
+ 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;
+};
+
+}
+
+rtlCipher SAL_CALL rtl_cipher_create(
+ rtlCipherAlgorithm Algorithm,
+ rtlCipherMode Mode) SAL_THROW_EXTERN_C()
+{
+ rtlCipher Cipher = nullptr;
+ 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;
+}
+
+rtlCipherError SAL_CALL rtl_cipher_init(
+ rtlCipher Cipher,
+ rtlCipherDirection Direction,
+ const sal_uInt8 *pKeyData, sal_Size nKeyLen,
+ const sal_uInt8 *pArgData, sal_Size nArgLen) SAL_THROW_EXTERN_C()
+{
+ Cipher_Impl *pImpl = static_cast<Cipher_Impl*>(Cipher);
+ if (!pImpl)
+ return rtl_Cipher_E_Argument;
+
+ if (!pImpl->m_init)
+ return rtl_Cipher_E_Unknown;
+
+ return (pImpl->m_init)(
+ Cipher, Direction, pKeyData, nKeyLen, pArgData, nArgLen);
+}
+
+rtlCipherError SAL_CALL rtl_cipher_encode(
+ rtlCipher Cipher,
+ const void *pData, sal_Size nDatLen,
+ sal_uInt8 *pBuffer, sal_Size nBufLen) SAL_THROW_EXTERN_C()
+{
+ Cipher_Impl *pImpl = static_cast<Cipher_Impl*>(Cipher);
+ if (!pImpl)
+ return rtl_Cipher_E_Argument;
+
+ if (!pImpl->m_encode)
+ return rtl_Cipher_E_Unknown;
+
+ return (pImpl->m_encode)(Cipher, pData, nDatLen, pBuffer, nBufLen);
+}
+
+rtlCipherError SAL_CALL rtl_cipher_decode(
+ rtlCipher Cipher,
+ const void *pData, sal_Size nDatLen,
+ sal_uInt8 *pBuffer, sal_Size nBufLen) SAL_THROW_EXTERN_C()
+{
+ Cipher_Impl *pImpl = static_cast<Cipher_Impl*>(Cipher);
+ if (!pImpl)
+ return rtl_Cipher_E_Argument;
+
+ if (!pImpl->m_decode)
+ return rtl_Cipher_E_Unknown;
+
+ return (pImpl->m_decode)(Cipher, pData, nDatLen, pBuffer, nBufLen);
+}
+
+void SAL_CALL rtl_cipher_destroy(rtlCipher Cipher) SAL_THROW_EXTERN_C()
+{
+ Cipher_Impl *pImpl = static_cast<Cipher_Impl*>(Cipher);
+ if (pImpl && pImpl->m_delete)
+ pImpl->m_delete(Cipher);
+}
+
+namespace {
+
+#if !defined LIBO_CIPHER_OPENSSL_BACKEND
+#define CIPHER_ROUNDS_BF 16
+
+struct CipherKeyBF
+{
+ sal_uInt32 m_S[4][256];
+ sal_uInt32 m_P[CIPHER_ROUNDS_BF + 2];
+};
+#endif
+
+struct CipherContextBF
+{
+#if defined LIBO_CIPHER_OPENSSL_BACKEND
+ EVP_CIPHER_CTX * m_context;
+#else
+ CipherKeyBF m_key;
+ union
+ {
+ sal_uInt32 m_long[2];
+ sal_uInt8 m_byte[8];
+ } m_iv;
+ sal_uInt32 m_offset;
+#endif
+};
+
+struct CipherBF_Impl
+{
+ Cipher_Impl m_cipher;
+ CipherContextBF m_context;
+};
+
+}
+
+#if !defined LIBO_CIPHER_OPENSSL_BACKEND
+static rtlCipherError BF_init(
+ CipherContextBF *ctx,
+ rtlCipherMode eMode,
+ const sal_uInt8 *pKeyData, sal_Size nKeyLen,
+ const sal_uInt8 *pArgData, sal_Size nArgLen);
+#endif
+
+static rtlCipherError BF_update(
+ CipherContextBF *ctx,
+ rtlCipherMode eMode,
+ rtlCipherDirection eDirection,
+ const sal_uInt8 *pData, sal_Size nDatLen,
+ sal_uInt8 *pBuffer, sal_Size nBufLen);
+
+#if !defined LIBO_CIPHER_OPENSSL_BACKEND
+static void BF_updateECB(
+ CipherContextBF *ctx,
+ rtlCipherDirection direction,
+ const sal_uInt8 *pData,
+ sal_uInt8 *pBuffer,
+ sal_Size nLength);
+
+static void BF_updateCBC(
+ CipherContextBF *ctx,
+ rtlCipherDirection direction,
+ const sal_uInt8 *pData,
+ sal_uInt8 *pBuffer,
+ sal_Size nLength);
+
+static void BF_updateCFB(
+ CipherContextBF *ctx,
+ rtlCipherDirection direction,
+ const sal_uInt8 *pData,
+ sal_uInt8 *pBuffer);
+
+static void BF_encode(CipherKeyBF *key, sal_uInt32 *xl, sal_uInt32 *xr);
+
+static void BF_decode(CipherKeyBF *key, sal_uInt32 *xl, sal_uInt32 *xr);
+
+static sal_uInt32 BF(CipherKeyBF *key, sal_uInt32 x);
+
+static const CipherKeyBF BF_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
+ }
+};
+#endif
+
+#if !defined LIBO_CIPHER_OPENSSL_BACKEND
+static rtlCipherError BF_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);
+
+ memcpy(key, &BF_key, sizeof (CipherKeyBF));
+ memset(&(ctx->m_iv), 0, 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;
+ }
+
+ rtl_secureZeroMemory(&DL, sizeof(DL));
+ rtl_secureZeroMemory(&DR, sizeof(DR));
+
+ for (i = 0; i < CIPHER_ROUNDS_BF + 2; i += 2)
+ {
+ BF_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)
+ {
+ BF_encode(key, &DL, &DR);
+ key->m_S[i][k ] = DL;
+ key->m_S[i][k + 1] = DR;
+ }
+ }
+
+ if (pArgData && nArgLen)
+ {
+ nArgLen = std::min<sal_Size>(nArgLen, 8);
+ if (eMode == rtl_Cipher_ModeStream)
+ {
+ memcpy(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;
+ }
+ }
+
+ return rtl_Cipher_E_None;
+}
+#endif
+
+static rtlCipherError BF_update(
+ CipherContextBF *ctx,
+ rtlCipherMode eMode,
+ rtlCipherDirection eDirection,
+ const sal_uInt8 *pData, sal_Size nDatLen,
+ sal_uInt8 *pBuffer, sal_Size nBufLen)
+{
+ /* Check arguments. */
+ if (!pData || !pBuffer)
+ return rtl_Cipher_E_Argument;
+
+ if (!((nDatLen > 0) && (nDatLen <= nBufLen)))
+ return rtl_Cipher_E_BufferSize;
+
+ /* Update. */
+#if defined LIBO_CIPHER_OPENSSL_BACKEND
+ assert(eMode == rtl_Cipher_ModeStream);
+ (void) eMode;
+ (void) eDirection;
+ while (nDatLen > o3tl::make_unsigned(std::numeric_limits<int>::max())) {
+ int outl;
+ if (EVP_CipherUpdate(ctx->m_context, pBuffer, &outl, pData, std::numeric_limits<int>::max())
+ == 0)
+ {
+ return rtl_Cipher_E_Unknown;
+ }
+ assert(outl == std::numeric_limits<int>::max());
+ pData += std::numeric_limits<int>::max();
+ nDatLen -= std::numeric_limits<int>::max();
+ pBuffer += std::numeric_limits<int>::max();
+ }
+ int outl;
+ if (EVP_CipherUpdate(ctx->m_context, pBuffer, &outl, pData, static_cast<int>(nDatLen)) == 0)
+ {
+ return rtl_Cipher_E_Unknown;
+ }
+ assert(outl == static_cast<int>(nDatLen));
+ // A final call to EVP_CipherFinal_ex is intentionally missing; it wouldn't fit the rtl/cipher.h
+ // interface, and is hopefully not needed, as each individual Blowfish CFB update step doesn't
+ // hold back any data that would need to be finally flushed.
+#else
+ if (eMode == rtl_Cipher_ModeECB)
+ {
+ /* Block mode. */
+ while (nDatLen > 8)
+ {
+ BF_updateECB(ctx, eDirection, pData, pBuffer, 8);
+ nDatLen -= 8;
+ pData += 8;
+ pBuffer += 8;
+ }
+ BF_updateECB(ctx, eDirection, pData, pBuffer, nDatLen);
+ }
+ else if (eMode == rtl_Cipher_ModeCBC)
+ {
+ /* Block mode. */
+ while (nDatLen > 8)
+ {
+ BF_updateCBC (ctx, eDirection, pData, pBuffer, 8);
+ nDatLen -= 8;
+ pData += 8;
+ pBuffer += 8;
+ }
+ BF_updateCBC (ctx, eDirection, pData, pBuffer, nDatLen);
+ }
+ else
+ {
+ /* Stream mode. */
+ while (nDatLen > 0)
+ {
+ BF_updateCFB (ctx, eDirection, pData, pBuffer);
+ nDatLen -= 1;
+ pData += 1;
+ pBuffer += 1;
+ }
+ }
+#endif
+ return rtl_Cipher_E_None;
+}
+
+#if !defined LIBO_CIPHER_OPENSSL_BACKEND
+static void BF_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);
+
+ BF_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);
+
+ BF_decode(key, &DL, &DR);
+
+ RTL_CIPHER_HTONL64(DL, DR, pBuffer, nLength);
+ }
+ rtl_secureZeroMemory(&DL, sizeof(DL));
+ rtl_secureZeroMemory(&DR, sizeof(DR));
+}
+
+static void BF_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];
+
+ BF_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;
+
+ BF_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);
+ }
+ rtl_secureZeroMemory(&DL, sizeof(DL));
+ rtl_secureZeroMemory(&DR, sizeof(DR));
+}
+
+static void BF_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);
+ BF_encode(&(ctx->m_key), &IVL, &IVR);
+ RTL_CIPHER_HTONL64(IVL, IVR, iv, 8);
+
+ rtl_secureZeroMemory(&IVL, sizeof(IVL));
+ rtl_secureZeroMemory(&IVR, sizeof(IVR));
+ }
+
+ if (direction == rtl_Cipher_DirectionEncode)
+ {
+ iv[k] ^= *pData;
+ *pBuffer = iv[k];
+ }
+ else
+ {
+ sal_uInt8 c = iv[k];
+ iv[k] = *pData;
+ *pBuffer = *pData ^ c;
+ }
+
+ ctx->m_offset = ((k + 1) & 0x07);
+ iv = nullptr;
+}
+
+static void BF_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 ^= BF (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;
+
+}
+
+static void BF_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 ^= BF (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;
+
+}
+
+static sal_uInt32 BF(CipherKeyBF *key, sal_uInt32 x)
+{
+ sal_uInt16 a, b, c, d;
+ sal_uInt32 y;
+
+ d = static_cast<sal_uInt16>(x & 0x00ff);
+ x >>= 8;
+ c = static_cast<sal_uInt16>(x & 0x00ff);
+ x >>= 8;
+ b = static_cast<sal_uInt16>(x & 0x00ff);
+ x >>= 8;
+ a = static_cast<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;
+}
+#endif
+
+/**
+ rtl_cipherBF (Blowfish) implementation.
+
+ Reference: Bruce Schneier: Applied Cryptography, 2nd edition, ch. 14.3
+*/
+rtlCipher SAL_CALL rtl_cipher_createBF(rtlCipherMode Mode) SAL_THROW_EXTERN_C()
+{
+ CipherBF_Impl *pImpl = nullptr;
+
+ if (Mode == rtl_Cipher_ModeInvalid)
+ return nullptr;
+#if defined LIBO_CIPHER_OPENSSL_BACKEND
+ if (Mode != rtl_Cipher_ModeStream) {
+ // Cannot easily support ModeECB and ModeCBC, and they aren't used in the LO code at least:
+ return nullptr;
+ }
+#endif
+
+ pImpl = static_cast<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 static_cast<rtlCipher>(pImpl);
+}
+
+rtlCipherError SAL_CALL rtl_cipher_initBF(
+ rtlCipher Cipher,
+ rtlCipherDirection Direction,
+ const sal_uInt8 *pKeyData, sal_Size nKeyLen,
+ const sal_uInt8 *pArgData, sal_Size nArgLen) SAL_THROW_EXTERN_C()
+{
+ CipherBF_Impl *pImpl = static_cast<CipherBF_Impl*>(Cipher);
+
+ if (!pImpl || !pKeyData)
+ 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;
+
+#if defined LIBO_CIPHER_OPENSSL_BACKEND
+ if (pImpl->m_cipher.m_direction == rtl_Cipher_DirectionBoth) {
+ // Cannot easily support DirectionBoth, and it isn't used in the LO code at least:
+ return rtl_Cipher_E_Direction;
+ }
+ if (nKeyLen > o3tl::make_unsigned(std::numeric_limits<int>::max())) {
+ return rtl_Cipher_E_BufferSize;
+ }
+ if (pImpl->m_context.m_context != nullptr) {
+ EVP_CIPHER_CTX_free(pImpl->m_context.m_context);
+ }
+ pImpl->m_context.m_context = EVP_CIPHER_CTX_new();
+ if (pImpl->m_context.m_context == nullptr) {
+ return rtl_Cipher_E_Memory;
+ }
+ unsigned char iv[8];
+ auto const n = std::min(nArgLen, sal_Size(8));
+ std::memcpy(iv, pArgData, n);
+ std::memset(iv + n, 0, 8 - n);
+ if (EVP_CipherInit_ex(
+ pImpl->m_context.m_context, EVP_bf_cfb(), nullptr, nullptr, iv,
+ pImpl->m_cipher.m_direction == rtl_Cipher_DirectionDecode ? 0 : 1)
+ == 0)
+ {
+ return rtl_Cipher_E_Unknown;
+ }
+ if (EVP_CIPHER_CTX_set_key_length(pImpl->m_context.m_context, static_cast<int>(nKeyLen)) == 0) {
+ return rtl_Cipher_E_Unknown;
+ }
+ if (EVP_CipherInit_ex(pImpl->m_context.m_context, nullptr, nullptr, pKeyData, nullptr, -1) == 0)
+ {
+ return rtl_Cipher_E_Unknown;
+ }
+ return rtl_Cipher_E_None;
+#else
+ return BF_init(
+ &(pImpl->m_context), pImpl->m_cipher.m_mode,
+ pKeyData, nKeyLen, pArgData, nArgLen);
+#endif
+}
+
+rtlCipherError SAL_CALL rtl_cipher_encodeBF(
+ rtlCipher Cipher,
+ const void *pData, sal_Size nDatLen,
+ sal_uInt8 *pBuffer, sal_Size nBufLen) SAL_THROW_EXTERN_C()
+{
+ CipherBF_Impl *pImpl = static_cast<CipherBF_Impl*>(Cipher);
+ if (!pImpl)
+ 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 BF_update(
+ &(pImpl->m_context), pImpl->m_cipher.m_mode,
+ rtl_Cipher_DirectionEncode,
+ static_cast<const sal_uInt8*>(pData), nDatLen, pBuffer, nBufLen);
+}
+
+rtlCipherError SAL_CALL rtl_cipher_decodeBF(
+ rtlCipher Cipher,
+ const void *pData, sal_Size nDatLen,
+ sal_uInt8 *pBuffer, sal_Size nBufLen) SAL_THROW_EXTERN_C()
+{
+ CipherBF_Impl *pImpl = static_cast<CipherBF_Impl*>(Cipher);
+ if (!pImpl)
+ 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 BF_update(
+ &(pImpl->m_context), pImpl->m_cipher.m_mode,
+ rtl_Cipher_DirectionDecode,
+ static_cast<const sal_uInt8*>(pData), nDatLen, pBuffer, nBufLen);
+}
+
+void SAL_CALL rtl_cipher_destroyBF(rtlCipher Cipher) SAL_THROW_EXTERN_C()
+{
+ CipherBF_Impl *pImpl = static_cast<CipherBF_Impl*>(Cipher);
+ if (!pImpl)
+ return;
+
+ if (pImpl->m_cipher.m_algorithm == rtl_Cipher_AlgorithmBF)
+ {
+#if defined LIBO_CIPHER_OPENSSL_BACKEND
+ if (pImpl->m_context.m_context != nullptr) {
+ EVP_CIPHER_CTX_free(pImpl->m_context.m_context);
+ }
+#endif
+ rtl_freeZeroMemory(pImpl, sizeof(CipherBF_Impl));
+ }
+ else
+ free(pImpl);
+}
+
+#if !defined LIBO_CIPHER_OPENSSL_BACKEND
+#define CIPHER_CBLOCK_ARCFOUR 256
+#endif
+
+namespace {
+
+struct ContextARCFOUR_Impl
+{
+#if defined LIBO_CIPHER_OPENSSL_BACKEND
+ EVP_CIPHER_CTX * m_context;
+#else
+ unsigned int m_S[CIPHER_CBLOCK_ARCFOUR];
+ unsigned int m_X, m_Y;
+#endif
+};
+
+struct CipherARCFOUR_Impl
+{
+ Cipher_Impl m_cipher;
+ ContextARCFOUR_Impl m_context;
+};
+
+}
+
+static rtlCipherError rtl_cipherARCFOUR_update_Impl(
+ ContextARCFOUR_Impl *ctx,
+ const sal_uInt8 *pData, sal_Size nDatLen,
+ sal_uInt8 *pBuffer, sal_Size nBufLen);
+
+static rtlCipherError rtl_cipherARCFOUR_init_Impl(
+ ContextARCFOUR_Impl *ctx,
+ const sal_uInt8 *pKeyData, sal_Size nKeyLen)
+{
+#if defined LIBO_CIPHER_OPENSSL_BACKEND
+ if (nKeyLen > o3tl::make_unsigned(std::numeric_limits<int>::max())) {
+ return rtl_Cipher_E_BufferSize;
+ }
+ if (ctx->m_context != nullptr) {
+ EVP_CIPHER_CTX_free(ctx->m_context);
+ }
+ ctx->m_context = EVP_CIPHER_CTX_new();
+ if (ctx->m_context == nullptr) {
+ return rtl_Cipher_E_Memory;
+ }
+ if (EVP_CipherInit_ex(ctx->m_context, EVP_rc4(), nullptr, nullptr, nullptr, 0) == 0) {
+ // RC4 en- and decryption is identical, so we can use 0=decrypt regardless of direction,
+ // and thus also support rtl_Cipher_DirectionBoth
+ return rtl_Cipher_E_Unknown;
+ }
+ if (EVP_CIPHER_CTX_set_key_length(ctx->m_context, static_cast<int>(nKeyLen)) == 0) {
+ return rtl_Cipher_E_Unknown;
+ }
+ if (EVP_CipherInit_ex(ctx->m_context, nullptr, nullptr, pKeyData, nullptr, -1) == 0) {
+ return rtl_Cipher_E_Unknown;
+ }
+#else
+ unsigned int K[CIPHER_CBLOCK_ARCFOUR];
+ unsigned int *L, *S;
+ unsigned int x, y;
+ 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;
+ /* swap S[x] and S[y] */
+ unsigned int t = S[x];
+ S[x] = S[y];
+ S[y] = t;
+ }
+
+ /* Initialize counters X and Y. */
+ ctx->m_X = 0;
+ ctx->m_Y = 0;
+#endif
+
+ return rtl_Cipher_E_None;
+}
+
+static rtlCipherError rtl_cipherARCFOUR_update_Impl(
+ ContextARCFOUR_Impl *ctx,
+ const sal_uInt8 *pData, sal_Size nDatLen,
+ sal_uInt8 *pBuffer, sal_Size nBufLen)
+{
+ /* Check arguments. */
+ if (!pData || !pBuffer)
+ return rtl_Cipher_E_Argument;
+
+ if (!((0 < nDatLen) && (nDatLen <= nBufLen)))
+ return rtl_Cipher_E_BufferSize;
+
+#if defined LIBO_CIPHER_OPENSSL_BACKEND
+ while (nDatLen > o3tl::make_unsigned(std::numeric_limits<int>::max())) {
+ int outl;
+ if (EVP_CipherUpdate(ctx->m_context, pBuffer, &outl, pData, std::numeric_limits<int>::max())
+ == 0)
+ {
+ return rtl_Cipher_E_Unknown;
+ }
+ assert(outl == std::numeric_limits<int>::max());
+ pData += std::numeric_limits<int>::max();
+ nDatLen -= std::numeric_limits<int>::max();
+ pBuffer += std::numeric_limits<int>::max();
+ }
+ int outl;
+ if (EVP_CipherUpdate(ctx->m_context, pBuffer, &outl, pData, static_cast<int>(nDatLen)) == 0) {
+ return rtl_Cipher_E_Unknown;
+ }
+ assert(outl == static_cast<int>(nDatLen));
+ // A final call to EVP_CipherFinal_ex is intentionally missing; it wouldn't fit the rtl/cipher.h
+ // interface, and is hopefully not needed, as each individual RC4 update step doesn't hold back
+ // any data that would need to be finally flushed.
+#else
+ unsigned int *S;
+ sal_Size k;
+
+ /* Update. */
+ S = &(ctx->m_S[0]);
+ for (k = 0; k < nDatLen; k++)
+ {
+ /* Update counters X and Y. */
+ unsigned int x = ctx->m_X;
+ unsigned int 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]. */
+ unsigned int 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] ^ static_cast<sal_uInt8>(S[t] & 0xff);
+ }
+#endif
+
+ return rtl_Cipher_E_None;
+}
+
+/**
+ rtl_cipher_ARCFOUR (RC4) implementation.
+
+ Reference: Bruce Schneier: Applied Cryptography, 2nd edition, ch. 17.1
+*/
+rtlCipher SAL_CALL rtl_cipher_createARCFOUR(rtlCipherMode Mode)
+ SAL_THROW_EXTERN_C()
+{
+ CipherARCFOUR_Impl *pImpl = nullptr;
+
+ if (Mode != rtl_Cipher_ModeStream)
+ return nullptr;
+
+ pImpl = static_cast<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 static_cast<rtlCipher>(pImpl);
+}
+
+rtlCipherError SAL_CALL rtl_cipher_initARCFOUR(
+ rtlCipher Cipher,
+ rtlCipherDirection Direction,
+ const sal_uInt8 *pKeyData, sal_Size nKeyLen,
+ SAL_UNUSED_PARAMETER const sal_uInt8 *, SAL_UNUSED_PARAMETER sal_Size)
+ SAL_THROW_EXTERN_C()
+{
+ CipherARCFOUR_Impl *pImpl = static_cast<CipherARCFOUR_Impl*>(Cipher);
+
+ if (!pImpl || !pKeyData)
+ 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);
+}
+
+rtlCipherError SAL_CALL rtl_cipher_encodeARCFOUR(
+ rtlCipher Cipher,
+ const void *pData, sal_Size nDatLen,
+ sal_uInt8 *pBuffer, sal_Size nBufLen) SAL_THROW_EXTERN_C()
+{
+ CipherARCFOUR_Impl *pImpl = static_cast<CipherARCFOUR_Impl*>(Cipher);
+ if (!pImpl)
+ 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),
+ static_cast<const sal_uInt8*>(pData), nDatLen, pBuffer, nBufLen);
+}
+
+rtlCipherError SAL_CALL rtl_cipher_decodeARCFOUR(
+ rtlCipher Cipher,
+ const void *pData, sal_Size nDatLen,
+ sal_uInt8 *pBuffer, sal_Size nBufLen) SAL_THROW_EXTERN_C()
+{
+ CipherARCFOUR_Impl *pImpl = static_cast<CipherARCFOUR_Impl*>(Cipher);
+ if (!pImpl)
+ 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),
+ static_cast<const sal_uInt8*>(pData), nDatLen, pBuffer, nBufLen);
+}
+
+void SAL_CALL rtl_cipher_destroyARCFOUR(rtlCipher Cipher) SAL_THROW_EXTERN_C()
+{
+ CipherARCFOUR_Impl *pImpl = static_cast<CipherARCFOUR_Impl*>(Cipher);
+ if (!pImpl)
+ return;
+
+ if (pImpl->m_cipher.m_algorithm == rtl_Cipher_AlgorithmARCFOUR)
+ {
+#if defined LIBO_CIPHER_OPENSSL_BACKEND
+ if (pImpl->m_context.m_context != nullptr) {
+ EVP_CIPHER_CTX_free(pImpl->m_context.m_context);
+ }
+#endif
+ rtl_freeZeroMemory(pImpl, sizeof(CipherARCFOUR_Impl));
+ }
+ else
+ free(pImpl);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/cmdargs.cxx b/sal/rtl/cmdargs.cxx
new file mode 100644
index 000000000..8eb328258
--- /dev/null
+++ b/sal/rtl/cmdargs.cxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/mutex.hxx>
+#include <rtl/alloc.h>
+#include <rtl/process.h>
+#include <rtl/ustring.hxx>
+
+namespace {
+
+rtl_uString ** g_ppCommandArgs = nullptr;
+sal_uInt32 g_nCommandArgCount = 0;
+
+struct ArgHolder
+{
+ ~ArgHolder();
+};
+
+ArgHolder::~ArgHolder()
+{
+ while (g_nCommandArgCount > 0)
+ rtl_uString_release (g_ppCommandArgs[--g_nCommandArgCount]);
+
+ free (g_ppCommandArgs);
+ g_ppCommandArgs = nullptr;
+}
+
+// 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)
+ return;
+
+ sal_Int32 i, n = osl_getCommandArgCount();
+
+ g_ppCommandArgs =
+ static_cast<rtl_uString**>(rtl_allocateZeroMemory (n * sizeof(rtl_uString*)));
+ for (i = 0; i < n; i++)
+ {
+ rtl_uString * pArg = nullptr;
+ osl_getCommandArg (i, &pArg);
+ if ((pArg->buffer[0] == '-' || pArg->buffer[0] == '/') &&
+ pArg->buffer[1] == 'e' &&
+ pArg->buffer[2] == 'n' &&
+ pArg->buffer[3] == 'v' &&
+ 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()
+{
+ init();
+ return g_nCommandArgCount;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/crc.cxx b/sal/rtl/crc.cxx
new file mode 100644
index 000000000..479281e76
--- /dev/null
+++ b/sal/rtl/crc.cxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#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
+};
+
+#define UPDCRC32(crc, octet) \
+ (rtl_crc32Table[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
+
+sal_uInt32 SAL_CALL rtl_crc32 (
+ sal_uInt32 Crc,
+ const void *Data, sal_uInt32 DatLen) SAL_THROW_EXTERN_C()
+{
+ if (Data)
+ {
+ const sal_uInt8 *p = static_cast<const sal_uInt8 *>(Data);
+ const sal_uInt8 *q = p + DatLen;
+
+ Crc = ~Crc;
+
+ while (p < q)
+ {
+ Crc = UPDCRC32(Crc, *(p++));
+ }
+
+ Crc = ~Crc;
+ }
+ return Crc;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/digest.cxx b/sal/rtl/digest.cxx
new file mode 100644
index 000000000..55af5ad7c
--- /dev/null
+++ b/sal/rtl/digest.cxx
@@ -0,0 +1,1897 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <sal/types.h>
+#include <osl/endian.h>
+#include <rtl/alloc.h>
+#include <rtl/digest.h>
+
+#define RTL_DIGEST_CREATE(T) (static_cast<T*>(rtl_allocateZeroMemory(sizeof(T))))
+
+#define RTL_DIGEST_ROTL(a,n) (((a) << (n)) | ((a) >> (32 - (n))))
+
+#define RTL_DIGEST_HTONL(l,c) \
+ (*((c)++) = static_cast<sal_uInt8>(((l) >> 24) & 0xff), \
+ *((c)++) = static_cast<sal_uInt8>(((l) >> 16) & 0xff), \
+ *((c)++) = static_cast<sal_uInt8>(((l) >> 8) & 0xff), \
+ *((c)++) = static_cast<sal_uInt8>(((l) ) & 0xff))
+
+#define RTL_DIGEST_LTOC(l,c) \
+ *((c)++) = static_cast<sal_uInt8>(((l) ) & 0xff); \
+ *((c)++) = static_cast<sal_uInt8>(((l) >> 8) & 0xff); \
+ *((c)++) = static_cast<sal_uInt8>(((l) >> 16) & 0xff); \
+ *((c)++) = static_cast<sal_uInt8>(((l) >> 24) & 0xff);
+
+typedef rtlDigestError (Digest_init_t) (
+ void *ctx, const sal_uInt8 *Data, sal_uInt32 DatLen);
+
+typedef void (Digest_delete_t) (void *ctx);
+
+typedef rtlDigestError (Digest_update_t) (
+ void *ctx, const void *Data, sal_uInt32 DatLen);
+
+typedef rtlDigestError (Digest_get_t) (
+ void *ctx, sal_uInt8 *Buffer, sal_uInt32 BufLen);
+
+namespace {
+
+struct Digest_Impl
+{
+ 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;
+};
+
+}
+
+static void swapLong(sal_uInt32 *pData, sal_uInt32 nDatLen)
+{
+ sal_uInt32 *X;
+ int i, n;
+
+ X = pData;
+ n = nDatLen;
+
+ for (i = 0; i < n; i++)
+ {
+ X[i] = OSL_SWAPDWORD(X[i]);
+ }
+}
+
+rtlDigest SAL_CALL rtl_digest_create(rtlDigestAlgorithm Algorithm)
+ SAL_THROW_EXTERN_C()
+{
+ rtlDigest Digest = nullptr;
+ 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;
+}
+
+rtlDigestAlgorithm SAL_CALL rtl_digest_queryAlgorithm(rtlDigest Digest)
+ SAL_THROW_EXTERN_C()
+{
+ Digest_Impl *pImpl = static_cast<Digest_Impl *>(Digest);
+ if (pImpl)
+ return pImpl->m_algorithm;
+ return rtl_Digest_AlgorithmInvalid;
+}
+
+sal_uInt32 SAL_CALL rtl_digest_queryLength(rtlDigest Digest)
+ SAL_THROW_EXTERN_C()
+{
+ Digest_Impl *pImpl = static_cast<Digest_Impl *>(Digest);
+ if (pImpl)
+ return pImpl->m_length;
+ return 0;
+}
+
+rtlDigestError SAL_CALL rtl_digest_init(
+ rtlDigest Digest, const sal_uInt8 *pData, sal_uInt32 nDatLen)
+ SAL_THROW_EXTERN_C()
+{
+ Digest_Impl *pImpl = static_cast<Digest_Impl *>(Digest);
+ if (pImpl)
+ {
+ if (pImpl->m_init)
+ return pImpl->m_init (Digest, pData, nDatLen);
+ return rtl_Digest_E_None;
+ }
+ return rtl_Digest_E_Argument;
+}
+
+rtlDigestError SAL_CALL rtl_digest_update(
+ rtlDigest Digest, const void *pData, sal_uInt32 nDatLen)
+ SAL_THROW_EXTERN_C()
+{
+ Digest_Impl *pImpl = static_cast<Digest_Impl *>(Digest);
+ if (pImpl && pImpl->m_update)
+ return pImpl->m_update(Digest, pData, nDatLen);
+ return rtl_Digest_E_Argument;
+}
+
+rtlDigestError SAL_CALL rtl_digest_get(
+ rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen)
+ SAL_THROW_EXTERN_C()
+{
+ Digest_Impl *pImpl = static_cast<Digest_Impl *>(Digest);
+ if (pImpl && pImpl->m_get)
+ return pImpl->m_get(Digest, pBuffer, nBufLen);
+ return rtl_Digest_E_Argument;
+}
+
+void SAL_CALL rtl_digest_destroy(rtlDigest Digest) SAL_THROW_EXTERN_C()
+{
+ Digest_Impl *pImpl = static_cast<Digest_Impl *>(Digest);
+ if (pImpl && pImpl->m_delete)
+ pImpl->m_delete(Digest);
+}
+
+#define DIGEST_CBLOCK_MD2 16
+#define DIGEST_LBLOCK_MD2 16
+
+namespace {
+
+struct DigestContextMD2
+{
+ 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];
+};
+
+struct DigestMD2_Impl
+{
+ Digest_Impl m_digest;
+ DigestContextMD2 m_context;
+};
+
+}
+
+static void initMD2 (DigestContextMD2 *ctx);
+static void updateMD2 (DigestContextMD2 *ctx);
+static void 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,
+};
+
+static const Digest_Impl MD2 =
+{
+ rtl_Digest_AlgorithmMD2,
+ RTL_DIGEST_LENGTH_MD2,
+ nullptr,
+ rtl_digest_destroyMD2,
+ rtl_digest_updateMD2,
+ rtl_digest_getMD2
+};
+
+static void initMD2(DigestContextMD2 *ctx)
+{
+ memset(ctx, 0, sizeof(DigestContextMD2));
+}
+
+static void updateMD2(DigestContextMD2 *ctx)
+{
+ sal_uInt8 *X;
+ sal_uInt32 *sp1, *sp2;
+ 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);
+ }
+
+ memcpy(sp1, state, 16 * sizeof(sal_uInt32));
+ rtl_secureZeroMemory(state, 48 * sizeof(sal_uInt32));
+}
+
+static void endMD2(DigestContextMD2 *ctx)
+{
+ sal_uInt8 *X;
+ 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] = static_cast<sal_uInt8>(n & 0xff);
+
+ updateMD2(ctx);
+
+ for (i = 0; i < DIGEST_CBLOCK_MD2; i++)
+ X[i] = static_cast<sal_uInt8>(C[i] & 0xff);
+ updateMD2(ctx);
+}
+
+rtlDigestError SAL_CALL rtl_digest_MD2(
+ const void *pData, sal_uInt32 nDatLen,
+ sal_uInt8 *pBuffer, sal_uInt32 nBufLen) SAL_THROW_EXTERN_C()
+{
+ DigestMD2_Impl digest;
+ rtlDigestError result;
+
+ digest.m_digest = MD2;
+ 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_secureZeroMemory(&digest, sizeof(digest));
+ return result;
+}
+
+rtlDigest SAL_CALL rtl_digest_createMD2() SAL_THROW_EXTERN_C()
+{
+ DigestMD2_Impl *pImpl = RTL_DIGEST_CREATE(DigestMD2_Impl);
+ if (pImpl)
+ {
+ pImpl->m_digest = MD2;
+ initMD2(&(pImpl->m_context));
+ }
+ return static_cast<rtlDigest>(pImpl);
+}
+
+rtlDigestError SAL_CALL rtl_digest_updateMD2(
+ rtlDigest Digest, const void *pData, sal_uInt32 nDatLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestMD2_Impl *pImpl = static_cast<DigestMD2_Impl *>(Digest);
+ const sal_uInt8 *d = static_cast<const sal_uInt8 *>(pData);
+
+ DigestContextMD2 *ctx;
+
+ if (!pImpl || !pData)
+ 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)
+ {
+ memcpy(p, d, nDatLen);
+ ctx->m_nDatLen += nDatLen;
+
+ return rtl_Digest_E_None;
+ }
+
+ memcpy(p, d, n);
+ d += n;
+ nDatLen -= n;
+
+ updateMD2(ctx);
+ ctx->m_nDatLen = 0;
+ }
+
+ while (nDatLen >= DIGEST_CBLOCK_MD2)
+ {
+ memcpy(ctx->m_pData, d, DIGEST_CBLOCK_MD2);
+ d += DIGEST_CBLOCK_MD2;
+ nDatLen -= DIGEST_CBLOCK_MD2;
+
+ updateMD2(ctx);
+ }
+
+ memcpy(ctx->m_pData, d, nDatLen);
+ ctx->m_nDatLen = nDatLen;
+
+ return rtl_Digest_E_None;
+}
+
+rtlDigestError SAL_CALL rtl_digest_getMD2(
+ rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestMD2_Impl *pImpl = static_cast<DigestMD2_Impl *>(Digest);
+ sal_uInt32 i;
+
+ DigestContextMD2 *ctx;
+
+ if (!pImpl || !pBuffer)
+ 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);
+
+ endMD2(ctx);
+ for (i = 0; i < DIGEST_CBLOCK_MD2; i++)
+ {
+ pBuffer[i] = static_cast<sal_uInt8>(ctx->m_state[i] & 0xff);
+ }
+
+ initMD2(ctx);
+
+ return rtl_Digest_E_None;
+}
+
+void SAL_CALL rtl_digest_destroyMD2(rtlDigest Digest) SAL_THROW_EXTERN_C()
+{
+ DigestMD2_Impl *pImpl = static_cast<DigestMD2_Impl *>(Digest);
+ if (pImpl)
+ {
+ if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmMD2)
+ rtl_freeZeroMemory(pImpl, sizeof(DigestMD2_Impl));
+ else
+ free(pImpl);
+ }
+}
+
+#define DIGEST_CBLOCK_MD5 64
+#define DIGEST_LBLOCK_MD5 16
+
+namespace {
+
+struct DigestContextMD5
+{
+ 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;
+};
+
+struct DigestMD5_Impl
+{
+ Digest_Impl m_digest;
+ DigestContextMD5 m_context;
+};
+
+}
+
+static void initMD5 (DigestContextMD5 *ctx);
+static void updateMD5 (DigestContextMD5 *ctx);
+static void 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; }
+
+static const Digest_Impl MD5 =
+{
+ rtl_Digest_AlgorithmMD5,
+ RTL_DIGEST_LENGTH_MD5,
+ nullptr,
+ rtl_digest_destroyMD5,
+ rtl_digest_updateMD5,
+ rtl_digest_getMD5
+};
+
+static void initMD5(DigestContextMD5 *ctx)
+{
+ memset(ctx, 0, 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);
+}
+
+static void updateMD5(DigestContextMD5 *ctx)
+{
+ sal_uInt32 A, B, C, D;
+ 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;
+}
+
+static void endMD5(DigestContextMD5 *ctx)
+{
+ static const sal_uInt8 end[4] =
+ {
+ 0x80, 0x00, 0x00, 0x00
+ };
+ const sal_uInt8 *p = end;
+
+ sal_uInt32 *X;
+ int i;
+
+ X = ctx->m_pData;
+ i = (ctx->m_nDatLen >> 2);
+
+#ifdef OSL_BIGENDIAN
+ 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] = static_cast<sal_uInt32>(*(p++)) << 0;
+ [[fallthrough]];
+ case 1: X[i] |= static_cast<sal_uInt32>(*(p++)) << 8;
+ [[fallthrough]];
+ case 2: X[i] |= static_cast<sal_uInt32>(*(p++)) << 16;
+ [[fallthrough]];
+ case 3: X[i] |= static_cast<sal_uInt32>(*p) << 24;
+ }
+
+ i += 1;
+
+ if (i > (DIGEST_LBLOCK_MD5 - 2))
+ {
+ for (; i < DIGEST_LBLOCK_MD5; i++)
+ {
+ X[i] = 0;
+ }
+
+ 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;
+
+ updateMD5(ctx);
+}
+
+rtlDigestError SAL_CALL rtl_digest_MD5(
+ const void *pData, sal_uInt32 nDatLen,
+ sal_uInt8 *pBuffer, sal_uInt32 nBufLen) SAL_THROW_EXTERN_C()
+{
+ DigestMD5_Impl digest;
+ rtlDigestError result;
+
+ digest.m_digest = MD5;
+ 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_secureZeroMemory(&digest, sizeof(digest));
+ return result;
+}
+
+rtlDigest SAL_CALL rtl_digest_createMD5() SAL_THROW_EXTERN_C()
+{
+ DigestMD5_Impl *pImpl = RTL_DIGEST_CREATE(DigestMD5_Impl);
+ if (pImpl)
+ {
+ pImpl->m_digest = MD5;
+ initMD5(&(pImpl->m_context));
+ }
+ return static_cast<rtlDigest>(pImpl);
+}
+
+rtlDigestError SAL_CALL rtl_digest_updateMD5(
+ rtlDigest Digest, const void *pData, sal_uInt32 nDatLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestMD5_Impl *pImpl = static_cast<DigestMD5_Impl *>(Digest);
+ const sal_uInt8 *d = static_cast<const sal_uInt8 *>(pData);
+
+ DigestContextMD5 *ctx;
+ sal_uInt32 len;
+
+ if (!pImpl || !pData)
+ 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 = reinterpret_cast<sal_uInt8 *>(ctx->m_pData) + ctx->m_nDatLen;
+ sal_uInt32 n = DIGEST_CBLOCK_MD5 - ctx->m_nDatLen;
+
+ if (nDatLen < n)
+ {
+ memcpy(p, d, nDatLen);
+ ctx->m_nDatLen += nDatLen;
+
+ return rtl_Digest_E_None;
+ }
+
+ memcpy(p, d, n);
+ d += n;
+ nDatLen -= n;
+
+#ifdef OSL_BIGENDIAN
+ swapLong(ctx->m_pData, DIGEST_LBLOCK_MD5);
+#endif /* OSL_BIGENDIAN */
+
+ updateMD5(ctx);
+ ctx->m_nDatLen = 0;
+ }
+
+ while (nDatLen >= DIGEST_CBLOCK_MD5)
+ {
+ memcpy(ctx->m_pData, d, DIGEST_CBLOCK_MD5);
+ d += DIGEST_CBLOCK_MD5;
+ nDatLen -= DIGEST_CBLOCK_MD5;
+
+#ifdef OSL_BIGENDIAN
+ swapLong(ctx->m_pData, DIGEST_LBLOCK_MD5);
+#endif /* OSL_BIGENDIAN */
+
+ updateMD5(ctx);
+ }
+
+ memcpy(ctx->m_pData, d, nDatLen);
+ ctx->m_nDatLen = nDatLen;
+
+ return rtl_Digest_E_None;
+}
+
+rtlDigestError SAL_CALL rtl_digest_getMD5(
+ rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestMD5_Impl *pImpl = static_cast<DigestMD5_Impl *>(Digest);
+ sal_uInt8 *p = pBuffer;
+
+ DigestContextMD5 *ctx;
+
+ if (!pImpl || !pBuffer)
+ 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);
+
+ 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);
+ initMD5(ctx);
+
+ return rtl_Digest_E_None;
+}
+
+rtlDigestError SAL_CALL rtl_digest_rawMD5(
+ rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestMD5_Impl *pImpl = static_cast<DigestMD5_Impl *>(Digest);
+ sal_uInt8 *p = pBuffer;
+
+ DigestContextMD5 *ctx;
+
+ if (!pImpl || !pBuffer)
+ 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);
+
+ /* 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);
+ initMD5(ctx);
+
+ return rtl_Digest_E_None;
+}
+
+void SAL_CALL rtl_digest_destroyMD5(rtlDigest Digest) SAL_THROW_EXTERN_C()
+{
+ DigestMD5_Impl *pImpl = static_cast<DigestMD5_Impl *>(Digest);
+ if (pImpl)
+ {
+ if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmMD5)
+ rtl_freeZeroMemory(pImpl, sizeof(DigestMD5_Impl));
+ else
+ free(pImpl);
+ }
+}
+
+#define DIGEST_CBLOCK_SHA 64
+#define DIGEST_LBLOCK_SHA 16
+
+typedef sal_uInt32 DigestSHA_update_t(sal_uInt32 x);
+
+static sal_uInt32 updateSHA_0(sal_uInt32 x);
+static sal_uInt32 updateSHA_1(sal_uInt32 x);
+
+namespace {
+
+struct DigestContextSHA
+{
+ 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;
+};
+
+struct DigestSHA_Impl
+{
+ Digest_Impl m_digest;
+ DigestContextSHA m_context;
+};
+
+}
+
+static void initSHA(
+ DigestContextSHA *ctx, DigestSHA_update_t *fct);
+
+static void updateSHA(DigestContextSHA *ctx);
+static void 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);
+
+static void initSHA(
+ DigestContextSHA *ctx, DigestSHA_update_t *fct)
+{
+ memset(ctx, 0, 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);
+}
+
+static void updateSHA(DigestContextSHA *ctx)
+{
+ sal_uInt32 A, B, C, D, E, T;
+ sal_uInt32 *X;
+
+ 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;
+}
+
+static void endSHA(DigestContextSHA *ctx)
+{
+ static const sal_uInt8 end[4] =
+ {
+ 0x80, 0x00, 0x00, 0x00
+ };
+ const sal_uInt8 *p = end;
+
+ sal_uInt32 *X;
+ int i;
+
+ X = ctx->m_pData;
+ i = (ctx->m_nDatLen >> 2);
+
+#ifdef OSL_BIGENDIAN
+ 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] = static_cast<sal_uInt32>(*(p++)) << 0;
+ [[fallthrough]];
+ case 1: X[i] |= static_cast<sal_uInt32>(*(p++)) << 8;
+ [[fallthrough]];
+ case 2: X[i] |= static_cast<sal_uInt32>(*(p++)) << 16;
+ [[fallthrough]];
+ case 3: X[i] |= static_cast<sal_uInt32>(*(p++)) << 24;
+ }
+
+ swapLong(X, i + 1);
+
+ i += 1;
+
+ // tdf#114939 NB: this is WRONG and should be ">" not ">=" but is not
+ // fixed as this buggy SHA1 implementation is needed for compatibility
+ if (i >= (DIGEST_LBLOCK_SHA - 2))
+ {
+ for (; i < DIGEST_LBLOCK_SHA; i++)
+ {
+ X[i] = 0;
+ }
+
+ 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;
+
+ updateSHA(ctx);
+}
+
+static const Digest_Impl SHA_0 =
+{
+ rtl_Digest_AlgorithmSHA,
+ RTL_DIGEST_LENGTH_SHA,
+ nullptr,
+ rtl_digest_destroySHA,
+ rtl_digest_updateSHA,
+ rtl_digest_getSHA
+};
+
+static sal_uInt32 updateSHA_0(sal_uInt32 x)
+{
+ return x;
+}
+
+rtlDigestError SAL_CALL rtl_digest_SHA(
+ const void *pData, sal_uInt32 nDatLen,
+ sal_uInt8 *pBuffer, sal_uInt32 nBufLen) SAL_THROW_EXTERN_C()
+{
+ DigestSHA_Impl digest;
+ rtlDigestError result;
+
+ digest.m_digest = SHA_0;
+ initSHA(&(digest.m_context), updateSHA_0);
+
+ result = rtl_digest_updateSHA(&digest, pData, nDatLen);
+ if (result == rtl_Digest_E_None)
+ result = rtl_digest_getSHA(&digest, pBuffer, nBufLen);
+
+ rtl_secureZeroMemory(&digest, sizeof(digest));
+ return result;
+}
+
+rtlDigest SAL_CALL rtl_digest_createSHA() SAL_THROW_EXTERN_C()
+{
+ DigestSHA_Impl *pImpl = RTL_DIGEST_CREATE(DigestSHA_Impl);
+ if (pImpl)
+ {
+ pImpl->m_digest = SHA_0;
+ initSHA(&(pImpl->m_context), updateSHA_0);
+ }
+ return static_cast<rtlDigest>(pImpl);
+}
+
+rtlDigestError SAL_CALL rtl_digest_updateSHA(
+ rtlDigest Digest, const void *pData, sal_uInt32 nDatLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestSHA_Impl *pImpl = static_cast<DigestSHA_Impl *>(Digest);
+ const sal_uInt8 *d = static_cast<const sal_uInt8 *>(pData);
+
+ DigestContextSHA *ctx;
+ sal_uInt32 len;
+
+ if (!pImpl || !pData)
+ 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 = reinterpret_cast<sal_uInt8 *>(ctx->m_pData) + ctx->m_nDatLen;
+ sal_uInt32 n = DIGEST_CBLOCK_SHA - ctx->m_nDatLen;
+
+ if (nDatLen < n)
+ {
+ memcpy(p, d, nDatLen);
+ ctx->m_nDatLen += nDatLen;
+
+ return rtl_Digest_E_None;
+ }
+
+ memcpy(p, d, n);
+ d += n;
+ nDatLen -= n;
+
+#ifndef OSL_BIGENDIAN
+ swapLong(ctx->m_pData, DIGEST_LBLOCK_SHA);
+#endif /* OSL_BIGENDIAN */
+
+ updateSHA(ctx);
+ ctx->m_nDatLen = 0;
+ }
+
+ while (nDatLen >= DIGEST_CBLOCK_SHA)
+ {
+ memcpy(ctx->m_pData, d, DIGEST_CBLOCK_SHA);
+ d += DIGEST_CBLOCK_SHA;
+ nDatLen -= DIGEST_CBLOCK_SHA;
+
+#ifndef OSL_BIGENDIAN
+ swapLong(ctx->m_pData, DIGEST_LBLOCK_SHA);
+#endif /* OSL_BIGENDIAN */
+
+ updateSHA(ctx);
+ }
+
+ memcpy(ctx->m_pData, d, nDatLen);
+ ctx->m_nDatLen = nDatLen;
+
+ return rtl_Digest_E_None;
+}
+
+rtlDigestError SAL_CALL rtl_digest_getSHA(
+ rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestSHA_Impl *pImpl = static_cast<DigestSHA_Impl *>(Digest);
+ sal_uInt8 *p = pBuffer;
+
+ DigestContextSHA *ctx;
+
+ if (!pImpl || !pBuffer)
+ 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);
+
+ 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);
+ initSHA(ctx, updateSHA_0);
+
+ return rtl_Digest_E_None;
+}
+
+void SAL_CALL rtl_digest_destroySHA(rtlDigest Digest) SAL_THROW_EXTERN_C()
+{
+ DigestSHA_Impl *pImpl = static_cast< DigestSHA_Impl * >(Digest);
+ if (pImpl)
+ {
+ if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmSHA)
+ rtl_freeZeroMemory(pImpl, sizeof(DigestSHA_Impl));
+ else
+ free(pImpl);
+ }
+}
+
+static const Digest_Impl SHA_1 =
+{
+ rtl_Digest_AlgorithmSHA1,
+ RTL_DIGEST_LENGTH_SHA1,
+ nullptr,
+ rtl_digest_destroySHA1,
+ rtl_digest_updateSHA1,
+ rtl_digest_getSHA1
+};
+
+static sal_uInt32 updateSHA_1(sal_uInt32 x)
+{
+ return RTL_DIGEST_ROTL(x, 1);
+}
+
+rtlDigestError SAL_CALL rtl_digest_SHA1(
+ const void *pData, sal_uInt32 nDatLen,
+ sal_uInt8 *pBuffer, sal_uInt32 nBufLen) SAL_THROW_EXTERN_C()
+{
+ DigestSHA_Impl digest;
+ rtlDigestError result;
+
+ digest.m_digest = SHA_1;
+ initSHA(&(digest.m_context), updateSHA_1);
+
+ result = rtl_digest_updateSHA1(&digest, pData, nDatLen);
+ if (result == rtl_Digest_E_None)
+ result = rtl_digest_getSHA1(&digest, pBuffer, nBufLen);
+
+ rtl_secureZeroMemory(&digest, sizeof(digest));
+ return result;
+}
+
+rtlDigest SAL_CALL rtl_digest_createSHA1() SAL_THROW_EXTERN_C()
+{
+ DigestSHA_Impl *pImpl = RTL_DIGEST_CREATE(DigestSHA_Impl);
+ if (pImpl)
+ {
+ pImpl->m_digest = SHA_1;
+ initSHA(&(pImpl->m_context), updateSHA_1);
+ }
+ return static_cast<rtlDigest>(pImpl);
+}
+
+rtlDigestError SAL_CALL rtl_digest_updateSHA1(
+ rtlDigest Digest, const void *pData, sal_uInt32 nDatLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestSHA_Impl *pImpl = static_cast< DigestSHA_Impl * >(Digest);
+ const sal_uInt8 *d = static_cast< const sal_uInt8 * >(pData);
+
+ DigestContextSHA *ctx;
+ sal_uInt32 len;
+
+ if (!pImpl || !pData)
+ 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 = reinterpret_cast<sal_uInt8 *>(ctx->m_pData) + ctx->m_nDatLen;
+ sal_uInt32 n = DIGEST_CBLOCK_SHA - ctx->m_nDatLen;
+
+ if (nDatLen < n)
+ {
+ memcpy(p, d, nDatLen);
+ ctx->m_nDatLen += nDatLen;
+
+ return rtl_Digest_E_None;
+ }
+
+ memcpy(p, d, n);
+ d += n;
+ nDatLen -= n;
+
+#ifndef OSL_BIGENDIAN
+ swapLong(ctx->m_pData, DIGEST_LBLOCK_SHA);
+#endif /* OSL_BIGENDIAN */
+
+ updateSHA(ctx);
+ ctx->m_nDatLen = 0;
+ }
+
+ while (nDatLen >= DIGEST_CBLOCK_SHA)
+ {
+ memcpy(ctx->m_pData, d, DIGEST_CBLOCK_SHA);
+ d += DIGEST_CBLOCK_SHA;
+ nDatLen -= DIGEST_CBLOCK_SHA;
+
+#ifndef OSL_BIGENDIAN
+ swapLong(ctx->m_pData, DIGEST_LBLOCK_SHA);
+#endif /* OSL_BIGENDIAN */
+
+ updateSHA(ctx);
+ }
+
+ memcpy(ctx->m_pData, d, nDatLen);
+ ctx->m_nDatLen = nDatLen;
+
+ return rtl_Digest_E_None;
+}
+
+rtlDigestError SAL_CALL rtl_digest_getSHA1 (
+ rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestSHA_Impl *pImpl = static_cast<DigestSHA_Impl *>(Digest);
+ sal_uInt8 *p = pBuffer;
+
+ DigestContextSHA *ctx;
+
+ if (!pImpl || !pBuffer)
+ 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);
+
+ 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);
+ initSHA(ctx, updateSHA_1);
+
+ return rtl_Digest_E_None;
+}
+
+void SAL_CALL rtl_digest_destroySHA1(rtlDigest Digest) SAL_THROW_EXTERN_C()
+{
+ DigestSHA_Impl *pImpl = static_cast< DigestSHA_Impl * >(Digest);
+ if (pImpl)
+ {
+ if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmSHA1)
+ rtl_freeZeroMemory(pImpl, sizeof(DigestSHA_Impl));
+ else
+ free(pImpl);
+ }
+}
+
+#define DIGEST_CBLOCK_HMAC_MD5 64
+
+namespace {
+
+struct ContextHMAC_MD5
+{
+ DigestMD5_Impl m_hash;
+ sal_uInt8 m_opad[DIGEST_CBLOCK_HMAC_MD5];
+};
+
+struct DigestHMAC_MD5_Impl
+{
+ Digest_Impl m_digest;
+ ContextHMAC_MD5 m_context;
+};
+
+}
+
+static void initHMAC_MD5(ContextHMAC_MD5 * ctx);
+static void ipadHMAC_MD5(ContextHMAC_MD5 * ctx);
+static void opadHMAC_MD5(ContextHMAC_MD5 * ctx);
+
+static const Digest_Impl 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
+};
+
+static void initHMAC_MD5(ContextHMAC_MD5 * ctx)
+{
+ DigestMD5_Impl *pImpl = &(ctx->m_hash);
+
+ pImpl->m_digest = MD5;
+ initMD5(&(pImpl->m_context));
+
+ memset(ctx->m_opad, 0, DIGEST_CBLOCK_HMAC_MD5);
+}
+
+static void ipadHMAC_MD5(ContextHMAC_MD5 * ctx)
+{
+ 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;
+ }
+}
+
+static void opadHMAC_MD5(ContextHMAC_MD5 * ctx)
+{
+ sal_uInt32 i;
+
+ for (i = 0; i < DIGEST_CBLOCK_HMAC_MD5; i++)
+ {
+ ctx->m_opad[i] ^= 0x5c;
+ }
+}
+
+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) SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_MD5_Impl digest;
+ rtlDigestError result;
+
+ digest.m_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_secureZeroMemory(&digest, sizeof(digest));
+ return result;
+}
+
+rtlDigest SAL_CALL rtl_digest_createHMAC_MD5() SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_MD5_Impl *pImpl = RTL_DIGEST_CREATE(DigestHMAC_MD5_Impl);
+ if (pImpl)
+ {
+ pImpl->m_digest = HMAC_MD5;
+ initHMAC_MD5(&(pImpl->m_context));
+ }
+ return static_cast< rtlDigest >(pImpl);
+}
+
+rtlDigestError SAL_CALL rtl_digest_initHMAC_MD5(
+ rtlDigest Digest, const sal_uInt8 *pKeyData, sal_uInt32 nKeyLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_MD5_Impl *pImpl = static_cast< DigestHMAC_MD5_Impl* >(Digest);
+ ContextHMAC_MD5 *ctx;
+
+ if (!pImpl || !pKeyData)
+ return rtl_Digest_E_Argument;
+
+ if (pImpl->m_digest.m_algorithm != rtl_Digest_AlgorithmHMAC_MD5)
+ return rtl_Digest_E_Algorithm;
+
+ ctx = &(pImpl->m_context);
+ 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' */
+ memcpy(ctx->m_opad, pKeyData, nKeyLen);
+ }
+
+ ipadHMAC_MD5(ctx);
+ opadHMAC_MD5(ctx);
+
+ return rtl_Digest_E_None;
+}
+
+rtlDigestError SAL_CALL rtl_digest_updateHMAC_MD5(
+ rtlDigest Digest, const void *pData, sal_uInt32 nDatLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_MD5_Impl *pImpl = static_cast< DigestHMAC_MD5_Impl* >(Digest);
+ ContextHMAC_MD5 *ctx;
+
+ if (!pImpl || !pData)
+ 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;
+}
+
+rtlDigestError SAL_CALL rtl_digest_getHMAC_MD5(
+ rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_MD5_Impl *pImpl = static_cast<DigestHMAC_MD5_Impl*>(Digest);
+ ContextHMAC_MD5 *ctx;
+
+ if (!pImpl || !pBuffer)
+ 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);
+
+ opadHMAC_MD5(ctx);
+ ipadHMAC_MD5(ctx);
+ opadHMAC_MD5(ctx);
+
+ return rtl_Digest_E_None;
+}
+
+void SAL_CALL rtl_digest_destroyHMAC_MD5(rtlDigest Digest) SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_MD5_Impl *pImpl = static_cast< DigestHMAC_MD5_Impl* >(Digest);
+ if (pImpl)
+ {
+ if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmHMAC_MD5)
+ rtl_freeZeroMemory(pImpl, sizeof(DigestHMAC_MD5_Impl));
+ else
+ free(pImpl);
+ }
+}
+
+#define DIGEST_CBLOCK_HMAC_SHA1 64
+
+namespace {
+
+struct ContextHMAC_SHA1
+{
+ DigestSHA_Impl m_hash;
+ sal_uInt8 m_opad[DIGEST_CBLOCK_HMAC_SHA1];
+};
+
+struct DigestHMAC_SHA1_Impl
+{
+ Digest_Impl m_digest;
+ ContextHMAC_SHA1 m_context;
+};
+
+}
+
+static void initHMAC_SHA1(ContextHMAC_SHA1 * ctx);
+static void ipadHMAC_SHA1(ContextHMAC_SHA1 * ctx);
+static void opadHMAC_SHA1(ContextHMAC_SHA1 * ctx);
+
+static const Digest_Impl 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
+};
+
+static void initHMAC_SHA1(ContextHMAC_SHA1 * ctx)
+{
+ DigestSHA_Impl *pImpl = &(ctx->m_hash);
+
+ pImpl->m_digest = SHA_1;
+ initSHA(&(pImpl->m_context), updateSHA_1);
+
+ memset(ctx->m_opad, 0, DIGEST_CBLOCK_HMAC_SHA1);
+}
+
+static void ipadHMAC_SHA1(ContextHMAC_SHA1 * ctx)
+{
+ 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;
+ }
+}
+
+static void opadHMAC_SHA1(ContextHMAC_SHA1 * ctx)
+{
+ sal_uInt32 i;
+
+ for (i = 0; i < DIGEST_CBLOCK_HMAC_SHA1; i++)
+ {
+ ctx->m_opad[i] ^= 0x5c;
+ }
+}
+
+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) SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_SHA1_Impl digest;
+ rtlDigestError result;
+
+ digest.m_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_secureZeroMemory(&digest, sizeof(digest));
+ return result;
+}
+
+rtlDigest SAL_CALL rtl_digest_createHMAC_SHA1() SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_SHA1_Impl *pImpl = RTL_DIGEST_CREATE(DigestHMAC_SHA1_Impl);
+ if (pImpl)
+ {
+ pImpl->m_digest = HMAC_SHA1;
+ initHMAC_SHA1(&(pImpl->m_context));
+ }
+ return static_cast<rtlDigest>(pImpl);
+}
+
+rtlDigestError SAL_CALL rtl_digest_initHMAC_SHA1(
+ rtlDigest Digest, const sal_uInt8 *pKeyData, sal_uInt32 nKeyLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_SHA1_Impl *pImpl = static_cast<DigestHMAC_SHA1_Impl*>(Digest);
+ ContextHMAC_SHA1 *ctx;
+
+ if (!pImpl || !pKeyData)
+ return rtl_Digest_E_Argument;
+
+ if (pImpl->m_digest.m_algorithm != rtl_Digest_AlgorithmHMAC_SHA1)
+ return rtl_Digest_E_Algorithm;
+
+ ctx = &(pImpl->m_context);
+ 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' */
+ memcpy(ctx->m_opad, pKeyData, nKeyLen);
+ }
+
+ ipadHMAC_SHA1(ctx);
+ opadHMAC_SHA1(ctx);
+
+ return rtl_Digest_E_None;
+}
+
+rtlDigestError SAL_CALL rtl_digest_updateHMAC_SHA1(
+ rtlDigest Digest, const void *pData, sal_uInt32 nDatLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_SHA1_Impl *pImpl = static_cast<DigestHMAC_SHA1_Impl*>(Digest);
+ ContextHMAC_SHA1 *ctx;
+
+ if (!pImpl || !pData)
+ 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;
+}
+
+rtlDigestError SAL_CALL rtl_digest_getHMAC_SHA1(
+ rtlDigest Digest, sal_uInt8 *pBuffer, sal_uInt32 nBufLen)
+ SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_SHA1_Impl *pImpl = static_cast<DigestHMAC_SHA1_Impl*>(Digest);
+ ContextHMAC_SHA1 *ctx;
+
+ if (!pImpl || !pBuffer)
+ 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);
+
+ opadHMAC_SHA1(ctx);
+ ipadHMAC_SHA1(ctx);
+ opadHMAC_SHA1(ctx);
+
+ return rtl_Digest_E_None;
+}
+
+void SAL_CALL rtl_digest_destroyHMAC_SHA1(rtlDigest Digest)
+ SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_SHA1_Impl *pImpl = static_cast<DigestHMAC_SHA1_Impl*>(Digest);
+ if (pImpl)
+ {
+ if (pImpl->m_digest.m_algorithm == rtl_Digest_AlgorithmHMAC_SHA1)
+ rtl_freeZeroMemory(pImpl, sizeof(DigestHMAC_SHA1_Impl));
+ else
+ free(pImpl);
+ }
+}
+
+#define DIGEST_CBLOCK_PBKDF2 RTL_DIGEST_LENGTH_HMAC_SHA1
+
+static void 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];
+ 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_secureZeroMemory(U, DIGEST_CBLOCK_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) SAL_THROW_EXTERN_C()
+{
+ DigestHMAC_SHA1_Impl digest;
+ sal_uInt32 i = 1;
+
+ if (!pKeyData || !pPassData || !pSaltData)
+ return rtl_Digest_E_Argument;
+
+ digest.m_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) */
+ 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) */
+ updatePBKDF2(
+ &digest, T,
+ pSaltData, nSaltLen,
+ nCount, OSL_NETDWORD(i));
+
+ /* DK ||= T_(i) */
+ memcpy(pKeyData, T, nKeyLen);
+ rtl_secureZeroMemory(T, DIGEST_CBLOCK_PBKDF2);
+ }
+
+ rtl_secureZeroMemory(&digest, sizeof(digest));
+ return rtl_Digest_E_None;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/hash.cxx b/sal/rtl/hash.cxx
new file mode 100644
index 000000000..4fed60889
--- /dev/null
+++ b/sal/rtl/hash.cxx
@@ -0,0 +1,241 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <stdlib.h>
+
+#include "hash.hxx"
+#include "strimp.hxx"
+#include <osl/diagnose.h>
+#include <sal/macros.h>
+
+namespace {
+
+struct StringHashTableImpl {
+ sal_uInt32 nEntries;
+ sal_uInt32 nSize;
+ rtl_uString **pData;
+};
+
+}
+
+typedef StringHashTableImpl StringHashTable;
+
+// Only for use in the implementation
+static StringHashTable *rtl_str_hash_new(sal_uInt32 nSize);
+static void rtl_str_hash_free(StringHashTable *pHash);
+
+static StringHashTable * getHashTable()
+{
+ static StringHashTable* pInternPool = rtl_str_hash_new(1024);
+ return pInternPool;
+}
+
+// Better / smaller / faster hash set...
+
+// TODO: add bottom bit-set list terminator to string list
+
+static sal_uInt32 getNextSize(sal_uInt32 nSize)
+{
+ // Sedgewick - Algorithms in C P577.
+ static const sal_uInt32 nPrimes[] = { 1021, 2039, 4093, 8191, 16381, 32749,
+ 65521, 131071,262139, 524287, 1048573,
+ 2097143, 4194301, 8388593, 16777213,
+ 33554393, 67108859, 134217689 };
+
+ for (sal_uInt32 nPrime : nPrimes)
+ {
+ if (nPrime > nSize)
+ return nPrime;
+ }
+ return nSize * 2;
+}
+
+static sal_uInt32 hashString(rtl_uString *pString)
+{
+ return static_cast<sal_uInt32>(rtl_ustr_hashCode_WithLength(pString->buffer,
+ pString->length));
+}
+
+static StringHashTable * rtl_str_hash_new(sal_uInt32 nSize)
+{
+ StringHashTable *pHash = static_cast<StringHashTable *>(malloc(sizeof(StringHashTable)));
+
+ pHash->nEntries = 0;
+ pHash->nSize = getNextSize (nSize);
+ pHash->pData = static_cast< rtl_uString ** >(calloc(sizeof(rtl_uString *), pHash->nSize));
+
+ return pHash;
+}
+
+static void rtl_str_hash_free(StringHashTable *pHash)
+{
+ if (!pHash)
+ return;
+
+ if (pHash->pData)
+ free(pHash->pData);
+
+ free(pHash);
+}
+
+static void
+rtl_str_hash_insert_nonequal(StringHashTable *pHash,
+ rtl_uString *pString)
+{
+ sal_uInt32 nHash = hashString(pString);
+ sal_uInt32 n;
+
+ n = nHash % pHash->nSize;
+ while (pHash->pData[n])
+ {
+ n++;
+ if (n >= pHash->nSize)
+ n = 0;
+ }
+ pHash->pData[n] = pString;
+}
+
+static void rtl_str_hash_resize(sal_uInt32 nNewSize)
+{
+ sal_uInt32 i;
+ StringHashTable *pNewHash;
+ StringHashTable *pHash = getHashTable();
+
+ OSL_ASSERT(nNewSize > pHash->nEntries);
+
+ pNewHash = rtl_str_hash_new(nNewSize);
+
+ for (i = 0; i < pHash->nSize; i++)
+ {
+ if (pHash->pData[i])
+ rtl_str_hash_insert_nonequal(pNewHash, pHash->pData[i]);
+ }
+
+ pNewHash->nEntries = pHash->nEntries;
+ free(pHash->pData);
+ *pHash = *pNewHash;
+ pNewHash->pData = nullptr;
+ rtl_str_hash_free(pNewHash);
+}
+
+static bool compareEqual(rtl_uString *pStringA, rtl_uString *pStringB)
+{
+ 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);
+}
+
+rtl_uString * rtl_str_hash_intern (
+ rtl_uString *pString,
+ int can_return)
+{
+ sal_uInt32 nHash = hashString(pString);
+ sal_uInt32 n;
+ rtl_uString *pHashStr;
+
+ StringHashTable *pHash = getHashTable();
+
+ // Should we resize ?
+ if (pHash->nEntries >= pHash->nSize/2)
+ rtl_str_hash_resize(getNextSize(pHash->nSize));
+
+ n = nHash % pHash->nSize;
+ while ((pHashStr = pHash->pData[n]))
+ {
+ if (compareEqual(pHashStr, pString))
+ {
+ rtl_uString_acquire(pHashStr);
+ return pHashStr;
+ }
+
+ n++;
+ if (n >= pHash->nSize)
+ n = 0;
+ }
+
+ if (!can_return)
+ {
+ rtl_uString *pCopy = nullptr;
+ rtl_uString_newFromString( &pCopy, pString );
+ pString = pCopy;
+
+ if (!pString)
+ return nullptr;
+ }
+
+ if (!SAL_STRING_IS_STATIC(pString))
+ pString->refCount |= SAL_STRING_INTERN_FLAG;
+
+ pHash->pData[n] = pString;
+ pHash->nEntries++;
+
+ return pString;
+}
+
+void rtl_str_hash_remove(rtl_uString *pString)
+{
+ sal_uInt32 n;
+ sal_uInt32 nHash = hashString(pString);
+ rtl_uString *pHashStr;
+
+ StringHashTable *pHash = getHashTable();
+
+ n = nHash % pHash->nSize;
+ while ((pHashStr = pHash->pData[n]))
+ {
+ if (compareEqual(pHashStr, pString))
+ break;
+
+ n++;
+
+ if (n >= pHash->nSize)
+ n = 0;
+ }
+
+ OSL_ASSERT(pHash->pData[n]);
+ if (!pHash->pData[n])
+ return;
+
+ pHash->pData[n++] = nullptr;
+ pHash->nEntries--;
+
+ if (n >= pHash->nSize)
+ n = 0;
+
+ while ((pHashStr = pHash->pData[n]))
+ {
+ pHash->pData[n] = nullptr;
+ // FIXME: rather unsophisticated and N^2 in chain-length, but robust.
+ rtl_str_hash_insert_nonequal(pHash, pHashStr);
+ n++;
+
+ if (n >= pHash->nSize)
+ n = 0;
+ }
+ // FIXME: Should we down-size ?
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/hash.hxx b/sal/rtl/hash.hxx
new file mode 100644
index 000000000..9f80448e7
--- /dev/null
+++ b/sal/rtl/hash.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SAL_RTL_HASH_HXX
+#define INCLUDED_SAL_RTL_HASH_HXX
+
+#include <rtl/ustring.h>
+
+/* 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);
+
+#endif // INCLUDED_SAL_RTL_HASH_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/locale.cxx b/sal/rtl/locale.cxx
new file mode 100644
index 000000000..bae0f40b3
--- /dev/null
+++ b/sal/rtl/locale.cxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stdlib.h>
+#include <rtl/locale.h>
+
+#include <osl/diagnose.h>
+
+#include <rtllifecycle.h>
+#include <memory>
+#include <unordered_map>
+
+namespace {
+
+struct locale_deleter
+{
+ void operator() (rtl_Locale* p) noexcept
+ {
+ rtl_uString_release(p->Language);
+ rtl_uString_release(p->Country);
+ rtl_uString_release(p->Variant);
+ delete p;
+ }
+};
+
+}
+
+using locale_unique_ptr = std::unique_ptr<rtl_Locale, locale_deleter>;
+
+static std::unordered_map<sal_Int32, locale_unique_ptr>* g_pLocaleTable = nullptr;
+
+static rtl_Locale* g_pDefaultLocale = nullptr;
+
+void rtl_locale_init()
+{
+ if (!g_pLocaleTable)
+ g_pLocaleTable = new std::unordered_map<sal_Int32, locale_unique_ptr>;
+}
+
+void rtl_locale_fini()
+{
+ if (g_pLocaleTable)
+ {
+ delete g_pLocaleTable;
+ g_pLocaleTable = nullptr;
+ }
+ g_pDefaultLocale = nullptr;
+}
+
+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 = nullptr;
+ rtl_uString* sCountry = nullptr;
+ rtl_uString* sVariant = nullptr;
+ sal_Int32 hashCode = -1;
+
+ if (!country)
+ country = &c;
+
+ if (!variant)
+ variant = &c;
+
+ ensureLocaleSingleton();
+
+ hashCode = rtl_ustr_hashCode(language) ^ rtl_ustr_hashCode(country) ^ rtl_ustr_hashCode(variant);
+
+ auto it = g_pLocaleTable->find(hashCode);
+ if (it != g_pLocaleTable->end())
+ return it->second.get();
+
+ rtl_uString_newFromStr(&sLanguage, language);
+ rtl_uString_newFromStr(&sCountry, country);
+ rtl_uString_newFromStr(&sVariant, variant);
+
+ locale_unique_ptr newLocale(new rtl_Locale);
+
+ newLocale->Language = sLanguage;
+ newLocale->Country = sCountry;
+ newLocale->Variant = sVariant;
+ newLocale->HashCode = hashCode;
+
+ auto ret = newLocale.get();
+ g_pLocaleTable->insert(it, std::pair<sal_Int32, locale_unique_ptr>( hashCode, std::move(newLocale) ) );
+ return ret;
+}
+
+rtl_Locale * SAL_CALL rtl_locale_getDefault()
+{
+ return g_pDefaultLocale;
+}
+
+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_uString * SAL_CALL rtl_locale_getLanguage(rtl_Locale * This)
+{
+ rtl_uString_acquire(This->Language);
+ return This->Language;
+}
+
+rtl_uString * SAL_CALL rtl_locale_getCountry(rtl_Locale * This)
+{
+ rtl_uString_acquire(This->Country);
+ return This->Country;
+}
+
+rtl_uString * SAL_CALL rtl_locale_getVariant(rtl_Locale * This)
+{
+ rtl_uString_acquire(This->Variant);
+ return This->Variant;
+}
+
+sal_Int32 SAL_CALL rtl_locale_hashCode(rtl_Locale * This)
+{
+ return This->HashCode;
+}
+
+sal_Int32 SAL_CALL rtl_locale_equals(rtl_Locale * This, rtl_Locale * obj)
+{
+ return This == obj;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/math.cxx b/sal/rtl/math.cxx
new file mode 100644
index 000000000..bd9d2c8a6
--- /dev/null
+++ b/sal/rtl/math.cxx
@@ -0,0 +1,1410 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rtl/math.h>
+
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <rtl/alloc.h>
+#include <rtl/character.hxx>
+#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 <cassert>
+#include <float.h>
+#include <limits>
+#include <limits.h>
+#include <math.h>
+#include <memory>
+#include <stdlib.h>
+
+#include <dtoa.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)
+ {
+ // && -nExp > 0 necessary for std::numeric_limits<int>::min()
+ // because -nExp = nExp
+ if (-nExp <= n10Count && -nExp > 0)
+ return n10s[1][-nExp-1];
+ return pow(10.0, static_cast<double>(nExp));
+ }
+ if (nExp > 0)
+ {
+ if (nExp <= n10Count)
+ return n10s[0][nExp-1];
+
+ return pow(10.0, static_cast<double>(nExp));
+ }
+ return 1.0;
+}
+
+namespace {
+
+double const nCorrVal[] = {
+ 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 void createString(rtl_String ** pString,
+ char const * pChars, sal_Int32 nLen)
+ {
+ rtl_string_newFromStr_WithLength(pString, pChars, nLen);
+ }
+
+ static void createBuffer(rtl_String ** pBuffer,
+ const sal_Int32 * pCapacity)
+ {
+ rtl_string_new_WithLength(pBuffer, *pCapacity);
+ }
+
+ static void appendChars(rtl_String ** pBuffer, sal_Int32 * pCapacity,
+ sal_Int32 * pOffset, char const * pChars,
+ sal_Int32 nLen)
+ {
+ assert(pChars);
+ rtl_stringbuffer_insert(pBuffer, pCapacity, *pOffset, pChars, nLen);
+ *pOffset += nLen;
+ }
+
+ static void appendAscii(rtl_String ** pBuffer, sal_Int32 * pCapacity,
+ sal_Int32 * pOffset, char const * pStr,
+ sal_Int32 nLen)
+ {
+ assert(pStr);
+ rtl_stringbuffer_insert(pBuffer, pCapacity, *pOffset, pStr, nLen);
+ *pOffset += nLen;
+ }
+};
+
+struct UStringTraits
+{
+ typedef sal_Unicode Char;
+
+ typedef rtl_uString String;
+
+ static void createString(rtl_uString ** pString,
+ sal_Unicode const * pChars, sal_Int32 nLen)
+ {
+ rtl_uString_newFromStr_WithLength(pString, pChars, nLen);
+ }
+
+ static void createBuffer(rtl_uString ** pBuffer,
+ const sal_Int32 * pCapacity)
+ {
+ rtl_uString_new_WithLength(pBuffer, *pCapacity);
+ }
+
+ static void appendChars(rtl_uString ** pBuffer,
+ sal_Int32 * pCapacity, sal_Int32 * pOffset,
+ sal_Unicode const * pChars, sal_Int32 nLen)
+ {
+ assert(pChars);
+ rtl_uStringbuffer_insert(pBuffer, pCapacity, *pOffset, pChars, nLen);
+ *pOffset += nLen;
+ }
+
+ static void appendAscii(rtl_uString ** pBuffer,
+ sal_Int32 * pCapacity, sal_Int32 * pOffset,
+ char const * pStr, sal_Int32 nLen)
+ {
+ rtl_uStringbuffer_insert_ascii(pBuffer, pCapacity, *pOffset, pStr,
+ nLen);
+ *pOffset += nLen;
+ }
+};
+
+/** If value (passed as absolute value) is an integer representable as double,
+ which we handle explicitly at some places.
+ */
+bool isRepresentableInteger(double fAbsValue)
+{
+ assert(fAbsValue >= 0.0);
+ const sal_Int64 kMaxInt = (static_cast< sal_Int64 >(1) << 53) - 1;
+ if (fAbsValue <= static_cast< double >(kMaxInt))
+ {
+ sal_Int64 nInt = static_cast< sal_Int64 >(fAbsValue);
+ // Check the integer range again because double comparison may yield
+ // true within the precision range.
+ // XXX loplugin:fpcomparison complains about floating-point comparison
+ // for static_cast<double>(nInt) == fAbsValue, though we actually want
+ // this here.
+ if (nInt > kMaxInt)
+ return false;
+ double fInt = static_cast< double >(nInt);
+ return !(fInt < fAbsValue) && !(fInt > fAbsValue);
+ }
+ return false;
+}
+
+// Returns 1-based index of least significant bit in a number, or zero if number is zero
+int findFirstSetBit(unsigned n)
+{
+#if defined _WIN32
+ unsigned long pos;
+ unsigned char bNonZero = _BitScanForward(&pos, n);
+ return (bNonZero == 0) ? 0 : pos + 1;
+#else
+ return __builtin_ffs(n);
+#endif
+}
+
+/** Returns number of binary bits for fractional part of the number
+ Expects a proper non-negative double value, not +-INF, not NAN
+ */
+int getBitsInFracPart(double fAbsValue)
+{
+ assert(std::isfinite(fAbsValue) && fAbsValue >= 0.0);
+ if (fAbsValue == 0.0)
+ return 0;
+ auto pValParts = reinterpret_cast< const sal_math_Double * >(&fAbsValue);
+ int nExponent = pValParts->inf_parts.exponent - 1023;
+ if (nExponent >= 52)
+ return 0; // All bits in fraction are in integer part of the number
+ int nLeastSignificant = findFirstSetBit(pValParts->inf_parts.fraction_lo);
+ if (nLeastSignificant == 0)
+ {
+ nLeastSignificant = findFirstSetBit(pValParts->inf_parts.fraction_hi);
+ if (nLeastSignificant == 0)
+ nLeastSignificant = 53; // the implied leading 1 is the least significant
+ else
+ nLeastSignificant += 32;
+ }
+ int nFracSignificant = 53 - nLeastSignificant;
+ int nBitsInFracPart = nFracSignificant - nExponent;
+
+ return std::max(nBitsInFracPart, 0);
+}
+
+template< typename T >
+void doubleToString(typename T::String ** 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 = std::signbit(fValue);
+
+ if (bSign)
+ fValue = -fValue;
+
+ if (std::isnan(fValue))
+ {
+ // #i112652# XMLSchema-2
+ sal_Int32 nCapacity = RTL_CONSTASCII_LENGTH("NaN");
+ if (!pResultCapacity)
+ {
+ 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 || std::isinf(fValue))
+ {
+ // #i112652# XMLSchema-2
+ sal_Int32 nCapacity = RTL_CONSTASCII_LENGTH("-INF");
+ if (!pResultCapacity)
+ {
+ 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;
+ }
+
+ // Unfortunately the old rounding below writes 1.79769313486232e+308 for
+ // DBL_MAX and 4 subsequent nextafter(...,0).
+ static const double fB1 = std::nextafter( DBL_MAX, 0);
+ static const double fB2 = std::nextafter( fB1, 0);
+ static const double fB3 = std::nextafter( fB2, 0);
+ static const double fB4 = std::nextafter( fB3, 0);
+ if ((fValue >= fB4) && eFormat != rtl_math_StringFormat_F)
+ {
+ // 1.7976931348623157e+308 instead of rounded 1.79769313486232e+308
+ // that can't be converted back as out of range. For rounded values if
+ // they exceed range they should not be written to exchange strings or
+ // file formats.
+
+ // Writing pDig up to decimals(-1,-2) then appending one digit from
+ // pRou xor one or two digits from pSlot[].
+ constexpr char pDig[] = "7976931348623157";
+ constexpr char pRou[] = "8087931359623267"; // the only up-carry is 80
+ static_assert(SAL_N_ELEMENTS(pDig) == SAL_N_ELEMENTS(pRou), "digit count mismatch");
+ constexpr sal_Int32 nDig2 = RTL_CONSTASCII_LENGTH(pRou) - 2;
+ sal_Int32 nCapacity = RTL_CONSTASCII_LENGTH(pRou) + 8; // + "-1.E+308"
+ const char pSlot[5][2][3] =
+ { // rounded, not
+ "67", "57", // DBL_MAX
+ "65", "55",
+ "53", "53",
+ "51", "51",
+ "59", "49",
+ };
+
+ if (!pResultCapacity)
+ {
+ pResultCapacity = &nCapacity;
+ T::createBuffer(pResult, pResultCapacity);
+ nResultOffset = 0;
+ }
+
+ if (bSign)
+ T::appendAscii(pResult, pResultCapacity, &nResultOffset,
+ RTL_CONSTASCII_STRINGPARAM("-"));
+
+ nDecPlaces = std::clamp<sal_Int32>( nDecPlaces, 0, RTL_CONSTASCII_LENGTH(pRou));
+ if (nDecPlaces == 0)
+ {
+ T::appendAscii(pResult, pResultCapacity, &nResultOffset,
+ RTL_CONSTASCII_STRINGPARAM("2"));
+ }
+ else
+ {
+ T::appendAscii(pResult, pResultCapacity, &nResultOffset,
+ RTL_CONSTASCII_STRINGPARAM("1"));
+ T::appendChars(pResult, pResultCapacity, &nResultOffset, &cDecSeparator, 1);
+ if (nDecPlaces <= 2)
+ {
+ T::appendAscii(pResult, pResultCapacity, &nResultOffset, pRou, nDecPlaces);
+ }
+ else if (nDecPlaces <= nDig2)
+ {
+ T::appendAscii(pResult, pResultCapacity, &nResultOffset, pDig, nDecPlaces - 1);
+ T::appendAscii(pResult, pResultCapacity, &nResultOffset, pRou + nDecPlaces - 1, 1);
+ }
+ else
+ {
+ const sal_Int32 nDec = nDecPlaces - nDig2;
+ nDecPlaces -= nDec;
+ // nDec-1 is also offset into slot, rounded(1-1=0) or not(2-1=1)
+ const size_t nSlot = ((fValue < fB3) ? 4 : ((fValue < fB2) ? 3
+ : ((fValue < fB1) ? 2 : ((fValue < DBL_MAX) ? 1 : 0))));
+
+ T::appendAscii(pResult, pResultCapacity, &nResultOffset, pDig, nDecPlaces);
+ T::appendAscii(pResult, pResultCapacity, &nResultOffset, pSlot[nSlot][nDec-1], nDec);
+ }
+ }
+ T::appendAscii(pResult, pResultCapacity, &nResultOffset,
+ RTL_CONSTASCII_STRINGPARAM("E+308"));
+
+ return;
+ }
+
+ // Use integer representation for integer values that fit into the
+ // mantissa (1.((2^53)-1)) with a precision of 1 for highest accuracy.
+ const sal_Int64 kMaxInt = (static_cast< sal_Int64 >(1) << 53) - 1;
+ if ((eFormat == rtl_math_StringFormat_Automatic ||
+ eFormat == rtl_math_StringFormat_F) && fValue <= static_cast< double >(kMaxInt))
+ {
+ sal_Int64 nInt = static_cast< sal_Int64 >(fValue);
+ // Check the integer range again because double comparison may yield
+ // true within the precision range.
+ if (nInt <= kMaxInt && static_cast< double >(nInt) == fValue)
+ {
+ if (nDecPlaces == rtl_math_DecimalPlaces_Max)
+ nDecPlaces = 0;
+ else
+ nDecPlaces = ::std::max< sal_Int32 >(::std::min<sal_Int32>(nDecPlaces, 15), -15);
+
+ if (bEraseTrailingDecZeros && nDecPlaces > 0)
+ nDecPlaces = 0;
+
+ // Round before decimal position.
+ if (nDecPlaces < 0)
+ {
+ sal_Int64 nRounding = static_cast< sal_Int64 >(getN10Exp(-nDecPlaces - 1));
+ sal_Int64 nTemp = nInt / nRounding;
+ int nDigit = nTemp % 10;
+ nTemp /= 10;
+
+ if (nDigit >= 5)
+ ++nTemp;
+
+ nTemp *= 10;
+ nTemp *= nRounding;
+ nInt = nTemp;
+ nDecPlaces = 0;
+ }
+
+ // Max 1 sign, 16 integer digits, 15 group separators, 1 decimal
+ // separator, 15 decimals digits.
+ typename T::Char aBuf[64];
+ typename T::Char * pBuf = aBuf;
+ typename T::Char * p = pBuf;
+
+ // Backward fill.
+ size_t nGrouping = 0;
+ sal_Int32 nGroupDigits = 0;
+ do
+ {
+ typename T::Char nDigit = nInt % 10;
+ nInt /= 10;
+ *p++ = nDigit + '0';
+ if (pGroups && pGroups[nGrouping] == ++nGroupDigits && nInt > 0 && cGroupSeparator)
+ {
+ *p++ = cGroupSeparator;
+ if (pGroups[nGrouping+1])
+ ++nGrouping;
+ nGroupDigits = 0;
+ }
+ }
+ while (nInt > 0);
+ if (bSign)
+ *p++ = '-';
+
+ // Reverse buffer content.
+ sal_Int32 n = (p - pBuf) / 2;
+ for (sal_Int32 i=0; i < n; ++i)
+ {
+ ::std::swap( pBuf[i], p[-i-1]);
+ }
+
+ // Append decimals.
+ if (nDecPlaces > 0)
+ {
+ *p++ = cDecSeparator;
+ while (nDecPlaces--)
+ *p++ = '0';
+ }
+
+ if (!pResultCapacity)
+ T::createString(pResult, pBuf, p - pBuf);
+ else
+ T::appendChars(pResult, pResultCapacity, &nResultOffset, pBuf, p - pBuf);
+
+ return;
+ }
+ }
+
+ // find the exponent
+ int nExp = 0;
+ if ( fValue > 0.0 )
+ {
+ // Cap nExp at a small value beyond which "fValue /= N10Exp" would lose precision (or N10Exp
+ // might even be zero); that will produce output with the decimal point in a non-normalized
+ // position, but the current quality of output for such small values is probably abysmal,
+ // anyway:
+ nExp = std::max(
+ static_cast< int >(floor(log10(fValue))), std::numeric_limits<double>::min_exponent10);
+ double const N10Exp = getN10Exp(nExp);
+ assert(N10Exp != 0);
+ fValue /= N10Exp;
+ }
+
+ switch (eFormat)
+ {
+ case rtl_math_StringFormat_Automatic:
+ { // E or F depending on exponent magnitude
+ int nPrec;
+ if (nExp <= -15 || nExp >= 15) // was <-16, >16 in ancient versions, which leads to inaccuracies
+ {
+ 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 :
+ case rtl_math_StringFormat_G1 :
+ case rtl_math_StringFormat_G2 :
+ { // 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);
+
+ if (eFormat == rtl_math_StringFormat_G)
+ eFormat = rtl_math_StringFormat_E;
+ else if (eFormat == rtl_math_StringFormat_G2)
+ eFormat = rtl_math_StringFormat_E2;
+ else if (eFormat == rtl_math_StringFormat_G1)
+ eFormat = rtl_math_StringFormat_E1;
+ }
+ else
+ {
+ nDecPlaces = std::max< sal_Int32 >(0, nDecPlaces - nExp - 1);
+ eFormat = rtl_math_StringFormat_F;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Too large values for nDecPlaces make no sense; it might also be
+ // rtl_math_DecimalPlaces_Max was passed with rtl_math_StringFormat_F or
+ // others, but we don't want to allocate/deallocate 2GB just to fill it
+ // with trailing '0' characters..
+ nDecPlaces = std::max<sal_Int32>(std::min<sal_Int32>(nDecPlaces, 20), -20);
+
+ sal_Int32 nDigits = nDecPlaces + 1;
+
+ if (eFormat == rtl_math_StringFormat_F)
+ nDigits += nExp;
+
+ // Round the number
+ if(nDigits >= 0)
+ {
+ fValue += nRoundVal[std::min<sal_Int32>(nDigits, 15)];
+ if (fValue >= 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 = static_cast< typename T::Char * >(
+ malloc(nBuf * sizeof (typename T::Char)));
+ OSL_ENSURE(pBuf, "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) // was 16 in ancient versions, which leads to inaccuracies
+ {
+ int nDigit;
+ if (nDigits-1 == 0 && i > 0 && i < 14)
+ nDigit = static_cast< int >(floor( fValue + nCorrVal[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 || (sLen == 0 && bSign))
+ {
+ // Assert that no one changed the logic we rely on.
+ assert(!bSign || *pBuf == static_cast< typename T::Char >('-'));
+ p = pBuf;
+ if (bSign)
+ ++p;
+ 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 (j == 0 && bSign)
+ {
+ // Do not touch leading minus sign put earlier.
+ assert(cS == static_cast< typename T::Char >('-'));
+ break; // for, this is the last character backwards.
+ }
+ 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 || (j == 1 && bSign))
+ {
+ 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 for rtl_math_StringFormat_E). The code in
+ // rtl_[u]str_valueOf{Float|Double} relies on this format.
+ if (eFormat == rtl_math_StringFormat_E || eFormat == rtl_math_StringFormat_E2 || eFormat == rtl_math_StringFormat_E1)
+ {
+ 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 (eFormat == rtl_math_StringFormat_E || nExp >= 100)
+ *p++ = static_cast< typename T::Char >(
+ nExp / 100 + static_cast< typename T::Char >('0') );
+
+ nExp %= 100;
+
+ if (eFormat == rtl_math_StringFormat_E || eFormat == rtl_math_StringFormat_E2 || nExp >= 10)
+ *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)
+ T::createString(pResult, pBuf, p - pBuf);
+ else
+ T::appendChars(pResult, pResultCapacity, &nResultOffset, pBuf, p - pBuf);
+
+ if (pBuf != &aBuf[0])
+ free(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,
+ char cDecSeparator,
+ sal_Int32 const * pGroups,
+ char cGroupSeparator,
+ sal_Bool bEraseTrailingDecZeros)
+ SAL_THROW_EXTERN_C()
+{
+ doubleToString< StringTraits >(
+ 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 >(
+ pResult, pResultCapacity, nResultOffset, fValue, eFormat, nDecPlaces,
+ cDecSeparator, pGroups, cGroupSeparator, bEraseTrailingDecZeros);
+}
+
+namespace {
+
+template< typename CharT >
+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 ((pEnd - p) >= 3)
+ {
+ 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
+ {
+ std::unique_ptr<char[]> bufInHeap;
+ std::unique_ptr<const CharT * []> bufInHeapMap;
+ constexpr int bufOnStackSize = 256;
+ char bufOnStack[bufOnStackSize];
+ const CharT* bufOnStackMap[bufOnStackSize];
+ char* buf = bufOnStack;
+ const CharT** bufmap = bufOnStackMap;
+ int bufpos = 0;
+ const size_t bufsize = pEnd - p + (bSign ? 2 : 1);
+ if (bufsize > bufOnStackSize)
+ {
+ bufInHeap = std::make_unique<char[]>(bufsize);
+ bufInHeapMap = std::make_unique<const CharT*[]>(bufsize);
+ buf = bufInHeap.get();
+ bufmap = bufInHeapMap.get();
+ }
+
+ if (bSign)
+ {
+ buf[0] = '-';
+ bufmap[0] = p; // yes, this may be the same pointer as for the next mapping
+ bufpos = 1;
+ }
+ // Put first zero to buffer for strings like "-0"
+ if (p != pEnd && *p == CharT('0'))
+ {
+ buf[bufpos] = '0';
+ bufmap[bufpos] = p;
+ ++bufpos;
+ ++p;
+ }
+ // Leading zeros and group separators between digits may be safely
+ // ignored. p0 < p implies that there was a leading 0 already,
+ // consecutive group separators may not happen as *(p+1) is checked for
+ // digit.
+ while (p != pEnd && (*p == CharT('0') || (*p == cGroupSeparator
+ && p0 < p && p+1 < pEnd && rtl::isAsciiDigit(*(p+1)))))
+ {
+ ++p;
+ }
+
+ // integer part of mantissa
+ for (; p != pEnd; ++p)
+ {
+ CharT c = *p;
+ if (rtl::isAsciiDigit(c))
+ {
+ buf[bufpos] = static_cast<char>(c);
+ bufmap[bufpos] = p;
+ ++bufpos;
+ }
+ else if (c != cGroupSeparator)
+ {
+ break;
+ }
+ else if (p == p0 || (p+1 == pEnd) || !rtl::isAsciiDigit(*(p+1)))
+ {
+ // A leading or trailing (not followed by a digit) group
+ // separator character is not a group separator.
+ break;
+ }
+ }
+
+ // fraction part of mantissa
+ if (p != pEnd && *p == cDecSeparator)
+ {
+ buf[bufpos] = '.';
+ bufmap[bufpos] = p;
+ ++bufpos;
+ ++p;
+
+ for (; p != pEnd; ++p)
+ {
+ CharT c = *p;
+ if (!rtl::isAsciiDigit(c))
+ {
+ break;
+ }
+ buf[bufpos] = static_cast<char>(c);
+ bufmap[bufpos] = p;
+ ++bufpos;
+ }
+ }
+
+ // Exponent
+ if (p != p0 && p != pEnd && (*p == CharT('E') || *p == CharT('e')))
+ {
+ buf[bufpos] = 'E';
+ bufmap[bufpos] = p;
+ ++bufpos;
+ ++p;
+ if (p != pEnd && *p == CharT('-'))
+ {
+ buf[bufpos] = '-';
+ bufmap[bufpos] = p;
+ ++bufpos;
+ ++p;
+ }
+ else if (p != pEnd && *p == CharT('+'))
+ ++p;
+
+ for (; p != pEnd; ++p)
+ {
+ CharT c = *p;
+ if (!rtl::isAsciiDigit(c))
+ break;
+
+ buf[bufpos] = static_cast<char>(c);
+ bufmap[bufpos] = p;
+ ++bufpos;
+ }
+ }
+ 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 && rtl::isAsciiDigit(*p))
+ ++p;
+ bDone = true;
+ }
+ 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 && rtl::isAsciiDigit(*p))
+ {
+ ++p;
+ }
+ bDone = true;
+ }
+ }
+
+ if (!bDone)
+ {
+ buf[bufpos] = '\0';
+ bufmap[bufpos] = p;
+ char* pCharParseEnd;
+ errno = 0;
+ fVal = strtod_nolocale(buf, &pCharParseEnd);
+ if (errno == ERANGE)
+ {
+ // Check for the dreaded rounded to 15 digits max value
+ // 1.79769313486232e+308 for 1.7976931348623157e+308 we wrote
+ // everywhere, accept with or without plus sign in exponent.
+ const char* b = buf;
+ if (b[0] == '-')
+ ++b;
+ if (((pCharParseEnd - b == 21) || (pCharParseEnd - b == 20))
+ && !strncmp( b, "1.79769313486232", 16)
+ && (b[16] == 'e' || b[16] == 'E')
+ && (((pCharParseEnd - b == 21) && !strncmp( b+17, "+308", 4))
+ || ((pCharParseEnd - b == 20) && !strncmp( b+17, "308", 3))))
+ {
+ fVal = (buf < b) ? -DBL_MAX : DBL_MAX;
+ }
+ else
+ {
+ eStatus = rtl_math_ConversionStatus_OutOfRange;
+ }
+ }
+ p = bufmap[pCharParseEnd - buf];
+ bSign = false;
+ }
+ }
+
+ // 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)
+ *pStatus = eStatus;
+
+ if (pParsedEnd)
+ *pParsedEnd = p == p0 ? pBegin : p;
+
+ return fVal;
+}
+
+}
+
+double SAL_CALL rtl_math_stringToDouble(char const * pBegin,
+ char const * pEnd,
+ char cDecSeparator,
+ char cGroupSeparator,
+ rtl_math_ConversionStatus * pStatus,
+ char const ** pParsedEnd)
+ SAL_THROW_EXTERN_C()
+{
+ return stringToDouble(
+ reinterpret_cast<unsigned char const *>(pBegin),
+ reinterpret_cast<unsigned char const *>(pEnd),
+ static_cast<unsigned char>(cDecSeparator),
+ static_cast<unsigned char>(cGroupSeparator), pStatus,
+ reinterpret_cast<unsigned char const **>(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;
+
+ if ( nDecPlaces == 0 && eMode == rtl_math_RoundingMode_Corrected )
+ return std::round( fValue );
+
+ // sign adjustment
+ bool bSign = std::signbit( 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;
+ }
+
+ 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;
+
+ if (nExp < 0)
+ nIndex = 15;
+ else if (nExp >= 14)
+ nIndex = 0;
+ else
+ nIndex = 15 - nExp;
+
+ fValue = floor(fValue + 0.5 + nCorrVal[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()
+{
+ const double fBigInt = 2199023255552.0; // 2^41 -> only 11 bits left for fractional part, fine as decimal
+ if (fValue == 0.0 || fValue == HUGE_VAL || !std::isfinite( fValue) || fValue > fBigInt)
+ {
+ // We don't handle these conditions. Bail out.
+ return fValue;
+ }
+
+ double fOrigValue = fValue;
+
+ bool bSign = std::signbit(fValue);
+ if (bSign)
+ fValue = -fValue;
+
+ // If the value is either integer representable as double,
+ // or only has small number of bits in fraction part, then we need not do any approximation
+ if (isRepresentableInteger(fValue) || getBitsInFracPart(fValue) <= 11)
+ return fOrigValue;
+
+ 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 (!std::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 (!std::isfinite(fValue))
+ return fOrigValue;
+
+ return bSign ? -fValue : fValue;
+}
+
+bool SAL_CALL rtl_math_approxEqual(double a, double b) SAL_THROW_EXTERN_C()
+{
+ static const double e48 = 1.0 / (16777216.0 * 16777216.0);
+ static const double e44 = e48 * 16.0;
+
+ if (a == b)
+ return true;
+
+ if (a == 0.0 || b == 0.0)
+ return false;
+
+ const double d = fabs(a - b);
+ if (!std::isfinite(d))
+ return false; // Nan or Inf involved
+
+ a = fabs(a);
+ if (d > (a * e44))
+ return false;
+ b = fabs(b);
+ if (d > (b * e44))
+ return false;
+
+ if (isRepresentableInteger(d) && isRepresentableInteger(a) && isRepresentableInteger(b))
+ return false; // special case for representable integers.
+
+ return (d < a * e48 && d < b * e48);
+}
+
+double SAL_CALL rtl_math_expm1(double fValue) SAL_THROW_EXTERN_C()
+{
+ return expm1(fValue);
+}
+
+double SAL_CALL rtl_math_log1p(double fValue) SAL_THROW_EXTERN_C()
+{
+#ifdef __APPLE__
+ if (fValue == -0.0)
+ return fValue; // macOS 10.8 libc returns 0.0 for -0.0
+#endif
+
+ return log1p(fValue);
+}
+
+double SAL_CALL rtl_math_atanh(double fValue) SAL_THROW_EXTERN_C()
+#if defined __clang__
+ __attribute__((no_sanitize("float-divide-by-zero"))) // atahn(1) -> inf
+#endif
+{
+ return 0.5 * rtl_math_log1p(2.0 * fValue / (1.0-fValue));
+}
+
+/** Parent error function (erf) */
+double SAL_CALL rtl_math_erf(double x) SAL_THROW_EXTERN_C()
+{
+ return erf(x);
+}
+
+/** Parent complementary error function (erfc) */
+double SAL_CALL rtl_math_erfc(double x) SAL_THROW_EXTERN_C()
+{
+ return erfc(x);
+}
+
+/** 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()
+{
+ if ( fX == 0.0 )
+ return 0.0;
+
+ double fSign = 1.0;
+ 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)));
+
+ if ( fX < 1.25e7 )
+ return fSign * log( fX + sqrt( 1.0 + fX*fX));
+
+ 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;
+ }
+ if ( fX == 1.0 )
+ return 0.0;
+
+ if ( fX < 1.1 )
+ return rtl_math_log1p( fZ + sqrt( fZ*fZ + 2.0*fZ));
+
+ if ( fX < 1.25e7 )
+ return log( fX + sqrt( fX*fX - 1.0));
+
+ return log( 2.0*fX);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/random.cxx b/sal/rtl/random.cxx
new file mode 100644
index 000000000..418358b22
--- /dev/null
+++ b/sal/rtl/random.cxx
@@ -0,0 +1,310 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cmath>
+
+#include <sal/types.h>
+#include <o3tl/temporary.hxx>
+#include <osl/thread.h>
+#include <osl/thread.hxx>
+#include <osl/time.h>
+#include <rtl/alloc.h>
+#include <rtl/digest.h>
+#include <rtl/random.h>
+#include <oslrandom.h>
+
+#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) += 30328; \
+ \
+ (y) = 171 * ((y) % 177) - 2 * ((y) / 177); \
+ if ((y) < 0) (y) += 30269; \
+ \
+ (z) = 172 * ((z) % 176) - 35 * ((z) / 176); \
+ if ((z) < 0) (z) += 30307; \
+}
+
+namespace {
+
+struct RandomData_Impl
+{
+ sal_Int16 m_nX;
+ sal_Int16 m_nY;
+ sal_Int16 m_nZ;
+};
+
+}
+
+static double data (RandomData_Impl *pImpl);
+
+#define RTL_RANDOM_DIGEST rtl_Digest_AlgorithmMD5
+#define RTL_RANDOM_SIZE_DIGEST RTL_DIGEST_LENGTH_MD5
+#define RTL_RANDOM_SIZE_POOL 1023
+
+namespace {
+
+struct RandomPool_Impl
+{
+ 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;
+};
+
+}
+
+static bool initPool(RandomPool_Impl *pImpl);
+
+static void seedPool(
+ RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen);
+
+static void readPool(
+ RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen);
+
+static double data(RandomData_Impl *pImpl)
+{
+ double random;
+
+ RTL_RANDOM_RNG (pImpl->m_nX, pImpl->m_nY, pImpl->m_nZ);
+ random = ((static_cast<double>(pImpl->m_nX) / 30328.0) +
+ (static_cast<double>(pImpl->m_nY) / 30269.0) +
+ (static_cast<double>(pImpl->m_nZ) / 30307.0) );
+
+ return std::modf(random, &o3tl::temporary(double()));
+}
+
+static bool initPool(RandomPool_Impl *pImpl)
+{
+ pImpl->m_hDigest = rtl_digest_create(RTL_RANDOM_DIGEST);
+ if (pImpl->m_hDigest)
+ {
+ oslThreadIdentifier tid;
+ 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.
+ */
+
+ /*
+ seedPool (pImpl, (sal_uInt8*)&tid, sizeof(tid));
+ seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv));
+ seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd));
+ */
+
+ tid = osl::Thread::getCurrentIdentifier();
+ tid = RTL_RANDOM_RNG_2(RTL_RANDOM_RNG_1(tid));
+ seedPool (pImpl, reinterpret_cast< sal_uInt8* >(&tid), sizeof(tid));
+
+ osl_getSystemTime (&tv);
+ tv.Seconds = RTL_RANDOM_RNG_2(tv.Seconds);
+ tv.Nanosec = RTL_RANDOM_RNG_2(tv.Nanosec);
+ seedPool (pImpl, reinterpret_cast< sal_uInt8* >(&tv), sizeof(tv));
+
+ rd.m_nX = static_cast<sal_Int16>(((tid >> 1) << 1) + 1);
+ rd.m_nY = static_cast<sal_Int16>(((tv.Seconds >> 1) << 1) + 1);
+ rd.m_nZ = static_cast<sal_Int16>(((tv.Nanosec >> 1) << 1) + 1);
+ seedPool (pImpl, reinterpret_cast< sal_uInt8* >(&rd), sizeof(rd));
+
+ while (pImpl->m_nData < RTL_RANDOM_SIZE_POOL)
+ {
+ seed = data (&rd);
+ seedPool (pImpl, reinterpret_cast< sal_uInt8* >(&seed), sizeof(seed));
+ }
+ return true;
+ }
+ return false;
+}
+
+static void 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;
+}
+
+static void 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);
+}
+
+rtlRandomPool SAL_CALL rtl_random_createPool() SAL_THROW_EXTERN_C()
+{
+ /* try to get system random number, if it fail fall back on own pool */
+ RandomPool_Impl *pImpl = static_cast< RandomPool_Impl* >(rtl_allocateZeroMemory(sizeof(RandomPool_Impl)));
+ if (pImpl)
+ {
+ char sanity[4];
+ if (!osl_get_system_random_data(sanity, 4))
+ {
+ if (!initPool(pImpl))
+ {
+ rtl_freeZeroMemory(pImpl, sizeof(RandomPool_Impl));
+ pImpl = nullptr;
+ }
+ }
+ }
+ return static_cast< rtlRandomPool >(pImpl);
+}
+
+void SAL_CALL rtl_random_destroyPool(rtlRandomPool Pool) SAL_THROW_EXTERN_C()
+{
+ RandomPool_Impl *pImpl = static_cast< RandomPool_Impl* >(Pool);
+ if (pImpl)
+ {
+ if (pImpl->m_hDigest)
+ rtl_digest_destroy(pImpl->m_hDigest);
+
+ rtl_freeZeroMemory (pImpl, sizeof(RandomPool_Impl));
+ }
+}
+
+rtlRandomError SAL_CALL rtl_random_addBytes(
+ rtlRandomPool Pool, const void *Buffer, sal_Size Bytes) SAL_THROW_EXTERN_C()
+{
+ RandomPool_Impl *pImpl = static_cast< RandomPool_Impl* >(Pool);
+ const sal_uInt8 *pBuffer = static_cast< const sal_uInt8* >(Buffer);
+
+ if (!pImpl || !pBuffer)
+ return rtl_Random_E_Argument;
+
+ if (pImpl->m_hDigest)
+ seedPool (pImpl, pBuffer, Bytes);
+
+ return rtl_Random_E_None;
+}
+
+rtlRandomError SAL_CALL rtl_random_getBytes (
+ rtlRandomPool Pool, void *Buffer, sal_Size Bytes) SAL_THROW_EXTERN_C()
+{
+ RandomPool_Impl *pImpl = static_cast< RandomPool_Impl* >(Pool);
+ sal_uInt8 *pBuffer = static_cast< sal_uInt8* >(Buffer);
+
+ if (!pImpl || !pBuffer)
+ return rtl_Random_E_Argument;
+
+ if (pImpl->m_hDigest || !osl_get_system_random_data(static_cast< char* >(Buffer), Bytes))
+ {
+ if (!pImpl->m_hDigest && !initPool(pImpl))
+ return rtl_Random_E_Unknown;
+ readPool(pImpl, pBuffer, Bytes);
+ }
+ return rtl_Random_E_None;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/rtl_process.cxx b/sal/rtl/rtl_process.cxx
new file mode 100644
index 000000000..42c24e800
--- /dev/null
+++ b/sal/rtl/rtl_process.cxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstring>
+
+#include <rtl/instance.hxx>
+#include <rtl/process.h>
+#include <rtl/uuid.h>
+#include <sal/types.h>
+
+namespace
+{
+
+class Id
+{
+public:
+ Id() { rtl_createUuid(uuid_, nullptr, false); }
+
+ Id(const Id&) = delete;
+ Id& operator=(const Id&) = delete;
+
+ void copy(sal_uInt8 * target) const
+ { std::memcpy(target, uuid_, UUID_SIZE); }
+
+private:
+ enum { UUID_SIZE = 16 };
+
+ sal_uInt8 uuid_[UUID_SIZE];
+};
+
+struct theId: public rtl::Static< Id, theId > {};
+
+} // end namespace
+
+void rtl_getGlobalProcessId(sal_uInt8 * pTargetUUID)
+{
+ theId::get().copy(pTargetUUID);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/strbuf.cxx b/sal/rtl/strbuf.cxx
new file mode 100644
index 000000000..b9f4cd688
--- /dev/null
+++ b/sal/rtl/strbuf.cxx
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+
+#include <osl/interlck.h>
+#include <rtl/strbuf.hxx>
+#include "strimp.hxx"
+
+/*************************************************************************
+ * rtl_stringbuffer_newFromStr_WithLength
+ */
+void SAL_CALL rtl_stringbuffer_newFromStr_WithLength( rtl_String ** newStr,
+ const char * value,
+ sal_Int32 count )
+{
+ assert(newStr);
+ assert(count >= 0);
+ if (!value)
+ {
+ rtl_string_new_WithLength( newStr, 16 );
+ return;
+ }
+
+ // use raw alloc to avoid overwriting the buffer twice
+ if ( *newStr)
+ rtl_string_release( *newStr );
+ *newStr = rtl_string_ImplAlloc( count + 16 );
+ (*newStr)->length = count;
+ memcpy( (*newStr)->buffer, value, count );
+ memset( (*newStr)->buffer + count, 0, 16 );
+}
+
+/*************************************************************************
+ * rtl_stringbuffer_newFromStringBuffer
+ */
+sal_Int32 SAL_CALL rtl_stringbuffer_newFromStringBuffer( rtl_String ** newStr,
+ sal_Int32 capacity,
+ rtl_String * oldStr )
+{
+ assert(newStr);
+ assert(oldStr);
+ assert(capacity >= 0);
+ 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;
+ memcpy( (*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)
+{
+ assert(This);
+// assert(capacity && *capacity >= 0);
+// assert(minimumCapacity >= 0);
+ if (minimumCapacity <= *capacity)
+ return;
+
+ rtl_String * pTmp = *This;
+ rtl_String * pNew = nullptr;
+ auto nLength = (*This)->length;
+ *capacity = (nLength + 1) * 2;
+ if (minimumCapacity > *capacity)
+ /* still lower, set to the minimum capacity */
+ *capacity = minimumCapacity;
+
+ // use raw alloc to avoid overwriting the buffer twice
+ pNew = rtl_string_ImplAlloc( *capacity );
+ pNew->length = nLength;
+ *This = pNew;
+
+ memcpy( (*This)->buffer, pTmp->buffer, nLength );
+ memset( (*This)->buffer + nLength, 0, *capacity - nLength );
+ rtl_string_release( pTmp );
+}
+
+/*************************************************************************
+ * rtl_stringbuffer_insert
+ */
+void SAL_CALL rtl_stringbuffer_insert( rtl_String ** This,
+ sal_Int32 * capacity,
+ sal_Int32 offset,
+ const char * str,
+ sal_Int32 len )
+{
+ assert(This);
+ assert(capacity && *capacity >= 0);
+ assert(offset >= 0 && offset <= (**This).length);
+ assert(len >= 0);
+ sal_Int32 nOldLen;
+ char * pBuf;
+ sal_Int32 n;
+ if( len == 0 )
+ return;
+
+ if (*capacity < (*This)->length + len)
+ rtl_stringbuffer_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 )
+ memmove( pBuf + offset + len, pBuf + offset, n * sizeof(char) );
+
+ /* insert the new characters */
+ if( str != nullptr )
+ {
+ if( len == 1 )
+ /* optimized for 1 character */
+ pBuf[offset] = *str;
+ else
+ memcpy( pBuf + offset, str, len * sizeof(char) );
+ }
+ (*This)->length = nOldLen + len;
+ pBuf[ nOldLen + len ] = 0;
+}
+
+/*************************************************************************
+ * rtl_stringbuffer_remove
+ */
+void SAL_CALL rtl_stringbuffer_remove( rtl_String ** This,
+ sal_Int32 start,
+ sal_Int32 len )
+{
+ assert(This);
+ assert(start >= 0 && start <= (**This).length);
+ assert(len >= 0);
+ sal_Int32 nTailLen;
+ char * pBuf;
+
+ if (len > (*This)->length - start)
+ len = (*This)->length - start;
+
+ //remove nothing
+ if (!len)
+ return;
+
+ pBuf = (*This)->buffer;
+ nTailLen = (*This)->length - ( start + len );
+
+ if (nTailLen)
+ {
+ /* move the tail */
+ memmove(pBuf + start, pBuf + start + len, nTailLen * sizeof(char));
+ }
+
+ (*This)->length-=len;
+ pBuf[ (*This)->length ] = 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/strimp.cxx b/sal/rtl/strimp.cxx
new file mode 100644
index 000000000..51a1a94bd
--- /dev/null
+++ b/sal/rtl/strimp.cxx
@@ -0,0 +1,120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <sal/config.h>
+
+#include <assert.h>
+#include <rtl/alloc.h>
+#include <rtl/ustring.h>
+#include <rtllifecycle.h>
+
+#include "strimp.hxx"
+#include "alloc_impl.hxx"
+#include "alloc_arena.hxx"
+
+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;
+}
+
+bool rtl_ImplIsWhitespace( sal_Unicode c )
+{
+ /* Space or Control character? */
+ if ( (c <= 32) && c )
+ return true;
+
+ /* Only in the General Punctuation area Space or Control characters are included? */
+ if ( (c < 0x2000) || (c > 0x206F) )
+ return false;
+
+ if ( ((c >= 0x2000) && (c <= 0x200B)) || /* All Spaces */
+ (c == 0x2028) || /* LINE SEPARATOR */
+ (c == 0x2029) ) /* PARAGRAPH SEPARATOR */
+ return true;
+
+ return false;
+}
+
+/*
+ * TODO: add a slower, more awful, but more space efficient
+ * custom allocator for the pre-init phase. Existing slab
+ * allocator's minimum alloc size is 24bytes, and by default
+ * is 32 bytes.
+ */
+static rtl_arena_type *pre_arena = nullptr;
+
+rtl_allocateStringFn rtl_allocateString = malloc;
+rtl_freeStringFn rtl_freeString = free;
+
+extern "C" {
+static void *pre_allocateStringFn(size_t n)
+{
+ sal_Size size = RTL_MEMORY_ALIGN(n + 4, 4);
+ char *addr = static_cast<char*>(rtl_arena_alloc(pre_arena, &size));
+ assert(size>= 12);
+ reinterpret_cast<sal_uInt32*>(addr)[0] = size - 12;
+ return addr + 4;
+}
+
+static void pre_freeStringFn(void *data)
+{
+ char *addr = static_cast<char*>(data) - 4;
+ sal_uInt32 size = reinterpret_cast<sal_uInt32*>(addr)[0] + 12;
+
+ rtl_arena_free(pre_arena, addr, size);
+}
+} // extern "C"
+
+static void mark_static(void *addr, sal_Size /* size */)
+{
+ char *inner = static_cast<char*>(addr) + 4;
+ rtl_uString *str = reinterpret_cast<rtl_uString *>(inner);
+ str->refCount |= SAL_STRING_STATIC_FLAG;
+}
+
+void SAL_CALL rtl_alloc_preInit (sal_Bool start) SAL_THROW_EXTERN_C()
+{
+ if (start)
+ {
+ rtl_allocateString = pre_allocateStringFn;
+ rtl_freeString = pre_freeStringFn;
+ pre_arena = rtl_arena_create("pre-init strings", 4, 0,
+ nullptr, rtl_arena_alloc,
+ rtl_arena_free, 0);
+
+ // To be consistent (and to ensure the rtl_cache threads are started).
+ ensureCacheSingleton();
+ }
+ else
+ {
+ rtl_arena_foreach(pre_arena, mark_static);
+ rtl_allocateString = malloc;
+ rtl_freeString = free;
+
+ // TODO: also re-initialize main allocator as well.
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/strimp.hxx b/sal/rtl/strimp.hxx
new file mode 100644
index 000000000..f3516f799
--- /dev/null
+++ b/sal/rtl/strimp.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SAL_RTL_STRIMP_HXX
+#define INCLUDED_SAL_RTL_STRIMP_HXX
+
+#include <config_probes.h>
+#if USE_SDT_PROBES
+#include <sys/sdt.h>
+#endif
+
+#include <sal/types.h>
+#include <rtl/string.hxx>
+#include <rtl/ustring.hxx>
+
+/* ======================================================================= */
+/* Help functions for String and UString */
+/* ======================================================================= */
+
+/*
+ * refCount is opaque and includes 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 );
+
+bool rtl_ImplIsWhitespace( sal_Unicode c );
+
+rtl_uString* rtl_uString_ImplAlloc( sal_Int32 nLen );
+
+rtl_String* rtl_string_ImplAlloc( sal_Int32 nLen );
+
+extern "C" {
+
+typedef void *(SAL_CALL * rtl_allocateStringFn)(size_t size);
+typedef void (*rtl_freeStringFn)(void *);
+
+}
+
+extern rtl_allocateStringFn rtl_allocateString;
+extern rtl_freeStringFn rtl_freeString;
+
+// string lifetime instrumentation / diagnostics
+#if USE_SDT_PROBES
+# define PROBE_SNAME(n,b) n ## _ ## b
+# define PROBE_NAME(n,b) PROBE_SNAME(n,b)
+# define PROBE_NEW PROBE_NAME (new_string,RTL_LOG_STRING_BITS)
+# define PROBE_DEL PROBE_NAME (delete_string,RTL_LOG_STRING_BITS)
+# define PROBE_INTERN_NEW PROBE_NAME (new_string_intern,RTL_LOG_STRING_BITS)
+# define PROBE_INTERN_DEL PROBE_NAME (delete_string_intern,RTL_LOG_STRING_BITS)
+# define RTL_LOG_STRING_NEW(s) \
+ DTRACE_PROBE4(libreoffice, PROBE_NEW, s, \
+ (s)->refCount, (s)->length, (s)->buffer)
+# define RTL_LOG_STRING_DELETE(s) \
+ DTRACE_PROBE4(libreoffice, PROBE_DEL, s, \
+ (s)->refCount, (s)->length, (s)->buffer)
+# define RTL_LOG_STRING_INTERN_NEW(s,o) \
+ DTRACE_PROBE5(libreoffice, PROBE_INTERN_NEW, s, \
+ (s)->refCount, (s)->length, (s)->buffer, o)
+# define RTL_LOG_STRING_INTERN_DELETE(s) \
+ DTRACE_PROBE4(libreoffice, PROBE_INTERN_DEL, s, \
+ (s)->refCount, (s)->length, (s)->buffer)
+#else
+# define RTL_LOG_STRING_NEW(s)
+# define RTL_LOG_STRING_DELETE(s)
+# define RTL_LOG_STRING_INTERN_NEW(s,o)
+# define RTL_LOG_STRING_INTERN_DELETE(s)
+#endif /* USE_SDT_PROBES */
+
+#endif // INCLUDED_SAL_RTL_STRIMP_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/string.cxx b/sal/rtl/string.cxx
new file mode 100644
index 000000000..13bf7542c
--- /dev/null
+++ b/sal/rtl/string.cxx
@@ -0,0 +1,394 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstdlib>
+
+#include <osl/interlck.h>
+#include <rtl/alloc.h>
+#include <osl/diagnose.h>
+#include <rtl/tencinfo.h>
+
+#include "strimp.hxx"
+#include <rtl/character.hxx>
+#include <rtl/string.h>
+
+#include <rtl/math.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 } /* char buffer[1]; */
+};
+
+/* ======================================================================= */
+/* These macros are for the "poor-man templates" included from
+ * the strtmpl.cxx just below, used to share code between here and
+ * ustring.cxx
+ */
+
+#define IMPL_RTL_IS_USTRING 0
+
+#define IMPL_RTL_STRCODE char
+#define IMPL_RTL_USTRCODE( c ) (static_cast<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
+
+#if USE_SDT_PROBES
+#define RTL_LOG_STRING_BITS 8
+#endif
+
+/* ======================================================================= */
+
+/* Include String/UString template code */
+
+#include "strtmpl.cxx"
+
+#undef IMPL_RTL_EMPTYSTRING
+#undef IMPL_RTL_IS_USTRING
+#undef IMPL_RTL_STRCODE
+#undef IMPL_RTL_STRINGDATA
+#undef IMPL_RTL_STRINGNAME
+#undef IMPL_RTL_STRNAME
+#undef IMPL_RTL_USTRCODE
+#undef RTL_LOG_STRING_BITS
+
+sal_Int32 SAL_CALL rtl_str_valueOfFloat(char * pStr, float f)
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ rtl_String * pResult = nullptr;
+ sal_Int32 nLen;
+ rtl_math_doubleToString(
+ &pResult, nullptr, 0, f, rtl_math_StringFormat_G,
+ RTL_STR_MAX_VALUEOFFLOAT - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', nullptr, 0,
+ true);
+ nLen = pResult->length;
+ OSL_ASSERT(nLen < RTL_STR_MAX_VALUEOFFLOAT);
+ memcpy(pStr, pResult->buffer, (nLen + 1) * sizeof(char));
+ rtl_string_release(pResult);
+ return nLen;
+}
+
+sal_Int32 SAL_CALL rtl_str_valueOfDouble(char * pStr, double d)
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ rtl_String * pResult = nullptr;
+ sal_Int32 nLen;
+ rtl_math_doubleToString(
+ &pResult, nullptr, 0, d, rtl_math_StringFormat_G,
+ RTL_STR_MAX_VALUEOFDOUBLE - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', nullptr,
+ 0, true);
+ nLen = pResult->length;
+ OSL_ASSERT(nLen < RTL_STR_MAX_VALUEOFDOUBLE);
+ memcpy(pStr, pResult->buffer, (nLen + 1) * sizeof(char));
+ rtl_string_release(pResult);
+ return nLen;
+}
+
+float SAL_CALL rtl_str_toFloat(char const * pStr) SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ return static_cast<float>(rtl_math_stringToDouble(pStr, pStr + rtl_str_getLength(pStr),
+ '.', 0, nullptr, nullptr));
+}
+
+double SAL_CALL rtl_str_toDouble(char const * pStr) SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ return rtl_math_stringToDouble(pStr, pStr + rtl_str_getLength(pStr), '.', 0,
+ nullptr, nullptr);
+}
+
+/* ======================================================================= */
+
+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 ( !rtl::isHighSurrogate(c) )
+ n += 3;
+ else
+ {
+ nUCS4Char = c;
+
+ if ( pStr+1 < pEndStr )
+ {
+ c = *(pStr+1);
+ if ( rtl::isLowSurrogate(c) )
+ {
+ nUCS4Char = rtl::combineSurrogates(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;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static bool rtl_impl_convertUStringToString(rtl_String ** pTarget,
+ sal_Unicode const * pSource,
+ sal_Int32 nLength,
+ rtl_TextEncoding nEncoding,
+ sal_uInt32 nFlags,
+ bool bCheckErrors)
+{
+ assert(pTarget != nullptr);
+ assert(pSource != nullptr || nLength == 0);
+ assert(nLength >= 0);
+ OSL_ASSERT(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 a 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 == static_cast<sal_Size>(nLength) )
+ {
+ char* pBuffer;
+ if ( *pTarget )
+ rtl_string_release( *pTarget );
+ *pTarget = rtl_string_ImplAlloc( nLength );
+ OSL_ASSERT(*pTarget != nullptr);
+ pBuffer = (*pTarget)->buffer;
+ do
+ {
+ /* Check ASCII range */
+ OSL_ENSURE( *pSource <= 127,
+ "rtl_uString2String() - UTF8 test is encoding is wrong" );
+
+ *pBuffer = static_cast<char>(static_cast<unsigned char>(*pSource));
+ pBuffer++;
+ pSource++;
+ nLength--;
+ }
+ while ( nLength );
+ return true;
+ }
+
+ nMaxCharLen = 4;
+ }
+ else
+ {
+ rtl_TextEncodingInfo aTextEncInfo;
+ aTextEncInfo.StructSize = sizeof( aTextEncInfo );
+ if ( !rtl_getTextEncodingInfo( nEncoding, &aTextEncInfo ) )
+ {
+ aTextEncInfo.AverageCharSize = 1;
+ aTextEncInfo.MaximumCharSize = 8;
+ }
+
+ nNewLen = nLength * static_cast<sal_Size>(aTextEncInfo.AverageCharSize);
+ nMaxCharLen = aTextEncInfo.MaximumCharSize;
+ }
+
+ nFlags |= RTL_UNICODETOTEXT_FLAGS_FLUSH;
+ hConverter = rtl_createUnicodeToTextConverter( nEncoding );
+
+ for (;;)
+ {
+ pTemp = rtl_string_ImplAlloc( nNewLen );
+ OSL_ASSERT(pTemp != nullptr);
+ nDestBytes = rtl_convertUnicodeToText( hConverter, nullptr,
+ pSource, nLength,
+ pTemp->buffer, nNewLen,
+ nFlags,
+ &nInfo, &nSrcChars );
+ if (bCheckErrors && (nInfo & RTL_UNICODETOTEXT_INFO_ERROR) != 0)
+ {
+ rtl_freeString(pTemp);
+ rtl_destroyUnicodeToTextConverter(hConverter);
+ return false;
+ }
+
+ if ((nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL) == 0)
+ break;
+
+ /* Buffer not big enough, try again with enough space */
+ rtl_freeString( 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 = rtl_string_ImplAlloc( nDestBytes );
+ OSL_ASSERT(pTemp2 != nullptr);
+ rtl_str_ImplCopy( pTemp2->buffer, pTemp->buffer, nDestBytes );
+ rtl_freeString( pTemp );
+ pTemp = pTemp2;
+ }
+ else
+ {
+ pTemp->length = nDestBytes;
+ pTemp->buffer[nDestBytes] = 0;
+ }
+
+ rtl_destroyUnicodeToTextConverter( hConverter );
+ if ( *pTarget )
+ rtl_string_release( *pTarget );
+ *pTarget = pTemp;
+
+ /* Results the conversion in an empty buffer -
+ create an empty string */
+ if ( pTemp && !nDestBytes )
+ rtl_string_new( pTarget );
+ }
+ return true;
+}
+
+void SAL_CALL rtl_uString2String( rtl_String** ppThis,
+ const sal_Unicode* pUStr,
+ sal_Int32 nULen,
+ rtl_TextEncoding eTextEncoding,
+ sal_uInt32 nCvtFlags )
+ SAL_THROW_EXTERN_C()
+{
+ rtl_impl_convertUStringToString(ppThis, pUStr, nULen, eTextEncoding,
+ nCvtFlags, false);
+}
+
+sal_Bool SAL_CALL rtl_convertUStringToString(rtl_String ** pTarget,
+ sal_Unicode const * pSource,
+ sal_Int32 nLength,
+ rtl_TextEncoding nEncoding,
+ sal_uInt32 nFlags)
+ SAL_THROW_EXTERN_C()
+{
+ return rtl_impl_convertUStringToString(pTarget, pSource, nLength, nEncoding,
+ nFlags, true);
+}
+
+void rtl_string_newReplaceFirst(
+ rtl_String ** newStr, rtl_String * str, char const * from,
+ sal_Int32 fromLength, char const * to, sal_Int32 toLength,
+ sal_Int32 * index) SAL_THROW_EXTERN_C()
+{
+ assert(str != nullptr);
+ assert(index != nullptr);
+ assert(*index >= 0 && *index <= str->length);
+ assert(fromLength >= 0);
+ assert(toLength >= 0);
+ sal_Int32 i = rtl_str_indexOfStr_WithLength(
+ str->buffer + *index, str->length - *index, from, fromLength);
+ if (i == -1) {
+ rtl_string_assign(newStr, str);
+ } else {
+ assert(i <= str->length - *index);
+ i += *index;
+ assert(fromLength <= str->length);
+ if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
+ std::abort();
+ }
+ sal_Int32 n = str->length - fromLength + toLength;
+ rtl_string_acquire(str); // in case *newStr == str
+ rtl_string_new_WithLength(newStr, n);
+ if (n != 0) {
+ (*newStr)->length = n;
+ assert(i >= 0 && i < str->length);
+ memcpy((*newStr)->buffer, str->buffer, i);
+ memcpy((*newStr)->buffer + i, to, toLength);
+ memcpy(
+ (*newStr)->buffer + i + toLength, str->buffer + i + fromLength,
+ str->length - i - fromLength);
+ }
+ rtl_string_release(str);
+ }
+ *index = i;
+}
+
+void rtl_string_newReplaceAll(
+ rtl_String ** newStr, rtl_String * str, char const * from,
+ sal_Int32 fromLength, char const * to, sal_Int32 toLength)
+ SAL_THROW_EXTERN_C()
+{
+ rtl_string_assign(newStr, str);
+ for (sal_Int32 i = 0;; i += toLength) {
+ rtl_string_newReplaceFirst(
+ newStr, *newStr, from, fromLength, to, toLength, &i);
+ if (i == -1) {
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/strtmpl.cxx b/sal/rtl/strtmpl.cxx
new file mode 100644
index 000000000..8ff170767
--- /dev/null
+++ b/sal/rtl/strtmpl.cxx
@@ -0,0 +1,1911 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+/* ======================================================================= */
+/* Internal C-String help functions which could be used without the */
+/* String-Class */
+/* ======================================================================= */
+
+#include <algorithm>
+#include <cassert>
+#include <limits>
+
+#include <cstring>
+#include <wchar.h>
+#include <sal/log.hxx>
+#include <rtl/character.hxx>
+
+/*
+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--;
+ }
+}
+*/
+
+static void rtl_str_ImplCopy( IMPL_RTL_STRCODE* _pDest,
+ const IMPL_RTL_STRCODE* _pSrc,
+ sal_Int32 _nCount )
+{
+ // take advantage of builtin optimisations
+ memcpy( _pDest, _pSrc, _nCount * sizeof(IMPL_RTL_STRCODE));
+}
+
+/* ======================================================================= */
+/* C-String functions which could be used without the String-Class */
+/* ======================================================================= */
+
+sal_Int32 SAL_CALL IMPL_RTL_STRNAME( getLength )( const IMPL_RTL_STRCODE* pStr )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+#if !IMPL_RTL_IS_USTRING
+ // take advantage of builtin optimisations
+ return strlen( pStr);
+#else
+ if (sizeof(IMPL_RTL_STRCODE) == sizeof(wchar_t))
+ {
+ // take advantage of builtin optimisations
+ return wcslen(reinterpret_cast<wchar_t const *>(pStr));
+ }
+ else
+ {
+ const IMPL_RTL_STRCODE* pTempStr = pStr;
+ while( *pTempStr )
+ pTempStr++;
+ return pTempStr-pStr;
+ }
+#endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Int32 SAL_CALL IMPL_RTL_STRNAME( compare )( const IMPL_RTL_STRCODE* pStr1,
+ const IMPL_RTL_STRCODE* pStr2 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr1);
+ assert(pStr2);
+#if !IMPL_RTL_IS_USTRING
+ // take advantage of builtin optimisations
+ return strcmp( pStr1, pStr2);
+#else
+ if (sizeof(IMPL_RTL_STRCODE) == sizeof(wchar_t))
+ {
+ // take advantage of builtin optimisations
+ return wcscmp(reinterpret_cast<wchar_t const *>(pStr1), reinterpret_cast<wchar_t const *>(pStr2));
+ }
+ else
+ {
+ sal_Int32 nRet;
+ for (;;)
+ {
+ nRet = static_cast<sal_Int32>(IMPL_RTL_USTRCODE(*pStr1)) -
+ static_cast<sal_Int32>(IMPL_RTL_USTRCODE(*pStr2));
+ if (!(nRet == 0 && *pStr2 ))
+ break;
+ pStr1++;
+ pStr2++;
+ }
+
+ return nRet;
+ }
+#endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+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_THROW_EXTERN_C()
+{
+ assert(nStr1Len >= 0);
+ assert(nStr2Len >= 0);
+#if !IMPL_RTL_IS_USTRING
+ // take advantage of builtin optimisations
+ sal_Int32 nMin = std::min(nStr1Len, nStr2Len);
+ sal_Int32 nRet = memcmp(pStr1, pStr2, nMin);
+ return nRet == 0 ? nStr1Len - nStr2Len : nRet;
+#else
+ if (sizeof(IMPL_RTL_STRCODE) == sizeof(wchar_t))
+ {
+ // take advantage of builtin optimisations
+ sal_Int32 nMin = std::min(nStr1Len, nStr2Len);
+ sal_Int32 nRet = wmemcmp(reinterpret_cast<wchar_t const *>(pStr1),
+ reinterpret_cast<wchar_t const *>(pStr2), nMin);
+ return nRet == 0 ? nStr1Len - nStr2Len : nRet;
+ }
+ else
+ {
+ sal_Int32 nRet = nStr1Len - nStr2Len;
+ int nCount = (nRet <= 0) ? nStr1Len : nStr2Len;
+
+ --pStr1;
+ --pStr2;
+ while( (--nCount >= 0) && (*++pStr1 == *++pStr2) ) ;
+
+ if( nCount >= 0 )
+ nRet = static_cast<sal_Int32>(IMPL_RTL_USTRCODE( *pStr1 ))
+ - static_cast<sal_Int32>(IMPL_RTL_USTRCODE( *pStr2 ));
+
+ return nRet;
+ }
+#endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nStr1Len >= 0);
+ assert(nStr2Len >= 0);
+ assert(nShortenedLength >= 0);
+#if !IMPL_RTL_IS_USTRING
+ // take advantage of builtin optimisations
+ sal_Int32 nMin = std::min(std::min(nStr1Len, nStr2Len), nShortenedLength);
+ sal_Int32 nRet = memcmp(pStr1, pStr2, nMin);
+ if (nRet == 0 && nShortenedLength > std::min(nStr1Len, nStr2Len))
+ return nStr1Len - nStr2Len;
+ return nRet;
+#else
+ if (sizeof(IMPL_RTL_STRCODE) == sizeof(wchar_t))
+ {
+ // take advantage of builtin optimisations
+ sal_Int32 nMin = std::min(std::min(nStr1Len, nStr2Len), nShortenedLength);
+ sal_Int32 nRet = wmemcmp(reinterpret_cast<wchar_t const *>(pStr1), reinterpret_cast<wchar_t const *>(pStr2), nMin);
+ if (nRet == 0 && nShortenedLength > std::min(nStr1Len, nStr2Len))
+ return nStr1Len - nStr2Len;
+ return nRet;
+ }
+ else
+ {
+ 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 = static_cast<sal_Int32>(IMPL_RTL_USTRCODE( *pStr1 ))-
+ static_cast<sal_Int32>(IMPL_RTL_USTRCODE( *pStr2 ));
+ if ( nRet )
+ return nRet;
+
+ nShortenedLength--;
+ pStr1++;
+ pStr2++;
+ }
+
+ if ( nShortenedLength <= 0 )
+ return 0;
+ return nStr1Len - nStr2Len;
+ }
+#endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nStr1Len >= 0);
+ assert(nStr2Len >= 0);
+ 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 = static_cast<sal_Int32>(IMPL_RTL_USTRCODE( *pStr1Run ))-
+ static_cast<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_THROW_EXTERN_C()
+{
+ assert(pStr1);
+ assert(pStr2);
+ sal_uInt32 c1;
+ do
+ {
+ c1 = IMPL_RTL_USTRCODE(*pStr1);
+ sal_Int32 nRet = rtl::compareIgnoreAsciiCase(
+ c1, IMPL_RTL_USTRCODE(*pStr2));
+ if ( nRet != 0 )
+ return nRet;
+
+ pStr1++;
+ pStr2++;
+ }
+ while (c1);
+
+ 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nStr1Len >= 0);
+ assert(nStr2Len >= 0);
+ const IMPL_RTL_STRCODE* pStr1End = pStr1 + nStr1Len;
+ const IMPL_RTL_STRCODE* pStr2End = pStr2 + nStr2Len;
+ while ( (pStr1 < pStr1End) && (pStr2 < pStr2End) )
+ {
+ sal_Int32 nRet = rtl::compareIgnoreAsciiCase(
+ IMPL_RTL_USTRCODE(*pStr1), IMPL_RTL_USTRCODE(*pStr2));
+ 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nStr1Len >= 0);
+ assert(nStr2Len >= 0);
+ assert(nShortenedLength >= 0);
+ const IMPL_RTL_STRCODE* pStr1End = pStr1 + nStr1Len;
+ const IMPL_RTL_STRCODE* pStr2End = pStr2 + nStr2Len;
+ while ( (nShortenedLength > 0) &&
+ (pStr1 < pStr1End) && (pStr2 < pStr2End) )
+ {
+ sal_Int32 nRet = rtl::compareIgnoreAsciiCase(
+ IMPL_RTL_USTRCODE(*pStr1), IMPL_RTL_USTRCODE(*pStr2));
+ 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 )
+ SAL_THROW_EXTERN_C()
+{
+ 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_THROW_EXTERN_C()
+{
+ assert(nLen >= 0);
+ sal_uInt32 h = static_cast<sal_uInt32>(nLen);
+ while ( nLen > 0 )
+ {
+ h = (h*37U) + IMPL_RTL_USTRCODE( *pStr );
+ pStr++;
+ nLen--;
+ }
+ return static_cast<sal_Int32>(h);
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Int32 SAL_CALL IMPL_RTL_STRNAME( indexOfChar )( const IMPL_RTL_STRCODE* pStr,
+ IMPL_RTL_STRCODE c )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+#if !IMPL_RTL_IS_USTRING
+ // take advantage of builtin optimisations
+ const IMPL_RTL_STRCODE* p = strchr(pStr, c);
+ return p ? p - pStr : -1;
+#else
+ if (sizeof(IMPL_RTL_STRCODE) == sizeof(wchar_t))
+ {
+ // take advantage of builtin optimisations
+ wchar_t const * p = wcschr(reinterpret_cast<wchar_t const *>(pStr), static_cast<wchar_t>(c));
+ return p ? p - reinterpret_cast<wchar_t const *>(pStr) : -1;
+ }
+ else
+ {
+ const IMPL_RTL_STRCODE* pTempStr = pStr;
+ while ( *pTempStr )
+ {
+ if ( *pTempStr == c )
+ return pTempStr-pStr;
+
+ pTempStr++;
+ }
+
+ return -1;
+ }
+#endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Int32 SAL_CALL IMPL_RTL_STRNAME( indexOfChar_WithLength )( const IMPL_RTL_STRCODE* pStr,
+ sal_Int32 nLen,
+ IMPL_RTL_STRCODE c )
+ SAL_THROW_EXTERN_C()
+{
+// assert(nLen >= 0);
+#if !IMPL_RTL_IS_USTRING
+ // take advantage of builtin optimisations
+ IMPL_RTL_STRCODE* p = static_cast<IMPL_RTL_STRCODE*>(std::memchr(const_cast<IMPL_RTL_STRCODE *>(pStr), c, nLen));
+ return p ? p - pStr : -1;
+#else
+ const IMPL_RTL_STRCODE* pTempStr = pStr;
+ while ( nLen > 0 )
+ {
+ if ( *pTempStr == c )
+ return pTempStr-pStr;
+
+ pTempStr++;
+ nLen--;
+ }
+
+ return -1;
+#endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Int32 SAL_CALL IMPL_RTL_STRNAME( lastIndexOfChar )( const IMPL_RTL_STRCODE* pStr,
+ IMPL_RTL_STRCODE c )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+#if !IMPL_RTL_IS_USTRING
+ // take advantage of builtin optimisations
+ const IMPL_RTL_STRCODE* p = strrchr(pStr, c);
+ return p ? p - pStr : -1;
+#else
+ if (sizeof(IMPL_RTL_STRCODE) == sizeof(wchar_t))
+ {
+ // take advantage of builtin optimisations
+ wchar_t const * p = wcsrchr(reinterpret_cast<wchar_t const *>(pStr), static_cast<wchar_t>(c));
+ return p ? p - reinterpret_cast<wchar_t const *>(pStr) : -1;
+ }
+ else
+ {
+ return IMPL_RTL_STRNAME( lastIndexOfChar_WithLength )( pStr, IMPL_RTL_STRNAME( getLength )( pStr ), c );
+ }
+#endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Int32 SAL_CALL IMPL_RTL_STRNAME( lastIndexOfChar_WithLength )( const IMPL_RTL_STRCODE* pStr,
+ sal_Int32 nLen,
+ IMPL_RTL_STRCODE c )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nLen >= 0);
+ 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ assert(pSubStr);
+#if !IMPL_RTL_IS_USTRING
+ // take advantage of builtin optimisations
+ const IMPL_RTL_STRCODE* p = strstr(pStr, pSubStr);
+ return p ? p - pStr : -1;
+#else
+ if (sizeof(IMPL_RTL_STRCODE) == sizeof(wchar_t))
+ {
+ // take advantage of builtin optimisations
+ wchar_t const * p = wcsstr(reinterpret_cast<wchar_t const *>(pStr), reinterpret_cast<wchar_t const *>(pSubStr));
+ return p ? p - reinterpret_cast<wchar_t const *>(pStr) : -1;
+ }
+ else
+ {
+ return IMPL_RTL_STRNAME( indexOfStr_WithLength )( pStr, IMPL_RTL_STRNAME( getLength )( pStr ),
+ pSubStr, IMPL_RTL_STRNAME( getLength )( pSubStr ) );
+ }
+#endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nStrLen >= 0);
+ assert(nSubLen >= 0);
+ /* faster search for a single character */
+ if ( nSubLen < 2 )
+ {
+ /* an empty SubString is always not findable */
+ 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 )
+ SAL_THROW_EXTERN_C()
+{
+ 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nStrLen >= 0);
+ assert(nSubLen >= 0);
+ /* faster search for a single character */
+ if ( nSubLen < 2 )
+ {
+ /* an empty SubString is always not findable */
+ 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nLen >= 0);
+ while ( nLen > 0 )
+ {
+ if ( *pStr == cOld )
+ *pStr = cNew;
+
+ pStr++;
+ nLen--;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRNAME( toAsciiLowerCase )( IMPL_RTL_STRCODE* pStr )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ while ( *pStr )
+ {
+ *pStr = rtl::toAsciiLowerCase(IMPL_RTL_USTRCODE(*pStr));
+
+ pStr++;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRNAME( toAsciiLowerCase_WithLength )( IMPL_RTL_STRCODE* pStr,
+ sal_Int32 nLen )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nLen >= 0);
+ while ( nLen > 0 )
+ {
+ *pStr = rtl::toAsciiLowerCase(IMPL_RTL_USTRCODE(*pStr));
+
+ pStr++;
+ nLen--;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRNAME( toAsciiUpperCase )( IMPL_RTL_STRCODE* pStr )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ while ( *pStr )
+ {
+ *pStr = rtl::toAsciiUpperCase(IMPL_RTL_USTRCODE(*pStr));
+
+ pStr++;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRNAME( toAsciiUpperCase_WithLength )( IMPL_RTL_STRCODE* pStr,
+ sal_Int32 nLen )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nLen >= 0);
+ while ( nLen > 0 )
+ {
+ *pStr = rtl::toAsciiUpperCase(IMPL_RTL_USTRCODE(*pStr));
+
+ pStr++;
+ nLen--;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Int32 SAL_CALL IMPL_RTL_STRNAME( trim )( IMPL_RTL_STRCODE* pStr )
+ SAL_THROW_EXTERN_C()
+{
+ 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_THROW_EXTERN_C()
+{
+ assert(nLen >= 0);
+ 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 )
+ {
+ nLen -= nPreSpaces;
+ memmove(pStr, pStr + nPreSpaces, nLen * sizeof(IMPL_RTL_STRCODE));
+ pStr += nLen;
+ *pStr = 0;
+ }
+
+ return nLen;
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Int32 SAL_CALL IMPL_RTL_STRNAME( valueOfBoolean )( IMPL_RTL_STRCODE* pStr, sal_Bool b )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ *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_THROW_EXTERN_C()
+{
+ assert(pStr);
+ assert( nRadix >= RTL_STR_MIN_RADIX && nRadix <= RTL_STR_MAX_RADIX );
+ char aBuf[RTL_STR_MAX_VALUEOFINT32];
+ 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 negative */
+ if ( n < 0 )
+ {
+ *pStr = '-';
+ pStr++;
+ nLen++;
+ nValue = n == SAL_MIN_INT32 ? static_cast<sal_uInt32>(n) : -n;
+ }
+ else
+ nValue = n;
+
+ /* create a recursive buffer with all values, except the last one */
+ do
+ {
+ char nDigit = static_cast<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_THROW_EXTERN_C()
+{
+ assert(pStr);
+ assert( nRadix >= RTL_STR_MIN_RADIX && nRadix <= RTL_STR_MAX_RADIX );
+ char aBuf[RTL_STR_MAX_VALUEOFINT64];
+ 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 negative */
+ if ( n < 0 )
+ {
+ *pStr = '-';
+ pStr++;
+ nLen++;
+ nValue = n == SAL_MIN_INT64 ? static_cast<sal_uInt64>(n) : -n;
+ }
+ else
+ nValue = n;
+
+ /* create a recursive buffer with all values, except the last one */
+ do
+ {
+ char nDigit = static_cast<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( valueOfUInt64 )( IMPL_RTL_STRCODE* pStr,
+ sal_uInt64 n,
+ sal_Int16 nRadix )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ assert( nRadix >= RTL_STR_MIN_RADIX && nRadix <= RTL_STR_MAX_RADIX );
+ char aBuf[RTL_STR_MAX_VALUEOFUINT64];
+ 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;
+
+ nValue = n;
+
+ /* create a recursive buffer with all values, except the last one */
+ do
+ {
+ char nDigit = static_cast<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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ if ( *pStr == '1' )
+ return 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 true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/* ----------------------------------------------------------------------- */
+namespace {
+ template<typename T, typename U> T IMPL_RTL_STRNAME( toInt_WithLength )( const IMPL_RTL_STRCODE* pStr,
+ sal_Int16 nRadix,
+ sal_Int32 nStrLength )
+ {
+ static_assert(std::numeric_limits<T>::is_signed, "is signed");
+ assert( nRadix >= RTL_STR_MIN_RADIX && nRadix <= RTL_STR_MAX_RADIX );
+ assert( nStrLength >= 0 );
+ bool bNeg;
+ sal_Int16 nDigit;
+ U n = 0;
+ const IMPL_RTL_STRCODE* pEnd = pStr + nStrLength;
+
+ if ( (nRadix < RTL_STR_MIN_RADIX) || (nRadix > RTL_STR_MAX_RADIX) )
+ nRadix = 10;
+
+ /* Skip whitespaces */
+ while ( pStr != pEnd && rtl_ImplIsWhitespace( IMPL_RTL_USTRCODE( *pStr ) ) )
+ pStr++;
+
+ if ( *pStr == '-' )
+ {
+ bNeg = true;
+ pStr++;
+ }
+ else
+ {
+ if ( *pStr == '+' )
+ pStr++;
+ bNeg = false;
+ }
+
+ T nDiv;
+ sal_Int16 nMod;
+ if ( bNeg )
+ {
+ nDiv = std::numeric_limits<T>::min() / nRadix;
+ nMod = std::numeric_limits<T>::min() % nRadix;
+ // Cater for C++03 implementations that round the quotient down
+ // instead of truncating towards zero as mandated by C++11:
+ if ( nMod > 0 )
+ {
+ --nDiv;
+ nMod -= nRadix;
+ }
+ nDiv = -nDiv;
+ nMod = -nMod;
+ }
+ else
+ {
+ nDiv = std::numeric_limits<T>::max() / nRadix;
+ nMod = std::numeric_limits<T>::max() % nRadix;
+ }
+
+ while ( pStr != pEnd )
+ {
+ nDigit = rtl_ImplGetDigit( IMPL_RTL_USTRCODE( *pStr ), nRadix );
+ if ( nDigit < 0 )
+ break;
+ assert(nDiv > 0);
+ if( static_cast<U>( nMod < nDigit ? nDiv-1 : nDiv ) < n )
+ return 0;
+
+ n *= nRadix;
+ n += nDigit;
+
+ pStr++;
+ }
+
+ if ( bNeg )
+ return n == static_cast<U>(std::numeric_limits<T>::min())
+ ? std::numeric_limits<T>::min() : -static_cast<T>(n);
+ else
+ return static_cast<T>(n);
+ }
+}
+
+sal_Int32 SAL_CALL IMPL_RTL_STRNAME( toInt32 )( const IMPL_RTL_STRCODE* pStr,
+ sal_Int16 nRadix )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ return IMPL_RTL_STRNAME( toInt_WithLength )<sal_Int32, sal_uInt32>(pStr, nRadix, IMPL_RTL_STRNAME( getLength )(pStr));
+}
+
+sal_Int64 SAL_CALL IMPL_RTL_STRNAME( toInt64 )( const IMPL_RTL_STRCODE* pStr,
+ sal_Int16 nRadix )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ return IMPL_RTL_STRNAME( toInt_WithLength )<sal_Int64, sal_uInt64>(pStr, nRadix, IMPL_RTL_STRNAME( getLength )(pStr));
+}
+
+sal_Int64 SAL_CALL IMPL_RTL_STRNAME( toInt64_WithLength )( const IMPL_RTL_STRCODE* pStr,
+ sal_Int16 nRadix,
+ sal_Int32 nStrLength)
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ return IMPL_RTL_STRNAME( toInt_WithLength )<sal_Int64, sal_uInt64>(pStr, nRadix, nStrLength);
+}
+
+/* ----------------------------------------------------------------------- */
+namespace {
+ template <typename T> T IMPL_RTL_STRNAME( toUInt )( const IMPL_RTL_STRCODE* pStr,
+ sal_Int16 nRadix )
+ {
+ static_assert(!std::numeric_limits<T>::is_signed, "is not signed");
+ assert( nRadix >= RTL_STR_MIN_RADIX && nRadix <= RTL_STR_MAX_RADIX );
+ sal_Int16 nDigit;
+ T 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;
+
+ // skip optional explicit sign
+ if ( *pStr == '+' )
+ ++pStr;
+
+ T nDiv = std::numeric_limits<T>::max() / nRadix;
+ sal_Int16 nMod = std::numeric_limits<T>::max() % nRadix;
+ while ( *pStr )
+ {
+ nDigit = rtl_ImplGetDigit( IMPL_RTL_USTRCODE( *pStr ), nRadix );
+ if ( nDigit < 0 )
+ break;
+ if( ( nMod < nDigit ? nDiv-1 : nDiv ) < n )
+ return 0;
+
+ n *= nRadix;
+ n += nDigit;
+
+ ++pStr;
+ }
+
+ return n;
+ }
+}
+
+sal_uInt32 SAL_CALL IMPL_RTL_STRNAME( toUInt32 )( const IMPL_RTL_STRCODE* pStr,
+ sal_Int16 nRadix )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ return IMPL_RTL_STRNAME( toUInt )<sal_uInt32>(pStr, nRadix);
+}
+
+sal_uInt64 SAL_CALL IMPL_RTL_STRNAME( toUInt64 )( const IMPL_RTL_STRCODE* pStr,
+ sal_Int16 nRadix )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ return IMPL_RTL_STRNAME( toUInt )<sal_uInt64>(pStr, nRadix);
+}
+
+/* ======================================================================= */
+/* Internal String-Class help functions */
+/* ======================================================================= */
+
+IMPL_RTL_STRINGDATA* IMPL_RTL_STRINGNAME( ImplAlloc )( sal_Int32 nLen )
+{
+ IMPL_RTL_STRINGDATA * pData
+ = (sal::static_int_cast< sal_uInt32 >(nLen)
+ <= ((SAL_MAX_UINT32 - sizeof (IMPL_RTL_STRINGDATA))
+ / sizeof (IMPL_RTL_STRCODE)))
+ ? static_cast<IMPL_RTL_STRINGDATA *>(rtl_allocateString(
+ sizeof (IMPL_RTL_STRINGDATA) + nLen * sizeof (IMPL_RTL_STRCODE)))
+ : nullptr;
+ if (pData != nullptr) {
+ 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 )
+{
+ assert(nCount >= 0);
+ IMPL_RTL_STRCODE* pDest;
+ const IMPL_RTL_STRCODE* pSrc;
+ IMPL_RTL_STRINGDATA* pData = IMPL_RTL_STRINGNAME( ImplAlloc )( pStr->length );
+ OSL_ASSERT(pData != nullptr);
+
+ pDest = pData->buffer;
+ pSrc = pStr->buffer;
+
+ memcpy( pDest, pSrc, nCount * sizeof(IMPL_RTL_STRCODE));
+
+ *ppThis = pData;
+
+ RTL_LOG_STRING_NEW( pData );
+ return pDest + nCount;
+}
+
+/* ======================================================================= */
+/* String-Class functions */
+/* ======================================================================= */
+
+namespace {
+
+void IMPL_RTL_ACQUIRE(IMPL_RTL_STRINGDATA * pThis)
+{
+ if (!SAL_STRING_IS_STATIC (pThis))
+ osl_atomic_increment( &((pThis)->refCount) );
+}
+
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRINGNAME( acquire )( IMPL_RTL_STRINGDATA* pThis )
+ SAL_THROW_EXTERN_C()
+{
+ IMPL_RTL_ACQUIRE( pThis );
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRINGNAME( release )( IMPL_RTL_STRINGDATA* pThis )
+ SAL_THROW_EXTERN_C()
+{
+ if (SAL_UNLIKELY(SAL_STRING_IS_STATIC (pThis)))
+ return;
+
+/* OString doesn't have an 'intern' */
+#if IMPL_RTL_IS_USTRING
+ if (SAL_STRING_IS_INTERN (pThis))
+ {
+ internRelease (pThis);
+ return;
+ }
+#endif
+
+ if ( !osl_atomic_decrement( &(pThis->refCount) ) )
+ {
+ RTL_LOG_STRING_DELETE( pThis );
+ rtl_freeString( pThis );
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRINGNAME( new )( IMPL_RTL_STRINGDATA** ppThis )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ if ( *ppThis)
+ IMPL_RTL_STRINGNAME( release )( *ppThis );
+
+ *ppThis = const_cast<IMPL_RTL_STRINGDATA*>(&IMPL_RTL_EMPTYSTRING);
+}
+
+/* ----------------------------------------------------------------------- */
+
+IMPL_RTL_STRINGDATA* SAL_CALL IMPL_RTL_STRINGNAME( alloc )( sal_Int32 nLen )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nLen >= 0);
+ return IMPL_RTL_STRINGNAME( ImplAlloc )( nLen );
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRINGNAME( new_WithLength )( IMPL_RTL_STRINGDATA** ppThis, sal_Int32 nLen )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ assert(nLen >= 0);
+ 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 != nullptr);
+ (*ppThis)->length = 0;
+
+ IMPL_RTL_STRCODE* pTempStr = (*ppThis)->buffer;
+ memset(pTempStr, 0, nLen*sizeof(IMPL_RTL_STRCODE));
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRINGNAME( newFromString )( IMPL_RTL_STRINGDATA** ppThis,
+ const IMPL_RTL_STRINGDATA* pStr )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ assert(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 != nullptr);
+ rtl_str_ImplCopy( (*ppThis)->buffer, pStr->buffer, pStr->length );
+ RTL_LOG_STRING_NEW( *ppThis );
+
+ /* must be done last, 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ IMPL_RTL_STRINGDATA* pOrg;
+ sal_Int32 nLen;
+
+ if ( pCharStr )
+ {
+ nLen = IMPL_RTL_STRNAME( getLength )( pCharStr );
+ }
+ else
+ nLen = 0;
+
+ if ( !nLen )
+ {
+ IMPL_RTL_STRINGNAME( new )( ppThis );
+ return;
+ }
+
+ pOrg = *ppThis;
+ *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen );
+ OSL_ASSERT(*ppThis != nullptr);
+ rtl_str_ImplCopy( (*ppThis)->buffer, pCharStr, nLen );
+ RTL_LOG_STRING_NEW( *ppThis );
+
+ /* must be done last, 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ assert(nLen >= 0);
+ 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 != nullptr);
+ rtl_str_ImplCopy( (*ppThis)->buffer, pCharStr, nLen );
+
+ RTL_LOG_STRING_NEW( *ppThis );
+
+ /* must be done last, if pCharStr == *ppThis */
+ if ( pOrg )
+ IMPL_RTL_STRINGNAME( release )( pOrg );
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRINGNAME( newFromSubString )( IMPL_RTL_STRINGDATA** ppThis,
+ const IMPL_RTL_STRINGDATA* pFrom,
+ sal_Int32 beginIndex,
+ sal_Int32 count )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ if ( beginIndex == 0 && count == pFrom->length )
+ {
+ IMPL_RTL_STRINGNAME( assign )( ppThis, const_cast< IMPL_RTL_STRINGDATA * >( pFrom ) );
+ return;
+ }
+ if ( count < 0 || beginIndex < 0 || beginIndex + count > pFrom->length )
+ {
+ assert(false); // fail fast at least in debug builds
+ IMPL_RTL_STRINGNAME( newFromLiteral )( ppThis, "!!br0ken!!", 10, 0 );
+ return;
+ }
+
+ IMPL_RTL_STRINGNAME( newFromStr_WithLength )( ppThis, pFrom->buffer + beginIndex, count );
+}
+
+/* ----------------------------------------------------------------------- */
+
+// Used when creating from string literals.
+void SAL_CALL IMPL_RTL_STRINGNAME( newFromLiteral )( IMPL_RTL_STRINGDATA** ppThis,
+ const char* pCharStr,
+ sal_Int32 nLen,
+ sal_Int32 allocExtra )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ assert(nLen >= 0);
+ assert(allocExtra >= 0);
+ if ( nLen + allocExtra == 0 )
+ {
+ IMPL_RTL_STRINGNAME( new )( ppThis );
+ return;
+ }
+
+ if ( *ppThis )
+ IMPL_RTL_STRINGNAME( release )( *ppThis );
+
+ *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen + allocExtra );
+ assert( *ppThis != nullptr );
+
+ (*ppThis)->length = nLen; // fix after possible allocExtra != 0
+ (*ppThis)->buffer[nLen] = 0;
+ IMPL_RTL_STRCODE* pBuffer = (*ppThis)->buffer;
+ sal_Int32 nCount;
+ for( nCount = nLen; nCount > 0; --nCount )
+ {
+#if IMPL_RTL_IS_USTRING
+ assert(static_cast<unsigned char>(*pCharStr) < 0x80); // ASCII range
+#endif
+ SAL_WARN_IF( (static_cast<unsigned char>(*pCharStr)) == '\0', "rtl.string",
+ "rtl_uString_newFromLiteral - Found embedded \\0 character" );
+
+ *pBuffer = *pCharStr;
+ pBuffer++;
+ pCharStr++;
+ }
+
+ RTL_LOG_STRING_NEW( *ppThis );
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRINGNAME( assign )( IMPL_RTL_STRINGDATA** ppThis,
+ IMPL_RTL_STRINGDATA* pStr )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ /* must be done at first, if pStr == *ppThis */
+ IMPL_RTL_ACQUIRE( pStr );
+
+ if ( *ppThis )
+ IMPL_RTL_STRINGNAME( release )( *ppThis );
+
+ *ppThis = pStr;
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Int32 SAL_CALL IMPL_RTL_STRINGNAME( getLength )( const IMPL_RTL_STRINGDATA* pThis )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pThis);
+ return pThis->length;
+}
+
+/* ----------------------------------------------------------------------- */
+
+IMPL_RTL_STRCODE* SAL_CALL IMPL_RTL_STRINGNAME( getStr )( IMPL_RTL_STRINGDATA * pThis )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pThis);
+ return pThis->buffer;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRINGNAME( newConcat )( IMPL_RTL_STRINGDATA** ppThis,
+ IMPL_RTL_STRINGDATA* pLeft,
+ IMPL_RTL_STRINGDATA* pRight )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ IMPL_RTL_STRINGDATA* pOrg = *ppThis;
+
+ /* Test for 0-Pointer - if not, change newReplaceStrAt! */
+ if ( !pRight || !pRight->length )
+ {
+ *ppThis = pLeft;
+ IMPL_RTL_ACQUIRE( pLeft );
+ }
+ else if ( !pLeft || !pLeft->length )
+ {
+ *ppThis = pRight;
+ IMPL_RTL_ACQUIRE( pRight );
+ }
+ else if (pLeft->length
+ > std::numeric_limits<sal_Int32>::max() - pRight->length)
+ {
+ *ppThis = nullptr;
+ }
+ else
+ {
+ IMPL_RTL_STRINGDATA* pTempStr = IMPL_RTL_STRINGNAME( ImplAlloc )( pLeft->length + pRight->length );
+ OSL_ASSERT(pTempStr != nullptr);
+ *ppThis = pTempStr;
+ if (*ppThis != nullptr) {
+ rtl_str_ImplCopy( pTempStr->buffer, pLeft->buffer, pLeft->length );
+ rtl_str_ImplCopy( pTempStr->buffer+pLeft->length, pRight->buffer, pRight->length );
+
+ RTL_LOG_STRING_NEW( *ppThis );
+ }
+ }
+
+ /* must be done last, if left or right == *ppThis */
+ if ( pOrg )
+ IMPL_RTL_STRINGNAME( release )( pOrg );
+}
+
+/* ----------------------------------------------------------------------- */
+
+void SAL_CALL IMPL_RTL_STRINGNAME( ensureCapacity )( IMPL_RTL_STRINGDATA** ppThis,
+ sal_Int32 size )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ IMPL_RTL_STRINGDATA* const pOrg = *ppThis;
+ if ( pOrg->refCount == 1 && pOrg->length >= size )
+ return;
+ assert( pOrg->length <= size ); // do not truncate
+ IMPL_RTL_STRINGDATA* pTempStr = IMPL_RTL_STRINGNAME( ImplAlloc )( size );
+ rtl_str_ImplCopy( pTempStr->buffer, pOrg->buffer, pOrg->length );
+ // right now the length is still the same as of the original
+ pTempStr->length = pOrg->length;
+ pTempStr->buffer[ pOrg->length ] = '\0';
+ *ppThis = pTempStr;
+ RTL_LOG_STRING_NEW( *ppThis );
+
+ 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ assert(nIndex >= 0 && nIndex <= pStr->length);
+ assert(nCount >= 0);
+ assert(nCount <= pStr->length - nIndex);
+ /* Append? */
+ if ( nIndex >= pStr->length )
+ {
+ /* newConcat test, if pNewSubStr is 0 */
+ IMPL_RTL_STRINGNAME( newConcat )( ppThis, pStr, pNewSubStr );
+ return;
+ }
+
+ /* negative 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 != nullptr);
+ 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 );
+
+ RTL_LOG_STRING_NEW( *ppThis );
+ /* must be done last, 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ assert(pStr);
+ IMPL_RTL_STRINGDATA* pOrg = *ppThis;
+ bool bChanged = false;
+ 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 = true;
+ break;
+ }
+
+ pCharStr++;
+ nLen--;
+ }
+
+ if ( !bChanged )
+ {
+ *ppThis = pStr;
+ IMPL_RTL_ACQUIRE( pStr );
+ }
+
+ RTL_LOG_STRING_NEW( *ppThis );
+ /* must be done last, 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ assert(pStr);
+ IMPL_RTL_STRINGDATA* pOrg = *ppThis;
+ bool bChanged = false;
+ sal_Int32 nLen = pStr->length;
+ const IMPL_RTL_STRCODE* pCharStr = pStr->buffer;
+
+ while ( nLen > 0 )
+ {
+ if ( rtl::isAsciiUpperCase(IMPL_RTL_USTRCODE(*pCharStr)) )
+ {
+ /* Copy String */
+ IMPL_RTL_STRCODE* pNewCharStr = IMPL_RTL_STRINGNAME( ImplNewCopy )( ppThis, pStr, pCharStr-pStr->buffer );
+
+ /* replace/copy rest of the string */
+ if ( pNewCharStr )
+ {
+ *pNewCharStr = rtl::toAsciiLowerCase(IMPL_RTL_USTRCODE(*pCharStr));
+ pNewCharStr++;
+ pCharStr++;
+ nLen--;
+
+ while ( nLen > 0 )
+ {
+ *pNewCharStr = rtl::toAsciiLowerCase(IMPL_RTL_USTRCODE(*pCharStr));
+
+ pNewCharStr++;
+ pCharStr++;
+ nLen--;
+ }
+ }
+
+ bChanged = true;
+ break;
+ }
+
+ pCharStr++;
+ nLen--;
+ }
+
+ if ( !bChanged )
+ {
+ *ppThis = pStr;
+ IMPL_RTL_ACQUIRE( pStr );
+ }
+
+ RTL_LOG_STRING_NEW( *ppThis );
+ /* must be done last, 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ assert(pStr);
+ IMPL_RTL_STRINGDATA* pOrg = *ppThis;
+ bool bChanged = false;
+ sal_Int32 nLen = pStr->length;
+ const IMPL_RTL_STRCODE* pCharStr = pStr->buffer;
+
+ while ( nLen > 0 )
+ {
+ if ( rtl::isAsciiLowerCase(IMPL_RTL_USTRCODE(*pCharStr)) )
+ {
+ /* Copy String */
+ IMPL_RTL_STRCODE* pNewCharStr = IMPL_RTL_STRINGNAME( ImplNewCopy )( ppThis, pStr, pCharStr-pStr->buffer );
+
+ /* replace/copy rest of the string */
+ if ( pNewCharStr )
+ {
+ *pNewCharStr = rtl::toAsciiUpperCase(IMPL_RTL_USTRCODE(*pCharStr));
+ pNewCharStr++;
+ pCharStr++;
+ nLen--;
+
+ while ( nLen > 0 )
+ {
+ *pNewCharStr = rtl::toAsciiUpperCase(IMPL_RTL_USTRCODE(*pCharStr));
+
+ pNewCharStr++;
+ pCharStr++;
+ nLen--;
+ }
+ }
+
+ bChanged = true;
+ break;
+ }
+
+ pCharStr++;
+ nLen--;
+ }
+
+ if ( !bChanged )
+ {
+ *ppThis = pStr;
+ IMPL_RTL_ACQUIRE( pStr );
+ }
+
+ RTL_LOG_STRING_NEW( *ppThis );
+ /* must be done last, 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ assert(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_ACQUIRE( pStr );
+ }
+ else
+ {
+ nLen -= nPostSpaces+nPreSpaces;
+ *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen );
+ assert(*ppThis);
+ rtl_str_ImplCopy( (*ppThis)->buffer, pStr->buffer+nPreSpaces, nLen );
+ }
+
+ RTL_LOG_STRING_NEW( *ppThis );
+ /* must be done last, 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 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ assert(pStr);
+ 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;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/unload.cxx b/sal/rtl/unload.cxx
new file mode 100644
index 000000000..975e575db
--- /dev/null
+++ b/sal/rtl/unload.cxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <osl/time.h>
+#include <rtl/unload.h>
+
+extern "C" void rtl_moduleCount_acquire(rtl_ModuleCount *) {}
+
+extern "C" void rtl_moduleCount_release(rtl_ModuleCount *) {}
+
+extern "C" sal_Bool rtl_moduleCount_canUnload(
+ rtl_StandardModuleCount *, TimeValue *)
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/uri.cxx b/sal/rtl/uri.cxx
new file mode 100644
index 000000000..441a6c69f
--- /dev/null
+++ b/sal/rtl/uri.cxx
@@ -0,0 +1,893 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rtl/character.hxx>
+#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 <sal/macros.h>
+
+#include <uri_internal.hxx>
+
+#include <algorithm>
+#include <cstddef>
+
+namespace {
+
+std::size_t const nCharClassSize = 128;
+
+sal_Unicode const cEscapePrefix = 0x25; // '%'
+
+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
+}
+
+bool isValid(sal_Bool const * pCharClass, sal_uInt32 nUtf32)
+{
+ return nUtf32 < nCharClassSize && pCharClass[nUtf32];
+}
+
+void writeUnicode(rtl_uString ** pBuffer, sal_Int32 * pCapacity,
+ sal_Unicode cChar)
+{
+ rtl_uStringbuffer_insert(pBuffer, pCapacity, (*pBuffer)->length, &cChar, 1);
+}
+
+}
+
+namespace rtl::uri::detail {
+
+/** Read any of the following:
+
+ @li sequence of escape sequences representing character from eCharset,
+ translated to single UCS4 character; or
+ @li pair of UTF-16 surrogates, translated to single UCS4 character; or
+ @li 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 = false;
+ break;
+ }
+ p += 3;
+ nEncoded |= ((nWeight1 & 3) << 4 | nWeight2) << nShift;
+ }
+ if (bUTF8 && rtl::isUnicodeScalarValue(nEncoded)
+ && nEncoded >= nMin)
+ {
+ *pBegin = p;
+ *pType = EscapeChar;
+ return nEncoded;
+ }
+ }
+ *pType = EscapeOctet;
+ }
+ else
+ {
+ 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, nullptr, aBuf.getStr(), aBuf.getLength(), aDst,
+ SAL_N_ELEMENTS( aDst ),
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR),
+ &nInfo, &nConverted);
+
+ if (nInfo == 0)
+ {
+ assert( nConverted
+ == sal::static_int_cast< sal_uInt32 >(
+ aBuf.getLength()));
+
+ rtl_destroyTextToUnicodeConverter(aConverter);
+ *pBegin = p;
+ *pType = EscapeChar;
+
+ assert( nDstSize == 1
+ || (nDstSize == 2 && rtl::isHighSurrogate(aDst[0])
+ && rtl::isLowSurrogate(aDst[1])));
+
+ return nDstSize == 1
+ ? aDst[0] : rtl::combineSurrogates(aDst[0], aDst[1]);
+ }
+ if (nInfo == RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOOSMALL
+ && 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_SRCBUFFERTOOSMALL
+ && p != pEnd && *p <= 0x7F)
+ {
+ aBuf.append(static_cast< char >(*p++));
+ }
+ else
+ {
+ assert(
+ (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL)
+ == 0);
+ break;
+ }
+ }
+ rtl_destroyTextToUnicodeConverter(aConverter);
+ *pType = EscapeOctet;
+ }
+ return nChar;
+ }
+
+ *pType = EscapeNo;
+ return rtl::isHighSurrogate(nChar) && *pBegin < pEnd
+ && rtl::isLowSurrogate(**pBegin) ?
+ rtl::combineSurrogates(nChar, *(*pBegin)++) : nChar;
+}
+
+}
+
+namespace {
+
+void writeUcs4(rtl_uString ** pBuffer, sal_Int32 * pCapacity, sal_uInt32 nUtf32)
+{
+ assert(rtl::isUnicodeCodePoint(nUtf32));
+ 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)
+{
+ assert(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)
+{
+ assert(rtl::isUnicodeCodePoint(nUtf32));
+ 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;
+ }
+
+ char aDst[32]; // FIXME random value
+ sal_uInt32 nInfo;
+ sal_Size nConverted;
+ sal_Size nDstSize = rtl_convertUnicodeToText(
+ aConverter, nullptr, aSrc, nSrcSize, aDst, sizeof aDst,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_FLUSH,
+ &nInfo, &nConverted);
+ assert((nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL) == 0);
+ rtl_destroyUnicodeToTextConverter(aConverter);
+
+ if (nInfo == 0)
+ {
+ assert(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;
+
+ writeUcs4(pBuffer, pCapacity, nUtf32);
+ }
+ }
+ return true;
+}
+
+struct Component
+{
+ sal_Unicode const * pBegin;
+ sal_Unicode const * pEnd;
+
+ Component(): pBegin(nullptr), pEnd(nullptr) {}
+
+ bool isPresent() const { return pBegin != nullptr; }
+
+ sal_Int32 getLength() const;
+};
+
+sal_Int32 Component::getLength() const
+{
+ assert(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 && rtl::isAsciiAlpha(*pPos))
+ {
+ for (sal_Unicode const * p = pPos + 1; p != pEnd; ++p)
+ {
+ if (*p == ':')
+ {
+ pComponents->aScheme.pBegin = pBegin;
+ pComponents->aScheme.pEnd = ++p;
+ pPos = p;
+ break;
+ }
+
+ if (!rtl::isAsciiAlphanumeric(*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)
+ {
+ assert(*pPos == '#');
+ pComponents->aFragment.pBegin = pPos;
+ pComponents->aFragment.pEnd = pEnd;
+ }
+}
+
+void appendPath(
+ OUStringBuffer & buffer, sal_Int32 bufferStart, bool precedingSlash,
+ sal_Unicode const * pathBegin, sal_Unicode const * pathEnd)
+{
+ while (precedingSlash || pathBegin != pathEnd)
+ {
+ sal_Unicode const * p = pathBegin;
+ while (p != pathEnd && *p != '/')
+ {
+ ++p;
+ }
+
+ std::size_t n = p - pathBegin;
+ if (n == 1 && pathBegin[0] == '.')
+ {
+ // input begins with "." -> remove from input (and done):
+ // i.e., !precedingSlash -> !precedingSlash
+ // input begins with "./" -> remove from input:
+ // i.e., !precedingSlash -> !precedingSlash
+ // input begins with "/." -> replace with "/" in input (and not yet
+ // done):
+ // i.e., precedingSlash -> precedingSlash
+ // input begins with "/./" -> replace with "/" in input:
+ // i.e., precedingSlash -> precedingSlash
+ }
+ else if (n == 2 && pathBegin[0] == '.' && pathBegin[1] == '.')
+ {
+ // input begins with ".." -> remove from input (and done):
+ // i.e., !precedingSlash -> !precedingSlash
+ // input begins with "../" -> remove from input
+ // i.e., !precedingSlash -> !precedingSlash
+ // input begins with "/.." -> replace with "/" in input, and shrink
+ // output (not yet done):
+ // i.e., precedingSlash -> precedingSlash
+ // input begins with "/../" -> replace with "/" in input, and shrink
+ // output:
+ // i.e., precedingSlash -> precedingSlash
+ if (precedingSlash)
+ {
+ buffer.truncate(
+ bufferStart
+ + std::max<sal_Int32>(
+ rtl_ustr_lastIndexOfChar_WithLength(
+ buffer.getStr() + bufferStart,
+ buffer.getLength() - bufferStart, '/'),
+ 0));
+ }
+ }
+ else
+ {
+ if (precedingSlash)
+ buffer.append('/');
+
+ buffer.append(pathBegin, n);
+ precedingSlash = p != pathEnd;
+ }
+ pathBegin = p + (p == pathEnd ? 0 : 1);
+ }
+}
+
+}
+
+sal_Bool const * SAL_CALL rtl_getUriCharClass(rtl_UriCharClass eCharClass)
+ SAL_THROW_EXTERN_C()
+{
+ static sal_Bool const aCharClass[][nCharClassSize] = {
+ {false, false, false, false, false, false, false, false,// None
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // !"#$%&'
+ false, false, false, false, false, false, false, false, // ()*+,-./
+ false, false, false, false, false, false, false, false, // 01234567
+ false, false, false, false, false, false, false, false, // 89:;<=>?
+ false, false, false, false, false, false, false, false, // @ABCDEFG
+ false, false, false, false, false, false, false, false, // HIJKLMNO
+ false, false, false, false, false, false, false, false, // PQRSTUVW
+ false, false, false, false, false, false, false, false, // XYZ[\]^_
+ false, false, false, false, false, false, false, false, // `abcdefg
+ false, false, false, false, false, false, false, false, // hijklmno
+ false, false, false, false, false, false, false, false, // pqrstuvw
+ false, false, false, false, false, false, false, false}, // xyz{|}~
+ {false, false, false, false, false, false, false, false,// Uric
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, true, false, false, true, false, true, true, // !"#$%&'
+ true, true, true, true, true, true, true, true, // ()*+,-./
+ true, true, true, true, true, true, true, true, // 01234567
+ true, true, true, true, false, true, false, true, // 89:;<=>?
+ true, true, true, true, true, true, true, true, // @ABCDEFG
+ true, true, true, true, true, true, true, true, // HIJKLMNO
+ true, true, true, true, true, true, true, true, // PQRSTUVW
+ true, true, true, true, false, true, false, true, // XYZ[\]^_
+ false, true, true, true, true, true, true, true, // `abcdefg
+ true, true, true, true, true, true, true, true, // hijklmno
+ true, true, true, true, true, true, true, true, // pqrstuvw
+ true, true, true, false, false, false, true, false}, // xyz{|}~
+ {false, false, false, false, false, false, false, false,// UricNoSlash
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, true, false, false, true, false, true, true, // !"#$%&'
+ true, true, true, true, true, true, true, false, // ()*+,-./
+ true, true, true, true, true, true, true, true, // 01234567
+ true, true, true, true, false, true, false, true, // 89:;<=>?
+ true, true, true, true, true, true, true, true, // @ABCDEFG
+ true, true, true, true, true, true, true, true, // HIJKLMNO
+ true, true, true, true, true, true, true, true, // PQRSTUVW
+ true, true, true, false, false, false, false, true, // XYZ[\]^_
+ false, true, true, true, true, true, true, true, // `abcdefg
+ true, true, true, true, true, true, true, true, // hijklmno
+ true, true, true, true, true, true, true, true, // pqrstuvw
+ true, true, true, false, false, false, true, false}, // xyz{|}~
+ {false, false, false, false, false, false, false, false,// RelSegment
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, true, false, false, true, false, true, true, // !"#$%&'
+ true, true, true, true, true, true, true, false, // ()*+,-./
+ true, true, true, true, true, true, true, true, // 01234567
+ true, true, false, true, false, true, false, false, // 89:;<=>?
+ true, true, true, true, true, true, true, true, // @ABCDEFG
+ true, true, true, true, true, true, true, true, // HIJKLMNO
+ true, true, true, true, true, true, true, true, // PQRSTUVW
+ true, true, true, false, false, false, false, true, // XYZ[\]^_
+ false, true, true, true, true, true, true, true, // `abcdefg
+ true, true, true, true, true, true, true, true, // hijklmno
+ true, true, true, true, true, true, true, true, // pqrstuvw
+ true, true, true, false, false, false, true, false}, // xyz{|}~
+ {false, false, false, false, false, false, false, false,// RegName
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, true, false, false, true, false, true, true, // !"#$%&'
+ true, true, true, true, true, true, true, false, // ()*+,-./
+ true, true, true, true, true, true, true, true, // 01234567
+ true, true, true, true, false, true, false, false, // 89:;<=>?
+ true, true, true, true, true, true, true, true, // @ABCDEFG
+ true, true, true, true, true, true, true, true, // HIJKLMNO
+ true, true, true, true, true, true, true, true, // PQRSTUVW
+ true, true, true, false, false, false, false, true, // XYZ[\]^_
+ false, true, true, true, true, true, true, true, // `abcdefg
+ true, true, true, true, true, true, true, true, // hijklmno
+ true, true, true, true, true, true, true, true, // pqrstuvw
+ true, true, true, false, false, false, true, false}, // xyz{|}~
+ {false, false, false, false, false, false, false, false,// Userinfo
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, true, false, false, true, false, true, true, // !"#$%&'
+ true, true, true, true, true, true, true, false, // ()*+,-./
+ true, true, true, true, true, true, true, true, // 01234567
+ true, true, true, true, false, true, false, false, // 89:;<=>?
+ false, true, true, true, true, true, true, true, // @ABCDEFG
+ true, true, true, true, true, true, true, true, // HIJKLMNO
+ true, true, true, true, true, true, true, true, // PQRSTUVW
+ true, true, true, false, false, false, false, true, // XYZ[\]^_
+ false, true, true, true, true, true, true, true, // `abcdefg
+ true, true, true, true, true, true, true, true, // hijklmno
+ true, true, true, true, true, true, true, true, // pqrstuvw
+ true, true, true, false, false, false, true, false}, // xyz{|}~
+ {false, false, false, false, false, false, false, false,// Pchar
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, true, false, false, true, false, true, true, // !"#$%&'
+ true, true, true, true, true, true, true, false, // ()*+,-./
+ true, true, true, true, true, true, true, true, // 01234567
+ true, true, true, false, false, true, false, false, // 89:;<=>?
+ true, true, true, true, true, true, true, true, // @ABCDEFG
+ true, true, true, true, true, true, true, true, // HIJKLMNO
+ true, true, true, true, true, true, true, true, // PQRSTUVW
+ true, true, true, false, false, false, false, true, // XYZ[\]^_
+ false, true, true, true, true, true, true, true, // `abcdefg
+ true, true, true, true, true, true, true, true, // hijklmno
+ true, true, true, true, true, true, true, true, // pqrstuvw
+ true, true, true, false, false, false, true, false}, // xyz{|}~
+ {false, false, false, false, false, false, false, false,// UnoParamValue
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, true, false, false, true, false, true, true, // !"#$%&'
+ true, true, true, true, false, true, true, true, // ()*+,-./
+ true, true, true, true, true, true, true, true, // 01234567
+ true, true, true, false, false, false, false, true, // 89:;<=>?
+ true, true, true, true, true, true, true, true, // @ABCDEFG
+ true, true, true, true, true, true, true, true, // HIJKLMNO
+ true, true, true, true, true, true, true, true, // PQRSTUVW
+ true, true, true, false, false, false, false, true, // XYZ[\]^_
+ false, true, true, true, true, true, true, true, // `abcdefg
+ true, true, true, true, true, true, true, true, // hijklmno
+ true, true, true, true, true, true, true, true, // pqrstuvw
+ true, true, true, false, false, false, true, false}}; // xyz{|}~
+
+ assert(
+ (eCharClass >= 0
+ && (sal::static_int_cast< std::size_t >(eCharClass)
+ < SAL_N_ELEMENTS(aCharClass)))); // 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()
+{
+ assert(!pCharClass[0x25]); // make sure the percent sign is encoded...
+
+ sal_Unicode const * p = pText->buffer;
+ sal_Unicode const * pEnd = p + pText->length;
+ sal_Int32 nCapacity = 256;
+ rtl_uString_new_WithLength(pResult, nCapacity);
+
+ while (p < pEnd)
+ {
+ rtl::uri::detail::EscapeType eType;
+ sal_uInt32 nUtf32 = rtl::uri::detail::readUcs4(
+ &p, pEnd,
+ (eMechanism == rtl_UriEncodeKeepEscapes
+ || eMechanism == rtl_UriEncodeCheckEscapes
+ || eMechanism == rtl_UriEncodeStrictKeepEscapes),
+ eCharset, &eType);
+
+ switch (eType)
+ {
+ case rtl::uri::detail::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 rtl::uri::detail::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 rtl::uri::detail::EscapeOctet:
+ writeEscapeOctet(pResult, &nCapacity, nUtf32);
+ break;
+ }
+ }
+ *pResult = rtl_uStringBuffer_makeStringAndClear(pResult, &nCapacity);
+}
+
+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;
+ [[fallthrough]];
+ default: // rtl_UriDecodeWithCharset, rtl_UriDecodeStrict
+ {
+ sal_Unicode const * p = pText->buffer;
+ sal_Unicode const * pEnd = p + pText->length;
+ sal_Int32 nCapacity = pText->length;
+ rtl_uString_new_WithLength(pResult, nCapacity);
+
+ while (p < pEnd)
+ {
+ rtl::uri::detail::EscapeType eType;
+ sal_uInt32 nUtf32 = rtl::uri::detail::readUcs4(&p, pEnd, true, eCharset, &eType);
+ switch (eType)
+ {
+ case rtl::uri::detail::EscapeChar:
+ if (nUtf32 <= 0x7F && eMechanism == rtl_UriDecodeToIuri)
+ {
+ writeEscapeOctet(pResult, &nCapacity, nUtf32);
+ break;
+ }
+ [[fallthrough]];
+
+ case rtl::uri::detail::EscapeNo:
+ writeUcs4(pResult, &nCapacity, nUtf32);
+ break;
+
+ case rtl::uri::detail::EscapeOctet:
+ if (eMechanism == rtl_UriDecodeStrict)
+ {
+ rtl_uString_new(pResult);
+ return;
+ }
+ writeEscapeOctet(pResult, &nCapacity, nUtf32);
+ break;
+ }
+ }
+
+ *pResult = rtl_uStringBuffer_makeStringAndClear( pResult, &nCapacity );
+ }
+ break;
+ }
+}
+
+sal_Bool SAL_CALL rtl_uriConvertRelToAbs(rtl_uString * pBaseUriRef,
+ rtl_uString * pRelUriRef,
+ rtl_uString ** pResult,
+ rtl_uString ** pException)
+ SAL_THROW_EXTERN_C()
+{
+ // Use the strict parser algorithm from RFC 3986, section 5.2, to turn the
+ // relative URI into an absolute one:
+ Components aRelComponents;
+ parseUriRef(pRelUriRef, &aRelComponents);
+ OUStringBuffer aBuffer(256);
+
+ if (aRelComponents.aScheme.isPresent())
+ {
+ aBuffer.append(aRelComponents.aScheme.pBegin,
+ aRelComponents.aScheme.getLength());
+
+ if (aRelComponents.aAuthority.isPresent())
+ {
+ aBuffer.append(aRelComponents.aAuthority.pBegin,
+ aRelComponents.aAuthority.getLength());
+ }
+
+ appendPath(
+ aBuffer, aBuffer.getLength(), false, aRelComponents.aPath.pBegin,
+ aRelComponents.aPath.pEnd);
+
+ if (aRelComponents.aQuery.isPresent())
+ {
+ aBuffer.append(aRelComponents.aQuery.pBegin,
+ aRelComponents.aQuery.getLength());
+ }
+ }
+ else
+ {
+ Components aBaseComponents;
+ parseUriRef(pBaseUriRef, &aBaseComponents);
+ if (!aBaseComponents.aScheme.isPresent())
+ {
+ rtl_uString_assign(
+ pException,
+ (OUString(
+ "<" + OUString::unacquired(&pBaseUriRef)
+ + "> does not start with a scheme component")
+ .pData));
+ return false;
+ }
+
+ aBuffer.append(aBaseComponents.aScheme.pBegin,
+ aBaseComponents.aScheme.getLength());
+ if (aRelComponents.aAuthority.isPresent())
+ {
+ aBuffer.append(aRelComponents.aAuthority.pBegin,
+ aRelComponents.aAuthority.getLength());
+ appendPath(
+ aBuffer, aBuffer.getLength(), false,
+ aRelComponents.aPath.pBegin, aRelComponents.aPath.pEnd);
+
+ 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)
+ {
+ aBuffer.append(aBaseComponents.aPath.pBegin,
+ aBaseComponents.aPath.getLength());
+ if (aRelComponents.aQuery.isPresent())
+ {
+ aBuffer.append(aRelComponents.aQuery.pBegin,
+ aRelComponents.aQuery.getLength());
+ }
+ else if (aBaseComponents.aQuery.isPresent())
+ {
+ aBuffer.append(aBaseComponents.aQuery.pBegin,
+ aBaseComponents.aQuery.getLength());
+ }
+ }
+ else
+ {
+ if (*aRelComponents.aPath.pBegin == '/')
+ {
+ appendPath(
+ aBuffer, aBuffer.getLength(), false,
+ aRelComponents.aPath.pBegin, aRelComponents.aPath.pEnd);
+ }
+ else if (aBaseComponents.aAuthority.isPresent()
+ && aBaseComponents.aPath.pBegin
+ == aBaseComponents.aPath.pEnd)
+ {
+ appendPath(
+ aBuffer, aBuffer.getLength(), true,
+ aRelComponents.aPath.pBegin, aRelComponents.aPath.pEnd);
+ }
+ else
+ {
+ sal_Int32 n = aBuffer.getLength();
+ sal_Int32 i = rtl_ustr_lastIndexOfChar_WithLength(
+ aBaseComponents.aPath.pBegin,
+ aBaseComponents.aPath.getLength(), '/');
+
+ if (i >= 0)
+ {
+ appendPath(
+ aBuffer, n, false, aBaseComponents.aPath.pBegin,
+ aBaseComponents.aPath.pBegin + i);
+ }
+
+ appendPath(
+ aBuffer, n, i >= 0, aRelComponents.aPath.pBegin,
+ aRelComponents.aPath.pEnd);
+ }
+
+ 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;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/ustrbuf.cxx b/sal/rtl/ustrbuf.cxx
new file mode 100644
index 000000000..53e178e58
--- /dev/null
+++ b/sal/rtl/ustrbuf.cxx
@@ -0,0 +1,268 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+
+#include <osl/interlck.h>
+#include <osl/diagnose.h>
+#include <rtl/character.hxx>
+#include <rtl/ustrbuf.hxx>
+#include "strimp.hxx"
+
+#if USE_SDT_PROBES
+#define RTL_LOG_STRING_BITS 16
+#endif
+
+void SAL_CALL rtl_uStringbuffer_newFromStr_WithLength( rtl_uString ** newStr,
+ const sal_Unicode * value,
+ sal_Int32 count)
+{
+ assert(newStr);
+ assert(count >= 0);
+ if (!value)
+ {
+ rtl_uString_new_WithLength( newStr, 16 );
+ return;
+ }
+
+ // use raw alloc to avoid overwriting the buffer twice
+ if ( *newStr)
+ rtl_uString_release( *newStr );
+ *newStr = rtl_uString_ImplAlloc( count + 16 );
+ (*newStr)->length = count;
+ memcpy( (*newStr)->buffer, value, count * sizeof(sal_Unicode) );
+ memset( (*newStr)->buffer + count, 0, 16 * sizeof(sal_Unicode) );
+ RTL_LOG_STRING_NEW( *newStr );
+}
+
+rtl_uString * SAL_CALL rtl_uStringBuffer_refReturn( rtl_uString * pThis )
+{
+ RTL_LOG_STRING_NEW( pThis );
+ rtl_uString_acquire( pThis );
+ return pThis;
+}
+
+rtl_uString * SAL_CALL rtl_uStringBuffer_makeStringAndClear( rtl_uString ** ppThis,
+ sal_Int32 *nCapacity )
+{
+ assert(ppThis);
+ assert(nCapacity);
+ // avoid an un-necessary atomic ref/unref pair
+ rtl_uString *pStr = *ppThis;
+ *ppThis = nullptr;
+
+ rtl_uString_new (ppThis);
+ *nCapacity = 0;
+
+ RTL_LOG_STRING_NEW( pStr );
+
+ return pStr;
+}
+
+sal_Int32 SAL_CALL rtl_uStringbuffer_newFromStringBuffer( rtl_uString ** newStr,
+ sal_Int32 capacity,
+ rtl_uString * oldStr )
+{
+ assert(newStr);
+ assert(capacity >= 0);
+ assert(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;
+ memcpy( (*newStr)->buffer, oldStr->buffer, oldStr->length * sizeof(sal_Unicode));
+ }
+ RTL_LOG_STRING_NEW( *newStr );
+ return newCapacity;
+}
+
+void SAL_CALL rtl_uStringbuffer_ensureCapacity
+ (rtl_uString ** This, sal_Int32* capacity, sal_Int32 minimumCapacity)
+{
+ assert(This);
+ assert(capacity && *capacity >= 0);
+ assert(minimumCapacity >= 0);
+ if (minimumCapacity <= *capacity)
+ return;
+
+ rtl_uString * pTmp = *This;
+ rtl_uString * pNew = nullptr;
+ auto nLength = (*This)->length;
+ *capacity = (nLength + 1) * 2;
+ if (minimumCapacity > *capacity)
+ /* still lower, set to the minimum capacity */
+ *capacity = minimumCapacity;
+
+ // use raw alloc to avoid overwriting the buffer twice
+ pNew = rtl_uString_ImplAlloc( *capacity );
+ pNew->length = nLength;
+ *This = pNew;
+
+ memcpy( (*This)->buffer, pTmp->buffer, nLength * sizeof(sal_Unicode) );
+ memset( (*This)->buffer + nLength, 0, (*capacity - nLength) * sizeof(sal_Unicode) );
+
+ RTL_LOG_STRING_NEW( pTmp ); // with accurate contents
+ rtl_uString_release( pTmp );
+}
+
+void SAL_CALL rtl_uStringbuffer_insert( rtl_uString ** This,
+ sal_Int32 * capacity,
+ sal_Int32 offset,
+ const sal_Unicode * str,
+ sal_Int32 len)
+{
+ assert(This);
+ assert(capacity && *capacity >= 0);
+ assert(offset >= 0 && offset <= (**This).length);
+ assert(len >= 0);
+ sal_Int32 nOldLen;
+ sal_Unicode * pBuf;
+ sal_Int32 n;
+ if( len == 0 )
+ return;
+
+ 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 )
+ memmove( pBuf + offset + len, pBuf + offset, n * sizeof(sal_Unicode) );
+
+ /* insert the new characters */
+ if( str != nullptr )
+ {
+ if( len == 1 )
+ /* optimized for 1 character */
+ pBuf[offset] = *str;
+ else
+ memcpy( 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_THROW_EXTERN_C()
+{
+ sal_Unicode buf[2];
+ sal_Int32 len;
+ OSL_ASSERT(rtl::isUnicodeScalarValue(c));
+ if (c <= 0xFFFF) {
+ buf[0] = static_cast<sal_Unicode>(c);
+ len = 1;
+ } else {
+ c -= 0x10000;
+ buf[0] = static_cast<sal_Unicode>((c >> 10) | 0xD800);
+ buf[1] = static_cast<sal_Unicode>((c & 0x3FF) | 0xDC00);
+ len = 2;
+ }
+ rtl_uStringbuffer_insert(pThis, capacity, offset, buf, len);
+}
+
+void SAL_CALL rtl_uStringbuffer_insert_ascii( /*inout*/rtl_uString ** This,
+ /*inout*/sal_Int32 * capacity,
+ sal_Int32 offset,
+ const char * str,
+ sal_Int32 len)
+{
+ assert(This);
+ assert(capacity && *capacity >= 0);
+ assert(offset >= 0 && offset <= (**This).length);
+ assert(len == 0 || str != nullptr);
+ assert(len >= 0);
+ sal_Int32 nOldLen;
+ sal_Unicode * pBuf;
+ sal_Int32 n;
+ if( len == 0 )
+ return;
+
+ 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 )
+ memmove( 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] = static_cast<sal_Unicode>(*(str++));
+ }
+
+ (*This)->length = nOldLen + len;
+ pBuf[ nOldLen + len ] = 0;
+}
+
+/*************************************************************************
+ * rtl_uStringbuffer_remove
+ */
+void SAL_CALL rtl_uStringbuffer_remove( rtl_uString ** This,
+ sal_Int32 start,
+ sal_Int32 len )
+{
+ assert(This);
+ assert(start >= 0 && start <= (**This).length);
+ assert(len >= 0);
+ sal_Int32 nTailLen;
+ sal_Unicode * pBuf;
+
+ if (len > (*This)->length - start)
+ len = (*This)->length - start;
+
+ //remove nothing
+ if (!len)
+ return;
+
+ pBuf = (*This)->buffer;
+ nTailLen = (*This)->length - ( start + len );
+
+ if (nTailLen)
+ {
+ /* move the tail */
+ memmove(pBuf + start, pBuf + start + len, nTailLen * sizeof(sal_Unicode));
+ }
+
+ (*This)->length-=len;
+ pBuf[ (*This)->length ] = 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/ustring.cxx b/sal/rtl/ustring.cxx
new file mode 100644
index 000000000..01fea63e1
--- /dev/null
+++ b/sal/rtl/ustring.cxx
@@ -0,0 +1,1562 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstdlib>
+#include <limits>
+#include <stdexcept>
+#include <string>
+
+#include <osl/diagnose.h>
+#include <osl/interlck.h>
+#include <rtl/alloc.h>
+#include <osl/mutex.h>
+#include <rtl/tencinfo.h>
+
+#include <string.h>
+#include <sal/alloca.h>
+#include <sal/log.hxx>
+
+#include "hash.hxx"
+#include "strimp.hxx"
+#include <rtl/character.hxx>
+#include <rtl/ustring.h>
+
+#include <rtl/math.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];*/
+};
+
+/* ======================================================================= */
+/* These macros are for the "poor-man templates" included from
+ * the strtmpl.cxx just below, used to share code between here and
+ * string.cxx
+ */
+
+#define IMPL_RTL_IS_USTRING 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
+
+static void internRelease (rtl_uString *pThis);
+
+#if USE_SDT_PROBES
+#define RTL_LOG_STRING_BITS 16
+#endif
+
+/* ======================================================================= */
+
+/* Include String/UString template code */
+
+#include "strtmpl.cxx"
+
+#undef IMPL_RTL_EMPTYSTRING
+#undef IMPL_RTL_IS_USTRING
+#undef IMPL_RTL_STRCODE
+#undef IMPL_RTL_STRINGDATA
+#undef IMPL_RTL_STRINGNAME
+#undef IMPL_RTL_STRNAME
+#undef IMPL_RTL_USTRCODE
+#undef RTL_LOG_STRING_BITS
+
+sal_Int32 rtl_ustr_indexOfAscii_WithLength(
+ sal_Unicode const * str, sal_Int32 len,
+ char const * subStr, sal_Int32 subLen) SAL_THROW_EXTERN_C()
+{
+ assert(len >= 0);
+ assert(subLen >= 0);
+ if (subLen > 0 && subLen <= len)
+ {
+ sal_Unicode const* end = str + len;
+ sal_Unicode const* cursor = str;
+
+ while(cursor < end)
+ {
+ cursor = std::char_traits<sal_Unicode>::find(cursor, end - cursor, *subStr);
+ if(!cursor || (end - cursor < subLen))
+ {
+ /* no enough left to actually have a match */
+ break;
+ }
+ /* now it is worth trying a full match */
+ if (rtl_ustr_asciil_reverseEquals_WithLength(cursor, subStr, subLen))
+ {
+ return cursor - str;
+ }
+ cursor += 1;
+ }
+ }
+ return -1;
+}
+
+sal_Int32 rtl_ustr_lastIndexOfAscii_WithLength(
+ sal_Unicode const * str, sal_Int32 len,
+ char const * subStr, sal_Int32 subLen) SAL_THROW_EXTERN_C()
+{
+ assert(len >= 0);
+ assert(subLen >= 0);
+ 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)
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ rtl_uString * pResult = nullptr;
+ sal_Int32 nLen;
+ rtl_math_doubleToUString(
+ &pResult, nullptr, 0, f, rtl_math_StringFormat_G,
+ RTL_USTR_MAX_VALUEOFFLOAT - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', nullptr,
+ 0, true);
+ nLen = pResult->length;
+ OSL_ASSERT(nLen < RTL_USTR_MAX_VALUEOFFLOAT);
+ memcpy(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)
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ rtl_uString * pResult = nullptr;
+ sal_Int32 nLen;
+ rtl_math_doubleToUString(
+ &pResult, nullptr, 0, d, rtl_math_StringFormat_G,
+ RTL_USTR_MAX_VALUEOFDOUBLE - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', nullptr,
+ 0, true);
+ nLen = pResult->length;
+ OSL_ASSERT(nLen < RTL_USTR_MAX_VALUEOFDOUBLE);
+ memcpy(pStr, pResult->buffer, (nLen + 1) * sizeof(sal_Unicode));
+ rtl_uString_release(pResult);
+ return nLen;
+}
+
+namespace {
+
+// Avoid -fsanitize=undefined warning e.g. "runtime error: value 1e+99 is
+// outside the range of representable values of type 'float'":
+float doubleToFloat(double x) {
+ return
+ x < -std::numeric_limits<float>::max()
+ ? -std::numeric_limits<float>::infinity()
+ : x > std::numeric_limits<float>::max()
+ ? std::numeric_limits<float>::infinity()
+ : static_cast<float>(x);
+}
+
+}
+
+float SAL_CALL rtl_ustr_toFloat(sal_Unicode const * pStr) SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ return doubleToFloat(rtl_math_uStringToDouble(pStr,
+ pStr + rtl_ustr_getLength(pStr),
+ '.', 0, nullptr, nullptr));
+}
+
+double SAL_CALL rtl_ustr_toDouble(sal_Unicode const * pStr) SAL_THROW_EXTERN_C()
+{
+ assert(pStr);
+ return rtl_math_uStringToDouble(pStr, pStr + rtl_ustr_getLength(pStr), '.',
+ 0, nullptr, nullptr);
+}
+
+/* ======================================================================= */
+
+sal_Int32 SAL_CALL rtl_ustr_ascii_compare( const sal_Unicode* pStr1,
+ const char* pStr2 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr1);
+ assert(pStr2);
+ sal_Int32 nRet;
+ for (;;)
+ {
+ nRet = static_cast<sal_Int32>(*pStr1)-
+ static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
+ if (!(nRet == 0 && *pStr2 ))
+ break;
+ /* Check ASCII range */
+ SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
+ "rtl_ustr_ascii_compare - Found char > 127" );
+ pStr1++;
+ pStr2++;
+ }
+
+ return nRet;
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Int32 SAL_CALL rtl_ustr_ascii_compare_WithLength( const sal_Unicode* pStr1,
+ sal_Int32 nStr1Len,
+ const char* pStr2 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr1);
+ assert(nStr1Len >= 0);
+ assert(pStr2);
+ sal_Int32 nRet = 0;
+ for (;;)
+ {
+ nRet = (nStr1Len ? static_cast<sal_Int32>(*pStr1) : 0) -
+ static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
+ if (!(nRet == 0 && nStr1Len && *pStr2 ))
+ break;
+ /* Check ASCII range */
+ SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
+ "rtl_ustr_ascii_compare_WithLength - Found char > 127" );
+ pStr1++;
+ pStr2++;
+ nStr1Len--;
+ }
+
+ return nRet;
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Int32 SAL_CALL rtl_ustr_ascii_shortenedCompare_WithLength( const sal_Unicode* pStr1,
+ sal_Int32 nStr1Len,
+ const char* pStr2,
+ sal_Int32 nShortenedLength )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nStr1Len >= 0);
+ assert(nShortenedLength >= 0);
+ const sal_Unicode* pStr1End = pStr1 + nStr1Len;
+ sal_Int32 nRet;
+ while ( (nShortenedLength > 0) &&
+ (pStr1 < pStr1End) && *pStr2 )
+ {
+ /* Check ASCII range */
+ SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
+ "rtl_ustr_ascii_shortenedCompare_WithLength - Found char > 127" );
+
+ nRet = static_cast<sal_Int32>(*pStr1)-
+ static_cast<sal_Int32>(static_cast<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 char* pStr2,
+ sal_Int32 nStr2Len )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nStr1Len >= 0 && nStr2Len >= 0);
+ const sal_Unicode* pStr1Run = pStr1+nStr1Len;
+ const char* pStr2Run = pStr2+nStr2Len;
+ sal_Int32 nRet;
+ while ( (pStr1 < pStr1Run) && (pStr2 < pStr2Run) )
+ {
+ /* Check ASCII range */
+ SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
+ "rtl_ustr_asciil_reverseCompare_WithLength - Found char > 127" );
+ pStr1Run--;
+ pStr2Run--;
+ nRet = static_cast<sal_Int32>(*pStr1Run)- static_cast<sal_Int32>(*pStr2Run);
+ if ( nRet )
+ return nRet;
+ }
+
+ return nStr1Len - nStr2Len;
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Bool SAL_CALL rtl_ustr_asciil_reverseEquals_WithLength( const sal_Unicode* pStr1,
+ const char* pStr2,
+ sal_Int32 nStrLen )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nStrLen >= 0);
+ const sal_Unicode* pStr1Run = pStr1+nStrLen;
+ const char* pStr2Run = pStr2+nStrLen;
+ while ( pStr1 < pStr1Run )
+ {
+ /* Check ASCII range */
+ SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
+ "rtl_ustr_asciil_reverseEquals_WithLength - Found char > 127" );
+ pStr1Run--;
+ pStr2Run--;
+ if( *pStr1Run != static_cast<sal_Unicode>(*pStr2Run) )
+ return false;
+ }
+
+ return true;
+}
+
+/* ----------------------------------------------------------------------- */
+
+sal_Int32 SAL_CALL rtl_ustr_ascii_compareIgnoreAsciiCase( const sal_Unicode* pStr1,
+ const char* pStr2 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(pStr1);
+ assert(pStr2);
+ sal_Int32 nRet;
+ sal_Int32 c1;
+ sal_Int32 c2;
+ do
+ {
+ /* Check ASCII range */
+ SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
+ "rtl_ustr_ascii_compareIgnoreAsciiCase - Found char > 127" );
+ /* If character between 'A' and 'Z', then convert it to lowercase */
+ c1 = static_cast<sal_Int32>(*pStr1);
+ c2 = static_cast<sal_Int32>(static_cast<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 char* pStr2 )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nStr1Len >= 0);
+ assert(pStr2);
+ sal_Int32 nRet;
+ sal_Int32 c1;
+ sal_Int32 c2;
+ do
+ {
+ /* Check ASCII range */
+ SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
+ "rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength - Found char > 127" );
+ if ( !nStr1Len )
+ return *pStr2 == '\0' ? 0 : -1;
+
+ /* If character between 'A' and 'Z', then convert it to lowercase */
+ c1 = static_cast<sal_Int32>(*pStr1);
+ c2 = static_cast<sal_Int32>(static_cast<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_THROW_EXTERN_C()
+{
+ assert(firstLen >= 0 && secondLen >= 0);
+ sal_Int32 i;
+ sal_Int32 len = std::min(firstLen, secondLen);
+ for (i = 0; i < len; ++i) {
+ /* Check ASCII range */
+ SAL_WARN_IF( (static_cast<unsigned char>(*second)) > 127, "rtl.string",
+ "rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths - Found char > 127" );
+ sal_Int32 c1 = *first++;
+ sal_Int32 c2 = static_cast<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 char* pStr2,
+ sal_Int32 nShortenedLength )
+ SAL_THROW_EXTERN_C()
+{
+ assert(nStr1Len >= 0);
+ assert(nShortenedLength >= 0);
+ const sal_Unicode* pStr1End = pStr1 + nStr1Len;
+ sal_Int32 nRet;
+ sal_Int32 c1;
+ sal_Int32 c2;
+ while ( (nShortenedLength > 0) &&
+ (pStr1 < pStr1End) && *pStr2 )
+ {
+ /* Check ASCII range */
+ SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
+ "rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength - Found char > 127" );
+
+ /* If character between 'A' and 'Z', then convert it to lowercase */
+ c1 = static_cast<sal_Int32>(*pStr1);
+ c2 = static_cast<sal_Int32>(static_cast<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 char* pCharStr )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ sal_Int32 nLen;
+
+ if ( pCharStr )
+ {
+ const char* pTempStr = pCharStr;
+ while( *pTempStr )
+ pTempStr++;
+ nLen = pTempStr-pCharStr;
+ }
+ else
+ nLen = 0;
+
+ if ( !nLen )
+ {
+ rtl_uString_new( ppThis );
+ return;
+ }
+
+ if ( *ppThis )
+ rtl_uString_release( *ppThis );
+
+ *ppThis = rtl_uString_ImplAlloc( nLen );
+ OSL_ASSERT(*ppThis != nullptr);
+ if ( *ppThis )
+ {
+ sal_Unicode* pBuffer = (*ppThis)->buffer;
+ do
+ {
+ assert(static_cast<unsigned char>(*pCharStr) < 0x80); // ASCII range
+ *pBuffer = *pCharStr;
+ pBuffer++;
+ pCharStr++;
+ }
+ while ( *pCharStr );
+
+ RTL_LOG_STRING_NEW( *ppThis );
+ }
+}
+
+void SAL_CALL rtl_uString_newFromCodePoints(
+ rtl_uString ** newString, sal_uInt32 const * codePoints,
+ sal_Int32 codePointCount) SAL_THROW_EXTERN_C()
+{
+ sal_Int32 n;
+ sal_Int32 i;
+ sal_Unicode * p;
+ assert(newString != nullptr);
+ assert((codePoints != nullptr || codePointCount == 0) && codePointCount >= 0);
+ if (codePointCount == 0) {
+ rtl_uString_new(newString);
+ return;
+ }
+ if (*newString != nullptr) {
+ rtl_uString_release(*newString);
+ }
+ n = codePointCount;
+ for (i = 0; i < codePointCount; ++i) {
+ OSL_ASSERT(rtl::isUnicodeCodePoint(codePoints[i]));
+ 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) {
+ // coverity[dead_error_begin] - assumes wrap around
+ *newString = nullptr;
+ return;
+ }
+ *newString = rtl_uString_ImplAlloc(n);
+ if (*newString == nullptr) {
+ return;
+ }
+ p = (*newString)->buffer;
+ for (i = 0; i < codePointCount; ++i) {
+ p += rtl::splitSurrogates(codePoints[i], p);
+ }
+ RTL_LOG_STRING_NEW( *newString );
+}
+
+void rtl_uString_newConcatAsciiL(
+ rtl_uString ** newString, rtl_uString * left, char const * right,
+ sal_Int32 rightLength)
+{
+ assert(newString != nullptr);
+ assert(left != nullptr);
+ assert(right != nullptr);
+ assert(rightLength >= 0);
+ if (left->length > std::numeric_limits<sal_Int32>::max() - rightLength) {
+#if !defined(__COVERITY__)
+ throw std::length_error("rtl_uString_newConcatAsciiL");
+#else
+ //coverity doesn't report std::bad_alloc as an unhandled exception when
+ //potentially thrown from destructors but does report std::length_error
+ throw std::bad_alloc();
+#endif
+ }
+ sal_Int32 n = left->length + rightLength;
+ rtl_uString_assign(newString, left);
+ rtl_uString_ensureCapacity(newString, n);
+ sal_Unicode * p = (*newString)->buffer + (*newString)->length;
+ for (sal_Int32 i = 0; i != rightLength; ++i) {
+ p[i] = static_cast<unsigned char>(right[i]);
+ }
+ (*newString)->buffer[n] = 0;
+ (*newString)->length = n;
+}
+
+void rtl_uString_newConcatUtf16L(
+ rtl_uString ** newString, rtl_uString * left, sal_Unicode const * right,
+ sal_Int32 rightLength)
+{
+ assert(newString != nullptr);
+ assert(left != nullptr);
+ assert(right != nullptr);
+ assert(rightLength >= 0);
+ if (left->length > std::numeric_limits<sal_Int32>::max() - rightLength) {
+#if !defined(__COVERITY__)
+ throw std::length_error("rtl_uString_newConcatUtf16L");
+#else
+ //coverity doesn't report std::bad_alloc as an unhandled exception when
+ //potentially thrown from destructors but does report std::length_error
+ throw std::bad_alloc();
+#endif
+ }
+ sal_Int32 n = left->length + rightLength;
+ rtl_uString_assign(newString, left);
+ rtl_uString_ensureCapacity(newString, n);
+ memcpy(
+ (*newString)->buffer + (*newString)->length, right,
+ rightLength * sizeof (sal_Unicode));
+ (*newString)->buffer[n] = 0;
+ (*newString)->length = n;
+}
+
+/* ======================================================================= */
+
+static int rtl_ImplGetFastUTF8UnicodeLen( const char* pStr, sal_Int32 nLen, bool * ascii )
+{
+ int n;
+ const char* pEndStr;
+
+ *ascii = true;
+ n = 0;
+ pEndStr = pStr+nLen;
+ while ( pStr < pEndStr )
+ {
+ unsigned char c = static_cast<unsigned char>(*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++;
+ *ascii = false;
+ }
+
+ n++;
+ }
+
+ return n;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void rtl_string2UString_status( rtl_uString** ppThis,
+ const char* pStr,
+ sal_Int32 nLen,
+ rtl_TextEncoding eTextEncoding,
+ sal_uInt32 nCvtFlags,
+ sal_uInt32 *pInfo )
+{
+ OSL_ENSURE(nLen == 0 || rtl_isOctetTextEncoding(eTextEncoding),
+ "rtl_string2UString_status() - Wrong TextEncoding" );
+
+ if ( !nLen )
+ {
+ rtl_uString_new( ppThis );
+ if (pInfo != nullptr) {
+ *pInfo = 0;
+ }
+ }
+ else
+ {
+ if ( *ppThis )
+ rtl_uString_release( *ppThis );
+
+ /* Optimization for US-ASCII */
+ if ( eTextEncoding == RTL_TEXTENCODING_ASCII_US )
+ {
+ sal_Unicode* pBuffer;
+ *ppThis = rtl_uString_ImplAlloc( nLen );
+ if (*ppThis == nullptr) {
+ if (pInfo != nullptr) {
+ *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
+ RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
+ }
+ return;
+ }
+ pBuffer = (*ppThis)->buffer;
+ sal_Int32 nLenCopy(nLen);
+ const char *pStrCopy(pStr);
+ do
+ {
+ /* Check ASCII range */
+ if (static_cast<unsigned char>(*pStrCopy) > 127)
+ {
+ rtl_uString_release(*ppThis);
+ goto retry; // cancel loop - try again with the converter
+ }
+
+ *pBuffer = *pStrCopy;
+ pBuffer++;
+ pStrCopy++;
+ nLenCopy--;
+ }
+ while (nLenCopy);
+ if (pInfo != nullptr) {
+ *pInfo = 0;
+ }
+ RTL_LOG_STRING_NEW( *ppThis );
+ return;
+ }
+retry:
+ {
+ rtl_uString* pTemp;
+ rtl_uString* pTemp2 = nullptr;
+ 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 )
+ {
+ bool ascii;
+ nNewLen = rtl_ImplGetFastUTF8UnicodeLen( pStr, nLen, &ascii );
+ /* Includes the string only ASCII, then we could copy
+ the buffer faster */
+ if ( ascii )
+ {
+ sal_Unicode* pBuffer;
+ *ppThis = rtl_uString_ImplAlloc( nLen );
+ if (*ppThis == nullptr)
+ {
+ if (pInfo != nullptr) {
+ *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
+ RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
+ }
+ return;
+ }
+ pBuffer = (*ppThis)->buffer;
+ do
+ {
+ assert((static_cast<unsigned char>(*pStr)) <= 127);
+ *pBuffer = *pStr;
+ pBuffer++;
+ pStr++;
+ nLen--;
+ }
+ while ( nLen );
+ if (pInfo != nullptr) {
+ *pInfo = 0;
+ }
+ RTL_LOG_STRING_NEW( *ppThis );
+ return;
+ }
+ }
+ else
+ nNewLen = nLen;
+
+ nCvtFlags |= RTL_TEXTTOUNICODE_FLAGS_FLUSH;
+ hConverter = rtl_createTextToUnicodeConverter( eTextEncoding );
+
+ pTemp = rtl_uString_ImplAlloc( nNewLen );
+ if (pTemp == nullptr) {
+ if (pInfo != nullptr) {
+ *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
+ RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
+ }
+ return;
+ }
+ nDestChars = rtl_convertTextToUnicode( hConverter, nullptr,
+ 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_DESTBUFFERTOOSMALL )
+ {
+ rtl_freeString( pTemp );
+ nNewLen += 8;
+ pTemp = rtl_uString_ImplAlloc( nNewLen );
+ if (pTemp == nullptr) {
+ if (pInfo != nullptr) {
+ *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
+ RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
+ }
+ return;
+ }
+ nDestChars = rtl_convertTextToUnicode( hConverter, nullptr,
+ 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 = rtl_uString_ImplAlloc( nDestChars );
+ }
+ if (pTemp2 != nullptr)
+ {
+ rtl_str_ImplCopy(pTemp2->buffer, pTemp->buffer, nDestChars);
+ rtl_freeString(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 );
+ }
+ }
+ RTL_LOG_STRING_NEW( *ppThis );
+}
+
+void SAL_CALL rtl_string2UString( rtl_uString** ppThis,
+ const char* pStr,
+ sal_Int32 nLen,
+ rtl_TextEncoding eTextEncoding,
+ sal_uInt32 nCvtFlags ) SAL_THROW_EXTERN_C()
+{
+ assert(ppThis);
+ assert(nLen >= 0);
+ rtl_string2UString_status( ppThis, pStr, nLen, eTextEncoding,
+ nCvtFlags, nullptr );
+}
+
+/* ----------------------------------------------------------------------- */
+
+namespace {
+
+enum StrLifecycle {
+ CANNOT_RETURN,
+ CAN_RETURN = 1
+};
+
+}
+
+static oslMutex
+getInternMutex()
+{
+ static oslMutex pPoolGuard = osl_createMutex();
+
+ 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 );
+
+ RTL_LOG_STRING_INTERN_NEW(*newStr, str);
+
+ if( can_return && *newStr != str )
+ { /* we dupped, then found a match */
+ rtl_freeString( str );
+ }
+}
+
+void SAL_CALL rtl_uString_intern( rtl_uString ** newStr,
+ rtl_uString * str) SAL_THROW_EXTERN_C()
+{
+ assert(newStr);
+ assert(str);
+ if (SAL_STRING_IS_INTERN(str))
+ {
+ IMPL_RTL_ACQUIRE( str );
+ *newStr = str;
+ }
+ else
+ {
+ rtl_uString *pOrg = *newStr;
+ *newStr = nullptr;
+ rtl_ustring_intern_internal( newStr, str, CANNOT_RETURN );
+ if (pOrg)
+ rtl_uString_release (pOrg);
+ }
+}
+
+static int rtl_canGuessUOutputLength( int len, rtl_TextEncoding eTextEncoding )
+{
+ // FIXME: Maybe we should use a bit flag in the higher bits of the
+ // eTextEncoding value itself to determine the encoding type. But if we
+ // do, be sure to mask the value in certain places that expect the values
+ // to be numbered serially from 0 and up. One such place is
+ // Impl_getTextEncodingData().
+
+ switch ( eTextEncoding )
+ {
+ // 1 to 1 (with no zero elements)
+ case RTL_TEXTENCODING_IBM_437:
+ case RTL_TEXTENCODING_IBM_850:
+ case RTL_TEXTENCODING_IBM_860:
+ case RTL_TEXTENCODING_IBM_861:
+ case RTL_TEXTENCODING_IBM_863:
+ case RTL_TEXTENCODING_IBM_865:
+ return len;
+ break;
+ }
+ return 0;
+}
+
+void SAL_CALL rtl_uString_internConvert( rtl_uString ** newStr,
+ const char * str,
+ sal_Int32 len,
+ rtl_TextEncoding eTextEncoding,
+ sal_uInt32 convertFlags,
+ sal_uInt32 * pInfo )
+ SAL_THROW_EXTERN_C()
+{
+ assert(newStr);
+ assert(len >= 0);
+ rtl_uString *scratch;
+
+ if (*newStr)
+ {
+ rtl_uString_release (*newStr);
+ *newStr = nullptr;
+ }
+
+ if ( len < 256 )
+ { // try various optimisations
+ sal_Int32 ulen;
+ if ( eTextEncoding == RTL_TEXTENCODING_ASCII_US )
+ {
+ int i;
+ rtl_uString *pScratch;
+ pScratch = static_cast< rtl_uString * >(
+ alloca(sizeof (rtl_uString) + len * sizeof (sal_Unicode)));
+ for (i = 0; i < len; i++)
+ {
+ /* Check ASCII range */
+ SAL_WARN_IF( (static_cast<unsigned char>(str[i])) > 127, "rtl.string",
+ "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;
+ }
+ if ( (ulen = rtl_canGuessUOutputLength(len, eTextEncoding)) != 0 )
+ {
+ rtl_uString *pScratch;
+ rtl_TextToUnicodeConverter hConverter;
+ sal_Size nSrcBytes;
+ sal_uInt32 nInfo;
+
+ pScratch = static_cast< rtl_uString * >(
+ alloca(
+ sizeof (rtl_uString) + ulen * sizeof (sal_Unicode)));
+
+ hConverter = rtl_createTextToUnicodeConverter( eTextEncoding );
+ rtl_convertTextToUnicode(
+ hConverter, nullptr, str, len, pScratch->buffer, ulen, convertFlags, &nInfo, &nSrcBytes );
+ rtl_destroyTextToUnicodeConverter( hConverter );
+
+ if (pInfo)
+ *pInfo = nInfo;
+
+ pScratch->length = ulen;
+ rtl_ustring_intern_internal( newStr, pScratch, CANNOT_RETURN );
+ return;
+ }
+
+ /* FIXME: we want a nice UTF-8 / alloca shortcut here */
+ }
+
+ scratch = nullptr;
+ 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 = nullptr;
+ if ( SAL_STRING_REFCOUNT(
+ osl_atomic_decrement( &(pThis->refCount) ) ) == 0)
+ {
+ RTL_LOG_STRING_INTERN_DELETE(pThis);
+ pPoolMutex = getInternMutex();
+ osl_acquireMutex( pPoolMutex );
+
+ rtl_str_hash_remove (pThis);
+
+ /* May have been separately acquired */
+ if ( SAL_STRING_REFCOUNT(
+ osl_atomic_increment( &(pThis->refCount) ) ) == 1 )
+ {
+ /* we got the last ref */
+ pFree = pThis;
+ }
+ else /* very unusual */
+ {
+ internRelease (pThis);
+ }
+
+ osl_releaseMutex( pPoolMutex );
+ }
+ if (pFree)
+ rtl_freeString (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;
+ assert(string != nullptr && indexUtf16 != nullptr);
+ n = *indexUtf16;
+ assert(n >= 0 && n <= string->length);
+ while (incrementCodePoints < 0) {
+ assert(n > 0);
+ cu = string->buffer[--n];
+ if (rtl::isLowSurrogate(cu) && n != 0 &&
+ rtl::isHighSurrogate(string->buffer[n - 1]))
+ {
+ --n;
+ }
+ ++incrementCodePoints;
+ }
+ assert(n >= 0 && n < string->length);
+ cu = string->buffer[n];
+ if (rtl::isHighSurrogate(cu) && string->length - n >= 2 &&
+ rtl::isLowSurrogate(string->buffer[n + 1]))
+ {
+ cp = rtl::combineSurrogates(cu, string->buffer[n + 1]);
+ } else {
+ cp = cu;
+ }
+ while (incrementCodePoints > 0) {
+ assert(n < string->length);
+ cu = string->buffer[n++];
+ if (rtl::isHighSurrogate(cu) && n != string->length &&
+ rtl::isLowSurrogate(string->buffer[n]))
+ {
+ ++n;
+ }
+ --incrementCodePoints;
+ }
+ 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()
+{
+ assert(target);
+ assert(length >= 0);
+ sal_uInt32 info;
+ rtl_string2UString_status(target, source, length, encoding, flags, &info);
+ return (info & RTL_TEXTTOUNICODE_INFO_ERROR) == 0;
+}
+
+void rtl_uString_newReplaceFirst(
+ rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
+ rtl_uString const * to, sal_Int32 * index) SAL_THROW_EXTERN_C()
+{
+ assert(str != nullptr);
+ assert(index != nullptr);
+ assert(*index >= 0 && *index <= str->length);
+ assert(from != nullptr);
+ assert(to != nullptr);
+ sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
+ str->buffer + *index, str->length - *index, from->buffer, from->length);
+ if (i == -1) {
+ rtl_uString_assign(newStr, str);
+ } else {
+ assert(i <= str->length - *index);
+ i += *index;
+ assert(from->length <= str->length);
+ if (str->length - from->length > SAL_MAX_INT32 - to->length) {
+ std::abort();
+ }
+ sal_Int32 n = str->length - from->length + to->length;
+ rtl_uString_acquire(str); // in case *newStr == str
+ rtl_uString_new_WithLength(newStr, n);
+ if (n != 0) {
+ (*newStr)->length = n;
+ assert(i >= 0 && i < str->length);
+ memcpy(
+ (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
+ memcpy(
+ (*newStr)->buffer + i, to->buffer,
+ to->length * sizeof (sal_Unicode));
+ memcpy(
+ (*newStr)->buffer + i + to->length,
+ str->buffer + i + from->length,
+ (str->length - i - from->length) * sizeof (sal_Unicode));
+ }
+ rtl_uString_release(str);
+ }
+ *index = i;
+}
+
+void rtl_uString_newReplaceFirstAsciiL(
+ rtl_uString ** newStr, rtl_uString * str, char const * from,
+ sal_Int32 fromLength, rtl_uString const * to, sal_Int32 * index)
+ SAL_THROW_EXTERN_C()
+{
+ assert(str != nullptr);
+ assert(index != nullptr);
+ assert(*index >= 0 && *index <= str->length);
+ assert(fromLength >= 0);
+ assert(to != nullptr);
+ sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
+ str->buffer + *index, str->length - *index, from, fromLength);
+ if (i == -1) {
+ rtl_uString_assign(newStr, str);
+ } else {
+ assert(i <= str->length - *index);
+ i += *index;
+ assert(fromLength <= str->length);
+ if (str->length - fromLength > SAL_MAX_INT32 - to->length) {
+ std::abort();
+ }
+ sal_Int32 n = str->length - fromLength + to->length;
+ rtl_uString_acquire(str); // in case *newStr == str
+ rtl_uString_new_WithLength(newStr, n);
+ if (n != 0) {
+ (*newStr)->length = n;
+ assert(i >= 0 && i < str->length);
+ memcpy(
+ (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
+ memcpy(
+ (*newStr)->buffer + i, to->buffer,
+ to->length * sizeof (sal_Unicode));
+ memcpy(
+ (*newStr)->buffer + i + to->length,
+ str->buffer + i + fromLength,
+ (str->length - i - fromLength) * sizeof (sal_Unicode));
+ }
+ rtl_uString_release(str);
+ }
+ *index = i;
+}
+
+void rtl_uString_newReplaceFirstToAsciiL(
+ rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
+ char const * to, sal_Int32 toLength, sal_Int32 * index)
+ SAL_THROW_EXTERN_C()
+{
+ assert(str != nullptr);
+ assert(index != nullptr);
+ assert(*index >= 0 && *index <= str->length);
+ assert(from != nullptr);
+ assert(toLength >= 0);
+ sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
+ str->buffer + *index, str->length - *index, from->buffer, from->length);
+ if (i == -1) {
+ rtl_uString_assign(newStr, str);
+ } else {
+ assert(i <= str->length - *index);
+ i += *index;
+ assert(from->length <= str->length);
+ if (str->length - from->length > SAL_MAX_INT32 - toLength) {
+ std::abort();
+ }
+ sal_Int32 n = str->length - from->length + toLength;
+ rtl_uString_acquire(str); // in case *newStr == str
+ rtl_uString_new_WithLength(newStr, n);
+ if (n != 0) {
+ (*newStr)->length = n;
+ assert(i >= 0 && i < str->length);
+ memcpy(
+ (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
+ for (sal_Int32 j = 0; j != toLength; ++j) {
+ assert(static_cast< unsigned char >(to[j]) <= 0x7F);
+ (*newStr)->buffer[i + j] = to[j];
+ }
+ memcpy(
+ (*newStr)->buffer + i + toLength,
+ str->buffer + i + from->length,
+ (str->length - i - from->length) * sizeof (sal_Unicode));
+ }
+ rtl_uString_release(str);
+ }
+ *index = i;
+}
+
+void rtl_uString_newReplaceFirstAsciiLAsciiL(
+ rtl_uString ** newStr, rtl_uString * str, char const * from,
+ sal_Int32 fromLength, char const * to, sal_Int32 toLength,
+ sal_Int32 * index) SAL_THROW_EXTERN_C()
+{
+ assert(str != nullptr);
+ assert(index != nullptr);
+ assert(*index >= 0 && *index <= str->length);
+ assert(fromLength >= 0);
+ assert(to != nullptr);
+ assert(toLength >= 0);
+ sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
+ str->buffer + *index, str->length - *index, from, fromLength);
+ if (i == -1) {
+ rtl_uString_assign(newStr, str);
+ } else {
+ assert(i <= str->length - *index);
+ i += *index;
+ assert(fromLength <= str->length);
+ if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
+ std::abort();
+ }
+ sal_Int32 n = str->length - fromLength + toLength;
+ rtl_uString_acquire(str); // in case *newStr == str
+ rtl_uString_new_WithLength(newStr, n);
+ if (n != 0) {
+ (*newStr)->length = n;
+ assert(i >= 0 && i < str->length);
+ memcpy(
+ (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
+ for (sal_Int32 j = 0; j != toLength; ++j) {
+ assert(static_cast< unsigned char >(to[j]) <= 0x7F);
+ (*newStr)->buffer[i + j] = to[j];
+ }
+ memcpy(
+ (*newStr)->buffer + i + toLength,
+ str->buffer + i + fromLength,
+ (str->length - i - fromLength) * sizeof (sal_Unicode));
+ }
+ rtl_uString_release(str);
+ }
+ *index = i;
+}
+
+void rtl_uString_newReplaceFirstAsciiLUtf16L(
+ rtl_uString ** newStr, rtl_uString * str, char const * from,
+ sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
+ sal_Int32 * index) SAL_THROW_EXTERN_C()
+{
+ assert(str != nullptr);
+ assert(index != nullptr);
+ assert(*index >= 0 && *index <= str->length);
+ assert(fromLength >= 0);
+ assert(to != nullptr);
+ assert(toLength >= 0);
+ sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
+ str->buffer + *index, str->length - *index, from, fromLength);
+ if (i == -1) {
+ rtl_uString_assign(newStr, str);
+ } else {
+ assert(i <= str->length - *index);
+ i += *index;
+ assert(fromLength <= str->length);
+ if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
+ rtl_uString_release(*newStr);
+ *newStr = nullptr;
+ } else {
+ sal_Int32 n = str->length - fromLength + toLength;
+ rtl_uString_acquire(str); // in case *newStr == str
+ rtl_uString_new_WithLength(newStr, n);
+ if (n != 0 && /*TODO:*/ *newStr != nullptr) {
+ (*newStr)->length = n;
+ assert(i >= 0 && i < str->length);
+ memcpy(
+ (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
+ memcpy(
+ (*newStr)->buffer + i, to, toLength * sizeof (sal_Unicode));
+ memcpy(
+ (*newStr)->buffer + i + toLength,
+ str->buffer + i + fromLength,
+ (str->length - i - fromLength) * sizeof (sal_Unicode));
+ }
+ rtl_uString_release(str);
+ }
+ }
+ *index = i;
+}
+
+void rtl_uString_newReplaceFirstUtf16LAsciiL(
+ rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+ sal_Int32 fromLength, char const * to, sal_Int32 toLength,
+ sal_Int32 * index) SAL_THROW_EXTERN_C()
+{
+ assert(str != nullptr);
+ assert(index != nullptr);
+ assert(*index >= 0 && *index <= str->length);
+ assert(fromLength >= 0);
+ assert(to != nullptr);
+ assert(toLength >= 0);
+ sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
+ str->buffer + *index, str->length - *index, from, fromLength);
+ if (i == -1) {
+ rtl_uString_assign(newStr, str);
+ } else {
+ assert(i <= str->length - *index);
+ i += *index;
+ assert(fromLength <= str->length);
+ if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
+ rtl_uString_release(*newStr);
+ *newStr = nullptr;
+ } else {
+ sal_Int32 n = str->length - fromLength + toLength;
+ rtl_uString_acquire(str); // in case *newStr == str
+ rtl_uString_new_WithLength(newStr, n);
+ if (n != 0 && /*TODO:*/ *newStr != nullptr) {
+ (*newStr)->length = n;
+ assert(i >= 0 && i < str->length);
+ memcpy(
+ (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
+ for (sal_Int32 j = 0; j != toLength; ++j) {
+ assert(static_cast< unsigned char >(to[j]) <= 0x7F);
+ (*newStr)->buffer[i + j] = to[j];
+ }
+ memcpy(
+ (*newStr)->buffer + i + toLength,
+ str->buffer + i + fromLength,
+ (str->length - i - fromLength) * sizeof (sal_Unicode));
+ }
+ rtl_uString_release(str);
+ }
+ }
+ *index = i;
+}
+
+void rtl_uString_newReplaceFirstUtf16LUtf16L(
+ rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+ sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
+ sal_Int32 * index) SAL_THROW_EXTERN_C()
+{
+ assert(str != nullptr);
+ assert(index != nullptr);
+ assert(*index >= 0 && *index <= str->length);
+ assert(fromLength >= 0);
+ assert(to != nullptr);
+ assert(toLength >= 0);
+ sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
+ str->buffer + *index, str->length - *index, from, fromLength);
+ if (i == -1) {
+ rtl_uString_assign(newStr, str);
+ } else {
+ assert(i <= str->length - *index);
+ i += *index;
+ assert(fromLength <= str->length);
+ if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
+ rtl_uString_release(*newStr);
+ *newStr = nullptr;
+ } else {
+ sal_Int32 n = str->length - fromLength + toLength;
+ rtl_uString_acquire(str); // in case *newStr == str
+ rtl_uString_new_WithLength(newStr, n);
+ if (n != 0 && /*TODO:*/ *newStr != nullptr) {
+ (*newStr)->length = n;
+ assert(i >= 0 && i < str->length);
+ memcpy(
+ (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
+ memcpy(
+ (*newStr)->buffer + i, to, toLength * sizeof (sal_Unicode));
+ memcpy(
+ (*newStr)->buffer + i + toLength,
+ str->buffer + i + fromLength,
+ (str->length - i - fromLength) * sizeof (sal_Unicode));
+ }
+ rtl_uString_release(str);
+ }
+ }
+ *index = i;
+}
+
+void rtl_uString_newReplaceAll(
+ rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
+ rtl_uString const * to) SAL_THROW_EXTERN_C()
+{
+ rtl_uString_newReplaceAllFromIndex( newStr, str, from, to, 0 );
+}
+
+void rtl_uString_newReplaceAllFromIndex(
+ rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
+ rtl_uString const * to, sal_Int32 fromIndex) SAL_THROW_EXTERN_C()
+{
+ assert(to != nullptr);
+ assert(fromIndex >= 0 && fromIndex <= str->length);
+ rtl_uString_assign(newStr, str);
+ for (sal_Int32 i = fromIndex;; i += to->length) {
+ rtl_uString_newReplaceFirst(newStr, *newStr, from, to, &i);
+ if (i == -1) {
+ break;
+ }
+ }
+}
+
+void rtl_uString_newReplaceAllAsciiL(
+ rtl_uString ** newStr, rtl_uString * str, char const * from,
+ sal_Int32 fromLength, rtl_uString const * to) SAL_THROW_EXTERN_C()
+{
+ assert(to != nullptr);
+ rtl_uString_assign(newStr, str);
+ for (sal_Int32 i = 0;; i += to->length) {
+ rtl_uString_newReplaceFirstAsciiL(
+ newStr, *newStr, from, fromLength, to, &i);
+ if (i == -1) {
+ break;
+ }
+ }
+}
+
+void rtl_uString_newReplaceAllToAsciiL(
+ rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
+ char const * to, sal_Int32 toLength) SAL_THROW_EXTERN_C()
+{
+ assert(from != nullptr);
+ rtl_uString_assign(newStr, str);
+ for (sal_Int32 i = 0;; i += toLength) {
+ rtl_uString_newReplaceFirstToAsciiL(
+ newStr, *newStr, from, to, toLength, &i);
+ if (i == -1) {
+ break;
+ }
+ }
+}
+
+void rtl_uString_newReplaceAllAsciiLAsciiL(
+ rtl_uString ** newStr, rtl_uString * str, char const * from,
+ sal_Int32 fromLength, char const * to, sal_Int32 toLength)
+ SAL_THROW_EXTERN_C()
+{
+ assert(toLength >= 0);
+ rtl_uString_assign(newStr, str);
+ for (sal_Int32 i = 0;; i += toLength) {
+ rtl_uString_newReplaceFirstAsciiLAsciiL(
+ newStr, *newStr, from, fromLength, to, toLength, &i);
+ if (i == -1) {
+ break;
+ }
+ }
+}
+
+void rtl_uString_newReplaceAllAsciiLUtf16L(
+ rtl_uString ** newStr, rtl_uString * str, char const * from,
+ sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
+ SAL_THROW_EXTERN_C()
+{
+ assert(toLength >= 0);
+ rtl_uString_assign(newStr, str);
+ for (sal_Int32 i = 0;; i += toLength) {
+ rtl_uString_newReplaceFirstAsciiLUtf16L(
+ newStr, *newStr, from, fromLength, to, toLength, &i);
+ if (i == -1 || *newStr == nullptr) {
+ break;
+ }
+ }
+}
+
+void rtl_uString_newReplaceAllUtf16LAsciiL(
+ rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+ sal_Int32 fromLength, char const * to, sal_Int32 toLength)
+ SAL_THROW_EXTERN_C()
+{
+ assert(toLength >= 0);
+ rtl_uString_assign(newStr, str);
+ for (sal_Int32 i = 0;; i += toLength) {
+ rtl_uString_newReplaceFirstUtf16LAsciiL(
+ newStr, *newStr, from, fromLength, to, toLength, &i);
+ if (i == -1 || *newStr == nullptr) {
+ break;
+ }
+ }
+}
+
+void rtl_uString_newReplaceAllUtf16LUtf16L(
+ rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+ sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
+ SAL_THROW_EXTERN_C()
+{
+ assert(toLength >= 0);
+ rtl_uString_assign(newStr, str);
+ for (sal_Int32 i = 0;; i += toLength) {
+ rtl_uString_newReplaceFirstUtf16LUtf16L(
+ newStr, *newStr, from, fromLength, to, toLength, &i);
+ if (i == -1 || *newStr == nullptr) {
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/rtl/uuid.cxx b/sal/rtl/uuid.cxx
new file mode 100644
index 000000000..130be1245
--- /dev/null
+++ b/sal/rtl/uuid.cxx
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#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 = reinterpret_cast<sal_uInt8 *>(&(x)); \
+ p[0] = static_cast<sal_uInt8>( ( y >> 24 ) & 0xff );\
+ p[1] = static_cast<sal_uInt8>( ( y >> 16 ) & 0xff );\
+ p[2] = static_cast<sal_uInt8>( ( y >> 8 ) & 0xff );\
+ p[3] = static_cast<sal_uInt8>( ( y ) & 0xff);\
+ }
+#define SWAP_INT16_TO_NETWORK(x)\
+ { sal_uInt16 y = x;\
+ sal_uInt8 *p = reinterpret_cast<sal_uInt8 *>(&(x)); \
+ p[0] = static_cast<sal_uInt8>( ( y >> 8 ) & 0xff );\
+ p[1] = static_cast<sal_uInt8>( ( y ) & 0xff);\
+ }
+
+#define SWAP_NETWORK_TO_INT16(x)\
+ { sal_uInt16 y = x;\
+ sal_uInt8 *p = reinterpret_cast<sal_uInt8 *>(&(y));\
+ x = ( ( (static_cast<sal_uInt16>(p[0])) & 0xff) << 8 ) |\
+ ( ( static_cast<sal_uInt16>(p[1])) & 0xff);\
+ }
+#define SWAP_NETWORK_TO_INT32(x)\
+ { sal_uInt32 y = x;\
+ sal_uInt8 *p = reinterpret_cast<sal_uInt8 *>(&(y)); \
+ x = ( ( (static_cast<sal_uInt32>(p[0])) & 0xff) << 24 ) |\
+ ( ( (static_cast<sal_uInt32>(p[1])) & 0xff) << 16 ) |\
+ ( ( (static_cast<sal_uInt32>(p[2])) & 0xff) << 8 ) |\
+ ( ( static_cast<sal_uInt32>(p[3])) & 0xff);\
+ }
+
+namespace {
+
+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];
+};
+
+}
+
+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 ,
+ SAL_UNUSED_PARAMETER const sal_uInt8 *,
+ SAL_UNUSED_PARAMETER sal_Bool)
+{
+ {
+ static rtlRandomPool pool = []() {
+ rtlRandomPool aPool = rtl_random_createPool();
+ if (!aPool)
+ {
+ abort();
+ // only possible way to signal failure here (rtl_createUuid
+ // being part of a fixed C API)
+ }
+ return aPool;
+ }();
+
+ osl::MutexGuard g(osl::Mutex::getGlobalMutex());
+ 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;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */