comparison ext/serd/src/string.c @ 226:c5cdc9e6a4bf

Add these external library files
author Chris Cannam <cannam@all-day-breakfast.com>
date Fri, 09 Jun 2017 16:41:31 +0100
parents
children
comparison
equal deleted inserted replaced
225:025b3e2f7c17 226:c5cdc9e6a4bf
1 /*
2 Copyright 2011-2016 David Robillard <http://drobilla.net>
3
4 Permission to use, copy, modify, and/or distribute this software for any
5 purpose with or without fee is hereby granted, provided that the above
6 copyright notice and this permission notice appear in all copies.
7
8 THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "serd_internal.h"
18
19 #include <math.h>
20
21 SERD_API
22 const uint8_t*
23 serd_strerror(SerdStatus st)
24 {
25 switch (st) {
26 case SERD_SUCCESS: return (const uint8_t*)"Success";
27 case SERD_FAILURE: return (const uint8_t*)"Non-fatal failure";
28 case SERD_ERR_UNKNOWN: return (const uint8_t*)"Unknown error";
29 case SERD_ERR_BAD_SYNTAX: return (const uint8_t*)"Invalid syntax";
30 case SERD_ERR_BAD_ARG: return (const uint8_t*)"Invalid argument";
31 case SERD_ERR_NOT_FOUND: return (const uint8_t*)"Not found";
32 case SERD_ERR_ID_CLASH: return (const uint8_t*)"Blank node ID clash";
33 case SERD_ERR_BAD_CURIE: return (const uint8_t*)"Invalid CURIE";
34 case SERD_ERR_INTERNAL: return (const uint8_t*)"Internal error";
35 }
36 return (const uint8_t*)"Unknown error"; // never reached
37 }
38
39 SERD_API
40 size_t
41 serd_strlen(const uint8_t* str, size_t* n_bytes, SerdNodeFlags* flags)
42 {
43 size_t n_chars = 0;
44 size_t i = 0;
45 SerdNodeFlags f = 0;
46 for (; str[i]; ++i) {
47 if ((str[i] & 0xC0) != 0x80) {
48 // Does not start with `10', start of a new character
49 ++n_chars;
50 switch (str[i]) {
51 case '\r': case '\n':
52 f |= SERD_HAS_NEWLINE;
53 break;
54 case '"':
55 f |= SERD_HAS_QUOTE;
56 }
57 }
58 }
59 if (n_bytes) {
60 *n_bytes = i;
61 }
62 if (flags) {
63 *flags = f;
64 }
65 return n_chars;
66 }
67
68 static inline double
69 read_sign(const char** sptr)
70 {
71 double sign = 1.0;
72 switch (**sptr) {
73 case '-': sign = -1.0;
74 case '+': ++(*sptr);
75 default: return sign;
76 }
77 }
78
79 SERD_API
80 double
81 serd_strtod(const char* str, char** endptr)
82 {
83 double result = 0.0;
84
85 // Point s at the first non-whitespace character
86 const char* s = str;
87 while (is_space(*s)) { ++s; }
88
89 // Read leading sign if necessary
90 const double sign = read_sign(&s);
91
92 // Parse integer part
93 for (; is_digit(*s); ++s) {
94 result = (result * 10.0) + (*s - '0');
95 }
96
97 // Parse fractional part
98 if (*s == '.') {
99 double denom = 10.0;
100 for (++s; is_digit(*s); ++s) {
101 result += (*s - '0') / denom;
102 denom *= 10.0;
103 }
104 }
105
106 // Parse exponent
107 if (*s == 'e' || *s == 'E') {
108 ++s;
109 double expt = 0.0;
110 double expt_sign = read_sign(&s);
111 for (; is_digit(*s); ++s) {
112 expt = (expt * 10.0) + (*s - '0');
113 }
114 result *= pow(10, expt * expt_sign);
115 }
116
117 if (endptr) {
118 *endptr = (char*)s;
119 }
120
121 return result * sign;
122 }
123
124 /**
125 Base64 decoding table.
126 This is indexed by encoded characters and returns the numeric value used
127 for decoding, shifted up by 47 to be in the range of printable ASCII.
128 A '$' is a placeholder for characters not in the base64 alphabet.
129 */
130 static const char b64_unmap[] =
131 "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$m$$$ncdefghijkl$$$$$$"
132 "$/0123456789:;<=>?@ABCDEFGH$$$$$$IJKLMNOPQRSTUVWXYZ[\\]^_`ab$$$$"
133 "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"
134 "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$";
135
136 static inline uint8_t unmap(const uint8_t in) { return b64_unmap[in] - 47; }
137
138 /**
139 Decode 4 base64 characters to 3 raw bytes.
140 */
141 static inline size_t
142 decode_chunk(const uint8_t in[4], uint8_t out[3])
143 {
144 out[0] = (uint8_t)(((unmap(in[0]) << 2)) | unmap(in[1]) >> 4);
145 out[1] = (uint8_t)(((unmap(in[1]) << 4) & 0xF0) | unmap(in[2]) >> 2);
146 out[2] = (uint8_t)(((unmap(in[2]) << 6) & 0xC0) | unmap(in[3]));
147 return 1 + (in[2] != '=') + ((in[2] != '=') && (in[3] != '='));
148 }
149
150 SERD_API
151 void*
152 serd_base64_decode(const uint8_t* str, size_t len, size_t* size)
153 {
154 void* buf = malloc((len * 3) / 4 + 2);
155 *size = 0;
156 for (size_t i = 0, j = 0; i < len; j += 3) {
157 uint8_t in[] = "====";
158 size_t n_in = 0;
159 for (; i < len && n_in < 4; ++n_in) {
160 for (; i < len && !is_base64(str[i]); ++i) {} // Skip junk
161 in[n_in] = str[i++];
162 }
163 if (n_in > 1) {
164 *size += decode_chunk(in, (uint8_t*)buf + j);
165 }
166 }
167 return buf;
168 }