00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <microfeed-common/microfeedmisc.h>
00021
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <stdarg.h>
00025 #include <stdlib.h>
00026 #include <sys/stat.h>
00027 #include <errno.h>
00028 #include <libgen.h>
00029
00030 typedef struct _FreeCallbackData FreeCallbackData;
00031
00032 struct _MicrofeedWeakReference {
00033 void* referenced;
00034 unsigned int reference_count;
00035 FreeCallbackData* free_callbacks;
00036 };
00037
00038 struct _FreeCallbackData {
00039 FreeCallbackData* next;
00040 MicrofeedFreeCallback free_callback;
00041 void* user_data;
00042 };
00043
00044 void* microfeed_memory_allocate_bytes(size_t size) {
00045 void* pointer;
00046
00047 if (!(pointer = malloc(size))) {
00048 fprintf(stderr, "ERROR: Failed to allocate memory.\n");
00049
00050 exit(126);
00051 }
00052 memset(pointer, 0, size);
00053
00054 return pointer;
00055 }
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 void microfeed_memory_free(void* pointer) {
00098 free(pointer);
00099 }
00100
00101 char* microfeed_util_string_concatenate(const char* s, ...) {
00102 char* result;
00103 size_t size;
00104 size_t length;
00105 va_list argp;
00106
00107 size = strlen(s);
00108 length = size + 1;
00109 result = (char*)malloc(length);
00110 memcpy(result, s, length);
00111 va_start(argp, s);
00112 while ((s = va_arg(argp, const char*))) {
00113 length = strlen(s);
00114 result = realloc(result, size + length + 1);
00115 memcpy(result + size, s, length + 1);
00116 size += length;
00117 }
00118 va_end(argp);
00119
00120 return result;
00121 }
00122
00123 char* microfeed_util_string_base64_encode(const char* s, size_t length) {
00124 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00125 char* result;
00126 size_t result_length;
00127 const unsigned char* from;
00128 const unsigned char* end;
00129 char* to;
00130
00131 result_length = ((length + 2) / 3) * 4;
00132 result = (char*)malloc(result_length + 1);
00133 result[result_length] = 0;
00134 for (from = (const unsigned char*)s, to = result, end = from + length; from + 2 < end; from += 3, to += 4) {
00135 to[0] = base64[from[0] >> 2];
00136 to[1] = base64[((from[0] & 0x3) << 4) | ((from[1] & 0xf0) >> 4)];
00137 to[2] = base64[((from[1] & 0xf) << 2) | ((from[2] & 0xc0) >> 6)];
00138 to[3] = base64[from[2] & 0x3f];
00139 }
00140 if (from + 1 < end) {
00141 to[0] = base64[from[0] >> 2];
00142 to[1] = base64[((from[0] & 0x3) << 4) | ((from[1] & 0xf0) >> 4)];
00143 to[2] = base64[((from[1] & 0xf) << 2)];
00144 to[3] = '=';
00145 } else if (from < end) {
00146 to[0] = base64[from[0] >> 2];
00147 to[1] = base64[(from[0] & 0x3) << 4];
00148 to[2] = '=';
00149 to[3] = '=';
00150 }
00151
00152 return result;
00153 }
00154
00155
00156 size_t microfeed_util_string_starts_with(const char* s, const char* prefix) {
00157 size_t length = 0;
00158 const char* p;
00159
00160 p = prefix;
00161 while (*s && *p && *s == *p) {
00162 s++;
00163 p++;
00164 }
00165 if (*p == 0) {
00166 length = p - prefix;
00167 }
00168
00169 return length;
00170 }
00171
00172 static int hexadecimal_char_to_int(char c) {
00173 int retvalue = -1;
00174
00175 if (c >= '0' && c <= '9') {
00176 retvalue = c - '0';
00177 } else if (c >= 'a' && c <= 'f') {
00178 retvalue = c - 'a' + 10;
00179 } else if (c >= 'A' && c <= 'F') {
00180 retvalue = c - 'A' + 10;
00181 }
00182
00183 return retvalue;
00184 }
00185
00186 char* microfeed_util_string_percent_encoding_escape(const char* s) {
00187 static const char hex[] = "0123456789ABCDEF";
00188 char* result;
00189 size_t length;
00190 const char* from;
00191 char* to;
00192 size_t offset;
00193
00194 length = strlen(s) + 1;
00195 result = (char*)malloc(length);
00196
00197 for (to = result, from = s; *from; from++, to++) {
00198 if ((*from >= 'a' && *from <= 'z') || (*from >= 'A' && *from <= 'Z') || (*from >= '0' && *from <= '9') ||
00199 *from == '-' || *from == '_' || *from == '.' || *from == '~') {
00200 *to = *from;
00201 } else {
00202 length += 2;
00203 offset = to - result;
00204 result = realloc(result, length);
00205 to = result + offset;
00206 *to++ = '%';
00207 *to++ = hex[((unsigned char)*from) >> 4];
00208 *to = hex[((unsigned char)*from) & 0xf];
00209 }
00210 }
00211 *to = 0;
00212
00213 return result;
00214 }
00215
00216 char* microfeed_util_string_percent_encoding_unescape(const char* s) {
00217 char* result;
00218 const char* from;
00219 char* to;
00220 int tempvalue;
00221 int value;
00222
00223 result = (char*)malloc(strlen(s) + 1);
00224 for (to = result, from = s; *from; from++, to++) {
00225 if (*from == '%') {
00226 if ((tempvalue = hexadecimal_char_to_int(from[1])) == -1) {
00227 free(result);
00228 result = NULL;
00229 break;
00230 }
00231 if ((value = hexadecimal_char_to_int(from[2])) == -1) {
00232 free(result);
00233 result = NULL;
00234 break;
00235 }
00236 value |= tempvalue << 4;
00237 if ((value >= 'a' && value <= 'z') || (value >= 'A' && value <= 'Z') || (value >= '0' && value <= '9') ||
00238 value == '-' || value == '_' || value == '.' || value == '~') {
00239 *to = value;
00240 } else {
00241 *to++ = *from++;
00242 *to++ = *from++;
00243 *to = *from;
00244 }
00245 } else {
00246 *to = *from;
00247 }
00248 }
00249 if (result) {
00250 *to++ = 0;
00251 result = (char*)realloc(result, result - to);
00252 }
00253
00254 return result;
00255 }
00256
00257 MicrofeedWeakReference* microfeed_weak_reference_new(void* referenced, MicrofeedWeakReference* existing_weak_reference) {
00258 if (existing_weak_reference) {
00259 existing_weak_reference->reference_count++;
00260 } else {
00261 existing_weak_reference = microfeed_memory_allocate(MicrofeedWeakReference);
00262 existing_weak_reference->referenced = referenced;
00263 existing_weak_reference->reference_count = 1;
00264 }
00265
00266 return existing_weak_reference;
00267 }
00268
00269 void microfeed_weak_reference_free(MicrofeedWeakReference* weak_reference) {
00270 weak_reference->reference_count--;
00271 if (weak_reference->reference_count == 0 && !weak_reference->referenced) {
00272 microfeed_memory_free(weak_reference);
00273 }
00274 }
00275
00276 void* microfeed_weak_reference_get_impl(MicrofeedWeakReference* weak_reference) {
00277
00278 return weak_reference->referenced;
00279 }
00280
00281 void microfeed_weak_reference_invalidate(MicrofeedWeakReference* weak_reference) {
00282 FreeCallbackData* fcd;
00283
00284 if (weak_reference) {
00285 for (fcd = weak_reference->free_callbacks; fcd; fcd = fcd->next) {
00286 fcd->free_callback(weak_reference->referenced, fcd->user_data);
00287 weak_reference->reference_count--;
00288 }
00289
00290 weak_reference->referenced = NULL;
00291
00292 if (weak_reference->reference_count == 0) {
00293 microfeed_memory_free(weak_reference);
00294 }
00295 }
00296 }
00297
00298 MicrofeedWeakReference* microfeed_weak_reference_add_free_callback(MicrofeedWeakReference* existing_weak_reference, void* referenced, MicrofeedFreeCallback free_callback, void* user_data) {
00299 MicrofeedWeakReference* weak_reference;
00300 FreeCallbackData* fcd;
00301
00302 weak_reference = microfeed_weak_reference_new(referenced, existing_weak_reference);
00303
00304 fcd = microfeed_memory_allocate(FreeCallbackData);
00305 fcd->free_callback = free_callback;
00306 fcd->user_data = user_data;
00307 fcd->next = weak_reference->free_callbacks;
00308 weak_reference->free_callbacks = fcd;
00309
00310 return weak_reference;
00311 }
00312
00313 void microfeed_weak_reference_remove_free_callback(MicrofeedWeakReference* weak_reference, MicrofeedFreeCallback free_callback, void* user_data) {
00314 FreeCallbackData* fcd;
00315 FreeCallbackData* previous = NULL;
00316
00317 for (fcd = weak_reference->free_callbacks; fcd; fcd = fcd->next) {
00318 if (fcd->free_callback == free_callback && fcd->user_data == user_data) {
00319 if (previous) {
00320 previous->next = fcd->next;
00321 } else {
00322 weak_reference->free_callbacks = fcd->next;
00323 }
00324 microfeed_memory_free(fcd);
00325 break;
00326 }
00327 previous = fcd;
00328 }
00329 }
00330
00331 int microfeed_util_create_directory_recursively(const char* directory) {
00332 int retval = 0;
00333 char* s1;
00334 char* s2;
00335
00336
00337 if (mkdir(directory, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0 || errno == EEXIST) {
00338 retval = 1;
00339 } if (errno == ENOENT) {
00340 s1 = strdup(directory);
00341 s2 = dirname(s1);
00342 if (strcmp(s2, ".") && strcmp(s2, "/")) {
00343 if (microfeed_util_create_directory_recursively(s2) && mkdir(directory, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0) {
00344 retval = 1;
00345 }
00346 }
00347 free(s1);
00348 }
00349
00350 return retval;
00351 }