1 /******************************************************************************
2 *
3 * utilstr.cpp - String utility functions
4 *
5 * $Id: utilstr.cpp 3515 2017-11-01 11:38:09Z scribe $
6 *
7 * Copyright 1997-2013 CrossWire Bible Society (http://www.crosswire.org)
8 * CrossWire Bible Society
9 * P. O. Box 2528
10 * Tempe, AZ 85280-2528
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation version 2.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 */
22
23 #include <utilstr.h>
24 #include <ctype.h>
25 #include <string.h>
26
27 #include <sysdata.h>
28 #include <swlog.h>
29 #include <swbuf.h>
30
31
32 SWORD_NAMESPACE_START
33
34 const unsigned char SW_toupper_array[256] = {
35 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
36 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
37 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
38 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
39 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
40 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
41 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
42 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
43 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
44 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
45 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
46 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
47 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
48 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
49 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
50 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
51 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
52 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
53 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
54 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
55 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
56 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
57 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
58 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
59 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
60 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
61 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
62 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
63 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
64 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
65 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7,
66 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xff
67 };
68
69
70
71 /******************************************************************************
72 * strstrip - Removes leading and trailing spaces from a string
73 *
74 * ENT: istr - string pointer to strip
75 *
76 * RET: *istr
77 */
78
strstrip(char * istr)79 char *strstrip(char *istr) {
80 char *tmp = istr;
81 char *rtmp;
82
83 int len = (int)strlen(istr);
84 if (len < 1)
85 return istr;
86 rtmp = istr + (len - 1);
87
88 while ((rtmp > istr)&&((*rtmp == ' ')||(*rtmp == '\t')||(*rtmp == 10)||(*rtmp == 13))) *(rtmp--) = 0;
89 while ((*tmp == ' ')||(*tmp == '\t')||(*tmp == 10)||(*tmp == 13)) tmp++;
90 memmove(istr, tmp, (rtmp - tmp) + 1);
91 istr[(rtmp - tmp) + 1] = 0;
92
93 return istr;
94 }
95
96
97 /******************************************************************************
98 * stristr - Scans a string for the occurrence of a given substring, no case
99 *
100 * ENT: scans s1 for the first occurrence of the substring s2, ingnoring case
101 *
102 * RET: a pointer to the element in s1, where s2 begins (points to s2 in s1).
103 * If s2 does not occur in s1, returns null.
104 */
105
stristr(const char * s1,const char * s2)106 const char *stristr(const char *s1, const char *s2) {
107 int tLen = (int)strlen(s2);
108 int cLen = (int)strlen(s1);
109 char *target = new char [ tLen + 1 ];
110 int i, j;
111 const char *retVal = 0;
112
113 strcpy(target, s2);
114 for (i = 0; i < tLen; i++)
115 target[i] = SW_toupper(target[i]);
116
117 for (i = 0; i < (cLen - tLen)+1; i++) {
118 if (SW_toupper(s1[i]) == (unsigned char)*target) {
119 for (j = 1; j < tLen; j++) {
120 if (SW_toupper(s1[i+j]) != (unsigned char)target[j])
121 break;
122 }
123 if (j == tLen) {
124 retVal = s1+i;
125 break;
126 }
127 }
128 }
129 delete [] target;
130 return retVal;
131 }
132
133 /******************************************************************************
134 * strnicmp - compares the first n bytes of 2 strings ignoring case
135 *
136 * ENT: compares s1 to s2 comparing the first n byte ingnoring case
137 *
138 * RET: same as strcmp
139 */
140
strnicmp(const char * s1,const char * s2,int len)141 int strnicmp(const char *s1, const char *s2, int len) {
142 int tLen = (int)strlen(s2);
143 int cLen = (int)strlen(s1);
144 char diff;
145 int i;
146 for (i = 0; ((i < len) && (i < tLen) && (i < cLen)); i++) {
147 if ((diff = SW_toupper(*s1) - SW_toupper(*s2)))
148 return diff;
149 s1++;
150 s2++;
151 }
152 return (i < len) ? cLen - tLen : 0;
153 }
154
stricmp(const char * s1,const char * s2)155 int stricmp(const char *s1, const char *s2) {
156 #if defined(__GNUC__)
157 return ::strcasecmp(s1, s2);
158 #else
159 #if defined(_WIN32_WCE)
160 return ::_stricmp(s1, s2);
161 #else
162 return ::stricmp(s1, s2);
163 #endif
164 #endif
165 }
166
167
assureValidUTF8(const char * buf)168 SWBuf assureValidUTF8(const char *buf) {
169
170 SWBuf myCopy = buf;
171 const unsigned char *b = (const unsigned char *)myCopy.c_str();
172 const unsigned char *q = 0;
173 bool invalidChar = false;
174 while (*b) {
175 q = b;
176 if (!getUniCharFromUTF8(&b)) {
177 long len = b - q;
178 if (len) {
179 invalidChar = true;
180 for (long start = q - (const unsigned char *)myCopy.c_str(); len; len--) {
181 myCopy[start+len-1] = 0x1a; // unicode replacement character
182 }
183
184 }
185 }
186 }
187 if (invalidChar) {
188 // SWLog::getSystemLog()->logWarning("Changing invalid UTF-8 string (%s) to (%s)\n", buf, myCopy.c_str());
189 }
190 return myCopy;
191 }
192
193
194 /****
195 * This can be called to convert a UTF8 stream to an SWBuf which manages
196 * a wchar_t[]
197 * access buffer with (wchar_t *)SWBuf::getRawData();
198 *
199 */
utf8ToWChar(const char * buf)200 SWBuf utf8ToWChar(const char *buf) {
201
202 const char *q = 0;
203 SWBuf wcharBuf;
204 while (*buf) {
205 q = buf;
206 wchar_t wc = getUniCharFromUTF8((const unsigned char **)&buf);
207 if (!wc) {
208 // if my buffer was advanced but nothing was converted, I had invalid data
209 if (buf - q) {
210 // invalid bytes in UTF8 stream
211 wcharBuf.append((wchar_t)0x1a); // unicode replacement character
212 }
213 }
214 else wcharBuf.append(wc);
215 }
216 return wcharBuf;
217 }
218
219
220 /****
221 * This can be called to convert a wchar_t[] to a UTF-8 SWBuf
222 *
223 */
wcharToUTF8(const wchar_t * buf)224 SWBuf wcharToUTF8(const wchar_t *buf) {
225
226 SWBuf utf8Buf;
227 while (*buf) {
228 getUTF8FromUniChar(*buf++, &utf8Buf);
229 }
230 return utf8Buf;
231 }
232
233
234 SWORD_NAMESPACE_END
235