forked from enlightenment/efl
758 lines
22 KiB
C
758 lines
22 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <Ecore.h>
|
|
#include "ecore_private.h"
|
|
|
|
#define MY_CLASS EFL_IO_COPIER_CLASS
|
|
#define DEF_READ_CHUNK_SIZE 4096
|
|
|
|
typedef struct _Efl_Io_Copier_Data
|
|
{
|
|
Efl_Io_Reader *source;
|
|
Efl_Io_Writer *destination;
|
|
Efl_Future *job;
|
|
Eina_Binbuf *buf;
|
|
uint8_t *read_chunk; /* TODO: method to grow Eina_Binbuf so we can expand it and read directly to that */
|
|
Eina_Slice line_delimiter;
|
|
size_t buffer_limit;
|
|
size_t read_chunk_size;
|
|
struct {
|
|
uint64_t read, written, total;
|
|
} progress;
|
|
Eina_Bool closed;
|
|
Eina_Bool done;
|
|
Eina_Bool close_on_exec;
|
|
Eina_Bool close_on_destructor;
|
|
} Efl_Io_Copier_Data;
|
|
|
|
static void _efl_io_copier_write(Eo *o, Efl_Io_Copier_Data *pd);
|
|
static void _efl_io_copier_read(Eo *o, Efl_Io_Copier_Data *pd);
|
|
|
|
#define _COPIER_DBG(o, pd) \
|
|
do \
|
|
{ \
|
|
if (eina_log_domain_level_check(_ecore_log_dom, EINA_LOG_LEVEL_DBG)) \
|
|
{ \
|
|
DBG("copier={%p %s, refs=%d, closed=%d, done=%d, buf=%zd}", \
|
|
o, \
|
|
efl_class_name_get(efl_class_get(o)), \
|
|
efl_ref_get(o), \
|
|
efl_io_closer_closed_get(o), \
|
|
pd->done, \
|
|
pd->buf ? eina_binbuf_length_get(pd->buf): 0); \
|
|
if (!pd->source) \
|
|
DBG("source=NULL"); \
|
|
else \
|
|
DBG("source={%p %s, refs=%d, can_read=%d, eos=%d, closed=%d}", \
|
|
pd->source, \
|
|
efl_class_name_get(efl_class_get(pd->source)), \
|
|
efl_ref_get(pd->source), \
|
|
efl_io_reader_can_read_get(pd->source), \
|
|
efl_io_reader_eos_get(pd->source), \
|
|
efl_isa(pd->source, EFL_IO_CLOSER_MIXIN) ? \
|
|
efl_io_closer_closed_get(pd->source) : 0); \
|
|
if (!pd->destination) \
|
|
DBG("destination=NULL"); \
|
|
else \
|
|
DBG("destination={%p %s, refs=%d, can_write=%d, closed=%d}", \
|
|
pd->destination, \
|
|
efl_class_name_get(efl_class_get(pd->destination)), \
|
|
efl_ref_get(pd->destination), \
|
|
efl_io_writer_can_write_get(pd->destination), \
|
|
efl_isa(pd->destination, EFL_IO_CLOSER_MIXIN) ? \
|
|
efl_io_closer_closed_get(pd->destination) : 0); \
|
|
} \
|
|
} \
|
|
while (0)
|
|
|
|
static void
|
|
_efl_io_copier_job(void *data, const Efl_Event *ev EINA_UNUSED)
|
|
{
|
|
Eo *o = data;
|
|
Efl_Io_Copier_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
|
|
|
_COPIER_DBG(o, pd);
|
|
efl_ref(o);
|
|
|
|
if (pd->source && efl_io_reader_can_read_get(pd->source))
|
|
_efl_io_copier_read(o, pd);
|
|
|
|
if (pd->destination && efl_io_writer_can_write_get(pd->destination))
|
|
_efl_io_copier_write(o, pd);
|
|
|
|
efl_event_callback_call(o, EFL_IO_COPIER_EVENT_PROGRESS, NULL);
|
|
|
|
if (!pd->source || efl_io_reader_eos_get(pd->source))
|
|
{
|
|
if ((!pd->done) &&
|
|
((!pd->destination) || (eina_binbuf_length_get(pd->buf) == 0)))
|
|
{
|
|
pd->done = EINA_TRUE;
|
|
efl_event_callback_call(o, EFL_IO_COPIER_EVENT_DONE, NULL);
|
|
}
|
|
}
|
|
|
|
efl_unref(o);
|
|
}
|
|
|
|
static void
|
|
_efl_io_copier_job_schedule(Eo *o, Efl_Io_Copier_Data *pd)
|
|
{
|
|
if (pd->job) return;
|
|
|
|
efl_future_use(&pd->job, efl_loop_job(efl_loop_get(o), o));
|
|
efl_future_then(pd->job, _efl_io_copier_job, NULL, NULL, o);
|
|
efl_future_link(o, pd->job);
|
|
}
|
|
|
|
/* NOTE: the returned slice may be smaller than requested since the
|
|
* internal binbuf may be modified from inside event calls.
|
|
*
|
|
* parameter slice_of_binbuf must have mem pointing to pd->binbuf
|
|
*/
|
|
static Eina_Slice
|
|
_efl_io_copier_dispatch_data_events(Eo *o, Efl_Io_Copier_Data *pd, Eina_Slice slice_of_binbuf)
|
|
{
|
|
Eina_Slice tmp;
|
|
size_t offset;
|
|
|
|
tmp = eina_binbuf_slice_get(pd->buf);
|
|
if ((slice_of_binbuf.bytes < tmp.bytes) ||
|
|
(eina_slice_end_get(slice_of_binbuf) > eina_slice_end_get(tmp)))
|
|
{
|
|
CRI("slice_of_binbuf=" EINA_SLICE_FMT " must be inside binbuf=" EINA_SLICE_FMT,
|
|
EINA_SLICE_PRINT(slice_of_binbuf), EINA_SLICE_PRINT(tmp));
|
|
return (Eina_Slice){.mem = NULL, .len = 0};
|
|
}
|
|
|
|
offset = slice_of_binbuf.bytes - tmp.bytes;
|
|
|
|
efl_event_callback_call(o, EFL_IO_COPIER_EVENT_DATA, &slice_of_binbuf);
|
|
/* user may have modified pd->buf, like calling
|
|
* efl_io_copier_buffer_limit_set()
|
|
*/
|
|
tmp = eina_binbuf_slice_get(pd->buf);
|
|
if (offset <= tmp.len)
|
|
{
|
|
tmp.len -= offset;
|
|
tmp.bytes += offset;
|
|
}
|
|
if (tmp.len > slice_of_binbuf.len)
|
|
tmp.len = slice_of_binbuf.len;
|
|
slice_of_binbuf = tmp;
|
|
|
|
if (pd->line_delimiter.len > 0)
|
|
{
|
|
efl_event_callback_call(o, EFL_IO_COPIER_EVENT_LINE, &slice_of_binbuf);
|
|
/* user may have modified pd->buf, like calling
|
|
* efl_io_copier_buffer_limit_set()
|
|
*/
|
|
tmp = eina_binbuf_slice_get(pd->buf);
|
|
if (offset <= tmp.len)
|
|
{
|
|
tmp.len -= offset;
|
|
tmp.bytes += offset;
|
|
}
|
|
if (tmp.len > slice_of_binbuf.len)
|
|
tmp.len = slice_of_binbuf.len;
|
|
slice_of_binbuf = tmp;
|
|
}
|
|
|
|
return slice_of_binbuf;
|
|
}
|
|
|
|
static void
|
|
_efl_io_copier_read(Eo *o, Efl_Io_Copier_Data *pd)
|
|
{
|
|
Eina_Rw_Slice rw_slice;
|
|
Eina_Slice ro_slice;
|
|
Eina_Error err;
|
|
size_t used;
|
|
|
|
EINA_SAFETY_ON_TRUE_RETURN(pd->closed);
|
|
|
|
rw_slice.mem = pd->read_chunk;
|
|
rw_slice.len = pd->read_chunk_size;
|
|
|
|
used = eina_binbuf_length_get(pd->buf);
|
|
if (pd->buffer_limit > 0)
|
|
{
|
|
if (pd->buffer_limit <= used)
|
|
{
|
|
// TODO: disconnect 'read' so stops calling?
|
|
return;
|
|
}
|
|
else if (pd->buffer_limit > used)
|
|
{
|
|
size_t available = pd->buffer_limit - used;
|
|
if (rw_slice.len > available)
|
|
rw_slice.len = available;
|
|
}
|
|
}
|
|
|
|
err = efl_io_reader_read(pd->source, &rw_slice);
|
|
if (err)
|
|
{
|
|
efl_event_callback_call(o, EFL_IO_COPIER_EVENT_ERROR, &err);
|
|
return;
|
|
}
|
|
|
|
ro_slice = eina_rw_slice_slice_get(rw_slice);
|
|
if (!eina_binbuf_append_slice(pd->buf, ro_slice))
|
|
{
|
|
err = ENOMEM;
|
|
efl_event_callback_call(o, EFL_IO_COPIER_EVENT_ERROR, &err);
|
|
return;
|
|
}
|
|
|
|
pd->progress.read += rw_slice.len;
|
|
pd->done = EINA_FALSE;
|
|
|
|
if (!pd->destination)
|
|
{
|
|
/* Note: if there is a destination, dispatch data and line
|
|
* from write since it will remove from binbuf and make it
|
|
* simple to not repeat data that was already sent.
|
|
*
|
|
* however, if there is no destination, then emit the event
|
|
* here.
|
|
*
|
|
* Remember to get the actual binbuf memory, rw_slice/ro_slice
|
|
* contains the pointer to pd->read_chunk and
|
|
* _efl_io_copier_dispatch_data_events() needs a slice to
|
|
* internal binbuf.
|
|
*/
|
|
Eina_Slice binbuf_slice = eina_binbuf_slice_get(pd->buf);
|
|
Eina_Slice ev_slice = {
|
|
.mem = binbuf_slice.bytes + used,
|
|
.len = binbuf_slice.len - used,
|
|
};
|
|
_efl_io_copier_dispatch_data_events(o, pd, ev_slice);
|
|
}
|
|
|
|
_efl_io_copier_job_schedule(o, pd);
|
|
}
|
|
|
|
static void
|
|
_efl_io_copier_write(Eo *o, Efl_Io_Copier_Data *pd)
|
|
{
|
|
Eina_Slice ro_slice = eina_binbuf_slice_get(pd->buf);
|
|
Eina_Error err;
|
|
|
|
EINA_SAFETY_ON_TRUE_RETURN(pd->closed);
|
|
|
|
if (ro_slice.len == 0)
|
|
{
|
|
// TODO: disconnect 'write' so stops calling?
|
|
return;
|
|
}
|
|
|
|
if ((pd->line_delimiter.len > 0) &&
|
|
(pd->source && !efl_io_reader_eos_get(pd->source)))
|
|
{
|
|
const uint8_t *p = eina_slice_find(ro_slice, pd->line_delimiter);
|
|
if (p)
|
|
ro_slice.len = p - ro_slice.bytes + pd->line_delimiter.len;
|
|
else if ((pd->buffer_limit == 0) || (ro_slice.len < pd->buffer_limit))
|
|
{
|
|
// TODO: disconnect 'write' so stops calling?
|
|
return;
|
|
}
|
|
}
|
|
|
|
err = efl_io_writer_write(pd->destination, &ro_slice, NULL);
|
|
if (err)
|
|
{
|
|
if (err != EAGAIN)
|
|
efl_event_callback_call(o, EFL_IO_COPIER_EVENT_ERROR, &err);
|
|
return;
|
|
}
|
|
pd->progress.written += ro_slice.len;
|
|
pd->done = EINA_FALSE;
|
|
|
|
/* Note: dispatch data and line from write since it will remove
|
|
* from binbuf and make it simple to not repeat data that was
|
|
* already sent.
|
|
*/
|
|
ro_slice = _efl_io_copier_dispatch_data_events(o, pd, ro_slice);
|
|
|
|
if (!eina_binbuf_remove(pd->buf, 0, ro_slice.len))
|
|
{
|
|
err = ENOMEM;
|
|
efl_event_callback_call(o, EFL_IO_COPIER_EVENT_ERROR, &err);
|
|
return;
|
|
}
|
|
|
|
_efl_io_copier_job_schedule(o, pd);
|
|
}
|
|
|
|
static void
|
|
_efl_io_copier_source_can_read_changed(void *data, const Efl_Event *event EINA_UNUSED)
|
|
{
|
|
Eo *o = data;
|
|
Efl_Io_Copier_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
|
if (pd->closed) return;
|
|
|
|
_COPIER_DBG(o, pd);
|
|
|
|
if (efl_io_reader_can_read_get(pd->source))
|
|
_efl_io_copier_job_schedule(o, pd);
|
|
}
|
|
|
|
static void
|
|
_efl_io_copier_source_eos(void *data, const Efl_Event *event EINA_UNUSED)
|
|
{
|
|
Eo *o = data;
|
|
Efl_Io_Copier_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
|
if (pd->closed) return;
|
|
|
|
_COPIER_DBG(o, pd);
|
|
|
|
_efl_io_copier_job_schedule(o, pd);
|
|
}
|
|
|
|
static void
|
|
_efl_io_copier_source_size_apply(Eo *o, Efl_Io_Copier_Data *pd)
|
|
{
|
|
if (pd->closed) return;
|
|
pd->progress.total = efl_io_sizer_size_get(pd->source);
|
|
|
|
_COPIER_DBG(o, pd);
|
|
|
|
if (pd->destination && efl_isa(pd->destination, EFL_IO_SIZER_MIXIN))
|
|
efl_io_sizer_resize(pd->destination, pd->progress.total);
|
|
|
|
efl_event_callback_call(o, EFL_IO_COPIER_EVENT_PROGRESS, NULL);
|
|
}
|
|
|
|
static void
|
|
_efl_io_copier_source_resized(void *data, const Efl_Event *event EINA_UNUSED)
|
|
{
|
|
Eo *o = data;
|
|
Efl_Io_Copier_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
|
_efl_io_copier_source_size_apply(o, pd);
|
|
}
|
|
|
|
static void
|
|
_efl_io_copier_source_closed(void *data, const Efl_Event *event EINA_UNUSED)
|
|
{
|
|
Eo *o = data;
|
|
Efl_Io_Copier_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
|
if (pd->closed) return;
|
|
|
|
_COPIER_DBG(o, pd);
|
|
|
|
_efl_io_copier_job_schedule(o, pd);
|
|
}
|
|
|
|
EFL_CALLBACKS_ARRAY_DEFINE(source_cbs,
|
|
{ EFL_IO_READER_EVENT_CAN_READ_CHANGED, _efl_io_copier_source_can_read_changed },
|
|
{ EFL_IO_READER_EVENT_EOS, _efl_io_copier_source_eos });
|
|
|
|
EOLIAN static Efl_Io_Reader *
|
|
_efl_io_copier_source_get(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd)
|
|
{
|
|
return pd->source;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_io_copier_source_set(Eo *o, Efl_Io_Copier_Data *pd, Efl_Io_Reader *source)
|
|
{
|
|
if (pd->source == source) return;
|
|
|
|
if (pd->source)
|
|
{
|
|
if (efl_isa(pd->source, EFL_IO_SIZER_MIXIN))
|
|
{
|
|
efl_event_callback_del(pd->source, EFL_IO_SIZER_EVENT_SIZE_CHANGED,
|
|
_efl_io_copier_source_resized, o);
|
|
pd->progress.total = 0;
|
|
}
|
|
if (efl_isa(pd->source, EFL_IO_CLOSER_MIXIN))
|
|
{
|
|
efl_event_callback_del(pd->source, EFL_IO_CLOSER_EVENT_CLOSED,
|
|
_efl_io_copier_source_closed, o);
|
|
}
|
|
efl_event_callback_array_del(pd->source, source_cbs(), o);
|
|
efl_unref(pd->source);
|
|
pd->source = NULL;
|
|
}
|
|
|
|
if (source)
|
|
{
|
|
EINA_SAFETY_ON_TRUE_RETURN(pd->closed);
|
|
pd->source = efl_ref(source);
|
|
efl_event_callback_array_add(pd->source, source_cbs(), o);
|
|
|
|
if (efl_isa(pd->source, EFL_IO_SIZER_MIXIN))
|
|
{
|
|
efl_event_callback_add(pd->source, EFL_IO_SIZER_EVENT_SIZE_CHANGED,
|
|
_efl_io_copier_source_resized, o);
|
|
_efl_io_copier_source_size_apply(o, pd);
|
|
}
|
|
|
|
if (efl_isa(pd->source, EFL_IO_CLOSER_MIXIN))
|
|
{
|
|
efl_io_closer_close_on_exec_set(pd->source, efl_io_closer_close_on_exec_get(o));
|
|
efl_io_closer_close_on_destructor_set(pd->source, efl_io_closer_close_on_destructor_get(o));
|
|
efl_event_callback_add(pd->source, EFL_IO_CLOSER_EVENT_CLOSED,
|
|
_efl_io_copier_source_closed, o);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_efl_io_copier_destination_can_write_changed(void *data, const Efl_Event *event EINA_UNUSED)
|
|
{
|
|
Eo *o = data;
|
|
Efl_Io_Copier_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
|
if (pd->closed) return;
|
|
|
|
_COPIER_DBG(o, pd);
|
|
|
|
if (efl_io_writer_can_write_get(pd->destination))
|
|
_efl_io_copier_job_schedule(o, pd);
|
|
}
|
|
|
|
static void
|
|
_efl_io_copier_destination_closed(void *data, const Efl_Event *event EINA_UNUSED)
|
|
{
|
|
Eo *o = data;
|
|
Efl_Io_Copier_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
|
if (pd->closed) return;
|
|
|
|
_COPIER_DBG(o, pd);
|
|
|
|
if (eina_binbuf_length_get(pd->buf) == 0)
|
|
{
|
|
if (!pd->done)
|
|
{
|
|
pd->done = EINA_TRUE;
|
|
efl_event_callback_call(o, EFL_IO_COPIER_EVENT_DONE, NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Eina_Error err = EBADF;
|
|
efl_event_callback_call(o, EFL_IO_COPIER_EVENT_ERROR, &err);
|
|
}
|
|
}
|
|
|
|
EFL_CALLBACKS_ARRAY_DEFINE(destination_cbs,
|
|
{ EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED, _efl_io_copier_destination_can_write_changed });
|
|
|
|
EOLIAN static Efl_Io_Writer *
|
|
_efl_io_copier_destination_get(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd)
|
|
{
|
|
return pd->destination;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_io_copier_destination_set(Eo *o, Efl_Io_Copier_Data *pd, Efl_Io_Writer *destination)
|
|
{
|
|
if (pd->destination == destination) return;
|
|
|
|
if (pd->destination)
|
|
{
|
|
efl_event_callback_array_del(pd->destination, destination_cbs(), o);
|
|
if (efl_isa(pd->destination, EFL_IO_CLOSER_MIXIN))
|
|
{
|
|
efl_event_callback_del(pd->destination, EFL_IO_CLOSER_EVENT_CLOSED,
|
|
_efl_io_copier_destination_closed, o);
|
|
}
|
|
efl_unref(pd->destination);
|
|
pd->destination = NULL;
|
|
}
|
|
|
|
if (destination)
|
|
{
|
|
EINA_SAFETY_ON_TRUE_RETURN(pd->closed);
|
|
pd->destination = efl_ref(destination);
|
|
efl_event_callback_array_add(pd->destination, destination_cbs(), o);
|
|
|
|
if (efl_isa(pd->destination, EFL_IO_CLOSER_MIXIN))
|
|
{
|
|
efl_io_closer_close_on_exec_set(pd->destination, efl_io_closer_close_on_exec_get(o));
|
|
efl_io_closer_close_on_destructor_set(pd->destination, efl_io_closer_close_on_destructor_get(o));
|
|
efl_event_callback_add(pd->destination, EFL_IO_CLOSER_EVENT_CLOSED,
|
|
_efl_io_copier_destination_closed, o);
|
|
}
|
|
if (efl_isa(pd->destination, EFL_IO_SIZER_MIXIN) &&
|
|
pd->source && efl_isa(pd->source, EFL_IO_SIZER_MIXIN))
|
|
{
|
|
efl_io_sizer_resize(pd->destination, pd->progress.total);
|
|
}
|
|
}
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_io_copier_buffer_limit_set(Eo *o, Efl_Io_Copier_Data *pd, size_t size)
|
|
{
|
|
size_t used;
|
|
|
|
EINA_SAFETY_ON_TRUE_RETURN(pd->closed);
|
|
|
|
if (pd->buffer_limit == size) return;
|
|
pd->buffer_limit = size;
|
|
if (size == 0) return;
|
|
|
|
used = eina_binbuf_length_get(pd->buf);
|
|
if (used > size) eina_binbuf_remove(pd->buf, size, used);
|
|
if (pd->read_chunk_size > size) efl_io_copier_read_chunk_size_set(o, size);
|
|
}
|
|
|
|
EOLIAN static size_t
|
|
_efl_io_copier_buffer_limit_get(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd)
|
|
{
|
|
return pd->buffer_limit;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_io_copier_line_delimiter_set(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd, const Eina_Slice *slice)
|
|
{
|
|
EINA_SAFETY_ON_NULL_RETURN(slice);
|
|
if (pd->line_delimiter.mem == slice->mem)
|
|
{
|
|
pd->line_delimiter.len = slice->len;
|
|
return;
|
|
}
|
|
|
|
free((void *)pd->line_delimiter.mem);
|
|
if (slice->len == 0)
|
|
{
|
|
pd->line_delimiter.mem = NULL;
|
|
pd->line_delimiter.len = 0;
|
|
}
|
|
else
|
|
{
|
|
Eina_Rw_Slice rw_slice = eina_slice_dup(*slice);
|
|
pd->line_delimiter = eina_rw_slice_slice_get(rw_slice);
|
|
}
|
|
}
|
|
|
|
EOLIAN static const Eina_Slice *
|
|
_efl_io_copier_line_delimiter_get(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd)
|
|
{
|
|
return &pd->line_delimiter;
|
|
}
|
|
|
|
|
|
EOLIAN static void
|
|
_efl_io_copier_read_chunk_size_set(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd, size_t size)
|
|
{
|
|
void *tmp;
|
|
|
|
EINA_SAFETY_ON_TRUE_RETURN(pd->closed);
|
|
|
|
if (size == 0) size = DEF_READ_CHUNK_SIZE;
|
|
if ((pd->read_chunk_size == size) && pd->read_chunk) return;
|
|
|
|
tmp = realloc(pd->read_chunk, size);
|
|
EINA_SAFETY_ON_NULL_RETURN(tmp);
|
|
|
|
pd->read_chunk = tmp;
|
|
pd->read_chunk_size = size;
|
|
}
|
|
|
|
EOLIAN static size_t
|
|
_efl_io_copier_read_chunk_size_get(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd)
|
|
{
|
|
return pd->read_chunk_size > 0 ? pd->read_chunk_size : DEF_READ_CHUNK_SIZE;
|
|
}
|
|
|
|
EOLIAN static Eina_Error
|
|
_efl_io_copier_efl_io_closer_close(Eo *o, Efl_Io_Copier_Data *pd)
|
|
{
|
|
Eina_Error err = 0, r;
|
|
|
|
EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->closed, EINVAL);
|
|
|
|
_COPIER_DBG(o, pd);
|
|
|
|
if (pd->job)
|
|
efl_future_cancel(pd->job);
|
|
|
|
if (pd->source)
|
|
{
|
|
if (efl_isa(pd->source, EFL_IO_SIZER_MIXIN))
|
|
{
|
|
efl_event_callback_del(pd->source, EFL_IO_SIZER_EVENT_SIZE_CHANGED,
|
|
_efl_io_copier_source_resized, o);
|
|
pd->progress.total = 0;
|
|
}
|
|
efl_event_callback_array_del(pd->source, source_cbs(), o);
|
|
if (efl_isa(pd->source, EFL_IO_CLOSER_MIXIN) &&
|
|
!efl_io_closer_closed_get(pd->source))
|
|
{
|
|
efl_event_callback_del(pd->source, EFL_IO_CLOSER_EVENT_CLOSED,
|
|
_efl_io_copier_source_closed, o);
|
|
err = efl_io_closer_close(pd->source);
|
|
}
|
|
}
|
|
|
|
if (pd->destination)
|
|
{
|
|
efl_event_callback_array_del(pd->destination, destination_cbs(), o);
|
|
if (efl_isa(pd->destination, EFL_IO_CLOSER_MIXIN) &&
|
|
!efl_io_closer_closed_get(pd->destination))
|
|
{
|
|
efl_event_callback_del(pd->destination, EFL_IO_CLOSER_EVENT_CLOSED,
|
|
_efl_io_copier_destination_closed, o);
|
|
r = efl_io_closer_close(pd->destination);
|
|
if (!err) err = r;
|
|
}
|
|
}
|
|
|
|
pd->closed = EINA_TRUE;
|
|
efl_event_callback_call(o, EFL_IO_CLOSER_EVENT_CLOSED, NULL);
|
|
|
|
if (pd->buf)
|
|
{
|
|
eina_binbuf_free(pd->buf);
|
|
pd->buf = NULL;
|
|
}
|
|
|
|
if (pd->read_chunk)
|
|
{
|
|
free(pd->read_chunk);
|
|
pd->read_chunk = NULL;
|
|
pd->read_chunk_size = 0;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_io_copier_efl_io_closer_closed_get(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd)
|
|
{
|
|
return pd->closed;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_io_copier_progress_get(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd, uint64_t *read, uint64_t *written, uint64_t *total)
|
|
{
|
|
if (read) *read = pd->progress.read;
|
|
if (written) *written = pd->progress.written;
|
|
if (total) *total = pd->progress.total;
|
|
}
|
|
|
|
EOLIAN static Eina_Binbuf *
|
|
_efl_io_copier_binbuf_steal(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd)
|
|
{
|
|
Eina_Binbuf *ret = pd->buf;
|
|
pd->buf = eina_binbuf_new();
|
|
return ret;
|
|
}
|
|
|
|
EOLIAN static Eo *
|
|
_efl_io_copier_efl_object_constructor(Eo *o, Efl_Io_Copier_Data *pd)
|
|
{
|
|
pd->buf = eina_binbuf_new();
|
|
pd->close_on_exec = EINA_TRUE;
|
|
pd->close_on_destructor = EINA_TRUE;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->buf, NULL);
|
|
|
|
return efl_constructor(efl_super(o, MY_CLASS));
|
|
}
|
|
|
|
EOLIAN static Eo *
|
|
_efl_io_copier_efl_object_finalize(Eo *o, Efl_Io_Copier_Data *pd)
|
|
{
|
|
if (pd->read_chunk_size == 0)
|
|
efl_io_copier_read_chunk_size_set(o, DEF_READ_CHUNK_SIZE);
|
|
|
|
if (!efl_loop_get(o))
|
|
{
|
|
ERR("Set a loop provider as parent of this copier!");
|
|
return NULL;
|
|
}
|
|
|
|
if ((pd->source && efl_io_reader_can_read_get(pd->source)) ||
|
|
(pd->destination && efl_io_writer_can_write_get(pd->destination)))
|
|
_efl_io_copier_job_schedule(o, pd);
|
|
|
|
_COPIER_DBG(o, pd);
|
|
|
|
return efl_finalize(efl_super(o, MY_CLASS));
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_io_copier_efl_object_destructor(Eo *o, Efl_Io_Copier_Data *pd)
|
|
{
|
|
_COPIER_DBG(o, pd);
|
|
|
|
if (efl_io_closer_close_on_destructor_get(o) &&
|
|
(!efl_io_closer_closed_get(o)))
|
|
efl_io_closer_close(o);
|
|
|
|
efl_io_copier_source_set(o, NULL);
|
|
efl_io_copier_destination_set(o, NULL);
|
|
|
|
efl_destructor(efl_super(o, MY_CLASS));
|
|
|
|
if (pd->buf)
|
|
{
|
|
eina_binbuf_free(pd->buf);
|
|
pd->buf = NULL;
|
|
}
|
|
|
|
if (pd->read_chunk)
|
|
{
|
|
free(pd->read_chunk);
|
|
pd->read_chunk = NULL;
|
|
pd->read_chunk_size = 0;
|
|
}
|
|
|
|
if (pd->line_delimiter.mem)
|
|
{
|
|
free((void *)pd->line_delimiter.mem);
|
|
pd->line_delimiter.mem = NULL;
|
|
pd->line_delimiter.len = 0;
|
|
}
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_io_copier_efl_io_closer_close_on_exec_set(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd, Eina_Bool close_on_exec)
|
|
{
|
|
if (pd->close_on_exec == close_on_exec) return EINA_TRUE;
|
|
pd->close_on_exec = close_on_exec;
|
|
|
|
if (pd->source && efl_isa(pd->source, EFL_IO_CLOSER_MIXIN))
|
|
efl_io_closer_close_on_exec_set(pd->source, close_on_exec);
|
|
|
|
if (pd->destination && efl_isa(pd->destination, EFL_IO_CLOSER_MIXIN))
|
|
efl_io_closer_close_on_exec_set(pd->destination, close_on_exec);
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_io_copier_efl_io_closer_close_on_exec_get(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd)
|
|
{
|
|
return pd->close_on_exec;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_io_copier_efl_io_closer_close_on_destructor_set(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd, Eina_Bool close_on_destructor)
|
|
{
|
|
if (pd->close_on_destructor == close_on_destructor) return;
|
|
pd->close_on_destructor = close_on_destructor;
|
|
|
|
if (pd->source && efl_isa(pd->source, EFL_IO_CLOSER_MIXIN))
|
|
efl_io_closer_close_on_destructor_set(pd->source, close_on_destructor);
|
|
|
|
if (pd->destination && efl_isa(pd->destination, EFL_IO_CLOSER_MIXIN))
|
|
efl_io_closer_close_on_destructor_set(pd->destination, close_on_destructor);
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_io_copier_efl_io_closer_close_on_destructor_get(Eo *o EINA_UNUSED, Efl_Io_Copier_Data *pd)
|
|
{
|
|
return pd->close_on_destructor;
|
|
}
|
|
|
|
#include "efl_io_copier.eo.c"
|