Coverage Report

Created: 2026-06-15 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/properties.cpp
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
#include <log4cxx/logstring.h>
19
#include <log4cxx/helpers/properties.h>
20
#include <log4cxx/helpers/inputstreamreader.h>
21
#include <log4cxx/helpers/exception.h>
22
#include <log4cxx/helpers/pool.h>
23
#include <cctype>
24
#include <algorithm>
25
26
using namespace LOG4CXX_NS;
27
using namespace LOG4CXX_NS::helpers;
28
29
template <typename Char>
30
struct Properties::Less
31
{
32
  bool operator()(const std::basic_string<Char>& str1, const std::basic_string<Char>& str2) const
33
0
  {
34
0
    return std::lexicographical_compare
35
0
      ( str1.begin(), str1.end()
36
0
      , str2.begin(), str2.end()
37
0
      , [](Char c1, Char c2)
38
0
        {
39
0
          return std::tolower(static_cast<unsigned char>(c1)) < std::tolower(static_cast<unsigned char>(c2));
40
0
        }
41
0
      );
42
0
  }
43
};
44
45
class PropertyParser
46
{
47
  public:
48
    void parse(LogString& in, Properties& properties)
49
0
    {
50
0
      LogString key, element;
51
0
      LexemType lexemType = BEGIN;
52
0
      logchar c;
53
0
      bool finished = false;
54
55
0
      if (!get(in, c))
56
0
      {
57
0
        return;
58
0
      }
59
60
0
      while (!finished)
61
0
      {
62
0
        switch (lexemType)
63
0
        {
64
0
          case BEGIN:
65
0
            switch (c)
66
0
            {
67
0
              case 0x20: // ' '
68
0
              case 0x09: // '\t'
69
0
              case 0x0A: // '\n'
70
0
              case 0x0D: // '\r'
71
0
                if (!get(in, c))
72
0
                {
73
0
                  finished = true;
74
0
                }
75
76
0
                break;
77
78
0
              case 0x23: // '#'
79
0
              case 0x21: // '!'
80
0
                lexemType = COMMENT;
81
82
0
                if (!get(in, c))
83
0
                {
84
0
                  finished = true;
85
0
                }
86
87
0
                break;
88
89
0
              default:
90
0
                lexemType = KEY;
91
0
                break;
92
0
            }
93
94
0
            break;
95
96
0
          case KEY:
97
0
            switch (c)
98
0
            {
99
0
              case 0x5C: // '\\'
100
0
                lexemType = KEY_ESCAPE;
101
102
0
                if (!get(in, c))
103
0
                {
104
0
                  finished = true;
105
0
                }
106
107
0
                break;
108
109
0
              case 0x09: // '\t'
110
0
              case 0x20: // ' '
111
0
              case 0x3A: // ':'
112
0
              case 0x3D: // '='
113
0
                lexemType = DELIMITER;
114
115
0
                if (!get(in, c))
116
0
                {
117
0
                  finished = true;
118
0
                }
119
120
0
                break;
121
122
0
              case 0x0A:
123
0
              case 0x0D:
124
                // key associated with an empty string element
125
0
                properties.setProperty(key, LogString());
126
0
                key.erase(key.begin(), key.end());
127
0
                lexemType = BEGIN;
128
129
0
                if (!get(in, c))
130
0
                {
131
0
                  finished = true;
132
0
                }
133
134
0
                break;
135
136
0
              default:
137
0
                key.append(1, c);
138
139
0
                if (!get(in, c))
140
0
                {
141
0
                  finished = true;
142
0
                }
143
144
0
                break;
145
0
            }
146
147
0
            break;
148
149
0
          case KEY_ESCAPE:
150
0
            switch (c)
151
0
            {
152
0
              case 0x74: // 't'
153
0
                key.append(1, 0x09);
154
0
                lexemType = KEY;
155
0
                break;
156
157
0
              case 0x6E: // 'n'
158
0
                key.append(1, 0x0A);
159
0
                lexemType = KEY;
160
0
                break;
161
162
0
              case 0x72: // 'r'
163
0
                key.append(1, 0x0D);
164
0
                lexemType = KEY;
165
0
                break;
166
167
0
              case 0x0A: // '\n'
168
0
                lexemType = KEY_CONTINUE;
169
0
                break;
170
171
0
              case 0x0D: // '\r'
172
0
                lexemType = KEY_CONTINUE2;
173
0
                break;
174
175
0
              default:
176
0
                key.append(1, c);
177
0
                lexemType = KEY;
178
0
            }
179
180
0
            if (!get(in, c))
181
0
            {
182
0
              finished = true;
183
0
            }
184
185
0
            break;
186
187
0
          case KEY_CONTINUE:
188
0
            switch (c)
189
0
            {
190
0
              case 0x20:  // ' '
191
0
              case 0x09: //  '\t'
192
0
                if (!get(in, c))
193
0
                {
194
0
                  finished = true;
195
0
                }
196
197
0
                break;
198
199
0
              default:
200
0
                lexemType = KEY;
201
0
                break;
202
0
            }
203
204
0
            break;
205
206
0
          case KEY_CONTINUE2:
207
0
            switch (c)
208
0
            {
209
0
              case 0x0A: // '\n'
210
0
                if (!get(in, c))
211
0
                {
212
0
                  finished = true;
213
0
                }
214
215
0
                lexemType = KEY_CONTINUE;
216
0
                break;
217
218
0
              default:
219
0
                lexemType = KEY_CONTINUE;
220
0
                break;
221
0
            }
222
223
0
            break;
224
225
0
          case DELIMITER:
226
0
            switch (c)
227
0
            {
228
0
              case 0x09: // '\t'
229
0
              case 0x20: // ' '
230
0
              case 0x3A: // ':'
231
0
              case 0x3D: // '='
232
0
                if (!get(in, c))
233
0
                {
234
0
                  finished = true;
235
0
                }
236
237
0
                break;
238
239
0
              default:
240
0
                lexemType = ELEMENT;
241
0
                break;
242
0
            }
243
244
0
            break;
245
246
0
          case ELEMENT:
247
0
            switch (c)
248
0
            {
249
0
              case 0x5C: // '\\'
250
0
                lexemType = ELEMENT_ESCAPE;
251
252
0
                if (!get(in, c))
253
0
                {
254
0
                  finished = true;
255
0
                }
256
257
0
                break;
258
259
0
              case 0x0A: // '\n'
260
0
              case 0x0D: // '\r'
261
                // key associated with an empty string element
262
0
                properties.setProperty(key, element);
263
0
                key.erase(key.begin(), key.end());
264
0
                element.erase(element.begin(), element.end());
265
0
                lexemType = BEGIN;
266
267
0
                if (!get(in, c))
268
0
                {
269
0
                  finished = true;
270
0
                }
271
272
0
                break;
273
274
0
              default:
275
0
                element.append(1, c);
276
277
0
                if (!get(in, c))
278
0
                {
279
0
                  finished = true;
280
0
                }
281
282
0
                break;
283
0
            }
284
285
0
            break;
286
287
0
          case ELEMENT_ESCAPE:
288
0
            switch (c)
289
0
            {
290
0
              case 0x74: // 't'
291
0
                element.append(1, 0x09);
292
0
                lexemType = ELEMENT;
293
0
                break;
294
295
0
              case 0x6E: // 'n'
296
0
                element.append(1, 0x0A);
297
0
                lexemType = ELEMENT;
298
0
                break;
299
300
0
              case 0x72: // 'r'
301
0
                element.append(1, 0x0D);
302
0
                lexemType = ELEMENT;
303
0
                break;
304
305
0
              case 0x0A: // '\n'
306
0
                lexemType = ELEMENT_CONTINUE;
307
0
                break;
308
309
0
              case 0x0D: // '\r'
310
0
                lexemType = ELEMENT_CONTINUE2;
311
0
                break;
312
313
0
              default:
314
0
                element.append(1, c);
315
0
                lexemType = ELEMENT;
316
0
                break;
317
0
            }
318
319
0
            if (!get(in, c))
320
0
            {
321
0
              finished = true;
322
0
            }
323
324
0
            break;
325
326
0
          case ELEMENT_CONTINUE:
327
0
            switch (c)
328
0
            {
329
0
              case 0x20: // ' '
330
0
              case 0x09: // '\t'
331
0
                if (!get(in, c))
332
0
                {
333
0
                  finished = true;
334
0
                }
335
336
0
                break;
337
338
0
              default:
339
0
                lexemType = ELEMENT;
340
0
                break;
341
0
            }
342
343
0
            break;
344
345
0
          case ELEMENT_CONTINUE2:
346
0
            switch (c)
347
0
            {
348
0
              case 0x0A: // '\n'
349
0
                if (!get(in, c))
350
0
                {
351
0
                  finished = true;
352
0
                }
353
354
0
                lexemType = ELEMENT_CONTINUE;
355
0
                break;
356
357
0
              default:
358
0
                lexemType = ELEMENT_CONTINUE;
359
0
                break;
360
0
            }
361
362
0
            break;
363
364
0
          case COMMENT:
365
0
            if (c == 0x0A || c == 0x0D)
366
0
            {
367
0
              lexemType = BEGIN;
368
0
            }
369
370
0
            if (!get(in, c))
371
0
            {
372
0
              finished = true;
373
0
            }
374
375
0
            break;
376
0
        }
377
0
      }
378
379
0
      if (!key.empty())
380
0
      {
381
0
        properties.setProperty(key, element);
382
0
      }
383
0
    }
384
385
  protected:
386
    static bool get(LogString& in, logchar& c)
387
0
    {
388
0
      if (in.empty())
389
0
      {
390
0
        c = 0;
391
0
        return false;
392
0
      }
393
394
0
      c = in[0];
395
0
      in.erase(in.begin());
396
0
      return true;
397
0
    }
398
399
    typedef enum
400
    {
401
      BEGIN,
402
      KEY,
403
      KEY_ESCAPE,
404
      KEY_CONTINUE,
405
      KEY_CONTINUE2,
406
      DELIMITER,
407
      ELEMENT,
408
      ELEMENT_ESCAPE,
409
      ELEMENT_CONTINUE,
410
      ELEMENT_CONTINUE2,
411
      COMMENT
412
    }
413
    LexemType;
414
};
415
416
0
Properties::Properties() : properties(new PropertyMap())
417
0
{
418
0
}
419
420
Properties::Properties(const Properties& other)
421
0
  : properties(new PropertyMap(*other.properties))
422
0
{
423
0
}
424
425
Properties& Properties::operator=(const Properties& other)
426
0
{
427
0
  delete this->properties;
428
0
  this->properties = new PropertyMap(*other.properties);
429
0
  return *this;
430
0
}
431
432
Properties::~Properties()
433
0
{
434
0
  delete properties;
435
0
}
436
437
LogString Properties::setProperty(const LogString& key, const LogString& value)
438
0
{
439
0
  return put(key, value);
440
0
}
441
442
LogString Properties::put(const LogString& key, const LogString& value)
443
0
{
444
0
  LogString oldValue((*properties)[key]);
445
0
  (*properties)[key] = value;
446
0
  return oldValue;
447
0
}
448
449
LogString Properties::getProperty(const LogString& key) const
450
0
{
451
0
  return get(key);
452
0
}
453
454
LogString Properties::get(const LogString& key) const
455
0
{
456
0
  PropertyMap::const_iterator it = properties->find(key);
457
0
  return (it != properties->end()) ? it->second : LogString();
458
0
}
459
460
void Properties::load(InputStreamPtr inStream)
461
0
{
462
0
  auto contents = InputStreamReader(inStream, CharsetDecoder::getISOLatinDecoder()).read();
463
0
  PropertyParser().parse(contents, *this);
464
0
}
465
466
std::vector<LogString> Properties::propertyNames() const
467
0
{
468
0
  std::vector<LogString> names;
469
0
  names.reserve(properties->size());
470
471
0
  for (auto const& item : *properties)
472
0
  {
473
0
    const LogString& key = item.first;
474
0
    names.push_back(key);
475
0
  }
476
477
0
  return names;
478
0
}
479
480
bool Properties::isEmpty() const
481
0
{
482
0
  return properties->empty();
483
0
}