Removed unescape/escape functions, switched to new instruction format.

This commit is contained in:
Michael Jumper 2011-09-09 23:59:07 -07:00
parent 621f369130
commit f5b44c97ad
3 changed files with 142 additions and 288 deletions

View File

@ -145,8 +145,7 @@ typedef struct guac_instruction {
int argc; int argc;
/** /**
* Array of all arguments passed to this instruction. Strings * Array of all arguments passed to this instruction.
* are not already unescaped.
*/ */
char** argv; char** argv;
@ -173,27 +172,7 @@ void guac_free_instruction_data(guac_instruction* instruction);
void guac_free_instruction(guac_instruction* instruction); void guac_free_instruction(guac_instruction* instruction);
/** /**
* Escapes the given string as necessary to be passed within * Sends an args instruction over the given GUACIO connection.
* a Guacamole instruction. The returned string must later be
* released with a call to free().
*
* @param str The string to escape.
* @return A new escaped string, which must be freed with free().
*/
char* guac_escape_string(const char* str);
/**
* Unescapes the given string in-place, as an unescaped string
* is always the same length or shorter than the original.
*
* @param str The string to unescape.
* @return A pointer to the original string, which is now unescaped.
*/
char* guac_unescape_string_inplace(char* str);
/**
* Sends an args instruction over the given GUACIO connection. Each
* argument name will be automatically escaped for transmission.
* *
* @param io The GUACIO connection to use. * @param io The GUACIO connection to use.
* @param args The NULL-terminated array of argument names (strings). * @param args The NULL-terminated array of argument names (strings).
@ -202,8 +181,7 @@ char* guac_unescape_string_inplace(char* str);
int guac_send_args(GUACIO* io, const char** name); int guac_send_args(GUACIO* io, const char** name);
/** /**
* Sends a name instruction over the given GUACIO connection. The * Sends a name instruction over the given GUACIO connection.
* name given will be automatically escaped for transmission.
* *
* @param io The GUACIO connection to use. * @param io The GUACIO connection to use.
* @param name The name to send within the name instruction. * @param name The name to send within the name instruction.
@ -222,9 +200,7 @@ int guac_send_name(GUACIO* io, const char* name);
int guac_send_sync(GUACIO* io, guac_timestamp_t timestamp); int guac_send_sync(GUACIO* io, guac_timestamp_t timestamp);
/** /**
* Sends an error instruction over the given GUACIO connection. The * Sends an error instruction over the given GUACIO connection.
* error description given will be automatically escaped for
* transmission.
* *
* @param io The GUACIO connection to use. * @param io The GUACIO connection to use.
* @param error The description associated with the error. * @param error The description associated with the error.
@ -233,8 +209,7 @@ int guac_send_sync(GUACIO* io, guac_timestamp_t timestamp);
int guac_send_error(GUACIO* io, const char* error); int guac_send_error(GUACIO* io, const char* error);
/** /**
* Sends a clipboard instruction over the given GUACIO connection. The * Sends a clipboard instruction over the given GUACIO connection.
* clipboard data given will be automatically escaped for transmission.
* *
* @param io The GUACIO connection to use. * @param io The GUACIO connection to use.
* @param data The clipboard data to send. * @param data The clipboard data to send.

View File

@ -41,6 +41,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <inttypes.h>
#ifdef __MINGW32__ #ifdef __MINGW32__
#include <winsock2.h> #include <winsock2.h>
@ -120,30 +121,8 @@ int64_t guac_parse_int(const char* str) {
ssize_t guac_write_int(GUACIO* io, int64_t i) { ssize_t guac_write_int(GUACIO* io, int64_t i) {
char buffer[128]; char buffer[128];
char* ptr = &(buffer[127]); snprintf(buffer, sizeof(buffer), "%"PRIi64, i);
int64_t nonneg; return guac_write_string(io, buffer);
/* Obtain non-negative value */
if (i < 0) nonneg = -i;
else nonneg = i;
/* Generate numeric string */
*ptr = 0;
do {
ptr--;
*ptr = '0' + (nonneg % 10);
nonneg /= 10;
} while (nonneg > 0 && ptr >= buffer);
/* Prepend with dash if negative */
if (i < 0 && ptr >= buffer) *(--ptr) = '-';
return guac_write_string(io, ptr);
} }

View File

@ -45,6 +45,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
@ -61,108 +63,20 @@
#include "guacio.h" #include "guacio.h"
#include "protocol.h" #include "protocol.h"
char* guac_escape_string(const char* str) { ssize_t __guac_write_length_string(GUACIO* io, const char* str) {
char* escaped; return
char* current; guac_write_int(io, strlen(str))
|| guac_write_string(io, ".")
int i; || guac_write_string(io, str);
int length = 0;
/* Determine length */
for (i=0; str[i] != '\0'; i++) {
switch (str[i]) {
case ';':
case ',':
case '\\':
length += 2;
break;
default:
length++;
}
}
/* Allocate new */
escaped = malloc(length+1);
current = escaped;
for (i=0; str[i] != '\0'; i++) {
switch (str[i]) {
case ';':
*(current++) = '\\';
*(current++) = 's';
break;
case ',':
*(current++) = '\\';
*(current++) = 'c';
break;
case '\\':
*(current++) = '\\';
*(current++) = '\\';
break;
default:
*(current++) = str[i];
}
} }
*current = '\0'; ssize_t __guac_write_length_int(GUACIO* io, int64_t i) {
return escaped; char buffer[128];
snprintf(buffer, sizeof(buffer), "%"PRIi64, i);
} return __guac_write_length_string(io, buffer);
char* guac_unescape_string_inplace(char* str) {
char* from;
char* to;
from = to = str;
for (;;) {
char c = *(from++);
if (c == '\\') {
c = *(from++);
if (c == 's')
*(to++) = ';';
else if (c == 'c')
*(to++) = ',';
else if (c == '\\')
*(to++) = '\\';
else if (c == '\0') {
*(to++) = '\\';
break;
}
else {
*(to++) = '\\';
*(to++) = c;
}
}
else if (c == '\0')
break;
else
*(to++) = c;
}
*to = '\0';
return str;
} }
@ -170,27 +84,15 @@ int guac_send_args(GUACIO* io, const char** args) {
int i; int i;
/* Handle protocols with no args */ if (guac_write_string(io, "4.args")) return -1;
if (args[0] == NULL)
return guac_write_string(io, "args;");
if (guac_write_string(io, "args:")) return -1;
for (i=0; args[i] != NULL; i++) { for (i=0; args[i] != NULL; i++) {
char* escaped;
if (i > 0) {
if (guac_write_string(io, ",")) if (guac_write_string(io, ","))
return -1; return -1;
}
escaped = guac_escape_string(args[i]); if (__guac_write_length_string(io, args[i]))
if (guac_write_string(io, escaped)) {
free(escaped);
return -1; return -1;
}
free(escaped);
} }
@ -200,74 +102,46 @@ int guac_send_args(GUACIO* io, const char** args) {
int guac_send_name(GUACIO* io, const char* name) { int guac_send_name(GUACIO* io, const char* name) {
char* escaped = guac_escape_string(name); return
guac_write_string(io, "4.name,")
if ( || __guac_write_length_string(io, name)
guac_write_string(io, "name:") || guac_write_string(io, ";");
|| guac_write_string(io, escaped)
|| guac_write_string(io, ";")
) {
free(escaped);
return -1;
}
free(escaped);
return 0;
} }
int guac_send_size(GUACIO* io, int w, int h) { int guac_send_size(GUACIO* io, int w, int h) {
return return
guac_write_string(io, "size:") guac_write_string(io, "4.size,")
|| guac_write_int(io, w) || __guac_write_length_int(io, w)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, h) || __guac_write_length_int(io, h)
|| guac_write_string(io, ";"); || guac_write_string(io, ";");
} }
int guac_send_clipboard(GUACIO* io, const char* data) { int guac_send_clipboard(GUACIO* io, const char* data) {
char* escaped = guac_escape_string(data); return
guac_write_string(io, "9.clipboard,")
if ( || __guac_write_length_string(io, data)
guac_write_string(io, "clipboard:") || guac_write_string(io, ";");
|| guac_write_string(io, escaped)
|| guac_write_string(io, ";")
) {
free(escaped);
return -1;
}
free(escaped);
return 0;
} }
int guac_send_error(GUACIO* io, const char* error) { int guac_send_error(GUACIO* io, const char* error) {
char* escaped = guac_escape_string(error); return
guac_write_string(io, "5.error,")
if ( || __guac_write_length_string(io, error)
guac_write_string(io, "error:") || guac_write_string(io, ";");
|| guac_write_string(io, escaped)
|| guac_write_string(io, ";")
) {
free(escaped);
return -1;
}
free(escaped);
return 0;
} }
int guac_send_sync(GUACIO* io, guac_timestamp_t timestamp) { int guac_send_sync(GUACIO* io, guac_timestamp_t timestamp) {
return return
guac_write_string(io, "sync:") guac_write_string(io, "4.sync,")
|| guac_write_int(io, timestamp) || __guac_write_length_int(io, timestamp)
|| guac_write_string(io, ";"); || guac_write_string(io, ";");
} }
@ -277,24 +151,24 @@ int guac_send_copy(GUACIO* io,
guac_composite_mode_t mode, const guac_layer* dstl, int dstx, int dsty) { guac_composite_mode_t mode, const guac_layer* dstl, int dstx, int dsty) {
return return
guac_write_string(io, "copy:") guac_write_string(io, "4.copy,")
|| guac_write_int(io, srcl->index) || __guac_write_length_int(io, srcl->index)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, srcx) || __guac_write_length_int(io, srcx)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, srcy) || __guac_write_length_int(io, srcy)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, w) || __guac_write_length_int(io, w)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, h) || __guac_write_length_int(io, h)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, mode) || __guac_write_length_int(io, mode)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, dstl->index) || __guac_write_length_int(io, dstl->index)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, dstx) || __guac_write_length_int(io, dstx)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, dsty) || __guac_write_length_int(io, dsty)
|| guac_write_string(io, ";"); || guac_write_string(io, ";");
} }
@ -305,26 +179,26 @@ int guac_send_rect(GUACIO* io,
int r, int g, int b, int a) { int r, int g, int b, int a) {
return return
guac_write_string(io, "rect:") guac_write_string(io, "4,rect,")
|| guac_write_int(io, mode) || __guac_write_length_int(io, mode)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, layer->index) || __guac_write_length_int(io, layer->index)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, x) || __guac_write_length_int(io, x)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, y) || __guac_write_length_int(io, y)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, width) || __guac_write_length_int(io, width)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, height) || __guac_write_length_int(io, height)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, r) || __guac_write_length_int(io, r)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, g) || __guac_write_length_int(io, g)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, b) || __guac_write_length_int(io, b)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, a) || __guac_write_length_int(io, a)
|| guac_write_string(io, ";"); || guac_write_string(io, ";");
} }
@ -333,94 +207,120 @@ int guac_send_clip(GUACIO* io, const guac_layer* layer,
int x, int y, int width, int height) { int x, int y, int width, int height) {
return return
guac_write_string(io, "clip:") guac_write_string(io, "4.clip,")
|| guac_write_int(io, layer->index) || __guac_write_length_int(io, layer->index)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, x) || __guac_write_length_int(io, x)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, y) || __guac_write_length_int(io, y)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, width) || __guac_write_length_int(io, width)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, height) || __guac_write_length_int(io, height)
|| guac_write_string(io, ";"); || guac_write_string(io, ";");
} }
typedef struct __guac_write_png_data {
GUACIO* io;
char* buffer;
int buffer_size;
int data_size;
} __guac_write_png_data;
cairo_status_t __guac_write_png(void* closure, const unsigned char* data, unsigned int length) { cairo_status_t __guac_write_png(void* closure, const unsigned char* data, unsigned int length) {
GUACIO* io = (GUACIO*) closure; __guac_write_png_data* png_data = (__guac_write_png_data*) closure;
if (guac_write_base64(io, data, length) < 0) /* Calculate next buffer size */
return CAIRO_STATUS_WRITE_ERROR; int next_size = png_data->data_size + length;
/* If need resizing, double buffer size until big enough */
if (next_size > png_data->buffer_size) {
char* new_buffer;
do {
png_data->buffer_size <<= 1;
} while (next_size > png_data->buffer_size);
/* Resize buffer */
new_buffer = realloc(png_data->buffer, png_data->buffer_size);
png_data->buffer = new_buffer;
}
/* Append data to buffer */
memcpy(png_data->buffer + png_data->data_size, data, length);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
int guac_send_png(GUACIO* io, guac_composite_mode_t mode, int __guac_write_length_png(GUACIO* io, cairo_surface_t* surface) {
const guac_layer* layer, int x, int y, cairo_surface_t* surface) {
/* Write instruction and args */ __guac_write_png_data png_data;
int base64_length;
if (
guac_write_string(io, "png:")
|| guac_write_int(io, mode)
|| guac_write_string(io, ",")
|| guac_write_int(io, layer->index)
|| guac_write_string(io, ",")
|| guac_write_int(io, x)
|| guac_write_string(io, ",")
|| guac_write_int(io, y)
|| guac_write_string(io, ",")
) {
return -1;
}
/* Write surface */ /* Write surface */
if (cairo_surface_write_to_png_stream(surface, __guac_write_png, io) != CAIRO_STATUS_SUCCESS) { png_data.io = io;
png_data.buffer_size = 8192;
png_data.buffer = malloc(png_data.buffer_size);
png_data.data_size = 0;
if (cairo_surface_write_to_png_stream(surface, __guac_write_png, &png_data) != CAIRO_STATUS_SUCCESS) {
return -1; return -1;
} }
if (guac_flush_base64(io) < 0) { base64_length = (png_data.data_size + 2) / 3 * 4;
/* Write instruction and args */
if (
guac_write_int(io, base64_length)
|| guac_write_string(io, ".")
|| guac_write_base64(io, png_data.buffer, png_data.data_size)
|| guac_flush_base64(io))
return -1; return -1;
free(png_data.buffer);
return 0;
} }
/* Finish instruction */
return guac_write_string(io, ";"); int guac_send_png(GUACIO* io, guac_composite_mode_t mode,
const guac_layer* layer, int x, int y, cairo_surface_t* surface) {
return
guac_write_string(io, "3.png,")
|| __guac_write_length_int(io, mode)
|| guac_write_string(io, ",")
|| __guac_write_length_int(io, layer->index)
|| guac_write_string(io, ",")
|| __guac_write_length_int(io, x)
|| guac_write_string(io, ",")
|| __guac_write_length_int(io, y)
|| guac_write_string(io, ",")
|| __guac_write_length_png(io, surface)
|| guac_write_string(io, ";");
} }
int guac_send_cursor(GUACIO* io, int x, int y, cairo_surface_t* surface) { int guac_send_cursor(GUACIO* io, int x, int y, cairo_surface_t* surface) {
/* Write instruction and args */ return
guac_write_string(io, "6.cursor,")
if ( || __guac_write_length_int(io, x)
guac_write_string(io, "cursor:")
|| guac_write_int(io, x)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
|| guac_write_int(io, y) || __guac_write_length_int(io, y)
|| guac_write_string(io, ",") || guac_write_string(io, ",")
) { || __guac_write_length_png(io, surface)
return -1; || guac_write_string(io, ";");
}
/* Write surface */
if (cairo_surface_write_to_png_stream(surface, __guac_write_png, io) != CAIRO_STATUS_SUCCESS) {
return -1;
}
if (guac_flush_base64(io) < 0) {
return -1;
}
/* Finish instruction */
return guac_write_string(io, ";");
} }