Coverage Report

Created: 2026-09-14 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/id_creator.cc
Line
Count
Source
1
/*
2
 * HEIF codec.
3
 * Copyright (c) 2026 Dirk Farin <dirk.farin@gmail.com>
4
 *
5
 * This file is part of libheif.
6
 *
7
 * libheif is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as
9
 * published by the Free Software Foundation, either version 3 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * libheif is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include "id_creator.h"
22
#include <cstdint>
23
24
namespace {
25
26
// The next free id after 'id', i.e. the value a counter should take once 'id'
27
// has been handed out or reserved. When 'id' is the maximum representable value
28
// there is no larger id, so the counter becomes 0 == "exhausted" and
29
// get_new_id() will refuse to hand out another id. Computing this explicitly
30
// (rather than 'id + 1') keeps the exhausted transition free of the unsigned
31
// wrap that the 'integer' sanitizer flags, while guaranteeing the counter always
32
// moves strictly past 'id' so no id is ever handed out twice.
33
inline uint32_t next_id_after(uint32_t id)
34
256k
{
35
256k
  return id == UINT32_MAX ? 0u : id + 1u;
36
256k
}
37
38
}
39
40
41
Result<uint32_t> IDCreator::get_new_id(Namespace ns)
42
0
{
43
0
  if (m_unif) {
44
0
    if (m_next_id_global == 0) {
45
0
      return Error(heif_error_Usage_error,
46
0
                   heif_suberror_Unspecified,
47
0
                   "ID namespace overflow");
48
0
    }
49
0
    uint32_t id = m_next_id_global;
50
0
    m_next_id_global = next_id_after(id);
51
0
    return id;
52
0
  }
53
54
0
  uint32_t* counter = nullptr;
55
0
  switch (ns) {
56
0
    case Namespace::item:
57
0
      counter = &m_next_id_item;
58
0
      break;
59
0
    case Namespace::track:
60
0
      counter = &m_next_id_track;
61
0
      break;
62
0
    case Namespace::entity_group:
63
0
      counter = &m_next_id_entity_group;
64
0
      break;
65
0
  }
66
67
0
  if (*counter == 0) {
68
0
    return Error(heif_error_Usage_error,
69
0
                 heif_suberror_Unspecified,
70
0
                 "ID namespace overflow");
71
0
  }
72
73
0
  uint32_t id = *counter;
74
0
  *counter = next_id_after(id);
75
76
  // Keep the global counter ahead of all namespace counters so that switching to
77
  // unif mode later does not reuse an ID that was already handed out.
78
0
  if (m_next_id_global != 0 && id >= m_next_id_global) {
79
0
    m_next_id_global = next_id_after(id);
80
0
  }
81
82
0
  return id;
83
0
}
84
85
86
void IDCreator::mark_id_used(Namespace ns, uint32_t id)
87
129k
{
88
129k
  uint32_t* counter = nullptr;
89
129k
  switch (ns) {
90
127k
    case Namespace::item:
91
127k
      counter = &m_next_id_item;
92
127k
      break;
93
516
    case Namespace::track:
94
516
      counter = &m_next_id_track;
95
516
      break;
96
1.39k
    case Namespace::entity_group:
97
1.39k
      counter = &m_next_id_entity_group;
98
1.39k
      break;
99
129k
  }
100
101
  // A counter value of 0 means "exhausted" (see get_new_id). Advancing past a
102
  // just-used id keeps get_new_id() from ever handing out the same id again;
103
  // marking 0xFFFFFFFF used moves the counter to 0 == exhausted.
104
129k
  if (*counter != 0 && id >= *counter) {
105
128k
    *counter = next_id_after(id);
106
128k
  }
107
108
129k
  if (m_next_id_global != 0 && id >= m_next_id_global) {
109
128k
    m_next_id_global = next_id_after(id);
110
128k
  }
111
129k
}