Coverage Report

Created: 2023-09-25 06:56

/src/FreeRDP/winpr/libwinpr/utils/collections/PubSub.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Publisher/Subscriber Pattern
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/config.h>
21
22
#include <winpr/crt.h>
23
24
#include <winpr/collections.h>
25
26
/**
27
 * Events (C# Programming Guide)
28
 * http://msdn.microsoft.com/en-us/library/awbftdfh.aspx
29
 */
30
31
struct s_wPubSub
32
{
33
  CRITICAL_SECTION lock;
34
  BOOL synchronized;
35
36
  size_t size;
37
  size_t count;
38
  wEventType* events;
39
};
40
41
/**
42
 * Properties
43
 */
44
45
wEventType* PubSub_GetEventTypes(wPubSub* pubSub, size_t* count)
46
0
{
47
0
  WINPR_ASSERT(pubSub);
48
0
  if (count)
49
0
    *count = pubSub->count;
50
51
0
  return pubSub->events;
52
0
}
53
54
/**
55
 * Methods
56
 */
57
58
void PubSub_Lock(wPubSub* pubSub)
59
0
{
60
0
  WINPR_ASSERT(pubSub);
61
0
  if (pubSub->synchronized)
62
0
    EnterCriticalSection(&pubSub->lock);
63
0
}
64
65
void PubSub_Unlock(wPubSub* pubSub)
66
0
{
67
0
  WINPR_ASSERT(pubSub);
68
0
  if (pubSub->synchronized)
69
0
    LeaveCriticalSection(&pubSub->lock);
70
0
}
71
72
wEventType* PubSub_FindEventType(wPubSub* pubSub, const char* EventName)
73
0
{
74
0
  size_t index;
75
0
  wEventType* event = NULL;
76
77
0
  WINPR_ASSERT(pubSub);
78
0
  WINPR_ASSERT(EventName);
79
0
  for (index = 0; index < pubSub->count; index++)
80
0
  {
81
0
    if (strcmp(pubSub->events[index].EventName, EventName) == 0)
82
0
    {
83
0
      event = &(pubSub->events[index]);
84
0
      break;
85
0
    }
86
0
  }
87
88
0
  return event;
89
0
}
90
91
void PubSub_AddEventTypes(wPubSub* pubSub, wEventType* events, size_t count)
92
0
{
93
0
  WINPR_ASSERT(pubSub);
94
0
  WINPR_ASSERT(events || (count == 0));
95
0
  if (pubSub->synchronized)
96
0
    PubSub_Lock(pubSub);
97
98
0
  while (pubSub->count + count >= pubSub->size)
99
0
  {
100
0
    size_t new_size;
101
0
    wEventType* new_event;
102
103
0
    new_size = pubSub->size * 2;
104
0
    new_event = (wEventType*)realloc(pubSub->events, new_size * sizeof(wEventType));
105
0
    if (!new_event)
106
0
      return;
107
0
    pubSub->size = new_size;
108
0
    pubSub->events = new_event;
109
0
  }
110
111
0
  CopyMemory(&pubSub->events[pubSub->count], events, count * sizeof(wEventType));
112
0
  pubSub->count += count;
113
114
0
  if (pubSub->synchronized)
115
0
    PubSub_Unlock(pubSub);
116
0
}
117
118
int PubSub_Subscribe(wPubSub* pubSub, const char* EventName, pEventHandler EventHandler)
119
0
{
120
0
  wEventType* event;
121
0
  int status = -1;
122
0
  WINPR_ASSERT(pubSub);
123
0
  WINPR_ASSERT(EventHandler);
124
125
0
  if (pubSub->synchronized)
126
0
    PubSub_Lock(pubSub);
127
128
0
  event = PubSub_FindEventType(pubSub, EventName);
129
130
0
  if (event)
131
0
  {
132
0
    status = 0;
133
134
0
    if (event->EventHandlerCount < MAX_EVENT_HANDLERS)
135
0
      event->EventHandlers[event->EventHandlerCount++] = EventHandler;
136
0
    else
137
0
      status = -1;
138
0
  }
139
140
0
  if (pubSub->synchronized)
141
0
    PubSub_Unlock(pubSub);
142
143
0
  return status;
144
0
}
145
146
int PubSub_Unsubscribe(wPubSub* pubSub, const char* EventName, pEventHandler EventHandler)
147
0
{
148
0
  size_t index;
149
0
  wEventType* event;
150
0
  int status = -1;
151
0
  WINPR_ASSERT(pubSub);
152
0
  WINPR_ASSERT(EventName);
153
0
  WINPR_ASSERT(EventHandler);
154
155
0
  if (pubSub->synchronized)
156
0
    PubSub_Lock(pubSub);
157
158
0
  event = PubSub_FindEventType(pubSub, EventName);
159
160
0
  if (event)
161
0
  {
162
0
    status = 0;
163
164
0
    for (index = 0; index < event->EventHandlerCount; index++)
165
0
    {
166
0
      if (event->EventHandlers[index] == EventHandler)
167
0
      {
168
0
        event->EventHandlers[index] = NULL;
169
0
        event->EventHandlerCount--;
170
0
        MoveMemory(&event->EventHandlers[index], &event->EventHandlers[index + 1],
171
0
                   (MAX_EVENT_HANDLERS - index - 1) * sizeof(pEventHandler));
172
0
        status = 1;
173
0
      }
174
0
    }
175
0
  }
176
177
0
  if (pubSub->synchronized)
178
0
    PubSub_Unlock(pubSub);
179
180
0
  return status;
181
0
}
182
183
int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, const wEventArgs* e)
184
0
{
185
0
  size_t index;
186
0
  wEventType* event;
187
0
  int status = -1;
188
189
0
  if (!pubSub)
190
0
    return -1;
191
0
  WINPR_ASSERT(e);
192
193
0
  if (pubSub->synchronized)
194
0
    PubSub_Lock(pubSub);
195
196
0
  event = PubSub_FindEventType(pubSub, EventName);
197
198
0
  if (pubSub->synchronized)
199
0
    PubSub_Unlock(pubSub);
200
201
0
  if (event)
202
0
  {
203
0
    status = 0;
204
205
0
    for (index = 0; index < event->EventHandlerCount; index++)
206
0
    {
207
0
      if (event->EventHandlers[index])
208
0
      {
209
0
        event->EventHandlers[index](context, e);
210
0
        status++;
211
0
      }
212
0
    }
213
0
  }
214
215
0
  return status;
216
0
}
217
218
/**
219
 * Construction, Destruction
220
 */
221
222
wPubSub* PubSub_New(BOOL synchronized)
223
0
{
224
0
  wPubSub* pubSub = (wPubSub*)calloc(1, sizeof(wPubSub));
225
226
0
  if (!pubSub)
227
0
    return NULL;
228
229
0
  pubSub->synchronized = synchronized;
230
231
0
  if (pubSub->synchronized && !InitializeCriticalSectionAndSpinCount(&pubSub->lock, 4000))
232
0
    goto fail;
233
234
0
  pubSub->count = 0;
235
0
  pubSub->size = 64;
236
237
0
  pubSub->events = (wEventType*)calloc(pubSub->size, sizeof(wEventType));
238
0
  if (!pubSub->events)
239
0
    goto fail;
240
241
0
  return pubSub;
242
0
fail:
243
0
  PubSub_Free(pubSub);
244
0
  return NULL;
245
0
}
246
247
void PubSub_Free(wPubSub* pubSub)
248
0
{
249
0
  if (pubSub)
250
0
  {
251
0
    if (pubSub->synchronized)
252
0
      DeleteCriticalSection(&pubSub->lock);
253
254
0
    free(pubSub->events);
255
0
    free(pubSub);
256
0
  }
257
0
}