Coverage Report

Created: 2026-02-26 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/utils/collections/PubSub.c
Line
Count
Source
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
23.7k
{
60
23.7k
  WINPR_ASSERT(pubSub);
61
23.7k
  if (pubSub->synchronized)
62
23.7k
    EnterCriticalSection(&pubSub->lock);
63
23.7k
}
64
65
void PubSub_Unlock(wPubSub* pubSub)
66
23.7k
{
67
23.7k
  WINPR_ASSERT(pubSub);
68
23.7k
  if (pubSub->synchronized)
69
23.7k
    LeaveCriticalSection(&pubSub->lock);
70
23.7k
}
71
72
wEventType* PubSub_FindEventType(wPubSub* pubSub, const char* EventName)
73
15.6k
{
74
15.6k
  wEventType* event = NULL;
75
76
15.6k
  WINPR_ASSERT(pubSub);
77
15.6k
  WINPR_ASSERT(EventName);
78
140k
  for (size_t index = 0; index < pubSub->count; index++)
79
125k
  {
80
125k
    if (strcmp(pubSub->events[index].EventName, EventName) == 0)
81
743
    {
82
743
      event = &(pubSub->events[index]);
83
743
      break;
84
743
    }
85
125k
  }
86
87
15.6k
  return event;
88
15.6k
}
89
90
void PubSub_AddEventTypes(wPubSub* pubSub, wEventType* events, size_t count)
91
8.02k
{
92
8.02k
  WINPR_ASSERT(pubSub);
93
8.02k
  WINPR_ASSERT(events || (count == 0));
94
8.02k
  if (pubSub->synchronized)
95
8.02k
    PubSub_Lock(pubSub);
96
97
8.02k
  const size_t required = pubSub->count + count;
98
8.02k
  WINPR_ASSERT((required >= pubSub->count) && (required >= count));
99
100
8.02k
  if (required >= pubSub->size)
101
0
  {
102
0
    size_t new_size = pubSub->size;
103
0
    do
104
0
    {
105
0
      WINPR_ASSERT(new_size <= SIZE_MAX - 128ull);
106
0
      new_size += 128ull;
107
0
    } while (new_size <= required);
108
109
0
    wEventType* new_event = (wEventType*)realloc(pubSub->events, new_size * sizeof(wEventType));
110
0
    if (!new_event)
111
0
      goto fail;
112
0
    pubSub->size = new_size;
113
0
    pubSub->events = new_event;
114
0
  }
115
116
8.02k
  CopyMemory(&pubSub->events[pubSub->count], events, count * sizeof(wEventType));
117
8.02k
  pubSub->count += count;
118
119
8.02k
fail:
120
8.02k
  if (pubSub->synchronized)
121
8.02k
    PubSub_Unlock(pubSub);
122
8.02k
}
123
124
int PubSub_Subscribe(wPubSub* pubSub, const char* EventName, ...)
125
0
{
126
0
  wEventType* event = NULL;
127
0
  int status = -1;
128
0
  WINPR_ASSERT(pubSub);
129
130
0
  va_list ap = WINPR_C_ARRAY_INIT;
131
0
  va_start(ap, EventName);
132
0
  pEventHandler EventHandler = va_arg(ap, pEventHandler);
133
134
0
  if (pubSub->synchronized)
135
0
    PubSub_Lock(pubSub);
136
137
0
  event = PubSub_FindEventType(pubSub, EventName);
138
139
0
  if (event)
140
0
  {
141
0
    status = 0;
142
143
0
    if (event->EventHandlerCount < MAX_EVENT_HANDLERS)
144
0
      event->EventHandlers[event->EventHandlerCount++] = EventHandler;
145
0
    else
146
0
      status = -1;
147
0
  }
148
149
0
  if (pubSub->synchronized)
150
0
    PubSub_Unlock(pubSub);
151
152
0
  va_end(ap);
153
0
  return status;
154
0
}
155
156
int PubSub_Unsubscribe(wPubSub* pubSub, const char* EventName, ...)
157
0
{
158
0
  wEventType* event = NULL;
159
0
  int status = -1;
160
0
  WINPR_ASSERT(pubSub);
161
0
  WINPR_ASSERT(EventName);
162
163
0
  va_list ap = WINPR_C_ARRAY_INIT;
164
0
  va_start(ap, EventName);
165
0
  pEventHandler EventHandler = va_arg(ap, pEventHandler);
166
167
0
  if (pubSub->synchronized)
168
0
    PubSub_Lock(pubSub);
169
170
0
  event = PubSub_FindEventType(pubSub, EventName);
171
172
0
  if (event)
173
0
  {
174
0
    status = 0;
175
176
0
    for (size_t index = 0; index < event->EventHandlerCount; index++)
177
0
    {
178
0
      if (event->EventHandlers[index] == EventHandler)
179
0
      {
180
0
        event->EventHandlers[index] = NULL;
181
0
        event->EventHandlerCount--;
182
0
        MoveMemory((void*)&event->EventHandlers[index],
183
0
                   (void*)&event->EventHandlers[index + 1],
184
0
                   (MAX_EVENT_HANDLERS - index - 1) * sizeof(pEventHandler));
185
0
        status = 1;
186
0
      }
187
0
    }
188
0
  }
189
190
0
  if (pubSub->synchronized)
191
0
    PubSub_Unlock(pubSub);
192
193
0
  va_end(ap);
194
0
  return status;
195
0
}
196
197
int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, const wEventArgs* e)
198
15.6k
{
199
15.6k
  wEventType* event = NULL;
200
15.6k
  int status = -1;
201
202
15.6k
  if (!pubSub)
203
0
    return -1;
204
15.6k
  WINPR_ASSERT(e);
205
206
15.6k
  if (pubSub->synchronized)
207
15.6k
    PubSub_Lock(pubSub);
208
209
15.6k
  event = PubSub_FindEventType(pubSub, EventName);
210
211
15.6k
  if (pubSub->synchronized)
212
15.6k
    PubSub_Unlock(pubSub);
213
214
15.6k
  if (event)
215
743
  {
216
743
    status = 0;
217
218
743
    for (size_t index = 0; index < event->EventHandlerCount; index++)
219
0
    {
220
0
      if (event->EventHandlers[index])
221
0
      {
222
0
        event->EventHandlers[index](context, e);
223
0
        status++;
224
0
      }
225
0
    }
226
743
  }
227
228
15.6k
  return status;
229
15.6k
}
230
231
/**
232
 * Construction, Destruction
233
 */
234
235
wPubSub* PubSub_New(BOOL synchronized)
236
14.4k
{
237
14.4k
  wPubSub* pubSub = (wPubSub*)calloc(1, sizeof(wPubSub));
238
239
14.4k
  if (!pubSub)
240
0
    return NULL;
241
242
14.4k
  pubSub->synchronized = synchronized;
243
244
14.4k
  if (pubSub->synchronized && !InitializeCriticalSectionAndSpinCount(&pubSub->lock, 4000))
245
0
    goto fail;
246
247
14.4k
  pubSub->count = 0;
248
14.4k
  pubSub->size = 64;
249
250
14.4k
  pubSub->events = (wEventType*)calloc(pubSub->size, sizeof(wEventType));
251
14.4k
  if (!pubSub->events)
252
0
    goto fail;
253
254
14.4k
  return pubSub;
255
0
fail:
256
0
  WINPR_PRAGMA_DIAG_PUSH
257
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
258
0
  PubSub_Free(pubSub);
259
0
  WINPR_PRAGMA_DIAG_POP
260
0
  return NULL;
261
14.4k
}
262
263
void PubSub_Free(wPubSub* pubSub)
264
14.4k
{
265
14.4k
  if (pubSub)
266
14.4k
  {
267
14.4k
    if (pubSub->synchronized)
268
14.4k
      DeleteCriticalSection(&pubSub->lock);
269
270
14.4k
    free(pubSub->events);
271
14.4k
    free(pubSub);
272
14.4k
  }
273
14.4k
}