s2n_stuffer_text.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License").
  5. * You may not use this file except in compliance with the License.
  6. * A copy of the License is located at
  7. *
  8. * http://aws.amazon.com/apache2.0
  9. *
  10. * or in the "license" file accompanying this file. This file is distributed
  11. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  12. * express or implied. See the License for the specific language governing
  13. * permissions and limitations under the License.
  14. */
  15. #include <string.h>
  16. #include "stuffer/s2n_stuffer.h"
  17. #include "utils/s2n_mem.h"
  18. #include "utils/s2n_safety.h"
  19. int s2n_stuffer_peek_char(struct s2n_stuffer *s2n_stuffer, char *c)
  20. {
  21. int r = s2n_stuffer_read_uint8(s2n_stuffer, (uint8_t *) c);
  22. if (r == S2N_SUCCESS) {
  23. s2n_stuffer->read_cursor--;
  24. }
  25. POSIX_POSTCONDITION(s2n_stuffer_validate(s2n_stuffer));
  26. return r;
  27. }
  28. /* Peeks in stuffer to see if expected string is present. */
  29. int s2n_stuffer_peek_check_for_str(struct s2n_stuffer *s2n_stuffer, const char *expected)
  30. {
  31. POSIX_PRECONDITION(s2n_stuffer_validate(s2n_stuffer));
  32. uint32_t orig_read_pos = s2n_stuffer->read_cursor;
  33. int rc = s2n_stuffer_read_expected_str(s2n_stuffer, expected);
  34. s2n_stuffer->read_cursor = orig_read_pos;
  35. POSIX_POSTCONDITION(s2n_stuffer_validate(s2n_stuffer));
  36. return rc;
  37. }
  38. int s2n_stuffer_skip_whitespace(struct s2n_stuffer *s2n_stuffer, uint32_t *skipped)
  39. {
  40. POSIX_PRECONDITION(s2n_stuffer_validate(s2n_stuffer));
  41. uint32_t initial_read_cursor = s2n_stuffer->read_cursor;
  42. while (s2n_stuffer_data_available(s2n_stuffer)) {
  43. uint8_t c = s2n_stuffer->blob.data[s2n_stuffer->read_cursor];
  44. /* We don't use isspace, because it changes under locales. */
  45. if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
  46. s2n_stuffer->read_cursor += 1;
  47. } else {
  48. break;
  49. }
  50. }
  51. if (skipped != NULL) {
  52. *skipped = s2n_stuffer->read_cursor - initial_read_cursor;
  53. }
  54. POSIX_POSTCONDITION(s2n_stuffer_validate(s2n_stuffer));
  55. return S2N_SUCCESS;
  56. }
  57. int s2n_stuffer_read_expected_str(struct s2n_stuffer *stuffer, const char *expected)
  58. {
  59. POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
  60. POSIX_ENSURE_REF(expected);
  61. size_t expected_length = strlen(expected);
  62. if (expected_length == 0) {
  63. return S2N_SUCCESS;
  64. }
  65. POSIX_ENSURE(s2n_stuffer_data_available(stuffer) >= expected_length, S2N_ERR_STUFFER_OUT_OF_DATA);
  66. uint8_t *actual = stuffer->blob.data + stuffer->read_cursor;
  67. POSIX_ENSURE_REF(actual);
  68. POSIX_ENSURE(!memcmp(actual, expected, expected_length), S2N_ERR_STUFFER_NOT_FOUND);
  69. stuffer->read_cursor += expected_length;
  70. POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
  71. return S2N_SUCCESS;
  72. }
  73. /* Read from stuffer until the target string is found, or until there is no more data. */
  74. int s2n_stuffer_skip_read_until(struct s2n_stuffer *stuffer, const char *target)
  75. {
  76. POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
  77. POSIX_ENSURE_REF(target);
  78. const uint32_t len = strlen(target);
  79. if (len == 0) {
  80. return S2N_SUCCESS;
  81. }
  82. while (s2n_stuffer_data_available(stuffer) >= len) {
  83. POSIX_GUARD(s2n_stuffer_skip_to_char(stuffer, target[0]));
  84. POSIX_GUARD(s2n_stuffer_skip_read(stuffer, len));
  85. uint8_t *actual = stuffer->blob.data + stuffer->read_cursor - len;
  86. POSIX_ENSURE_REF(actual);
  87. if (strncmp((char *) actual, target, len) == 0) {
  88. return S2N_SUCCESS;
  89. } else {
  90. /* If string doesn't match, rewind stuffer to 1 byte after last read */
  91. POSIX_GUARD(s2n_stuffer_rewind_read(stuffer, len - 1));
  92. continue;
  93. }
  94. }
  95. POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
  96. return S2N_SUCCESS;
  97. }
  98. /* Skips the stuffer until the first instance of the target character or until there is no more data. */
  99. int s2n_stuffer_skip_to_char(struct s2n_stuffer *stuffer, const char target)
  100. {
  101. POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
  102. while (s2n_stuffer_data_available(stuffer) > 0) {
  103. if (stuffer->blob.data[stuffer->read_cursor] == target) {
  104. break;
  105. }
  106. stuffer->read_cursor += 1;
  107. }
  108. POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
  109. return S2N_SUCCESS;
  110. }
  111. /* Skips an expected character in the stuffer between min and max times */
  112. int s2n_stuffer_skip_expected_char(struct s2n_stuffer *stuffer, const char expected, const uint32_t min,
  113. const uint32_t max, uint32_t *skipped)
  114. {
  115. POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
  116. POSIX_ENSURE(min <= max, S2N_ERR_SAFETY);
  117. uint32_t skip = 0;
  118. while (stuffer->read_cursor < stuffer->write_cursor && skip < max) {
  119. if (stuffer->blob.data[stuffer->read_cursor] == expected) {
  120. stuffer->read_cursor += 1;
  121. skip += 1;
  122. } else {
  123. break;
  124. }
  125. }
  126. POSIX_ENSURE(skip >= min, S2N_ERR_STUFFER_NOT_FOUND);
  127. if (skipped != NULL) {
  128. *skipped = skip;
  129. }
  130. POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
  131. return S2N_SUCCESS;
  132. }
  133. /* Read a line of text. Agnostic to LF or CR+LF line endings. */
  134. int s2n_stuffer_read_line(struct s2n_stuffer *stuffer, struct s2n_stuffer *token)
  135. {
  136. POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
  137. POSIX_PRECONDITION(s2n_stuffer_validate(token));
  138. /* Consume an LF terminated line */
  139. POSIX_GUARD(s2n_stuffer_read_token(stuffer, token, '\n'));
  140. /* Snip off the carriage return if it's present */
  141. if ((s2n_stuffer_data_available(token) > 0) && (token->blob.data[(token->write_cursor - 1)] == '\r')) {
  142. token->write_cursor--;
  143. }
  144. POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
  145. POSIX_POSTCONDITION(s2n_stuffer_validate(token));
  146. return S2N_SUCCESS;
  147. }
  148. int s2n_stuffer_read_token(struct s2n_stuffer *stuffer, struct s2n_stuffer *token, char delim)
  149. {
  150. POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
  151. POSIX_PRECONDITION(s2n_stuffer_validate(token));
  152. uint32_t token_size = 0;
  153. while ((stuffer->read_cursor + token_size) < stuffer->write_cursor) {
  154. if (stuffer->blob.data[stuffer->read_cursor + token_size] == delim) {
  155. break;
  156. }
  157. token_size++;
  158. }
  159. POSIX_GUARD(s2n_stuffer_copy(stuffer, token, token_size));
  160. /* Consume the delimiter too */
  161. if (stuffer->read_cursor < stuffer->write_cursor) {
  162. stuffer->read_cursor++;
  163. }
  164. POSIX_POSTCONDITION(s2n_stuffer_validate(stuffer));
  165. POSIX_POSTCONDITION(s2n_stuffer_validate(token));
  166. return S2N_SUCCESS;
  167. }
  168. int s2n_stuffer_alloc_ro_from_string(struct s2n_stuffer *stuffer, const char *str)
  169. {
  170. POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
  171. POSIX_ENSURE_REF(str);
  172. uint32_t length = strlen(str);
  173. POSIX_GUARD(s2n_stuffer_alloc(stuffer, length + 1));
  174. return s2n_stuffer_write_bytes(stuffer, (const uint8_t *) str, length);
  175. }
  176. int s2n_stuffer_init_ro_from_string(struct s2n_stuffer *stuffer, uint8_t *data, uint32_t length)
  177. {
  178. POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
  179. POSIX_ENSURE_REF(data);
  180. struct s2n_blob data_blob = { 0 };
  181. POSIX_GUARD(s2n_blob_init(&data_blob, data, length));
  182. POSIX_GUARD(s2n_stuffer_init(stuffer, &data_blob));
  183. POSIX_GUARD(s2n_stuffer_skip_write(stuffer, length));
  184. return S2N_SUCCESS;
  185. }