xeme/xeme
Clone
Summary
Browse
Changes
Graph
Add a simple unit test for the input stream and fix a few issues
11 months ago, Gary Kramlich
3225679278bb
Add a simple unit test for the input stream and fix a few issues
/*
* Copyright (C) 2023 Dodo Developers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <https://www.gnu.org/licenses/>.
*/
#include
"dodocore.h"
#include
"dodooutputstream.h"
#include
"dodostring.h"
struct
_DodoOutputStream
{
DodoStream
parent
;
gboolean
running
;
GBytes
*
buffer
;
GOutputStream
*
output
;
};
G_DEFINE_TYPE
(
DodoOutputStream
,
dodo_output_stream
,
DODO_TYPE_STREAM
)
/******************************************************************************
* Helpers
*****************************************************************************/
static
GBytes
*
dodo_output_stream_serialize
(
DodoOutputStream
*
output_stream
)
{
DodoStream
*
stream
=
DODO_STREAM
(
output_stream
);
GBytes
*
bytes
=
NULL
;
GString
*
str
=
NULL
;
const
char
*
value
=
NULL
;
str
=
g_string_new
(
DODO_STREAM_PI
);
g_string_append
(
str
,
"<stream:stream"
);
/* to and from are validated to not be empty in
* dodo_output_stream_start. */
g_string_append_printf
(
str
,
" from=
\"
%s
\"
"
,
dodo_stream_get_from
(
stream
));
g_string_append_printf
(
str
,
" to=
\"
%s
\"
"
,
dodo_stream_get_to
(
stream
));
value
=
dodo_stream_get_id
(
stream
);
if
(
!
dodo_str_is_empty
(
value
))
{
g_string_append_printf
(
str
,
" id=
\"
%s
\"
"
,
value
);
}
value
=
dodo_stream_get_version
(
stream
);
if
(
!
dodo_str_is_empty
(
value
))
{
g_string_append_printf
(
str
,
" version=
\"
%s
\"
"
,
value
);
}
value
=
dodo_stream_get_language
(
stream
);
if
(
!
dodo_str_is_empty
(
value
))
{
g_string_append_printf
(
str
,
" xml:lang=
\"
%s
\"
"
,
value
);
}
g_string_append_printf
(
str
,
" xmlns=
\"
%s
\"
"
,
DODO_STREAM_XMLNS
);
g_string_append_printf
(
str
,
" xmlns:stream=
\"
%s
\"
"
,
DODO_STREAM_XMLNS_STREAM
);
g_string_append
(
str
,
">"
);
/* Create a GBytes with the value from the GString and free the GString
* container.
*/
bytes
=
g_bytes_new_take
(
str
->
str
,
str
->
len
);
g_string_free
(
str
,
FALSE
);
return
bytes
;
}
/******************************************************************************
* Callbacks
*****************************************************************************/
static
void
dodo_output_stream_write_cb
(
G_GNUC_UNUSED
GObject
*
source
,
GAsyncResult
*
res
,
gpointer
data
)
{
DodoOutputStream
*
stream
=
data
;
GError
*
error
=
NULL
;
gssize
written
=
0
;
gsize
expected
=
0
;
expected
=
g_bytes_get_size
(
stream
->
buffer
);
written
=
g_output_stream_write_bytes_finish
(
stream
->
output
,
res
,
&
error
);
/* handle error */
if
((
gsize
)
written
!=
expected
)
{
GBytes
*
remaining
=
NULL
;
GCancellable
*
cancellable
=
NULL
;
remaining
=
g_bytes_new_from_bytes
(
stream
->
buffer
,
(
gsize
)
written
,
expected
-
(
gsize
)
written
);
g_set_object
(
&
stream
->
buffer
,
remaining
);
g_bytes_unref
(
remaining
);
cancellable
=
dodo_stream_get_cancellable
(
DODO_STREAM
(
stream
));
g_output_stream_write_bytes_async
(
stream
->
output
,
stream
->
buffer
,
G_PRIORITY_DEFAULT
,
cancellable
,
dodo_output_stream_write_cb
,
stream
);
}
else
{
g_clear_pointer
(
&
stream
->
buffer
,
g_bytes_unref
);
}
}
/******************************************************************************
* GObject Implementation
*****************************************************************************/
static
void
dodo_output_stream_finalize
(
GObject
*
obj
)
{
DodoOutputStream
*
stream
=
DODO_OUTPUT_STREAM
(
obj
);
g_clear_pointer
(
&
stream
->
buffer
,
g_bytes_unref
);
g_clear_object
(
&
stream
->
output
);
G_OBJECT_CLASS
(
dodo_output_stream_parent_class
)
->
finalize
(
obj
);
}
static
void
dodo_output_stream_init
(
DodoOutputStream
*
stream
)
{
stream
->
running
=
FALSE
;
}
static
void
dodo_output_stream_class_init
(
DodoOutputStreamClass
*
klass
)
{
GObjectClass
*
obj_class
=
G_OBJECT_CLASS
(
klass
);
obj_class
->
finalize
=
dodo_output_stream_finalize
;
}
/******************************************************************************
* Public API
*****************************************************************************/
DodoOutputStream
*
dodo_output_stream_new
(
const
char
*
to
,
const
char
*
from
,
GCancellable
*
cancellable
)
{
return
g_object_new
(
DODO_TYPE_OUTPUT_STREAM
,
"cancellable"
,
cancellable
,
"from"
,
from
,
"to"
,
to
,
NULL
);
}
gboolean
dodo_output_stream_start
(
DodoOutputStream
*
stream
,
GOutputStream
*
output
,
GError
**
error
)
{
GCancellable
*
cancellable
=
NULL
;
g_return_val_if_fail
(
DODO_IS_OUTPUT_STREAM
(
stream
),
FALSE
);
g_return_val_if_fail
(
G_IS_OUTPUT_STREAM
(
output
),
FALSE
);
g_return_val_if_fail
(
error
==
NULL
||
*
error
==
NULL
,
FALSE
);
if
(
stream
->
running
)
{
g_set_error_literal
(
error
,
DODO_DOMAIN
,
0
,
"output stream has already been started"
);
return
FALSE
;
}
if
(
!
g_set_object
(
&
stream
->
output
,
output
))
{
g_set_error_literal
(
error
,
DODO_DOMAIN
,
0
,
"failed to set the output stream"
);
return
FALSE
;
}
cancellable
=
dodo_stream_get_cancellable
(
DODO_STREAM
(
stream
));
stream
->
buffer
=
dodo_output_stream_serialize
(
stream
);
g_output_stream_write_bytes_async
(
stream
->
output
,
stream
->
buffer
,
G_PRIORITY_DEFAULT
,
cancellable
,
dodo_output_stream_write_cb
,
stream
);
stream
->
running
=
TRUE
;
return
TRUE
;
}
gboolean
dodo_output_stream_stop
(
DodoOutputStream
*
stream
,
GError
**
error
)
{
GCancellable
*
cancellable
=
NULL
;
GError
*
local_error
=
NULL
;
gboolean
ret
=
TRUE
;
g_return_val_if_fail
(
DODO_IS_OUTPUT_STREAM
(
stream
),
FALSE
);
cancellable
=
dodo_stream_get_cancellable
(
DODO_STREAM
(
stream
));
if
(
!
g_output_stream_close
(
stream
->
output
,
cancellable
,
&
local_error
))
{
g_propagate_error
(
error
,
local_error
);
ret
=
FALSE
;
}
stream
->
output
=
NULL
;
return
ret
;
}