Coverage Report

Created: 2025-08-26 06:48

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