| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include "config.h" |
| |
| #include "common/json.h" |
| |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <guacamole/protocol.h> |
| #include <guacamole/socket.h> |
| #include <guacamole/stream.h> |
| #include <guacamole/user.h> |
| |
| void guac_common_json_flush(guac_user* user, guac_stream* stream, |
| guac_common_json_state* json_state) { |
| |
| /* If JSON buffer is non-empty, write contents to blob and reset */ |
| if (json_state->size > 0) { |
| guac_protocol_send_blob(user->socket, stream, |
| json_state->buffer, json_state->size); |
| |
| /* Reset JSON buffer size */ |
| json_state->size = 0; |
| |
| } |
| |
| } |
| |
| int guac_common_json_write(guac_user* user, guac_stream* stream, |
| guac_common_json_state* json_state, const char* buffer, int length) { |
| |
| int blob_written = 0; |
| |
| /* |
| * Append to and flush the JSON buffer as necessary to write the given |
| * data |
| */ |
| while (length > 0) { |
| |
| /* Ensure provided data does not exceed size of buffer */ |
| int blob_length = length; |
| if (blob_length > sizeof(json_state->buffer)) |
| blob_length = sizeof(json_state->buffer); |
| |
| /* Flush if more room is needed */ |
| if (json_state->size + blob_length > sizeof(json_state->buffer)) { |
| guac_common_json_flush(user, stream, json_state); |
| blob_written = 1; |
| } |
| |
| /* Append data to JSON buffer */ |
| memcpy(json_state->buffer + json_state->size, |
| buffer, blob_length); |
| |
| json_state->size += blob_length; |
| |
| /* Advance to next blob of data */ |
| buffer += blob_length; |
| length -= blob_length; |
| |
| } |
| |
| return blob_written; |
| |
| } |
| |
| int guac_common_json_write_string(guac_user* user, |
| guac_stream* stream, guac_common_json_state* json_state, |
| const char* str) { |
| |
| int blob_written = 0; |
| |
| /* Write starting quote */ |
| blob_written |= guac_common_json_write(user, stream, |
| json_state, "\"", 1); |
| |
| /* Write given string, escaping as necessary */ |
| const char* current = str; |
| for (; *current != '\0'; current++) { |
| |
| /* Escape all quotes */ |
| if (*current == '"') { |
| |
| /* Write any string content up to current character */ |
| if (current != str) |
| blob_written |= guac_common_json_write(user, stream, |
| json_state, str, current - str); |
| |
| /* Escape the quote that was just read */ |
| blob_written |= guac_common_json_write(user, stream, |
| json_state, "\\", 1); |
| |
| /* Reset string */ |
| str = current; |
| |
| } |
| |
| } |
| |
| /* Write any remaining string content */ |
| if (current != str) |
| blob_written |= guac_common_json_write(user, stream, |
| json_state, str, current - str); |
| |
| /* Write ending quote */ |
| blob_written |= guac_common_json_write(user, stream, |
| json_state, "\"", 1); |
| |
| return blob_written; |
| |
| } |
| |
| int guac_common_json_write_property(guac_user* user, guac_stream* stream, |
| guac_common_json_state* json_state, const char* name, |
| const char* value) { |
| |
| int blob_written = 0; |
| |
| /* Write leading comma if not first property */ |
| if (json_state->properties_written != 0) |
| blob_written |= guac_common_json_write(user, stream, |
| json_state, ",", 1); |
| |
| /* Write property name */ |
| blob_written |= guac_common_json_write_string(user, stream, |
| json_state, name); |
| |
| /* Separate name from value with colon */ |
| blob_written |= guac_common_json_write(user, stream, |
| json_state, ":", 1); |
| |
| /* Write property value */ |
| blob_written |= guac_common_json_write_string(user, stream, |
| json_state, value); |
| |
| json_state->properties_written++; |
| |
| return blob_written; |
| |
| } |
| |
| void guac_common_json_begin_object(guac_user* user, guac_stream* stream, |
| guac_common_json_state* json_state) { |
| |
| /* Init JSON state */ |
| json_state->size = 0; |
| json_state->properties_written = 0; |
| |
| /* Write leading brace - no blob can possibly be written by this */ |
| assert(!guac_common_json_write(user, stream, json_state, "{", 1)); |
| |
| } |
| |
| int guac_common_json_end_object(guac_user* user, guac_stream* stream, |
| guac_common_json_state* json_state) { |
| |
| /* Write final brace of JSON object */ |
| return guac_common_json_write(user, stream, json_state, "}", 1); |
| |
| } |
| |