• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OpenLightingProject / ola / 16900099157

12 Aug 2025 05:43AM UTC coverage: 45.72% (-0.02%) from 45.742%
16900099157

Pull #2016

github

web-flow
Merge c368ef6ae into eaf937e80
Pull Request #2016: Bump actions/checkout from 4 to 5

7586 of 17462 branches covered (43.44%)

22424 of 49046 relevant lines covered (45.72%)

51.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.52
/common/utils/DmxBuffer.cpp
1
/*
2
 * This library is free software; you can redistribute it and/or
3
 * modify it under the terms of the GNU Lesser General Public
4
 * License as published by the Free Software Foundation; either
5
 * version 2.1 of the License, or (at your option) any later version.
6
 *
7
 * This library is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10
 * Lesser General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU Lesser General Public
13
 * License along with this library; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
 *
16
 * DmxBuffer.cpp
17
 * The DmxBuffer class
18
 * Copyright (C) 2005 Simon Newton
19
 *
20
 * This implements a DmxBuffer which uses copy-on-write and delayed init.
21
 *
22
 * A DmxBuffer can hold up to 512 bytes of channel information. The amount of
23
 * valid data is returned by calling Size().
24
 */
25

26
/**
27
 * @file DmxBuffer.cpp
28
 */
29

30
#include <string.h>
31
#include <algorithm>
32
#include <iostream>
33
#include <string>
34
#include <vector>
35
#include "ola/Constants.h"
36
#include "ola/DmxBuffer.h"
37
#include "ola/Logging.h"
38
#include "ola/StringUtils.h"
39

40
namespace ola {
41

42
using std::min;
43
using std::max;
44
using std::string;
45
using std::vector;
46

47
DmxBuffer::DmxBuffer()
692✔
48
    : m_ref_count(NULL),
692✔
49
      m_copy_on_write(false),
692✔
50
      m_data(NULL),
692✔
51
      m_length(0) {
692✔
52
}
692✔
53

54

55
DmxBuffer::DmxBuffer(const DmxBuffer &other)
17✔
56
    : m_ref_count(NULL),
17✔
57
      m_copy_on_write(false),
17✔
58
      m_data(NULL),
17✔
59
      m_length(0) {
17✔
60

61
  if (other.m_data && other.m_ref_count) {
17✔
62
    CopyFromOther(other);
16✔
63
  }
64
}
17✔
65

66

67
DmxBuffer::DmxBuffer(const uint8_t *data, unsigned int length)
37✔
68
    : m_ref_count(0),
37✔
69
      m_copy_on_write(false),
37✔
70
      m_data(NULL),
37✔
71
      m_length(0) {
37✔
72
  Set(data, length);
37✔
73
}
37✔
74

75

76
DmxBuffer::DmxBuffer(const string &data)
13✔
77
    : m_ref_count(0),
13✔
78
      m_copy_on_write(false),
13✔
79
      m_data(NULL),
13✔
80
      m_length(0) {
13✔
81
    Set(data);
13✔
82
}
13✔
83

84

85
DmxBuffer::~DmxBuffer() {
759✔
86
  CleanupMemory();
759✔
87
}
759✔
88

89

90
DmxBuffer& DmxBuffer::operator=(const DmxBuffer &other) {
183✔
91
  if (this != &other) {
183✔
92
    CleanupMemory();
182✔
93
    if (other.m_data) {
182✔
94
      CopyFromOther(other);
178✔
95
    }
96
  }
97
  return *this;
183✔
98
}
99

100

101
bool DmxBuffer::operator==(const DmxBuffer &other) const {
67✔
102
  return (m_length == other.m_length &&
67✔
103
          (m_data == other.m_data ||
65✔
104
           0 == memcmp(m_data, other.m_data, m_length)));
54✔
105
}
106

107

108
bool DmxBuffer::operator!=(const DmxBuffer &other) const {
2✔
109
  return !(*this == other);
2✔
110
}
111

112

113
bool DmxBuffer::HTPMerge(const DmxBuffer &other) {
16✔
114
  if (!m_data) {
16✔
115
    if (!Init())
1✔
116
      return false;
117
  }
118
  DuplicateIfNeeded();
16✔
119

120
  unsigned int other_length = min((unsigned int) DMX_UNIVERSE_SIZE,
16✔
121
                                  other.m_length);
16✔
122
  unsigned int merge_length = min(m_length, other.m_length);
16✔
123

124
  for (unsigned int i = 0; i < merge_length; i++) {
63✔
125
    m_data[i] = max(m_data[i], other.m_data[i]);
69✔
126
  }
127

128
  if (other_length > m_length) {
16✔
129
    memcpy(m_data + merge_length, other.m_data + merge_length,
8✔
130
           other_length - merge_length);
8✔
131
    m_length = other_length;
8✔
132
  }
133
  return true;
×
134
}
135

136

137
bool DmxBuffer::Set(const uint8_t *data, unsigned int length) {
131✔
138
  if (!data)
131✔
139
    return false;
140

141
  if (m_copy_on_write)
130✔
142
    CleanupMemory();
4✔
143
  if (!m_data) {
130✔
144
    if (!Init())
100✔
145
      return false;
146
  }
147
  m_length = min(length, (unsigned int) DMX_UNIVERSE_SIZE);
130✔
148
  memcpy(m_data, data, m_length);
130✔
149
  return true;
130✔
150
}
151

152

153
bool DmxBuffer::Set(const string &data) {
30✔
154
  return Set(reinterpret_cast<const uint8_t*>(data.data()), data.length());
30✔
155
}
156

157

158
bool DmxBuffer::Set(const DmxBuffer &other) {
21✔
159
  return Set(other.m_data, other.m_length);
21✔
160
}
161

162

163
bool DmxBuffer::SetFromString(const string &input) {
170✔
164
  unsigned int i = 0;
170✔
165
  vector<string> dmx_values;
170✔
166
  vector<string>::const_iterator iter;
170✔
167

168
  if (m_copy_on_write)
170✔
169
    CleanupMemory();
3✔
170
  if (!m_data)
170✔
171
    if (!Init())
108✔
172
      return false;
173

174
  if (input.empty()) {
170✔
175
    m_length = 0;
1✔
176
    return true;
1✔
177
  }
178
  StringSplit(input, &dmx_values, ",");
169✔
179
  for (iter = dmx_values.begin();
169✔
180
      iter != dmx_values.end() && i < DMX_UNIVERSE_SIZE; ++iter, ++i) {
25,196✔
181
    m_data[i] = atoi(iter->data());
25,027✔
182
  }
183
  m_length = i;
169✔
184
  return true;
169✔
185
}
170✔
186

187

188
bool DmxBuffer::SetRangeToValue(unsigned int offset,
40✔
189
                                uint8_t value,
190
                                unsigned int length) {
191
  if (offset >= DMX_UNIVERSE_SIZE)
40✔
192
    return false;
193

194
  if (!m_data) {
39✔
195
    Blackout();
6✔
196
  }
197

198
  if (offset > m_length)
39✔
199
    return false;
200

201
  DuplicateIfNeeded();
39✔
202

203
  unsigned int copy_length = min(length, DMX_UNIVERSE_SIZE - offset);
39✔
204
  memset(m_data + offset, value, copy_length);
39✔
205
  m_length = max(m_length, offset + copy_length);
39✔
206
  return true;
39✔
207
}
208

209

210
bool DmxBuffer::SetRange(unsigned int offset,
29✔
211
                         const uint8_t *data,
212
                         unsigned int length) {
213
  if (!data || offset >= DMX_UNIVERSE_SIZE)
29✔
214
    return false;
215

216
  if (!m_data) {
27✔
217
    Blackout();
4✔
218
  }
219

220
  if (offset > m_length)
27✔
221
    return false;
222

223
  DuplicateIfNeeded();
25✔
224

225
  unsigned int copy_length = min(length, DMX_UNIVERSE_SIZE - offset);
25✔
226
  memcpy(m_data + offset, data, copy_length);
25✔
227
  m_length = max(m_length, offset + copy_length);
25✔
228
  return true;
25✔
229
}
230

231

232
void DmxBuffer::SetChannel(unsigned int channel, uint8_t data) {
28✔
233
  if (channel >= DMX_UNIVERSE_SIZE)
28✔
234
    return;
235

236
  if (!m_data) {
27✔
237
    Blackout();
3✔
238
  }
239

240
  if (channel > m_length) {
27✔
241
    OLA_WARN << "Attempting to set channel " << channel << " when length is "
4✔
242
             << m_length;
2✔
243
    return;
2✔
244
  }
245

246
  DuplicateIfNeeded();
25✔
247
  m_data[channel] = data;
25✔
248
  m_length = max(channel+1, m_length);
25✔
249
}
250

251

252
void DmxBuffer::Get(uint8_t *data, unsigned int *length) const {
32✔
253
  if (m_data) {
32✔
254
    *length = min(*length, m_length);
27✔
255
    memcpy(data, m_data, *length);
27✔
256
  } else {
257
    *length = 0;
5✔
258
  }
259
}
32✔
260

261

262
void DmxBuffer::GetRange(unsigned int slot, uint8_t *data,
13✔
263
                         unsigned int *length) const {
264
  if (slot >= m_length) {
13✔
265
    *length = 0;
×
266
    return;
×
267
  }
268

269
  if (m_data) {
13✔
270
    *length = min(*length, m_length - slot);
13✔
271
    memcpy(data, m_data + slot, *length);
13✔
272
  } else {
273
    *length = 0;
×
274
  }
275
}
276

277

278
uint8_t DmxBuffer::Get(unsigned int channel) const {
4,246✔
279
  if (m_data && channel < m_length) {
4,246✔
280
    return m_data[channel];
4,244✔
281
  } else {
282
    return 0;
283
  }
284
}
285

286

287
string DmxBuffer::Get() const {
32✔
288
  string data;
32✔
289
  data.append(reinterpret_cast<char*>(m_data), m_length);
32✔
290
  return data;
32✔
291
}
×
292

293

294
bool DmxBuffer::Blackout() {
21✔
295
  if (m_copy_on_write) {
21✔
296
    CleanupMemory();
×
297
  }
298
  if (!m_data) {
21✔
299
    if (!Init()) {
21✔
300
      return false;
301
    }
302
  }
303
  memset(m_data, DMX_MIN_SLOT_VALUE, DMX_UNIVERSE_SIZE);
21✔
304
  m_length = DMX_UNIVERSE_SIZE;
21✔
305
  return true;
21✔
306
}
307

308

309
void DmxBuffer::Reset() {
12✔
310
  if (m_data) {
12✔
311
    m_length = 0;
11✔
312
  }
313
}
12✔
314

315

316
string DmxBuffer::ToString() const {
18✔
317
  if (!m_data) {
18✔
318
    return "";
1✔
319
  }
320

321
  // TODO(Peter): Change to the uint8_t version of StringJoin
322
  std::ostringstream str;
17✔
323
  for (unsigned int i = 0; i < Size(); i++) {
120✔
324
    if (i) {
103✔
325
      str << ",";
86✔
326
    }
327
    str << static_cast<int>(m_data[i]);
103✔
328
  }
329
  return str.str();
17✔
330
}
17✔
331

332

333
/*
334
 * Allocate memory
335
 * @return true on success, otherwise raises an exception
336
 */
337
bool DmxBuffer::Init() {
244✔
338
  m_data = new uint8_t[DMX_UNIVERSE_SIZE];
244✔
339
  m_ref_count = new unsigned int;
244✔
340
  m_length = 0;
244✔
341
  *m_ref_count = 1;
244✔
342
  return true;
244✔
343
}
344

345

346
/*
347
 * Called before making a change, this duplicates the data if required.
348
 * @return true on Duplication, and false it duplication was not needed
349
 */
350
bool DmxBuffer::DuplicateIfNeeded() {
105✔
351
  if (m_copy_on_write && *m_ref_count == 1) {
105✔
352
    m_copy_on_write = false;
×
353
  }
354

355
  if (m_copy_on_write && *m_ref_count > 1) {
105✔
356
    unsigned int *old_ref_count = m_ref_count;
14✔
357
    uint8_t *original_data = m_data;
14✔
358
    unsigned int length = m_length;
14✔
359
    m_copy_on_write = false;
14✔
360
    if (Init()) {
14✔
361
      Set(original_data, length);
14✔
362
      (*old_ref_count)--;
14✔
363
      return true;
14✔
364
    }
365
    return false;
366
  }
367
  return true;
368
}
369

370

371
/*
372
 * Setup this buffer to point to the data of the other buffer
373
 * @param other the source buffer
374
 * @pre other.m_data and other.m_ref_count are not NULL
375
 */
376
void DmxBuffer::CopyFromOther(const DmxBuffer &other) {
194✔
377
  m_copy_on_write = true;
194✔
378
  other.m_copy_on_write = true;
194✔
379
  m_ref_count = other.m_ref_count;
194✔
380
  (*m_ref_count)++;
194✔
381
  m_data = other.m_data;
194✔
382
  m_length = other.m_length;
194✔
383
}
194✔
384

385

386
/*
387
 * Decrement the ref count by one and free the memory if required
388
 */
389
void DmxBuffer::CleanupMemory() {
948✔
390
  if (m_ref_count && m_data) {
948✔
391
    (*m_ref_count)--;
424✔
392
    if (!*m_ref_count) {
424✔
393
      delete[] m_data;
244✔
394
      delete m_ref_count;
244✔
395
    }
396
    m_data = NULL;
424✔
397
    m_ref_count = NULL;
424✔
398
    m_length = 0;
424✔
399
  }
400
}
948✔
401

402
std::ostream& operator<<(std::ostream &out, const DmxBuffer &data) {
1✔
403
  return out << data.ToString();
2✔
404
}
405
}  // namespace  ola
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc