GUAC-236: Assemble entire image data prior to decoding. Switch to simple decoder function (no struct).
This commit is contained in:
parent
3661cadf4e
commit
a15a86ed00
@ -30,14 +30,16 @@
|
|||||||
#include "webp.h"
|
#include "webp.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cairo/cairo.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
guacenc_decoder_mapping guacenc_decoder_map[] = {
|
guacenc_decoder_mapping guacenc_decoder_map[] = {
|
||||||
{"image/png", &guacenc_png_decoder},
|
{"image/png", guacenc_png_decoder},
|
||||||
{"image/jpeg", &guacenc_jpeg_decoder},
|
{"image/jpeg", guacenc_jpeg_decoder},
|
||||||
#ifdef ENABLE_WEBP
|
#ifdef ENABLE_WEBP
|
||||||
{"image/webp", &guacenc_webp_decoder},
|
{"image/webp", guacenc_webp_decoder},
|
||||||
#endif
|
#endif
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
@ -78,9 +80,12 @@ guacenc_image_stream* guacenc_image_stream_alloc(int mask, int index,
|
|||||||
stream->y = y;
|
stream->y = y;
|
||||||
|
|
||||||
/* Associate with corresponding decoder */
|
/* Associate with corresponding decoder */
|
||||||
guacenc_decoder* decoder = stream->decoder = guacenc_get_decoder(mimetype);
|
stream->decoder = guacenc_get_decoder(mimetype);
|
||||||
if (decoder != NULL)
|
|
||||||
decoder->init_handler(stream);
|
/* Allocate initial buffer */
|
||||||
|
stream->length = 0;
|
||||||
|
stream->max_length = GUACENC_IMAGE_STREAM_INITIAL_LENGTH;
|
||||||
|
stream->buffer = (unsigned char*) malloc(stream->max_length);
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
|
|
||||||
@ -89,12 +94,27 @@ guacenc_image_stream* guacenc_image_stream_alloc(int mask, int index,
|
|||||||
int guacenc_image_stream_receive(guacenc_image_stream* stream,
|
int guacenc_image_stream_receive(guacenc_image_stream* stream,
|
||||||
unsigned char* data, int length) {
|
unsigned char* data, int length) {
|
||||||
|
|
||||||
/* Invoke data handler of corresponding decoder (if any) */
|
/* Allocate more space if necessary */
|
||||||
guacenc_decoder* decoder = stream->decoder;
|
if (stream->max_length - stream->length < length) {
|
||||||
if (decoder != NULL)
|
|
||||||
return decoder->data_handler(stream, data, length);
|
|
||||||
|
|
||||||
/* If there is no decoder, simply return success */
|
/* Calculate a reasonable new max length guaranteed to fit buffer */
|
||||||
|
int new_max_length = stream->max_length * 2 + length;
|
||||||
|
|
||||||
|
/* Attempt to resize buffer */
|
||||||
|
unsigned char* new_buffer =
|
||||||
|
(unsigned char*) realloc(stream->buffer, new_max_length);
|
||||||
|
if (new_buffer == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Store updated buffer and size */
|
||||||
|
stream->buffer = new_buffer;
|
||||||
|
stream->max_length = new_max_length;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append data */
|
||||||
|
memcpy(stream->buffer + stream->length, data, length);
|
||||||
|
stream->length += length;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -102,12 +122,20 @@ int guacenc_image_stream_receive(guacenc_image_stream* stream,
|
|||||||
int guacenc_image_stream_end(guacenc_image_stream* stream,
|
int guacenc_image_stream_end(guacenc_image_stream* stream,
|
||||||
guacenc_buffer* buffer) {
|
guacenc_buffer* buffer) {
|
||||||
|
|
||||||
/* Invoke end handler of corresponding decoder (if any) */
|
|
||||||
guacenc_decoder* decoder = stream->decoder;
|
|
||||||
if (decoder != NULL)
|
|
||||||
return decoder->end_handler(stream, buffer);
|
|
||||||
|
|
||||||
/* If there is no decoder, simply return success */
|
/* If there is no decoder, simply return success */
|
||||||
|
guacenc_decoder* decoder = stream->decoder;
|
||||||
|
if (decoder == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Decode received data to a Cairo surface */
|
||||||
|
cairo_surface_t* surface = stream->decoder(stream->buffer, stream->length);
|
||||||
|
if (surface == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Draw surface to buffer */
|
||||||
|
cairo_set_source_surface(buffer->cairo, surface, stream->x, stream->y);
|
||||||
|
cairo_fill(buffer->cairo);
|
||||||
|
cairo_surface_destroy(surface);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -118,10 +146,8 @@ int guacenc_image_stream_free(guacenc_image_stream* stream) {
|
|||||||
if (stream == NULL)
|
if (stream == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Invoke free handler for decoder (if associated) */
|
/* Free image buffer */
|
||||||
guacenc_decoder* decoder = stream->decoder;
|
free(stream->buffer);
|
||||||
if (decoder != NULL)
|
|
||||||
decoder->free_handler(stream);
|
|
||||||
|
|
||||||
/* Free actual stream */
|
/* Free actual stream */
|
||||||
free(stream);
|
free(stream);
|
||||||
|
@ -26,11 +26,31 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
|
#include <cairo/cairo.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A decoder implementation which processes arbitrary image data of a
|
* The initial number of bytes to allocate for the image data buffer. If this
|
||||||
* particular type. Image data is fed explicitly into the decoder as chunks.
|
* buffer is not sufficiently larged, it will be dynamically reallocated as it
|
||||||
|
* grows.
|
||||||
*/
|
*/
|
||||||
typedef struct guacenc_decoder guacenc_decoder;
|
#define GUACENC_IMAGE_STREAM_INITIAL_LENGTH 4096
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function which is provided raw, encoded image data of the given
|
||||||
|
* length. The function is expected to return a new Cairo surface which will
|
||||||
|
* later (by guacenc) be freed via cairo_surface_destroy().
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* The raw encoded image data that this function must decode.
|
||||||
|
*
|
||||||
|
* @param length
|
||||||
|
* The length of the image data, in bytes.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A newly-allocated Cairo surface containing the decoded image, or NULL
|
||||||
|
* or decoding fails.
|
||||||
|
*/
|
||||||
|
typedef cairo_surface_t* guacenc_decoder(unsigned char* data, int length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current state of an allocated Guacamole image stream.
|
* The current state of an allocated Guacamole image stream.
|
||||||
@ -60,117 +80,34 @@ typedef struct guacenc_image_stream {
|
|||||||
*/
|
*/
|
||||||
int y;
|
int y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buffer of image data which will be built up over time as chunks are
|
||||||
|
* received via "blob" instructions. This will ultimately be passed in its
|
||||||
|
* entirety to the decoder function.
|
||||||
|
*/
|
||||||
|
unsigned char* buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of bytes currently stored in the buffer.
|
||||||
|
*/
|
||||||
|
int length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of bytes that can be stored in the current buffer
|
||||||
|
* before it must be reallocated.
|
||||||
|
*/
|
||||||
|
int max_length;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The decoder to use when decoding the raw data received along this
|
* The decoder to use when decoding the raw data received along this
|
||||||
* stream, or NULL if no such decoder exists.
|
* stream, or NULL if no such decoder exists.
|
||||||
*/
|
*/
|
||||||
guacenc_decoder* decoder;
|
guacenc_decoder* decoder;
|
||||||
|
|
||||||
/**
|
|
||||||
* Arbitrary implementation-specific data associated with the stream.
|
|
||||||
*/
|
|
||||||
void* data;
|
|
||||||
|
|
||||||
} guacenc_image_stream;
|
} guacenc_image_stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback function which is invoked when a decoder has been assigned to an
|
* Mapping of image mimetype to corresponding decoder function.
|
||||||
* image stream.
|
|
||||||
*
|
|
||||||
* @param stream
|
|
||||||
* The image stream that the decoder has been assigned to.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* Zero if initialization was successful, non-zero otherwise.
|
|
||||||
*/
|
|
||||||
typedef int guacenc_decoder_init_handler(guacenc_image_stream* stream);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback function which is invoked when data has been received along an
|
|
||||||
* image stream with an associated decoder.
|
|
||||||
*
|
|
||||||
* @param stream
|
|
||||||
* The image stream that the decoder was assigned to.
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* The chunk of data received along the image stream.
|
|
||||||
*
|
|
||||||
* @param length
|
|
||||||
* The length of the chunk of data received, in bytes.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* Zero if the provided data was processed successfully, non-zero
|
|
||||||
* otherwise.
|
|
||||||
*/
|
|
||||||
typedef int guacenc_decoder_data_handler(guacenc_image_stream* stream,
|
|
||||||
unsigned char* data, int length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback function which is invoked when an image stream with an associated
|
|
||||||
* decoder has ended (reached end-of-stream). The image stream will contain
|
|
||||||
* the required meta-information describing the drawing operation, including
|
|
||||||
* the destination X/Y coordinates.
|
|
||||||
*
|
|
||||||
* @param stream
|
|
||||||
* The image stream that has ended.
|
|
||||||
*
|
|
||||||
* @param buffer
|
|
||||||
* The buffer to which the decoded image should be drawn.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* Zero if the end of the stream has been processed successfully and the
|
|
||||||
* resulting image has been rendered to the given buffer, non-zero
|
|
||||||
* otherwise.
|
|
||||||
*/
|
|
||||||
typedef int guacenc_decoder_end_handler(guacenc_image_stream* stream,
|
|
||||||
guacenc_buffer* buffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback function which will be invoked when the data associated with an
|
|
||||||
* image stream must be freed. This may happen at any time, and will not
|
|
||||||
* necessarily occur only after the image stream has ended. It is possible
|
|
||||||
* that an image stream will be in-progress at the end of a protocol dump, thus
|
|
||||||
* the memory associated with the stream will need to be freed without ever
|
|
||||||
* ending.
|
|
||||||
*
|
|
||||||
* @param stream
|
|
||||||
* The stream whose associated data must be freed.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* Zero if the data was successfully freed, non-zero otherwise.
|
|
||||||
*/
|
|
||||||
typedef int guacenc_decoder_free_handler(guacenc_image_stream* stream);
|
|
||||||
|
|
||||||
struct guacenc_decoder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback invoked when this decoder has just been assigned to an image
|
|
||||||
* stream.
|
|
||||||
*/
|
|
||||||
guacenc_decoder_init_handler* init_handler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback invoked when data has been received along an image stream to
|
|
||||||
* which this decoder has been assigned.
|
|
||||||
*/
|
|
||||||
guacenc_decoder_data_handler* data_handler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback invoked when an image stream to which this decoder has been
|
|
||||||
* assigned has ended (reached end-of-stream).
|
|
||||||
*/
|
|
||||||
guacenc_decoder_end_handler* end_handler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback invoked when data associated with an image stream by this
|
|
||||||
* decoder must be freed.
|
|
||||||
*/
|
|
||||||
guacenc_decoder_free_handler* free_handler;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mapping of image mimetype to corresponding decoder.
|
|
||||||
*/
|
*/
|
||||||
typedef struct guacenc_decoder_mapping {
|
typedef struct guacenc_decoder_mapping {
|
||||||
|
|
||||||
@ -180,8 +117,8 @@ typedef struct guacenc_decoder_mapping {
|
|||||||
const char* mimetype;
|
const char* mimetype;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The decoder to use when an image stream of the associated mimetype is
|
* The decoder function to use when an image stream of the associated
|
||||||
* received.
|
* mimetype is received.
|
||||||
*/
|
*/
|
||||||
guacenc_decoder* decoder;
|
guacenc_decoder* decoder;
|
||||||
|
|
||||||
@ -238,9 +175,9 @@ guacenc_image_stream* guacenc_image_stream_alloc(int mask, int index,
|
|||||||
const char* mimetype, int x, int y);
|
const char* mimetype, int x, int y);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals the decoder of the given image stream that a chunk of image data
|
* Appends newly-received data to the internal buffer of the given image
|
||||||
* has been received. If no decoder is associated with the given image stream,
|
* stream, such that the entire received image can be fed to the decoder as one
|
||||||
* this function has no effect.
|
* buffer once the stream ends.
|
||||||
*
|
*
|
||||||
* @param stream
|
* @param stream
|
||||||
* The image stream that received the data.
|
* The image stream that received the data.
|
||||||
@ -252,18 +189,19 @@ guacenc_image_stream* guacenc_image_stream_alloc(int mask, int index,
|
|||||||
* The length of the chunk of data received, in bytes.
|
* The length of the chunk of data received, in bytes.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* Zero if the given data was handled successfully by the decoder, or
|
* Zero if the given data was successfully appended to the in-progress
|
||||||
* non-zero if an error occurs.
|
* image, non-zero if an error occurs.
|
||||||
*/
|
*/
|
||||||
int guacenc_image_stream_receive(guacenc_image_stream* stream,
|
int guacenc_image_stream_receive(guacenc_image_stream* stream,
|
||||||
unsigned char* data, int length);
|
unsigned char* data, int length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals the decoder of the given image stream that no more data will be
|
* Marks the end of the given image stream (no more data will be received) and
|
||||||
* received and the image should be written to the given buffer as-is. If no
|
* invokes the associated decoder. The decoded image will be written to the
|
||||||
* decoder is associated with the given image stream, this function has no
|
* given buffer as-is. If no decoder is associated with the given image stream,
|
||||||
* effect. Meta-information describing the image draw operation itself is
|
* this function has no effect. Meta-information describing the image draw
|
||||||
* stored within the guacenc_image_stream.
|
* operation itself is pulled from the guacenc_image_stream, having been stored
|
||||||
|
* there when the image stream was created.
|
||||||
*
|
*
|
||||||
* @param stream
|
* @param stream
|
||||||
* The image stream that has ended.
|
* The image stream that has ended.
|
||||||
|
@ -21,37 +21,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "buffer.h"
|
|
||||||
#include "image-stream.h"
|
|
||||||
#include "jpeg.h"
|
#include "jpeg.h"
|
||||||
|
|
||||||
|
#include <cairo/cairo.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
int guacenc_jpeg_init(guacenc_image_stream* stream) {
|
cairo_surface_t* guacenc_jpeg_decoder(unsigned char* data, int length) {
|
||||||
/* STUB */
|
/* STUB */
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int guacenc_jpeg_data(guacenc_image_stream* stream, unsigned char* data,
|
|
||||||
int length) {
|
|
||||||
/* STUB */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int guacenc_jpeg_end(guacenc_image_stream* stream, guacenc_buffer* buffer) {
|
|
||||||
/* STUB */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int guacenc_jpeg_free(guacenc_image_stream* stream) {
|
|
||||||
/* STUB */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
guacenc_decoder guacenc_jpeg_decoder = {
|
|
||||||
.init_handler = guacenc_jpeg_init,
|
|
||||||
.data_handler = guacenc_jpeg_data,
|
|
||||||
.end_handler = guacenc_jpeg_end,
|
|
||||||
.free_handler = guacenc_jpeg_free
|
|
||||||
};
|
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
/**
|
/**
|
||||||
* Decoder implementation which handles "image/jpeg" images.
|
* Decoder implementation which handles "image/jpeg" images.
|
||||||
*/
|
*/
|
||||||
extern guacenc_decoder guacenc_jpeg_decoder;
|
guacenc_decoder guacenc_jpeg_decoder;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -21,37 +21,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "buffer.h"
|
|
||||||
#include "image-stream.h"
|
|
||||||
#include "png.h"
|
#include "png.h"
|
||||||
|
|
||||||
|
#include <cairo/cairo.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
int guacenc_png_init(guacenc_image_stream* stream) {
|
cairo_surface_t* guacenc_png_decoder(unsigned char* data, int length) {
|
||||||
/* STUB */
|
/* STUB */
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int guacenc_png_data(guacenc_image_stream* stream, unsigned char* data,
|
|
||||||
int length) {
|
|
||||||
/* STUB */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int guacenc_png_end(guacenc_image_stream* stream, guacenc_buffer* buffer) {
|
|
||||||
/* STUB */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int guacenc_png_free(guacenc_image_stream* stream) {
|
|
||||||
/* STUB */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
guacenc_decoder guacenc_png_decoder = {
|
|
||||||
.init_handler = guacenc_png_init,
|
|
||||||
.data_handler = guacenc_png_data,
|
|
||||||
.end_handler = guacenc_png_end,
|
|
||||||
.free_handler = guacenc_png_free
|
|
||||||
};
|
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
/**
|
/**
|
||||||
* Decoder implementation which handles "image/png" images.
|
* Decoder implementation which handles "image/png" images.
|
||||||
*/
|
*/
|
||||||
extern guacenc_decoder guacenc_png_decoder;
|
guacenc_decoder guacenc_png_decoder;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -21,37 +21,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "buffer.h"
|
|
||||||
#include "image-stream.h"
|
|
||||||
#include "webp.h"
|
#include "webp.h"
|
||||||
|
|
||||||
|
#include <cairo/cairo.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
int guacenc_webp_init(guacenc_image_stream* stream) {
|
cairo_surface_t* guacenc_webp_decoder(unsigned char* data, int length) {
|
||||||
/* STUB */
|
/* STUB */
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int guacenc_webp_data(guacenc_image_stream* stream, unsigned char* data,
|
|
||||||
int length) {
|
|
||||||
/* STUB */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int guacenc_webp_end(guacenc_image_stream* stream, guacenc_buffer* buffer) {
|
|
||||||
/* STUB */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int guacenc_webp_free(guacenc_image_stream* stream) {
|
|
||||||
/* STUB */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
guacenc_decoder guacenc_webp_decoder = {
|
|
||||||
.init_handler = guacenc_webp_init,
|
|
||||||
.data_handler = guacenc_webp_data,
|
|
||||||
.end_handler = guacenc_webp_end,
|
|
||||||
.free_handler = guacenc_webp_free
|
|
||||||
};
|
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
/**
|
/**
|
||||||
* Decoder implementation which handles "image/webp" images.
|
* Decoder implementation which handles "image/webp" images.
|
||||||
*/
|
*/
|
||||||
extern guacenc_decoder guacenc_webp_decoder;
|
guacenc_decoder guacenc_webp_decoder;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user