/* copyright: Steve Dekorte, 2006. All rights reserved. license: See _BSDLicense.txt. */ #include "UArray.h" #include "cencode.h" #include "cdecode.h" #include #include #include #include #include void UArray_append_(UArray *self, const UArray *other) { if(UArray_itemSize(self) < UArray_itemSize(other)) { UArray_convertToItemType_(self, (int)UArray_itemType(other)); } UArray_at_putAll_(self, self->size, other); } void UArray_appendCString_(UArray *self, const char *s) { /* TODO: pass in the length of the string since it's usually known. */ UArray_appendBytes_size_(self, (const uint8_t *) s, strlen(s)); } void UArray_prepend_(UArray *self, const UArray *other) { UArray_at_putAll_(self, 0, other); } int UArray_equalsAnyCase_(const UArray *self, const UArray *other) { if (self->size == other->size) { return UArray_findAnyCase_(self, other) == 0; } return 0; } void UArray_replace_with_(UArray *self, const UArray *a1, const UArray *a2) { long i; size_t start = 0; UArray visible = UArray_stackRange(self, start, self->size); if (UArray_size(a1) == 0) return; while ((i = UArray_find_(&visible, a1)) != -1) { size_t index = start + i; UArray_removeRange(self, index, a1->size); UArray_at_putAll_(self, index, a2); start = index + a2->size; visible = UArray_stackRange(self, start, self->size - start); } UArray_changed(self); } BASEKIT_API void UArray_replaceCString_withCString_(UArray *self, const char *s1, const char *s2) { UArray a1 = UArray_stackAllocedWithCString_((char *)s1); UArray a2 = UArray_stackAllocedWithCString_((char *)s2); UArray_replace_with_(self, &a1, &a2); } void UArray_replaceAnyCase_with_(UArray *self, const UArray *a1, const UArray *a2) { long i; size_t start = 0; UArray visible = UArray_stackRange(self, start, self->size); while ((i = UArray_findAnyCase_(&visible, a1)) != -1) { size_t index = start + i; UArray_removeRange(self, index, a1->size); UArray_at_putAll_(self, index, a2); start = index + a2->size; visible = UArray_stackRange(self, start, self->size - start); } UArray_changed(self); } BASEKIT_API void UArray_remove_(UArray *self, const UArray *a1) { UArray blank = UArray_stackAllocedEmptyUArray(); UArray_replace_with_(self, a1, &blank); } BASEKIT_API void UArray_removeAnyCase_(UArray *self, const UArray *a1) { UArray blank = UArray_stackAllocedEmptyUArray(); UArray_replaceAnyCase_with_(self, a1, &blank); } // clipping BASEKIT_API int UArray_clipBefore_(UArray *self, const UArray *other) { long index = UArray_find_(self, other); if (index > -1) { UArray_removeRange(self, 0, index); return 1; } return 0; } BASEKIT_API int UArray_clipBeforeEndOf_(UArray *self, const UArray *other) { long index = UArray_find_(self, other); /* printf("UArray_find_('%s', '%s')\n", UArray_bytes(self), UArray_bytes(other)); printf("find index = %i\n", index); printf("prefix sizeInBytes = %i\n", UArray_sizeInBytes(other)); printf("prefix size = %i\n", UArray_size(other)); */ if (index > -1 && other->size) { //printf("UArray_removeRange(0, %i)\n", index + other->size - 1); UArray_removeRange(self, 0, index + other->size); //printf("result = '%s'\n", UArray_bytes(self)); return 1; } return 0; } BASEKIT_API int UArray_clipAfter_(UArray *self, const UArray *other) { long index = UArray_find_(self, other); if (index > -1) { UArray_removeRange(self, index + other->size, self->size); return 1; } return 0; } BASEKIT_API int UArray_clipAfterStartOf_(UArray *self, const UArray *other) { long index = UArray_find_(self, other); if (index > -1) { UArray_removeRange(self, index, self->size); return 1; } return 0; } // strip void UArray_lstrip_(UArray *self, const UArray *other) { size_t amount = 0; if (UArray_isFloatType(self)) { UARRAY_FOREACH(self, i, v, amount = i+1; if (!UArray_containsDouble_(other, v)) { amount --; break; } ) } else { UARRAY_FOREACH(self, i, v, amount = i+1; if (!UArray_containsLong_(other, v)) { amount --; break; } ) } UArray_removeRange(self, 0, amount); } void UArray_rstrip_(UArray *self, const UArray *other) { size_t index = 0; // initial value is only needed when FOREACHes don't work if (UArray_isFloatType(self)) { UARRAY_RFOREACH(self, i, v, index = i; if (!UArray_containsDouble_(other, v)) { index++; break; } ) } else { UARRAY_RFOREACH(self, i, v, index = i; if (!UArray_containsLong_(other, v)) { index++; break; } ) } UArray_removeRange(self, index, self->size); } BASEKIT_API void UArray_strip_(UArray *self, const UArray *other) { UArray_lstrip_(self, other); UArray_rstrip_(self, other); } // swap BASEKIT_API void UArray_swapIndex_withIndex_(UArray *self, size_t i, size_t j) { size_t itemSize = self->itemSize; uint8_t *data = self->data; void *ip = data + i * itemSize; void *jp = data + j * itemSize; UArrayValueUnion b; memcpy(&b, ip, sizeof(UArray)); memcpy(ip, jp, sizeof(UArray)); memcpy(jp, &b, sizeof(UArray)); UArray_changed(self); } // reverse BASEKIT_API void UArray_reverse(UArray *self) { long i = 0; long j = self->size - 1; UArrayValueUnion b; size_t itemSize = self->itemSize; uint8_t *data = self->data; while (j > i) { void *ip = data + i * itemSize; void *jp = data + j * itemSize; memcpy(&b, ip, itemSize); memcpy(ip, jp, itemSize); memcpy(jp, &b, itemSize); j --; i ++; } UArray_changed(self); } /* #define UARRAY_MATCHPREFIXLENGTH_TYPES(OP2, TYPE1, self, TYPE2, other)\ {\ long i, minSize = (self->size < other->size) ? self->size : other->size;\ for(i = 0; i < minSize; i ++)\ {\ TYPE1 v1 = ((TYPE1 *)self->data)[i];\ TYPE2 v2 = ((TYPE2 *)other->data)[i];\ if (v1 != v2) break;\ }\ return i;\ } BASEKIT_API size_t UArray_matchingPrefixSizeWith_(const UArray *self, const UArray *other) { DUARRAY_OP(UARRAY_MATCHPREFIXLENGTH_TYPES, NULL, self, other); } */ // split PtrUArray *UArray_split_(const UArray *self, const PtrUArray *delims) { PtrUArray *results = UArray_new(); size_t i, last = 0; UArray_setItemType_(results, CTYPE_uintptr_t); for (i = 0; i < self->size; i ++) { UArray slice = UArray_stackRange(self, i, self->size - i); size_t j; for (j = 0; j < delims->size; j ++) { UArray *delim = UArray_rawPointerAt_(delims, j); if (UArray_beginsWith_(&slice, delim)) { UArray_appendPointer_(results, UArray_range(self, last, i - last)); last = i + delim->size; i = last - 1; // since for() will increment it break; } } } if (last != self->size) { UArray_appendPointer_(results, UArray_range(self, last, self->size - last)); } return results; } size_t UArray_splitCount_(const UArray *self, const PtrUArray *delims) { PtrUArray *r = UArray_split_(self, delims); size_t count = UArray_size(r); UArray_free(r); return count; } // find BASEKIT_API int UArray_beginsWith_(UArray *self, const UArray *other) { size_t msize = self->size; size_t osize = other->size; if (msize >= osize) { /* A common case seems to be comparing against a single byte, which * happens all of the place internally (not sure why yet, but it would * be good to investigate this)*/ if (osize == 1) { return (*(self->data) == *(other->data)); } else if (memcmp(self->data, other->data, osize) == 0) { return 1; } return 0; } return 0; } BASEKIT_API int UArray_endsWith_(UArray *self, const UArray *other) { if (self->size >= other->size) { UArray tmp = UArray_stackRange(self, self->size - other->size, other->size); return UArray_find_(&tmp, other) != -1; } return 0; } // escape and quote void UArray_swapWith_(UArray *self, UArray *other) { UArray b; memcpy(&b, other, sizeof(UArray)); memcpy(other, self, sizeof(UArray)); memcpy(self, &b, sizeof(UArray)); UArray_changed(self); } void UArray_escape(UArray *self) { UArray *out = UArray_new(); out->itemType = self->itemType; out->itemSize = self->itemSize; UARRAY_FOREACH(self, i, v, switch ((int)v) { case '"': UArray_appendCString_(out, "\\\""); break; case '\a': UArray_appendCString_(out, "\\a"); break; case '\b': UArray_appendCString_(out, "\\b"); break; case '\f': UArray_appendCString_(out, "\\f"); break; case '\n': UArray_appendCString_(out, "\\n"); break; case '\r': UArray_appendCString_(out, "\\r"); break; case '\t': UArray_appendCString_(out, "\\t"); break; case '\v': UArray_appendCString_(out, "\\v"); break; case '\0': UArray_appendCString_(out, "\\0"); break; case '\\': UArray_appendCString_(out, "\\\\"); break; default: UArray_appendLong_(out, v); } ); UArray_swapWith_(self, out); UArray_free(out); UArray_changed(self); } void UArray_unescape(UArray *self) { size_t getIndex = 0; size_t putIndex = 0; while (getIndex < self->size) { long c = UArray_longAt_(self, getIndex); long nextChar = UArray_longAt_(self, getIndex + 1); if (c != '\\') { if (getIndex != putIndex) { UArray_at_putLong_(self, putIndex, c); } putIndex ++; } else { c = nextChar; switch (c) { case 'a': c = '\a'; break; case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; case '\0': c = '\\'; break; default: if (isdigit((int)c)) { c -= 48; } } UArray_at_putLong_(self, putIndex, c); getIndex ++; putIndex ++; } getIndex ++; } UArray_setSize_(self, putIndex); UArray_changed(self); } void UArray_quote(UArray *self) { UArray q = UArray_stackAllocedWithCString_("\""); UArray_prepend_(self, &q); UArray_append_(self, &q); UArray_changed(self); } void UArray_unquote(UArray *self) { UArray q = UArray_stackAllocedWithCString_("\""); if(UArray_beginsWith_(self, &q) && UArray_endsWith_(self, &q)) { UArray_removeFirst(self); UArray_removeLast(self); UArray_changed(self); } } void UArray_translate(UArray *self, UArray *fromChars, UArray *toChars) { double max = 4096; double fromMax = UArray_maxAsDouble(fromChars); double toMax = UArray_maxAsDouble(toChars); if (UArray_size(fromChars) != UArray_size(toChars)) { printf("UArray_translate: translation strings must be of the same length"); return; } if ((0 < fromMax && fromMax < max) && (0 < toMax && toMax < 256)) { size_t i; uint8_t *map = io_calloc(1, fromMax); memset(map, 0x0, fromMax); for(i = 0; i < UArray_size(fromChars); i ++) { map[UArray_longAt_(fromChars, i)] = UArray_longAt_(toChars, i); } for(i = 0; i < UArray_size(self); i ++) { self->data[i] = map[self->data[i]]; } io_free(map); return; } /* UARRAY_FOREACH(self, i, currChar, UARRAY_FOREACH(fromChars, j, fromChar, if(currChar == fromChar) { UARRAY_RAWAT_PUT_(self, i, UARRAY_RAWAT_(toChars, j)); break; } ); ); */ UArray_error_(self, "UArray_translate unimplemented for this type"); } size_t UArray_count_(const UArray *self, const UArray *other) { long i = 0; size_t count = 0; while ((i = UArray_find_from_(self, other, i)) != -1) { i += UArray_size(other); count ++; } return count; } UArray *UArray_asBase64(const UArray *self, int charsPerLine) { base64_encodestate state; size_t unencodedBytesSize; uint8_t *encodedBytes; size_t encodedBytesSize; UArray *encoded; base64_init_encodestate(&state); state.chars_per_line = charsPerLine; unencodedBytesSize = UArray_sizeInBytes(self); encodedBytes = io_calloc(2 * unencodedBytesSize, 1); encoded = UArray_new(); UArray_setItemType_(encoded, CTYPE_uint8_t); encodedBytesSize = base64_encode_block((char *)UArray_bytes(self), (int)unencodedBytesSize, (char *)encodedBytes, &state); UArray_appendBytes_size_(encoded, encodedBytes, encodedBytesSize); encodedBytesSize = base64_encode_blockend((char *)encodedBytes, &state); UArray_appendBytes_size_(encoded, encodedBytes, encodedBytesSize); io_free(encodedBytes); return encoded; } UArray *UArray_fromBase64(const UArray *self) { base64_decodestate state; size_t undecodedBytesSize; uint8_t *decodedBytes; size_t decodedBytesSize; UArray *decoded; base64_init_decodestate(&state); undecodedBytesSize = UArray_sizeInBytes(self); decodedBytes = io_calloc(2 * undecodedBytesSize, 1); decoded = UArray_new(); UArray_setItemType_(decoded, CTYPE_uint8_t); decodedBytesSize = base64_decode_block((char *)UArray_bytes(self), (int)undecodedBytesSize, (char *)decodedBytes, &state); UArray_appendBytes_size_(decoded, decodedBytes, decodedBytesSize); io_free(decodedBytes); return decoded; }