Coverage Report

Created: 2025-07-01 06:08

/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
0
    {
32
0
      LogString key, element;
33
0
      LexemType lexemType = BEGIN;
34
0
      logchar c;
35
0
      bool finished = false;
36
37
0
      if (!get(in, c))
38
0
      {
39
0
        return;
40
0
      }
41
42
0
      while (!finished)
43
0
      {
44
0
        switch (lexemType)
45
0
        {
46
0
          case BEGIN:
47
0
            switch (c)
48
0
            {
49
0
              case 0x20: // ' '
50
0
              case 0x09: // '\t'
51
0
              case 0x0A: // '\n'
52
0
              case 0x0D: // '\r'
53
0
                if (!get(in, c))
54
0
                {
55
0
                  finished = true;
56
0
                }
57
58
0
                break;
59
60
0
              case 0x23: // '#'
61
0
              case 0x21: // '!'
62
0
                lexemType = COMMENT;
63
64
0
                if (!get(in, c))
65
0
                {
66
0
                  finished = true;
67
0
                }
68
69
0
                break;
70
71
0
              default:
72
0
                lexemType = KEY;
73
0
                break;
74
0
            }
75
76
0
            break;
77
78
0
          case KEY:
79
0
            switch (c)
80
0
            {
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
0
              case 0x3D: // '='
95
0
                lexemType = DELIMITER;
96
97
0
                if (!get(in, c))
98
0
                {
99
0
                  finished = true;
100
0
                }
101
102
0
                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
0
              default:
119
0
                key.append(1, c);
120
121
0
                if (!get(in, c))
122
0
                {
123
0
                  finished = true;
124
0
                }
125
126
0
                break;
127
0
            }
128
129
0
            break;
130
131
0
          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
0
          case DELIMITER:
208
0
            switch (c)
209
0
            {
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
0
              default:
222
0
                lexemType = ELEMENT;
223
0
                break;
224
0
            }
225
226
0
            break;
227
228
0
          case ELEMENT:
229
0
            switch (c)
230
0
            {
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
0
              case 0x0A: // '\n'
242
0
              case 0x0D: // '\r'
243
                // key associated with an empty string element
244
0
                properties.setProperty(key, element);
245
0
                key.erase(key.begin(), key.end());
246
0
                element.erase(element.begin(), element.end());
247
0
                lexemType = BEGIN;
248
249
0
                if (!get(in, c))
250
0
                {
251
0
                  finished = true;
252
0
                }
253
254
0
                break;
255
256
0
              default:
257
0
                element.append(1, c);
258
259
0
                if (!get(in, c))
260
0
                {
261
0
                  finished = true;
262
0
                }
263
264
0
                break;
265
0
            }
266
267
0
            break;
268
269
0
          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
0
          case COMMENT:
347
0
            if (c == 0x0A || c == 0x0D)
348
0
            {
349
0
              lexemType = BEGIN;
350
0
            }
351
352
0
            if (!get(in, c))
353
0
            {
354
0
              finished = true;
355
0
            }
356
357
0
            break;
358
0
        }
359
0
      }
360
361
0
      if (!key.empty())
362
0
      {
363
0
        properties.setProperty(key, element);
364
0
      }
365
0
    }
366
367
  protected:
368
    static bool get(LogString& in, logchar& c)
369
0
    {
370
0
      if (in.empty())
371
0
      {
372
0
        c = 0;
373
0
        return false;
374
0
      }
375
376
0
      c = in[0];
377
0
      in.erase(in.begin());
378
0
      return true;
379
0
    }
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
0
Properties::Properties() : properties(new PropertyMap())
399
0
{
400
0
}
401
402
Properties::~Properties()
403
0
{
404
0
  delete properties;
405
0
}
406
407
LogString Properties::setProperty(const LogString& key, const LogString& value)
408
0
{
409
0
  return put(key, value);
410
0
}
411
412
LogString Properties::put(const LogString& key, const LogString& value)
413
0
{
414
0
  LogString oldValue((*properties)[key]);
415
0
  (*properties)[key] = value;
416
0
  return oldValue;
417
0
}
418
419
LogString Properties::getProperty(const LogString& key) const
420
0
{
421
0
  return get(key);
422
0
}
423
424
LogString Properties::get(const LogString& key) const
425
0
{
426
0
  PropertyMap::const_iterator it = properties->find(key);
427
0
  return (it != properties->end()) ? it->second : LogString();
428
0
}
429
430
void Properties::load(InputStreamPtr inStream)
431
0
{
432
0
  Pool pool;
433
0
  auto lineReader = std::make_shared<InputStreamReader>(inStream, CharsetDecoder::getISOLatinDecoder());
434
0
  LogString contents = lineReader->read(pool);
435
0
  properties->clear();
436
0
  PropertyParser parser;
437
0
  parser.parse(contents, *this);
438
0
}
439
440
std::vector<LogString> Properties::propertyNames() const
441
0
{
442
0
  std::vector<LogString> names;
443
0
  names.reserve(properties->size());
444
445
0
  for (auto const& item : *properties)
446
0
  {
447
0
    const LogString& key = item.first;
448
0
    names.push_back(key);
449
0
  }
450
451
0
  return names;
452
0
}
453