pure_routines.h (5946B)
1 int pure_eq( 2 const uint8_t* buffer, 3 const uint64_t buffer_size, // The absolute length of the entire buffer. 4 const uint64_t buffer_offset, // The offset from which to start comparing. 5 const uint8_t* string, 6 const uint64_t string_size 7 ) { 8 assert(buffer_offset <= buffer_size); 9 assert(string_size > 0); 10 if (buffer_offset + string_size > buffer_size) return 0; 11 return memcmp(buffer + buffer_offset, string, (size_t) string_size) == 0; 12 } 13 14 int pure_free(uint8_t** data, uint64_t* data_size) { 15 if (*data_size == 0) { 16 assert(*data == NULL); 17 // We never call malloc for 0. 18 // We always assert that `required` is greater than 0. 19 // We may therefore use `data_size == 0` to indicate the lack of allocation. 20 } else { 21 assert(*data != NULL); 22 free(*data); 23 *data = NULL; 24 *data_size = 0; 25 } 26 return 0; 27 } 28 29 int pure_overflow( 30 const uint64_t offset, 31 const uint64_t length, 32 const uint64_t available 33 ) { 34 if (available < length) return 1; 35 if (offset > available - length) return 1; 36 return 0; 37 } 38 39 int pure_realloc( 40 uint8_t** data, 41 uint64_t* data_size, 42 const uint64_t required 43 ) { 44 assert(required > 0); // N.B. See comment in pure_free(). 45 assert(required <= SIZE_MAX); 46 if (*data_size > 0 && *data_size < required) { 47 pure_free(data, data_size); 48 assert(*data == NULL); 49 assert(*data_size == 0); 50 } 51 if (*data_size == 0) { 52 assert(*data == NULL); 53 uint64_t size = required; 54 if (size < PURE_MALLOC_MIN) size = PURE_MALLOC_MIN; 55 *data = (uint8_t*) malloc(size); 56 if (*data == NULL) return PURE_E_MALLOC; 57 *data_size = size; 58 } 59 assert(*data != NULL); 60 assert(*data_size >= required); 61 return 0; 62 } 63 64 int pure_search( 65 const uint8_t* buffer, 66 const uint64_t buffer_size, 67 const uint64_t search_offset, 68 uint64_t search_size, 69 const uint8_t* string, 70 const uint64_t string_size, 71 uint64_t* offset 72 ) { 73 assert(*offset == 0); 74 assert(string_size > 0); 75 if (search_offset >= buffer_size) return PURE_E_STRING_NOT_FOUND; 76 if (search_offset + search_size > buffer_size) { 77 search_size = buffer_size - search_offset; 78 } 79 assert(search_offset + search_size <= buffer_size); 80 if (search_size < string_size) return PURE_E_STRING_NOT_FOUND; 81 uint64_t index = search_offset; 82 uint64_t length = search_offset + search_size - string_size; 83 assert(length + string_size <= buffer_size); 84 while (index < length) { 85 if ( 86 // Avoid a function call most of the time: 87 buffer[index] == string[0] && 88 // Check the string in full: 89 pure_eq( 90 buffer, 91 buffer_size, 92 index, 93 string, 94 string_size 95 ) 96 ) { 97 *offset = index; 98 return 0; 99 } 100 index++; 101 } 102 return PURE_E_STRING_NOT_FOUND; 103 } 104 105 uint16_t pure_u16(const uint8_t* buffer) { 106 const uint8_t a = buffer[0]; 107 const uint8_t b = buffer[1]; 108 return (a << 0) | (b << 8); 109 } 110 111 uint32_t pure_u32(const uint8_t* buffer) { 112 const uint8_t a = buffer[0]; 113 const uint8_t b = buffer[1]; 114 const uint8_t c = buffer[2]; 115 const uint8_t d = buffer[3]; 116 return (a << 0) | (b << 8) | (c << 16) | (d << 24); 117 } 118 119 uint64_t pure_u64(const uint8_t* buffer) { 120 const uint32_t a = pure_u32(buffer + 0); 121 const uint32_t b = pure_u32(buffer + 4); 122 return ((uint64_t) b << 32) + a; 123 } 124 125 int pure_zeroes( 126 const uint8_t* buffer, 127 uint64_t offset, 128 const uint64_t length 129 ) { 130 assert(offset <= length); 131 // TO DO: Optimize: Perform 64-bit comparisons: 132 while (offset < length) { 133 if (buffer[offset++] != 0) return 0; 134 } 135 return 1; 136 } 137 138 // Find end of component delimited by slash or EOF. 139 uint64_t pure_path_component_index( 140 const uint8_t* path, 141 uint64_t index, 142 const uint64_t length 143 ) { 144 assert(index <= length); 145 while (index < length) { 146 if (path[index] == PURE_BACKSLASH || path[index] == PURE_FORWARD_SLASH) { 147 return index; 148 } else { 149 index++; 150 } 151 } 152 return index; 153 } 154 155 int pure_path_component_overflow(const uint8_t* path, const uint64_t length) { 156 if (length < PURE_PATH_COMPONENT_MAX) return 0; 157 uint64_t start = 0; 158 while (start < length) { 159 uint64_t end = pure_path_component_index(path, start, length); 160 if (end - start > PURE_PATH_COMPONENT_MAX) return 1; 161 start = end + 1; 162 } 163 return 0; 164 } 165 166 int pure_path_control_characters_iconr( 167 const uint8_t* path, 168 const uint64_t length 169 ) { 170 if (length < PURE_L_ICONR) return 0; 171 uint64_t offset = length - PURE_L_ICONR; 172 if (!pure_eq(path, length, offset, PURE_S_ICONR, PURE_L_ICONR)) return 0; 173 return ( 174 offset == 0 || 175 // Do not fall for partial path component matches: 176 path[offset - 1] == PURE_BACKSLASH || 177 path[offset - 1] == PURE_FORWARD_SLASH 178 ); 179 } 180 181 int pure_path_control_characters(const uint8_t* path, const uint64_t length) { 182 // We want to check for control characters, except the "\r" in "Icon\r" files: 183 uint64_t excluding_iconr_length = (uint64_t) length; 184 if (pure_path_control_characters_iconr(path, length)) { 185 assert(excluding_iconr_length >= PURE_L_ICONR); 186 excluding_iconr_length -= PURE_L_ICONR; 187 } 188 for (uint64_t index = 0; index < excluding_iconr_length; index++) { 189 if (PURE_CONTROL_CHARACTER[path[index]]) return 1; 190 } 191 return 0; 192 } 193 194 int pure_path_double_dots(const uint8_t* path, const uint64_t length) { 195 uint64_t start = 0; 196 while (start < length) { 197 uint64_t end = pure_path_component_index(path, start, length); 198 // Check two-character components for double dots (".."): 199 if (end - start == 2 && path[start + 0] == 46 && path[start + 1] == 46) { 200 return 1; 201 } 202 start = end + 1; 203 } 204 return 0; 205 } 206 207 int pure_path_drive(const uint8_t* path, const uint64_t length) { 208 return ( 209 length >= 2 && 210 path[1] == 58 && // ":" 211 path[0] >= 65 && // "A" 212 path[0] <= 122 // "z" 213 ); 214 } 215 216 int pure_path_relative(const uint8_t* path, const uint64_t length) { 217 if (length == 0) return 0; 218 return path[0] == PURE_BACKSLASH || path[0] == PURE_FORWARD_SLASH; 219 }