1 /* sdb - MIT - Copyright 2011-2018 - pancake */
2 
3 #include "sdb.h"
4 
5 #define FORCE_COLLISION 0
6 
7 #if USE_MONOTONIC_CLOCK
8 #include <time.h>
9 #else
10 
11 #ifdef _MSC_VER
12 #pragma message ("gettimeofday: Windows support is ugly here")
13 #include <windows.h>
14 #include <time.h>
15 
16 struct timezone {
17 	int  tz_minuteswest; /* minutes W of Greenwich */
18 	int  tz_dsttime;     /* type of dst correction */
19 };
20 
gettimeofday(struct timeval * p,struct timezone * tz)21 SDB_API int gettimeofday (struct timeval* p, struct timezone * tz) {
22 	//ULARGE_INTEGER ul; // As specified on MSDN.
23 	ut64 ul = 0;
24 	static int tzflag = 0;
25 	FILETIME ft;
26 	if (p) {
27 		// Returns a 64-bit value representing the number of
28 		// 100-nanosecond intervals since January 1, 1601 (UTC).
29 		GetSystemTimeAsFileTime (&ft);
30 		// Fill ULARGE_INTEGER low and high parts.
31 		//ul.LowPart = ft.dwLowDateTime;
32 		//ul.HighPart = ft.dwHighDateTime;
33 		ul |= ft.dwHighDateTime;
34 		ul <<= 32;
35 		ul |= ft.dwLowDateTime;
36 		// Convert to microseconds.
37 		//ul.QuadPart /= 10ULL;
38 		ul /= 10;
39 		// Remove Windows to UNIX Epoch delta.
40 		//ul.QuadPart -= 11644473600000000ULL;
41 		ul -= 11644473600000000ULL;
42 		// Modulo to retrieve the microseconds.
43 		//p->tv_usec = (long)(ul.QuadPart % 1000000LL);
44 		// Divide to retrieve the seconds.
45 		//p->tv_sec = (long)(ul.QuadPart / 1000000LL);
46 		p->tv_sec = (long)(ul / 1000000LL);
47 		p->tv_usec = (long)(ul % 1000000LL);
48 	}
49 	if (tz) {
50 		if (!tzflag) {
51 			_tzset ();
52 			tzflag++;
53 		}
54 		tz->tz_minuteswest = _timezone / 60;
55 		tz->tz_dsttime = _daylight;
56 	}
57 	return 0;
58 }
59 
60 #else
61 #include <sys/time.h>
62 #endif
63 #endif
64 
sdb_hash_len(const char * s,ut32 * len)65 SDB_API ut32 sdb_hash_len(const char *s, ut32 *len) {
66 	ut32 h = CDB_HASHSTART;
67 #if FORCE_COLLISION
68 	h = 0;
69 	while (*s) {
70 		h += *s;
71 		s++;
72 	}
73 #else
74 	ut32 count = 0;
75 	if (s) {
76 		while (*s) {
77 			h = (h + (h << 5)) ^ *s++;
78 			count++;
79 		}
80 	}
81 	if (len) {
82 		*len = count;
83 	}
84 #endif
85 	return h;
86 }
87 
sdb_hash(const char * s)88 SDB_API ut32 sdb_hash(const char *s) {
89 	return sdb_hash_len (s, NULL);
90 }
91 
sdb_hash_byte(const char * s)92 SDB_API ut8 sdb_hash_byte(const char *s) {
93 	const ut32 hash = sdb_hash_len (s, NULL);
94 	const ut8 *h = (const ut8*)&hash;
95 	return h[0] ^ h[1] ^ h[2] ^ h[3];
96 }
97 
sdb_itoca(ut64 n)98 SDB_API const char *sdb_itoca(ut64 n) {
99 	return sdb_itoa (n, sdb_fmt (NULL), 16);
100 }
101 
102 // assert (sizeof (s)>64)
103 // if s is null, the returned pointer must be freed!!
sdb_itoa(ut64 n,char * s,int base)104 SDB_API char *sdb_itoa(ut64 n, char *s, int base) {
105 	static const char* lookup = "0123456789abcdef";
106 	char tmpbuf[64], *os = NULL;
107 	const int imax = 62;
108 	int i = imax, copy_string = 1;
109 	if (s) {
110 		*s = 0;
111 		os = NULL;
112 	} else {
113 		os = s = tmpbuf;
114 	}
115 	if (base < 0) {
116 		copy_string = 0;
117 		base = -base;
118 	}
119 	if ((base > 16) || (base < 1)) {
120 		return NULL;
121 	}
122 	if (!n) {
123 		if (os) {
124 			return strdup ("0");
125 		}
126 		strcpy (s, "0");
127 		return s;
128 	}
129 	s[imax + 1] = '\0';
130 	if (base <= 10) {
131 		for (; n && i > 0; n /= base) {
132 			s[i--] = (n % base) + '0';
133 		}
134 	} else {
135 		for (; n && i > 0; n /= base) {
136 			s[i--] = lookup[(n % base)];
137 		}
138 		if (i != imax) {
139 			s[i--] = 'x';
140 		}
141 		s[i--] = '0';
142 	}
143 	if (os) {
144 		return strdup (s + i + 1);
145 	}
146 	if (copy_string) {
147 		// unnecessary memmove in case we use the return value
148 		// return s + i + 1;
149 		memmove (s, s + i + 1, strlen (s + i + 1) + 1);
150 		return s;
151 	}
152 	return s + i + 1;
153 }
154 
sdb_atoi(const char * s)155 SDB_API ut64 sdb_atoi(const char *s) {
156 	char *p;
157 	ut64 ret;
158 	if (!s || *s == '-') {
159 		return 0LL;
160 	}
161 	ret = strtoull (s, &p, 0);
162 	return p ? ret: 0LL;
163 }
164 
165 // NOTE: Reuses memory. probably not bindings friendly..
sdb_array_compact(char * p)166 SDB_API char *sdb_array_compact(char *p) {
167 	char *e;
168 	// remove empty elements
169 	while (*p) {
170 		if (!strncmp (p, ",,", 2)) {
171 			p++;
172 			for (e = p + 1; *e == ','; e++) {};
173 			memmove (p, e, strlen (e) + 1);
174 		} else {
175 			p++;
176 		}
177 	}
178 	return p;
179 }
180 
181 // NOTE: Reuses memory. probably not bindings friendly..
sdb_aslice(char * out,int from,int to)182 SDB_API char *sdb_aslice(char *out, int from, int to) {
183 	int len, idx = 0;
184 	char *str = NULL;
185 	char *end = NULL;
186 	char *p = out;
187 	if (from >= to) {
188 		return NULL;
189 	}
190 	while (*p) {
191 		if (!str && idx == from) {
192 			str = p;
193 		}
194 		if (idx == to) {
195 			end = p;
196 			break;
197 		}
198 		if (*p == ',') {
199 			idx++;
200 		}
201 		p++;
202 	}
203 	if (str) {
204 		if (!end) {
205 			end = str + strlen (str);
206 		}
207 		len = (size_t)(end - str);
208 		memmove (out, str, len);
209 		out[len] = 0;
210 		return out;
211 	}
212 	return NULL;
213 }
214 
215 // TODO: find better name for it
216 // TODO: optimize, because this is the main bottleneck for sdb_array_set()
sdb_alen(const char * str)217 SDB_API int sdb_alen(const char *str) {
218 	int len = 1;
219 	const char *n, *p = str;
220 	if (!p|| !*p) {
221 		return 0;
222 	}
223 	for (len = 0; ; len++) {
224 		n = strchr (p, SDB_RS);
225 		if (!n) {
226 			break;
227 		}
228 		p = n + 1;
229 	}
230 	return ++len;
231 }
232 
sdb_alen_ignore_empty(const char * str)233 SDB_API int sdb_alen_ignore_empty(const char *str) {
234 	int len = 1;
235 	const char *n, *p = str;
236 	if (!p || !*p) {
237 		return 0;
238 	}
239 	while (*p == SDB_RS) {
240 		p++;
241 	}
242 	for (len = 0; ; ) {
243 		n = strchr (p, SDB_RS);
244 		if (!n) {
245 			break;
246 		}
247 		p = n + 1;
248 		if (*(p) == SDB_RS) {
249 			continue;
250 		}
251 		len++;
252 	}
253 	if (*p) len++;
254 	return len;
255 }
256 
sdb_anext(char * str,char ** next)257 SDB_API char *sdb_anext(char *str, char **next) {
258 	char *nxt, *p = strchr (str, SDB_RS);
259 	if (p) {
260 		*p = 0;
261 		nxt = p + 1;
262 	} else {
263 		nxt = NULL;
264 	}
265 	if (next) {
266 		*next = nxt;
267 	}
268 	return str;
269 }
270 
sdb_const_anext(const char * str)271 SDB_API const char *sdb_const_anext(const char *str) {
272 	const char *p = strchr (str, SDB_RS);
273 	return p ? p + 1 : NULL;
274 }
275 
sdb_now(void)276 SDB_API ut64 sdb_now (void) {
277 #if USE_MONOTONIC_CLOCK
278 	struct timespec ts;
279 	if (!clock_gettime (CLOCK_MONOTONIC, &ts)) {
280 		return ts.tv_sec;
281 	}
282 #else
283 	struct timeval now;
284 	if (!gettimeofday (&now, NULL)) {
285 		return now.tv_sec;
286 	}
287 #endif
288 	return 0LL;
289 }
290 
sdb_unow(void)291 SDB_API ut64 sdb_unow (void) {
292 	ut64 x = 0LL;
293 #if USE_MONOTONIC_CLOCK
294 	struct timespec ts;
295 	if (!clock_gettime (CLOCK_MONOTONIC, &ts)) {
296 		x = ts.tv_sec;
297 		x <<= 32;
298 		x += ts.tv_nsec / 1000;
299 	}
300 #else
301         struct timeval now;
302         if (!gettimeofday (&now, NULL)) {
303 		x = now.tv_sec;
304 		x <<= 32;
305 		x += now.tv_usec;
306 	}
307 #endif
308 	return x;
309 }
310 
sdb_isnum(const char * s)311 SDB_API int sdb_isnum(const char *s) {
312 	const char vs = *s;
313 	return ((vs == '-' || vs == '+') || (vs >= '0' && vs <= '9'));
314 }
315 
sdb_num_base(const char * s)316 SDB_API int sdb_num_base(const char *s) {
317 	if (!s) {
318 		return SDB_NUM_BASE;
319 	}
320 	if (!strncmp (s, "0x", 2)) {
321 		return 16;
322 	}
323 	return (*s=='0' && s[1]) ? 8: 10;
324 }
325 
sdb_type(const char * k)326 SDB_API const char *sdb_type(const char *k) {
327 	if (!k || !*k) {
328 		return "undefined";
329 	}
330 	if (sdb_isnum (k)) {
331 		return "number";
332 	}
333 	if (sdb_isjson (k)) {
334 		return "json";
335 	}
336 	if (strchr (k, ',')) {
337 		return "array";
338 	}
339 	if (!strcmp (k, "true") || !strcmp (k, "false")) {
340 		return "boolean";
341 	}
342 	return "string";
343 }
344 
345 // TODO: check all the values
sdb_isjson(const char * k)346 SDB_API bool sdb_isjson (const char *k) {
347 	int level = 0;
348 	bool quotes = false;
349 	if (!k || (*k != '{' && *k != '[')) {
350 		return false;
351 	}
352 	for (; *k; k++) {
353 		if (quotes) {
354 			if (*k == '"') {
355 				quotes = false;
356 			}
357 			continue;
358 		}
359 		switch (*k) {
360 		case '"':
361 			quotes = true;
362 			break;
363 		case '[':
364 		case '{':
365 			level++;
366 			break;
367 		case ']':
368 		case '}':
369 			level--;
370 			if (level < 0) {
371 				/* invalid json */
372 				return false;
373 			}
374 			break;
375 		}
376 	}
377 	return (!quotes && !level);
378 }
379