| 106 | } |
| 107 | |
| 108 | static SC::Result scHttpWebSocketBase64Encode(SC::Span<const uint8_t> data, SC::Span<char> storage, |
| 109 | SC::StringSpan& output) |
| 110 | { |
| 111 | const size_t encodedLength = ((data.sizeInBytes() + 2) / 3) * 4; |
| 112 | SC_TRY_MSG(storage.sizeInBytes() >= encodedLength, "HttpWebSocketHandshake base64 output too small"); |
| 113 | |
| 114 | size_t inputOffset = 0; |
| 115 | size_t outputOffset = 0; |
| 116 | while (inputOffset < data.sizeInBytes()) |
| 117 | { |
| 118 | const uint32_t a = data[inputOffset++]; |
| 119 | const uint32_t b = inputOffset < data.sizeInBytes() ? data[inputOffset++] : 0; |
| 120 | const uint32_t c = inputOffset < data.sizeInBytes() ? data[inputOffset++] : 0; |
| 121 | const uint32_t n = (a << 16) | (b << 8) | c; |
| 122 | |
| 123 | storage[outputOffset++] = SC_HTTP_WEBSOCKET_BASE64[(n >> 18) & 0x3F]; |
| 124 | storage[outputOffset++] = SC_HTTP_WEBSOCKET_BASE64[(n >> 12) & 0x3F]; |
| 125 | storage[outputOffset++] = |
| 126 | inputOffset - 1 <= data.sizeInBytes() ? SC_HTTP_WEBSOCKET_BASE64[(n >> 6) & 0x3F] : '='; |
| 127 | storage[outputOffset++] = inputOffset <= data.sizeInBytes() ? SC_HTTP_WEBSOCKET_BASE64[n & 0x3F] : '='; |
| 128 | } |
| 129 | |
| 130 | const size_t remainder = data.sizeInBytes() % 3; |
| 131 | if (remainder == 1) |
| 132 | { |
| 133 | storage[encodedLength - 2] = '='; |
| 134 | storage[encodedLength - 1] = '='; |
| 135 | } |
| 136 | else if (remainder == 2) |
| 137 | { |
| 138 | storage[encodedLength - 1] = '='; |
| 139 | } |
| 140 | |
| 141 | output = {{storage.data(), encodedLength}, false, SC::StringEncoding::Ascii}; |
| 142 | return SC::Result(true); |
| 143 | } |
| 144 | |
| 145 | static int scHttpWebSocketBase64Value(char value) |
| 146 | { |
no test coverage detected