mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-30 05:47:57 +03:00
Imported Upstream version 0.26.0
This commit is contained in:
commit
9a2b6c69b6
1398 changed files with 212217 additions and 0 deletions
82
components/misc/slice_array.hpp
Normal file
82
components/misc/slice_array.hpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008-2010 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.sourceforge.net/
|
||||
|
||||
This file (slice_array.h) is part of the OpenMW package.
|
||||
|
||||
OpenMW is distributed as free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
version 3, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 3 along with this program. If not, see
|
||||
http://www.gnu.org/licenses/ .
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MISC_SLICE_ARRAY_H
|
||||
#define MISC_SLICE_ARRAY_H
|
||||
|
||||
// A simple array implementation containing a pointer and a
|
||||
// length. Used for holding slices into a data buffer.
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
|
||||
template <class T>
|
||||
struct SliceArray
|
||||
{
|
||||
const T* ptr;
|
||||
size_t length;
|
||||
|
||||
/// Initialize to zero length
|
||||
SliceArray() : ptr(0), length(0) {}
|
||||
|
||||
/// Initialize from pointer + length
|
||||
SliceArray(const T* _ptr, size_t _length)
|
||||
: ptr(_ptr), length(_length) {}
|
||||
|
||||
/// Initialize from null-terminated string
|
||||
SliceArray(const char* str)
|
||||
{
|
||||
ptr = str;
|
||||
length = strlen(str);
|
||||
}
|
||||
|
||||
bool operator==(SliceArray &t)
|
||||
{
|
||||
return
|
||||
length == t.length &&
|
||||
(memcmp(ptr,t.ptr, length*sizeof(T)) == 0);
|
||||
}
|
||||
|
||||
/// Only use this for stings
|
||||
bool operator==(const char* str)
|
||||
{
|
||||
return
|
||||
str[length] == 0 &&
|
||||
(strncmp(ptr, str, length) == 0);
|
||||
}
|
||||
|
||||
/** This allocates a copy of the data. Only use this for debugging
|
||||
and error messages. */
|
||||
std::string toString()
|
||||
{ return std::string(ptr,length); }
|
||||
};
|
||||
|
||||
typedef SliceArray<char> SString;
|
||||
typedef SliceArray<int> IntArray;
|
||||
typedef SliceArray<float> FloatArray;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
70
components/misc/stringops.cpp
Normal file
70
components/misc/stringops.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include "stringops.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include <string.h>
|
||||
#include <libs/platform/strings.h>
|
||||
|
||||
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
|
||||
bool begins(const char* str1, const char* str2)
|
||||
{
|
||||
while(*str2)
|
||||
{
|
||||
if(*str1 == 0 || *str1 != *str2) return false;
|
||||
|
||||
str1++;
|
||||
str2++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ends(const char* str1, const char* str2)
|
||||
{
|
||||
int len1 = strlen(str1);
|
||||
int len2 = strlen(str2);
|
||||
|
||||
if(len1 < len2) return false;
|
||||
|
||||
return strcmp(str2, str1+len1-len2) == 0;
|
||||
}
|
||||
|
||||
// True if the given chars match, case insensitive
|
||||
static bool icmp(char a, char b)
|
||||
{
|
||||
if(a >= 'A' && a <= 'Z')
|
||||
a += 'a' - 'A';
|
||||
if(b >= 'A' && b <= 'Z')
|
||||
b += 'a' - 'A';
|
||||
|
||||
return a == b;
|
||||
}
|
||||
|
||||
bool ibegins(const char* str1, const char* str2)
|
||||
{
|
||||
while(*str2)
|
||||
{
|
||||
if(*str1 == 0 || !icmp(*str1,*str2)) return false;
|
||||
|
||||
str1++;
|
||||
str2++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool iends(const char* str1, const char* str2)
|
||||
{
|
||||
int len1 = strlen(str1);
|
||||
int len2 = strlen(str2);
|
||||
|
||||
if(len1 < len2) return false;
|
||||
|
||||
return strcasecmp(str2, str1+len1-len2) == 0;
|
||||
}
|
||||
|
||||
}
|
92
components/misc/stringops.hpp
Normal file
92
components/misc/stringops.hpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
#ifndef MISC_STRINGOPS_H
|
||||
#define MISC_STRINGOPS_H
|
||||
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
class StringUtils
|
||||
{
|
||||
struct ci
|
||||
{
|
||||
bool operator()(int x, int y) const {
|
||||
return std::tolower(x) < std::tolower(y);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static bool ciLess(const std::string &x, const std::string &y) {
|
||||
return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci());
|
||||
}
|
||||
|
||||
static bool ciEqual(const std::string &x, const std::string &y) {
|
||||
if (x.size() != y.size()) {
|
||||
return false;
|
||||
}
|
||||
std::string::const_iterator xit = x.begin();
|
||||
std::string::const_iterator yit = y.begin();
|
||||
for (; xit != x.end(); ++xit, ++yit) {
|
||||
if (std::tolower(*xit) != std::tolower(*yit)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ciCompareLen(const std::string &x, const std::string &y, size_t len)
|
||||
{
|
||||
std::string::const_iterator xit = x.begin();
|
||||
std::string::const_iterator yit = y.begin();
|
||||
for(;xit != x.end() && yit != y.end() && len > 0;++xit,++yit,--len)
|
||||
{
|
||||
int res = *xit - *yit;
|
||||
if(res != 0 && std::tolower(*xit) != std::tolower(*yit))
|
||||
return (res > 0) ? 1 : -1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
if(xit != x.end())
|
||||
return 1;
|
||||
if(yit != y.end())
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Transforms input string to lower case w/o copy
|
||||
static std::string &toLower(std::string &inout) {
|
||||
std::transform(
|
||||
inout.begin(),
|
||||
inout.end(),
|
||||
inout.begin(),
|
||||
(int (*)(int)) std::tolower
|
||||
);
|
||||
return inout;
|
||||
}
|
||||
|
||||
/// Returns lower case copy of input string
|
||||
static std::string lowerCase(const std::string &in)
|
||||
{
|
||||
std::string out = in;
|
||||
return toLower(out);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Returns true if str1 begins with substring str2
|
||||
bool begins(const char* str1, const char* str2);
|
||||
|
||||
/// Returns true if str1 ends with substring str2
|
||||
bool ends(const char* str1, const char* str2);
|
||||
|
||||
/// Case insensitive, returns true if str1 begins with substring str2
|
||||
bool ibegins(const char* str1, const char* str2);
|
||||
|
||||
/// Case insensitive, returns true if str1 ends with substring str2
|
||||
bool iends(const char* str1, const char* str2);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
12
components/misc/tests/Makefile
Normal file
12
components/misc/tests/Makefile
Normal file
|
@ -0,0 +1,12 @@
|
|||
GCC=g++
|
||||
|
||||
all: strops_test slice_test
|
||||
|
||||
slice_test: slice_test.cpp ../slice_array.hpp
|
||||
$(GCC) $< -o $@
|
||||
|
||||
strops_test: strops_test.cpp ../stringops.hpp ../stringops.cpp
|
||||
$(GCC) $< -o $@ ../stringops.cpp
|
||||
|
||||
clean:
|
||||
rm *_test
|
6
components/misc/tests/output/slice_test.out
Normal file
6
components/misc/tests/output/slice_test.out
Normal file
|
@ -0,0 +1,6 @@
|
|||
hello, len=5
|
||||
001
|
||||
hell, len=4
|
||||
010
|
||||
01
|
||||
4 3
|
0
components/misc/tests/output/strops_test.out
Normal file
0
components/misc/tests/output/strops_test.out
Normal file
28
components/misc/tests/slice_test.cpp
Normal file
28
components/misc/tests/slice_test.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "../slice_array.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
Misc::SString s, t;
|
||||
s = Misc::SString("hello");
|
||||
cout << s.toString() << ", len=" << s.length << endl;
|
||||
cout << (s=="hel") << (s=="hell") << (s=="hello") << endl;
|
||||
t = s;
|
||||
|
||||
s = Misc::SString("othello"+2, 4);
|
||||
cout << s.toString() << ", len=" << s.length << endl;
|
||||
cout << (s=="hel") << (s=="hell") << (s=="hello") << endl;
|
||||
|
||||
cout << (s==t) << (Misc::SString("hello")==t) << endl;
|
||||
|
||||
const int arr[4] = {1,2,3,4};
|
||||
|
||||
Misc::IntArray ia(arr,4);
|
||||
|
||||
cout << ia.length << " " << ia.ptr[2] << endl;
|
||||
|
||||
return 0;
|
||||
}
|
48
components/misc/tests/strops_test.cpp
Normal file
48
components/misc/tests/strops_test.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include <cassert>
|
||||
|
||||
#include "../stringops.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
assert(Misc::begins("abc", "a"));
|
||||
assert(Misc::begins("abc", "ab"));
|
||||
assert(Misc::begins("abc", "abc"));
|
||||
assert(Misc::begins("abcd", "abc"));
|
||||
|
||||
assert(!Misc::begins("abc", "b"));
|
||||
assert(!Misc::begins("abc", "bc"));
|
||||
assert(!Misc::begins("abc", "bcd"));
|
||||
assert(!Misc::begins("abc", "abcd"));
|
||||
|
||||
assert(Misc::ibegins("Abc", "a"));
|
||||
assert(Misc::ibegins("aBc", "ab"));
|
||||
assert(Misc::ibegins("abC", "abc"));
|
||||
assert(Misc::ibegins("abcD", "abc"));
|
||||
|
||||
assert(!Misc::ibegins("abc", "b"));
|
||||
assert(!Misc::ibegins("abc", "bc"));
|
||||
assert(!Misc::ibegins("abc", "bcd"));
|
||||
assert(!Misc::ibegins("abc", "abcd"));
|
||||
|
||||
assert(Misc::ends("abc", "c"));
|
||||
assert(Misc::ends("abc", "bc"));
|
||||
assert(Misc::ends("abc", "abc"));
|
||||
assert(Misc::ends("abcd", "abcd"));
|
||||
|
||||
assert(!Misc::ends("abc", "b"));
|
||||
assert(!Misc::ends("abc", "ab"));
|
||||
assert(!Misc::ends("abc", "bcd"));
|
||||
assert(!Misc::ends("abc", "abcd"));
|
||||
|
||||
assert(Misc::iends("Abc", "c"));
|
||||
assert(Misc::iends("aBc", "bc"));
|
||||
assert(Misc::iends("abC", "abc"));
|
||||
assert(Misc::iends("abcD", "abcd"));
|
||||
|
||||
assert(!Misc::iends("abc", "b"));
|
||||
assert(!Misc::iends("abc", "ab"));
|
||||
assert(!Misc::iends("abc", "bcd"));
|
||||
assert(!Misc::iends("abc", "abcd"));
|
||||
|
||||
return 0;
|
||||
}
|
18
components/misc/tests/test.sh
Executable file
18
components/misc/tests/test.sh
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
|
||||
make || exit
|
||||
|
||||
mkdir -p output
|
||||
|
||||
PROGS=*_test
|
||||
|
||||
for a in $PROGS; do
|
||||
if [ -f "output/$a.out" ]; then
|
||||
echo "Running $a:"
|
||||
./$a | diff output/$a.out -
|
||||
else
|
||||
echo "Creating $a.out"
|
||||
./$a > "output/$a.out"
|
||||
git add "output/$a.out"
|
||||
fi
|
||||
done
|
116
components/misc/utf8stream.hpp
Normal file
116
components/misc/utf8stream.hpp
Normal file
|
@ -0,0 +1,116 @@
|
|||
#ifndef MISC_UTF8ITER_HPP
|
||||
#define MISC_UTF8ITER_HPP
|
||||
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
class Utf8Stream
|
||||
{
|
||||
public:
|
||||
|
||||
typedef uint32_t UnicodeChar;
|
||||
typedef unsigned char const * Point;
|
||||
|
||||
//static const unicode_char sBadChar = 0xFFFFFFFF; gcc can't handle this
|
||||
static UnicodeChar sBadChar () { return UnicodeChar (0xFFFFFFFF); }
|
||||
|
||||
Utf8Stream (Point begin, Point end) :
|
||||
cur (begin), nxt (begin), end (end)
|
||||
{
|
||||
}
|
||||
|
||||
Utf8Stream (std::pair <Point, Point> range) :
|
||||
cur (range.first), nxt (range.first), end (range.second)
|
||||
{
|
||||
}
|
||||
|
||||
bool eof () const
|
||||
{
|
||||
return cur == end;
|
||||
}
|
||||
|
||||
Point current () const
|
||||
{
|
||||
return cur;
|
||||
}
|
||||
|
||||
UnicodeChar peek ()
|
||||
{
|
||||
if (cur == nxt)
|
||||
next ();
|
||||
return val;
|
||||
}
|
||||
|
||||
UnicodeChar consume ()
|
||||
{
|
||||
if (cur == nxt)
|
||||
next ();
|
||||
cur = nxt;
|
||||
return val;
|
||||
}
|
||||
|
||||
static std::pair <UnicodeChar, Point> decode (Point cur, Point end)
|
||||
{
|
||||
if ((*cur & 0x80) == 0)
|
||||
{
|
||||
UnicodeChar chr = *cur++;
|
||||
|
||||
return std::make_pair (chr, cur);
|
||||
}
|
||||
|
||||
int octets;
|
||||
UnicodeChar chr;
|
||||
|
||||
boost::tie (octets, chr) = octet_count (*cur++);
|
||||
|
||||
if (octets > 5)
|
||||
return std::make_pair (sBadChar(), cur);
|
||||
|
||||
Point eoc = cur + octets;
|
||||
|
||||
if (eoc > end)
|
||||
return std::make_pair (sBadChar(), cur);
|
||||
|
||||
while (cur != eoc)
|
||||
{
|
||||
if ((*cur & 0xC0) != 0x80) // check continuation mark
|
||||
return std::make_pair (sBadChar(), cur);;
|
||||
|
||||
chr = (chr << 6) | UnicodeChar ((*cur++) & 0x3F);
|
||||
}
|
||||
|
||||
return std::make_pair (chr, cur);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static std::pair <int, UnicodeChar> octet_count (unsigned char octet)
|
||||
{
|
||||
int octets;
|
||||
|
||||
unsigned char mark = 0xC0;
|
||||
unsigned char mask = 0xE0;
|
||||
|
||||
for (octets = 1; octets <= 5; ++octets)
|
||||
{
|
||||
if ((octet & mask) == mark)
|
||||
break;
|
||||
|
||||
mark = (mark >> 1) | 0x80;
|
||||
mask = (mask >> 1) | 0x80;
|
||||
}
|
||||
|
||||
return std::make_pair (octets, octet & ~mask);
|
||||
}
|
||||
|
||||
void next ()
|
||||
{
|
||||
boost::tie (val, nxt) = decode (nxt, end);
|
||||
}
|
||||
|
||||
Point cur;
|
||||
Point nxt;
|
||||
Point end;
|
||||
UnicodeChar val;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue