Coverage Report

Created: 2026-07-20 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvisio/src/lib/VSDXMLHelper.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/*
3
 * This file is part of the libvisio project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#include "VSDXMLHelper.h"
11
12
#include <memory>
13
#include <sstream>
14
#include <istream>
15
#include <vector>
16
#include <boost/algorithm/string.hpp>
17
#include <librevenge-stream/librevenge-stream.h>
18
#include "libvisio_utils.h"
19
#include "libvisio_xml.h"
20
21
// VSDXRelationship
22
23
libvisio::VSDXRelationship::VSDXRelationship(xmlTextReaderPtr reader)
24
30.5k
  : m_id(), m_type(), m_target()
25
30.5k
{
26
30.5k
  if (reader)
27
    // TODO: check whether we are actually parsing "Relationship" element
28
30.5k
  {
29
121k
    while (xmlTextReaderMoveToNextAttribute(reader))
30
90.5k
    {
31
90.5k
      const xmlChar *name = xmlTextReaderConstName(reader);
32
90.5k
      const xmlChar *value = xmlTextReaderConstValue(reader);
33
90.5k
      if (xmlStrEqual(name, BAD_CAST("Id")))
34
30.2k
        m_id = (const char *)value;
35
60.3k
      else if (xmlStrEqual(name, BAD_CAST("Type")))
36
29.9k
        m_type = (const char *)value;
37
30.3k
      else if (xmlStrEqual(name, BAD_CAST("Target")))
38
29.5k
        m_target = (const char *)value;
39
90.5k
    }
40
    // VSD_DEBUG_MSG(("Relationship : %s type: %s target: %s\n", m_id.c_str(), m_type.c_str(), m_target.c_str()));
41
30.5k
  }
42
30.5k
}
43
44
libvisio::VSDXRelationship::VSDXRelationship()
45
57.1k
  : m_id(), m_type(), m_target()
46
57.1k
{
47
57.1k
}
48
49
libvisio::VSDXRelationship::~VSDXRelationship()
50
87.6k
{
51
87.6k
}
52
53
void libvisio::VSDXRelationship::rebaseTarget(const char *baseDir)
54
27.3k
{
55
27.3k
  std::string target(baseDir ? baseDir : "");
56
27.3k
  if (!target.empty())
57
26.9k
    target += "/";
58
27.3k
  target += m_target;
59
60
  // normalize path by resolving any ".." or "." segments
61
  // and eliminating duplicate path separators
62
27.3k
  std::vector<std::string> segments;
63
27.3k
  boost::split(segments, target, boost::is_any_of("/\\"));
64
27.3k
  std::vector<std::string> normalizedSegments;
65
66
27.3k
  for (auto &segment : segments)
67
107k
  {
68
107k
    if (segment == "..")
69
1.86k
    {
70
      // guard against a malformed Target with excess ".." segments
71
1.86k
      if (!normalizedSegments.empty())
72
1.86k
        normalizedSegments.pop_back();
73
1.86k
    }
74
105k
    else if (segment != "." && !segment.empty())
75
77.9k
      normalizedSegments.push_back(segment);
76
107k
  }
77
78
27.3k
  target.clear();
79
27.3k
  for (const auto &normalizedSegment : normalizedSegments)
80
76.0k
  {
81
76.0k
    if (!target.empty())
82
49.0k
      target.append("/");
83
76.0k
    target.append(normalizedSegment);
84
76.0k
  }
85
86
  // VSD_DEBUG_MSG(("VSDXRelationship::rebaseTarget %s -> %s\n", m_target.c_str(), target.c_str()));
87
27.3k
  m_target = target;
88
27.3k
}
89
90
91
// VSDXRelationships
92
93
libvisio::VSDXRelationships::VSDXRelationships(librevenge::RVNGInputStream *input)
94
11.2k
  : m_relsByType(), m_relsById()
95
11.2k
{
96
11.2k
  if (input)
97
9.60k
  {
98
9.60k
    auto reader = xmlReaderForStream(input);
99
9.60k
    if (reader)
100
9.60k
    {
101
9.60k
      bool inRelationships = false;
102
9.60k
      int ret = xmlTextReaderRead(reader.get());
103
58.4k
      while (ret == 1)
104
48.8k
      {
105
48.8k
        const xmlChar *name = xmlTextReaderConstName(reader.get());
106
48.8k
        if (name)
107
48.8k
        {
108
48.8k
          if (xmlStrEqual(name, BAD_CAST("Relationships")))
109
17.8k
          {
110
17.8k
            if (xmlTextReaderNodeType(reader.get()) == 1)
111
9.08k
            {
112
              // VSD_DEBUG_MSG(("Relationships ON\n"));
113
9.08k
              inRelationships = true;
114
9.08k
            }
115
8.76k
            else if (xmlTextReaderNodeType(reader.get()) == 15)
116
8.76k
            {
117
              // VSD_DEBUG_MSG(("Relationships OFF\n"));
118
8.76k
              inRelationships = false;
119
8.76k
            }
120
17.8k
          }
121
30.9k
          else if (xmlStrEqual(name, BAD_CAST("Relationship")))
122
30.5k
          {
123
30.5k
            if (inRelationships)
124
30.5k
            {
125
30.5k
              VSDXRelationship relationship(reader.get());
126
30.5k
              m_relsByType[relationship.getType()] = relationship;
127
30.5k
              m_relsById[relationship.getId()] = relationship;
128
30.5k
            }
129
30.5k
          }
130
48.8k
        }
131
48.8k
        ret = xmlTextReaderRead(reader.get());
132
48.8k
      }
133
9.60k
    }
134
9.60k
  }
135
11.2k
}
136
137
libvisio::VSDXRelationships::~VSDXRelationships()
138
11.2k
{
139
11.2k
}
140
141
void libvisio::VSDXRelationships::rebaseTargets(const char *baseDir)
142
8.02k
{
143
8.02k
  std::map<std::string, libvisio::VSDXRelationship>::iterator iter;
144
20.0k
  for (iter = m_relsByType.begin(); iter != m_relsByType.end(); ++iter)
145
12.0k
    iter->second.rebaseTarget(baseDir);
146
23.3k
  for (iter = m_relsById.begin(); iter != m_relsById.end(); ++iter)
147
15.3k
    iter->second.rebaseTarget(baseDir);
148
8.02k
}
149
150
const libvisio::VSDXRelationship *libvisio::VSDXRelationships::getRelationshipByType(const char *type) const
151
13.8k
{
152
13.8k
  if (!type)
153
0
    return nullptr;
154
13.8k
  auto iter = m_relsByType.find(type);
155
13.8k
  if (iter != m_relsByType.end())
156
11.1k
    return &(iter->second);
157
2.65k
  return nullptr;
158
13.8k
}
159
160
const libvisio::VSDXRelationship *libvisio::VSDXRelationships::getRelationshipById(const char *id) const
161
3.64k
{
162
3.64k
  if (!id)
163
0
    return nullptr;
164
3.64k
  auto iter = m_relsById.find(id);
165
3.64k
  if (iter != m_relsById.end())
166
2.98k
    return &(iter->second);
167
654
  return nullptr;
168
3.64k
}
169
170
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */