Exemplo n.º 1
0
int guac_parser_append(guac_parser* parser, void* buffer, int length) {

    char* char_buffer = (char*) buffer;
    int bytes_parsed = 0;

    /* Do not exceed maximum number of elements */
    if (parser->__elementc == GUAC_INSTRUCTION_MAX_ELEMENTS
            && parser->state != GUAC_PARSE_COMPLETE) {
        parser->state = GUAC_PARSE_ERROR;
        return 0;
    }

    /* Parse element length */
    if (parser->state == GUAC_PARSE_LENGTH) {

        int parsed_length = parser->__element_length;
        while (bytes_parsed < length) {

            /* Pull next character */
            char c = *(char_buffer++);
            bytes_parsed++;

            /* If digit, add to length */
            if (c >= '0' && c <= '9')
                parsed_length = parsed_length*10 + c - '0';

            /* If period, switch to parsing content */
            else if (c == '.') {
                parser->__elementv[parser->__elementc++] = char_buffer;
                parser->state = GUAC_PARSE_CONTENT;
                break;
            }

            /* If not digit, parse error */
            else {
                parser->state = GUAC_PARSE_ERROR;
                return 0;
            }

        }

        /* If too long, parse error */
        if (parsed_length > GUAC_INSTRUCTION_MAX_LENGTH) {
            parser->state = GUAC_PARSE_ERROR;
            return 0;
        }

        /* Save length */
        parser->__element_length = parsed_length;

    } /* end parse length */

    /* Parse element content */
    if (parser->state == GUAC_PARSE_CONTENT) {

        while (bytes_parsed < length && parser->__element_length >= 0) {

            /* Get length of current character */
            char c = *char_buffer;
            int char_length = guac_utf8_charsize((unsigned char) c);

            /* If full character not present in buffer, stop now */
            if (char_length + bytes_parsed > length)
                break;

            /* Record character as parsed */
            bytes_parsed += char_length;

            /* If end of element, handle terminator */
            if (parser->__element_length == 0) {

                *char_buffer = '\0';

                /* If semicolon, store end-of-instruction */
                if (c == ';') {
                    parser->state = GUAC_PARSE_COMPLETE;
                    parser->opcode = parser->__elementv[0];
                    parser->argv = &(parser->__elementv[1]);
                    parser->argc = parser->__elementc - 1;
                    break;
                }

                /* If comma, move on to next element */
                else if (c == ',') {
                    parser->state = GUAC_PARSE_LENGTH;
                    break;
                }

                /* Otherwise, parse error */
                else {
                    parser->state = GUAC_PARSE_ERROR;
                    return 0;
                }

            } /* end if end of element */

            /* Advance to next character */
            parser->__element_length--;
            char_buffer += char_length;

        }

    } /* end parse content */

    return bytes_parsed;

}
Exemplo n.º 2
0
ssize_t __guac_socket_nest_write_handler(guac_socket* socket,
        const void* buf, size_t count) {

    __guac_socket_nest_data* data = (__guac_socket_nest_data*) socket->data;
    unsigned char* source = (unsigned char*) buf;

    /* Current location in destination buffer during copy */
    char* current = data->buffer;

    /* Number of bytes remaining in source buffer */
    int remaining = count;

    /* If we can't actually store that many bytes, reduce number of bytes
     * expected to be written */
    if (remaining > GUAC_SOCKET_NEST_BUFFER_SIZE)
        remaining = GUAC_SOCKET_NEST_BUFFER_SIZE;

    /* Current offset within destination buffer */
    int offset;

    /* Number of characters before start of next character */
    int skip = 0;

    /* Copy UTF-8 characters into buffer */
    for (offset = 0; offset < GUAC_SOCKET_NEST_BUFFER_SIZE; offset++) {

        /* Get next byte */
        unsigned char c = *source;
        remaining--;

        /* If skipping, then skip */
        if (skip > 0) skip--;

        /* Otherwise, determine next skip value, and increment length */
        else {

            /* Determine skip value (size in bytes of rest of character) */
            skip = guac_utf8_charsize(c) - 1;

            /* If not enough bytes to complete character, break */
            if (skip > remaining)
                break;

        }

        /* Store byte */
        *current = c;

        /* Advance to next character */
        source++;
        current++;

    }

    /* Append null-terminator */
    *current = 0;

    /* Send nest instruction containing read UTF-8 segment */
    guac_protocol_send_nest(data->parent, data->index, data->buffer);

    /* Return number of bytes actually written */
    return offset;

}
Exemplo n.º 3
0
/* Returns new instruction if one exists, or NULL if no more instructions. */
guac_instruction* guac_instruction_read(guac_socket* socket,
        int usec_timeout) {

    int retval;
   
    /* Loop until a instruction is read */
    for (;;) {

        /* Length of element, in Unicode characters */
        int element_length = 0;

        /* Length of element, in bytes */
        int element_byte_length = 0;

        /* Current position within the element, in Unicode characters */
        int current_unicode_length = 0;

        /* Position within buffer */
        int i = socket->__instructionbuf_parse_start;

        /* Parse instruction in buffer */
        while (i < socket->__instructionbuf_used_length) {

            /* Read character from buffer */
            char c = socket->__instructionbuf[i++];

            /* If digit, calculate element length */
            if (c >= '0' && c <= '9')
                element_length = element_length * 10 + c - '0';

            /* Otherwise, if end of length */
            else if (c == '.') {

                /* Calculate element byte length by walking buffer */
                while (i + element_byte_length <
                            socket->__instructionbuf_used_length
                    && current_unicode_length < element_length) {

                    /* Get next byte */
                    c = socket->__instructionbuf[i + element_byte_length];

                    /* Update byte and character lengths */
                    element_byte_length += guac_utf8_charsize((unsigned) c);
                    current_unicode_length++;

                }

                /* Verify element is fully read */
                if (current_unicode_length == element_length) {

                    /* Get element value */
                    char* elementv = &(socket->__instructionbuf[i]);
                   
                    /* Get terminator, set null terminator of elementv */ 
                    char terminator = elementv[element_byte_length];
                    elementv[element_byte_length] = '\0';

                    /* Move to char after terminator of element */
                    i += element_byte_length+1;

                    /* Reset element length */
                    element_length =
                    element_byte_length =
                    current_unicode_length = 0;

                    /* As element has been read successfully, update
                     * parse start */
                    socket->__instructionbuf_parse_start = i;

                    /* Save element */
                    socket->__instructionbuf_elementv[socket->__instructionbuf_elementc++] = elementv;

                    /* Finish parse if terminator is a semicolon */
                    if (terminator == ';') {

                        guac_instruction* parsed_instruction;
                        int j;

                        /* Allocate instruction */
                        parsed_instruction = malloc(sizeof(guac_instruction));
                        if (parsed_instruction == NULL) {
                            guac_error = GUAC_STATUS_NO_MEMORY;
                            guac_error_message = "Could not allocate memory for parsed instruction";
                            return NULL;
                        }

                        /* Init parsed instruction */
                        parsed_instruction->argc = socket->__instructionbuf_elementc - 1;
                        parsed_instruction->argv = malloc(sizeof(char*) * parsed_instruction->argc);

                        /* Fail if memory could not be alloc'd for argv */
                        if (parsed_instruction->argv == NULL) {
                            guac_error = GUAC_STATUS_NO_MEMORY;
                            guac_error_message = "Could not allocate memory for arguments of parsed instruction";
                            free(parsed_instruction);
                            return NULL;
                        }

                        /* Set opcode */
                        parsed_instruction->opcode = strdup(socket->__instructionbuf_elementv[0]);

                        /* Fail if memory could not be alloc'd for opcode */
                        if (parsed_instruction->opcode == NULL) {
                            guac_error = GUAC_STATUS_NO_MEMORY;
                            guac_error_message = "Could not allocate memory for opcode of parsed instruction";
                            free(parsed_instruction->argv);
                            free(parsed_instruction);
                            return NULL;
                        }


                        /* Copy element values to parsed instruction */
                        for (j=0; j<parsed_instruction->argc; j++) {
                            parsed_instruction->argv[j] = strdup(socket->__instructionbuf_elementv[j+1]);

                            /* Free memory and fail if out of mem */
                            if (parsed_instruction->argv[j] == NULL) {
                                guac_error = GUAC_STATUS_NO_MEMORY;
                                guac_error_message = "Could not allocate memory for single argument of parsed instruction";

                                /* Free all alloc'd argv values */
                                while (--j >= 0)
                                    free(parsed_instruction->argv[j]);

                                free(parsed_instruction->opcode);
                                free(parsed_instruction->argv);
                                free(parsed_instruction);
                                return NULL;
                            }

                        }

                        /* Reset buffer */
                        memmove(socket->__instructionbuf, socket->__instructionbuf + i, socket->__instructionbuf_used_length - i);
                        socket->__instructionbuf_used_length -= i;
                        socket->__instructionbuf_parse_start = 0;
                        socket->__instructionbuf_elementc = 0;

                        /* Done */
                        return parsed_instruction;

                    } /* end if terminator */

                    /* Error if expected comma is not present */
                    else if (terminator != ',') {
                        guac_error = GUAC_STATUS_BAD_ARGUMENT;
                        guac_error_message = "Element terminator of instruction was not ';' nor ','";
                        return NULL;
                    }

                } /* end if element fully read */

                /* Otherwise, read more data */
                else
                    break;

            }

            /* Error if length is non-numeric or does not end in a period */
            else {
                guac_error = GUAC_STATUS_BAD_ARGUMENT;
                guac_error_message = "Non-numeric character in element length";
                return NULL;
            }

        }

        /* No instruction yet? Get more data ... */
        retval = guac_socket_select(socket, usec_timeout);
        if (retval <= 0)
            return NULL;

        /* If more data is available, fill into buffer */
        retval = __guac_fill_instructionbuf(socket);

        /* Error, guac_error already set */
        if (retval < 0)
            return NULL;

        /* EOF */
        if (retval == 0) {
            guac_error = GUAC_STATUS_NO_INPUT;
            guac_error_message = "End of stream reached while reading instruction";
            return NULL;
        }

    }

}