1 /***********************************************************************************************************************************
2 IO Filter Interface
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5 
6 #include "common/debug.h"
7 #include "common/io/filter/filter.h"
8 #include "common/log.h"
9 #include "common/memContext.h"
10 
11 /***********************************************************************************************************************************
12 Object type
13 ***********************************************************************************************************************************/
14 struct IoFilter
15 {
16     IoFilterPub pub;                                                // Publicly accessible variables
17     bool flushing;                                                  // Has the filter started flushing?
18 };
19 
20 /***********************************************************************************************************************************
21 Allocations will be in the memory context of the caller.
22 ***********************************************************************************************************************************/
23 IoFilter *
ioFilterNew(const String * type,void * driver,VariantList * paramList,IoFilterInterface interface)24 ioFilterNew(const String *type, void *driver, VariantList *paramList, IoFilterInterface interface)
25 {
26     FUNCTION_LOG_BEGIN(logLevelTrace);
27         FUNCTION_LOG_PARAM(STRING, type);
28         FUNCTION_LOG_PARAM_P(VOID, driver);
29         FUNCTION_LOG_PARAM(VARIANT_LIST, paramList);
30         FUNCTION_LOG_PARAM(IO_FILTER_INTERFACE, interface);
31     FUNCTION_LOG_END();
32 
33     ASSERT(type != NULL);
34     ASSERT(driver != NULL);
35     // One of processIn or processInOut must be set
36     ASSERT(interface.in != NULL || interface.inOut != NULL);
37     // But not both of them
38     ASSERT(!(interface.in != NULL && interface.inOut != NULL));
39     // If the filter does not produce output then it should produce a result
40     ASSERT(interface.in == NULL || (interface.result != NULL && interface.done == NULL && interface.inputSame == NULL));
41 
42     IoFilter *this = memNew(sizeof(IoFilter));
43 
44     *this = (IoFilter)
45     {
46         .pub =
47         {
48             .memContext = memContextCurrent(),
49             .type = type,
50             .driver = driver,
51             .paramList = paramList,
52             .interface = interface,
53         },
54     };
55 
56     FUNCTION_LOG_RETURN(IO_FILTER, this);
57 }
58 
59 /**********************************************************************************************************************************/
60 void
ioFilterProcessIn(IoFilter * this,const Buffer * input)61 ioFilterProcessIn(IoFilter *this, const Buffer *input)
62 {
63     FUNCTION_TEST_BEGIN();
64         FUNCTION_TEST_PARAM(IO_FILTER, this);
65         FUNCTION_TEST_PARAM(BUFFER, input);
66     FUNCTION_TEST_END();
67 
68     ASSERT(this != NULL);
69     ASSERT(this->pub.interface.in != NULL);
70     CHECK(input == NULL || !bufEmpty(input));
71     CHECK(!this->flushing || input == NULL);
72 
73     if (input == NULL)
74         this->flushing = true;
75     else
76         this->pub.interface.in(this->pub.driver, input);
77 
78     FUNCTION_TEST_RETURN_VOID();
79 }
80 
81 /**********************************************************************************************************************************/
82 void
ioFilterProcessInOut(IoFilter * this,const Buffer * input,Buffer * output)83 ioFilterProcessInOut(IoFilter *this, const Buffer *input, Buffer *output)
84 {
85     FUNCTION_TEST_BEGIN();
86         FUNCTION_TEST_PARAM(IO_FILTER, this);
87         FUNCTION_TEST_PARAM(BUFFER, input);
88         FUNCTION_TEST_PARAM(BUFFER, output);
89     FUNCTION_TEST_END();
90 
91     ASSERT(this != NULL);
92     ASSERT(output != NULL);
93     ASSERT(this->pub.interface.inOut != NULL);
94     CHECK(input == NULL || !bufEmpty(input));
95     CHECK(!this->flushing || input == NULL);
96 
97     if (input == NULL && !this->flushing)
98         this->flushing = true;
99 
100     if (!ioFilterDone(this))
101         this->pub.interface.inOut(this->pub.driver, input, output);
102 
103     CHECK(!ioFilterInputSame(this) || !bufEmpty(output));
104     FUNCTION_TEST_RETURN_VOID();
105 }
106 
107 /***********************************************************************************************************************************
108 If done is not defined by the filter then check inputSame.  If inputSame is true then the filter is not done.  Even if the filter
109 is done the interface will not report done until the interface is flushing.
110 ***********************************************************************************************************************************/
111 bool
ioFilterDone(const IoFilter * this)112 ioFilterDone(const IoFilter *this)
113 {
114     FUNCTION_TEST_BEGIN();
115         FUNCTION_TEST_PARAM(IO_FILTER, this);
116     FUNCTION_TEST_END();
117 
118     ASSERT(this != NULL);
119 
120     bool result = false;
121 
122     if (this->flushing)
123         result = this->pub.interface.done != NULL ? this->pub.interface.done(this->pub.driver) : !ioFilterInputSame(this);
124 
125     FUNCTION_TEST_RETURN(result);
126 }
127 
128 /**********************************************************************************************************************************/
129 bool
ioFilterInputSame(const IoFilter * this)130 ioFilterInputSame(const IoFilter *this)
131 {
132     FUNCTION_TEST_BEGIN();
133         FUNCTION_TEST_PARAM(IO_FILTER, this);
134     FUNCTION_TEST_END();
135 
136     ASSERT(this != NULL);
137 
138     FUNCTION_TEST_RETURN(this->pub.interface.inputSame != NULL ? this->pub.interface.inputSame(this->pub.driver) : false);
139 }
140 
141 /**********************************************************************************************************************************/
142 Variant *
ioFilterResult(const IoFilter * this)143 ioFilterResult(const IoFilter *this)
144 {
145     FUNCTION_TEST_BEGIN();
146         FUNCTION_TEST_PARAM(IO_FILTER, this);
147     FUNCTION_TEST_END();
148 
149     ASSERT(this != NULL);
150 
151     FUNCTION_TEST_RETURN(this->pub.interface.result ? this->pub.interface.result(this->pub.driver) : NULL);
152 }
153 
154 /**********************************************************************************************************************************/
155 String *
ioFilterToLog(const IoFilter * this)156 ioFilterToLog(const IoFilter *this)
157 {
158     return strNewFmt("{type: %s}", strZ(ioFilterType(this)));
159 }
160