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