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