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

OpenLightingProject / ola / 22869778617

09 Mar 2026 06:57PM UTC coverage: 45.174% (-0.7%) from 45.909%
22869778617

Pull #2033

github

web-flow
Merge 15948e72b into 3566c28d9
Pull Request #2033: Fix Sid dependencies and autopkgtest

8051 of 18455 branches covered (43.63%)

20598 of 45597 relevant lines covered (45.17%)

51.23 hits per line

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

87.01
/common/rdm/StringMessageBuilder.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
 * StringMessageBuilder.cpp
17
 * Builds a Message object from a list of strings & a Descriptor.
18
 * Copyright (C) 2011 Simon Newton
19
 */
20

21

22
#include <ola/Logging.h>
23
#include <ola/StringUtils.h>
24
#include <ola/messaging/Descriptor.h>
25
#include <ola/messaging/Message.h>
26
#include <ola/network/IPV4Address.h>
27
#include <ola/network/MACAddress.h>
28
#include <ola/rdm/StringMessageBuilder.h>
29
#include <ola/rdm/UID.h>
30
#include <memory>
31
#include <string>
32
#include <vector>
33

34
#include "common/rdm/GroupSizeCalculator.h"
35

36
namespace ola {
37
namespace rdm {
38

39
using ola::messaging::MessageFieldInterface;
40
using ola::rdm::UID;
41
using std::auto_ptr;
42
using std::string;
43
using std::vector;
44

45

46
StringMessageBuilder::StringMessageBuilder()
27✔
47
    : m_offset(0),
27✔
48
      m_input_size(0),
27✔
49
      m_group_instance_count(0),
27✔
50
      m_error(false) {
27✔
51
}
27✔
52

53

54
/**
55
 * @brief Clean up
56
 */
57
StringMessageBuilder::~StringMessageBuilder() {
27✔
58
  CleanUpVector();
27✔
59
}
27✔
60

61

62
/**
63
 * @brief Get the Message object that this Builder created
64
 *
65
 * This method is *not* re-entrant.
66
 * @param inputs the string inputs provided to build the Message
67
 * @param descriptor the descriptor to use to build the Message
68
 * @returns a Message object, or NULL if the inputs failed.
69
 */
70
const ola::messaging::Message *StringMessageBuilder::GetMessage(
27✔
71
    const vector<string> &inputs,
72
    const ola::messaging::Descriptor *descriptor) {
73
  InitVars(inputs);
27✔
74

75
  // first figure out if the number of inputs provided matches the number
76
  // expected by the descriptor. This accounts for repeating groups.
77
  GroupSizeCalculator calculator;
27✔
78
  GroupSizeCalculator::calculator_state state = calculator.CalculateGroupSize(
27✔
79
      inputs.size(),
27✔
80
      descriptor,
81
      &m_group_instance_count);
82

83
  switch (state) {
27✔
84
    case GroupSizeCalculator::INSUFFICIENT_TOKENS:
1✔
85
      SetError("Insufficient tokens");
1✔
86
      return NULL;
1✔
87
    case GroupSizeCalculator::EXTRA_TOKENS:
1✔
88
      SetError("Extra tokens");
1✔
89
      return NULL;
1✔
90
    case GroupSizeCalculator::MISMATCHED_TOKENS:
×
91
      SetError("Mismatched tokens");
×
92
      return NULL;
×
93
    case GroupSizeCalculator::MULTIPLE_VARIABLE_GROUPS:
×
94
      SetError("Multiple variable groups");
×
95
      return NULL;
×
96
    case GroupSizeCalculator::NESTED_VARIABLE_GROUPS:
×
97
      SetError("Nested variable groups");
×
98
      return NULL;
×
99
    case GroupSizeCalculator::SINGLE_VARIABLE_GROUP:
100
    case GroupSizeCalculator::NO_VARIABLE_GROUPS:
101
      break;
102
  }
103

104
  // now we now that this list of inputs can be parsed, and we know the number
105
  // of instances of a repeating group if there is one.
106
  descriptor->Accept(this);
25✔
107

108
  if (m_error) {
25✔
109
    OLA_WARN << "Error building message, field is: " << m_error_string;
9✔
110
    return NULL;
9✔
111
  }
112

113
  if (m_groups.size() != 1) {
16✔
114
    OLA_WARN << "Mismatched stack, size was " << m_groups.size();
×
115
    return NULL;
×
116
  }
117

118
  const ola::messaging::Message *message =  new ola::messaging::Message(
16✔
119
      m_groups.top());
16✔
120
  m_groups.top().clear();
16✔
121
  return message;
122
}
27✔
123

124

125
/**
126
 * Bool values can be true,false,0,1
127
 */
128
void StringMessageBuilder::Visit(
23✔
129
    const ola::messaging::BoolFieldDescriptor *descriptor) {
130
  if (StopParsing())
23✔
131
    return;
2✔
132

133
  bool value = false;
23✔
134
  bool valid = false;
23✔
135
  string token = m_inputs[m_offset++];
23✔
136
  ola::StringTrim(&token);
23✔
137
  ola::ToLower(&token);
23✔
138

139
  if (token == "true") {
23✔
140
    valid = value = true;
141
  } else if (token == "false") {
9✔
142
    value = false;
143
    valid = true;
144
  }
145

146
  if (!valid) {
4✔
147
    uint8_t int_value;
4✔
148
    if (ola::StringToInt(token, &int_value)) {
4✔
149
      if (int_value == 1) {
3✔
150
        valid = value = true;
151
      } else if (int_value == 0) {
2✔
152
        valid = true;
1✔
153
        value = false;
1✔
154
      }
155
    }
156
  }
157

158
  if (!valid) {
18✔
159
    SetError(descriptor->Name());
2✔
160
    return;
2✔
161
  }
162

163
  m_groups.top().push_back(
21✔
164
      new ola::messaging::BoolMessageField(descriptor, value));
21✔
165
}
23✔
166

167

168
/**
169
 * IPV4 Addresses
170
 */
171
void StringMessageBuilder::Visit(
2✔
172
    const ola::messaging::IPV4FieldDescriptor *descriptor) {
173
  if (StopParsing())
2✔
174
    return;
×
175

176
  string token = m_inputs[m_offset++];
2✔
177
  ola::network::IPV4Address ip_address;
2✔
178
  if (!ola::network::IPV4Address::FromString(token, &ip_address)) {
2✔
179
    SetError(descriptor->Name());
×
180
    return;
×
181
  }
182

183
  m_groups.top().push_back(
2✔
184
      new ola::messaging::IPV4MessageField(descriptor, ip_address));
2✔
185
}
2✔
186

187

188
/**
189
 * MAC Addresses
190
 */
191
void StringMessageBuilder::Visit(
2✔
192
    const ola::messaging::MACFieldDescriptor *descriptor) {
193
  if (StopParsing())
2✔
194
    return;
×
195

196
  string token = m_inputs[m_offset++];
2✔
197
  ola::network::MACAddress mac_address;
2✔
198
  if (!ola::network::MACAddress::FromString(token, &mac_address)) {
2✔
199
    SetError(descriptor->Name());
×
200
    return;
×
201
  }
202

203
  m_groups.top().push_back(
2✔
204
      new ola::messaging::MACMessageField(descriptor, mac_address));
4✔
205
}
2✔
206

207

208
/**
209
 * UIDs.
210
 */
211
void StringMessageBuilder::Visit(
1✔
212
    const ola::messaging::UIDFieldDescriptor *descriptor) {
213
  if (StopParsing())
1✔
214
    return;
×
215

216
  string token = m_inputs[m_offset++];
1✔
217
  auto_ptr<UID> uid(UID::FromString(token));
1✔
218

219
  if (!uid.get()) {
1✔
220
    SetError(descriptor->Name());
×
221
    return;
×
222
  }
223

224
  m_groups.top().push_back(
1✔
225
      new ola::messaging::UIDMessageField(descriptor, *uid));
1✔
226
}
1✔
227

228

229
/**
230
 * Handle strings
231
 */
232
void StringMessageBuilder::Visit(
7✔
233
    const ola::messaging::StringFieldDescriptor *descriptor) {
234
  if (StopParsing())
7✔
235
    return;
236

237
  const string &token = m_inputs[m_offset++];
7✔
238
  if (descriptor->MaxSize() != 0 &&
7✔
239
      token.size() > descriptor->MaxSize()) {
7✔
240
    SetError(descriptor->Name());
1✔
241
    return;
1✔
242
  }
243

244
  m_groups.top().push_back(
6✔
245
      new ola::messaging::StringMessageField(descriptor, token));
12✔
246
}
247

248

249
/**
250
 * uint8
251
 */
252
void StringMessageBuilder::Visit(
26✔
253
    const ola::messaging::UInt8FieldDescriptor *descriptor) {
254
  VisitInt(descriptor);
26✔
255
}
26✔
256

257

258
void StringMessageBuilder::Visit(
13✔
259
    const ola::messaging::UInt16FieldDescriptor *descriptor) {
260
  VisitInt(descriptor);
13✔
261
}
13✔
262

263

264
void StringMessageBuilder::Visit(
10✔
265
    const ola::messaging::UInt32FieldDescriptor *descriptor) {
266
  VisitInt(descriptor);
10✔
267
}
10✔
268

269

270
void StringMessageBuilder::Visit(
6✔
271
    const ola::messaging::Int8FieldDescriptor *descriptor) {
272
  VisitInt(descriptor);
6✔
273
}
6✔
274

275

276
void StringMessageBuilder::Visit(
6✔
277
    const ola::messaging::Int16FieldDescriptor *descriptor) {
278
  VisitInt(descriptor);
6✔
279
}
6✔
280

281

282
void StringMessageBuilder::Visit(
3✔
283
    const ola::messaging::Int32FieldDescriptor *descriptor) {
284
  VisitInt(descriptor);
3✔
285
}
3✔
286

287

288
/**
289
 * Visit a group
290
 */
291
void StringMessageBuilder::Visit(
10✔
292
    const ola::messaging::FieldDescriptorGroup *descriptor) {
293

294
  unsigned int iterations = descriptor->FixedSize() ? descriptor->MinBlocks() :
10✔
295
    m_group_instance_count;
10✔
296

297
  for (unsigned int i = 0; i < iterations; ++i) {
30✔
298
    vector<const MessageFieldInterface*> fields;
20✔
299
    m_groups.push(fields);
20✔
300

301
    for (unsigned int j = 0; j < descriptor->FieldCount(); ++j) {
54✔
302
      descriptor->GetField(j)->Accept(this);
68✔
303
    }
304

305
    const vector<const MessageFieldInterface*> &populated_fields =
20✔
306
        m_groups.top();
20✔
307
    const ola::messaging::MessageFieldInterface *message =
20✔
308
        new ola::messaging::GroupMessageField(descriptor, populated_fields);
20✔
309
    m_groups.pop();
20✔
310
    m_groups.top().push_back(message);
20✔
311
  }
20✔
312
}
10✔
313

314

315
/**
316
 * This is a no-op since we handle descending ourselves in Visit()
317
 */
318
void StringMessageBuilder::PostVisit(
10✔
319
    const ola::messaging::FieldDescriptorGroup *descriptor) {
320
  (void) descriptor;
10✔
321
}
10✔
322

323

324
bool StringMessageBuilder::StopParsing() const {
99✔
325
  return m_error ||  m_offset >= m_input_size;
99✔
326
}
327

328

329
void StringMessageBuilder::SetError(const string &error) {
11✔
330
  m_error = true;
11✔
331
  m_error_string = error;
11✔
332
}
11✔
333

334

335
template<typename type>
336
void StringMessageBuilder::VisitInt(
13✔
337
    const ola::messaging::IntegerFieldDescriptor<type> *descriptor) {
338
  if (StopParsing())
13✔
339
    return;
×
340

341
  type int_value;
342
  string input = m_inputs[m_offset++];
13✔
343
  if (descriptor->LookupLabel(input, &int_value) ||
26✔
344
      ola::PrefixedHexStringToInt(input, &int_value) ||
25✔
345
      ola::StringToInt(input, &int_value)) {
12✔
346
    m_groups.top().push_back(
13✔
347
        new ola::messaging::BasicMessageField<type>(descriptor, int_value));
13✔
348
  } else {
349
    SetError(descriptor->Name());
×
350
  }
351
}
13✔
352

353

354
void StringMessageBuilder::InitVars(const vector<string> &inputs) {
27✔
355
  CleanUpVector();
27✔
356
  // add the first fields vector to the stack
357
  vector<const MessageFieldInterface*> fields;
27✔
358
  m_groups.push(fields);
27✔
359

360
  m_inputs = inputs;
27✔
361
  m_input_size = inputs.size();
27✔
362
  m_error = false;
27✔
363
  m_offset = 0;
27✔
364
}
27✔
365

366

367
void StringMessageBuilder::CleanUpVector() {
54✔
368
  while (!m_groups.empty()) {
81✔
369
    const vector<const MessageFieldInterface*> &fields = m_groups.top();
27✔
370
    vector<const MessageFieldInterface*>::const_iterator iter = fields.begin();
27✔
371
    for (; iter != fields.end(); ++iter) {
27✔
372
      delete *iter;
×
373
    }
374
    m_groups.pop();
27✔
375
  }
376
}
54✔
377
}  // namespace rdm
378
}  // 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

© 2026 Coveralls, Inc