Coverage Report

Created: 2026-06-09 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/src/info.cpp
Line
Count
Source
1
/******************************************************************************
2
 * Project:  PROJ
3
 * Purpose:  proj_info() and proj_pj_info()
4
 *
5
 * Author:   Thomas Knudsen,  thokn@sdfe.dk,  2016-06-09/2016-11-06
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2016, 2017 Thomas Knudsen/SDFE
9
 *
10
 * Permission is hereby granted, free of charge, to any person obtaining a
11
 * copy of this software and associated documentation files (the "Software"),
12
 * to deal in the Software without restriction, including without limitation
13
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14
 * and/or sell copies of the Software, and to permit persons to whom the
15
 * Software is furnished to do so, subject to the following conditions:
16
 *
17
 * The above copyright notice and this permission notice shall be included
18
 * in all copies or substantial portions of the Software.
19
 *
20
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26
 * DEALINGS IN THE SOFTWARE.
27
 *****************************************************************************/
28
29
#define FROM_PROJ_CPP
30
31
#include "proj.h"
32
#include "proj_internal.h"
33
34
#include "filemanager.hpp"
35
36
/*****************************************************************************/
37
0
static char *path_append(char *buf, const char *app, size_t *buf_size) {
38
    /******************************************************************************
39
        Helper for proj_info() below. Append app to buf, separated by a
40
        semicolon. Also handle allocation of longer buffer if needed.
41
42
        Returns buffer and adjusts *buf_size through provided pointer arg.
43
    ******************************************************************************/
44
0
    char *p;
45
0
    size_t len, applen = 0, buflen = 0;
46
#ifdef _WIN32
47
    const char *delim = ";";
48
#else
49
0
    const char *delim = ":";
50
0
#endif
51
52
    /* Nothing to do? */
53
0
    if (nullptr == app)
54
0
        return buf;
55
0
    applen = strlen(app);
56
0
    if (0 == applen)
57
0
        return buf;
58
59
    /* Start checking whether buf is long enough */
60
0
    if (nullptr != buf)
61
0
        buflen = strlen(buf);
62
0
    len = buflen + applen + strlen(delim) + 1;
63
64
    /* "pj_realloc", so to speak */
65
0
    if (*buf_size < len) {
66
0
        p = static_cast<char *>(calloc(2 * len, sizeof(char)));
67
0
        if (nullptr == p) {
68
0
            free(buf);
69
0
            return nullptr;
70
0
        }
71
0
        *buf_size = 2 * len;
72
0
        if (buf != nullptr)
73
0
            strcpy(p, buf);
74
0
        free(buf);
75
0
        buf = p;
76
0
    }
77
0
    assert(buf);
78
79
    /* Only append a delimiter if something's already there */
80
0
    if (0 != buflen)
81
0
        strcat(buf, delim);
82
0
    strcat(buf, app);
83
0
    return buf;
84
0
}
85
86
static const char *empty = {""};
87
static char version[64] = {""};
88
static PJ_INFO info = {0, 0, 0, nullptr, nullptr, nullptr, nullptr, 0};
89
90
/*****************************************************************************/
91
0
PJ_INFO proj_info(void) {
92
    /******************************************************************************
93
        Basic info about the current instance of the PROJ.4 library.
94
95
        Returns PJ_INFO struct.
96
    ******************************************************************************/
97
0
    size_t buf_size = 0;
98
0
    char *buf = nullptr;
99
100
0
    pj_acquire_lock();
101
102
0
    info.major = PROJ_VERSION_MAJOR;
103
0
    info.minor = PROJ_VERSION_MINOR;
104
0
    info.patch = PROJ_VERSION_PATCH;
105
106
    /* A normal version string is xx.yy.zz which is 8 characters
107
    long and there is room for 64 bytes in the version string. */
108
0
    snprintf(version, sizeof(version), "%d.%d.%d", info.major, info.minor,
109
0
             info.patch);
110
111
0
    info.version = version;
112
0
    info.release = pj_get_release();
113
114
    /* build search path string */
115
0
    auto ctx = pj_get_default_ctx();
116
0
    if (ctx->search_paths.empty()) {
117
0
        const auto searchpaths = pj_get_default_searchpaths(ctx);
118
0
        for (const auto &path : searchpaths) {
119
0
            buf = path_append(buf, path.c_str(), &buf_size);
120
0
        }
121
0
    } else {
122
0
        for (const auto &path : ctx->search_paths) {
123
0
            buf = path_append(buf, path.c_str(), &buf_size);
124
0
        }
125
0
    }
126
127
0
    if (info.searchpath != empty)
128
0
        free(const_cast<char *>(info.searchpath));
129
0
    info.searchpath = buf ? buf : empty;
130
131
0
    info.paths = ctx->c_compat_paths;
132
0
    info.path_count = static_cast<int>(ctx->search_paths.size());
133
134
0
    pj_release_lock();
135
0
    return info;
136
0
}
137
138
/*****************************************************************************/
139
void pj_clear_proj_info()
140
/*****************************************************************************
141
     Release memory associated to "info" singleton
142
 *****************************************************************************/
143
11.4k
{
144
11.4k
    pj_acquire_lock();
145
11.4k
    if (info.searchpath != empty)
146
11.4k
        free(const_cast<char *>(info.searchpath));
147
11.4k
    info.searchpath = nullptr;
148
11.4k
    pj_release_lock();
149
11.4k
}
150
151
/*****************************************************************************/
152
0
PJ_PROJ_INFO proj_pj_info(PJ *P) {
153
    /******************************************************************************
154
        Basic info about a particular instance of a projection object.
155
156
        Returns PJ_PROJ_INFO struct.
157
    ******************************************************************************/
158
0
    PJ_PROJ_INFO pjinfo;
159
0
    char *def;
160
161
0
    memset(&pjinfo, 0, sizeof(PJ_PROJ_INFO));
162
163
0
    pjinfo.accuracy = -1.0;
164
165
0
    if (nullptr == P)
166
0
        return pjinfo;
167
168
    /* coordinate operation description */
169
0
    if (!P->alternativeCoordinateOperations.empty()) {
170
0
        if (P->iCurCoordOp >= 0) {
171
0
            P = P->alternativeCoordinateOperations[P->iCurCoordOp].pj;
172
0
        } else {
173
0
            PJ *candidateOp = nullptr;
174
            // If there's just a single coordinate operation which is
175
            // instantiable, use it.
176
0
            for (const auto &op : P->alternativeCoordinateOperations) {
177
0
                if (op.isInstantiable()) {
178
0
                    if (candidateOp == nullptr) {
179
0
                        candidateOp = op.pj;
180
0
                    } else {
181
0
                        candidateOp = nullptr;
182
0
                        break;
183
0
                    }
184
0
                }
185
0
            }
186
0
            if (candidateOp) {
187
0
                P = candidateOp;
188
0
            } else {
189
0
                pjinfo.id = "unknown";
190
0
                pjinfo.description = "unavailable until proj_trans is called";
191
0
                pjinfo.definition = "unavailable until proj_trans is called";
192
0
                return pjinfo;
193
0
            }
194
0
        }
195
0
    }
196
197
    /* projection id */
198
0
    if (pj_param(P->ctx, P->params, "tproj").i)
199
0
        pjinfo.id = pj_param(P->ctx, P->params, "sproj").s;
200
201
0
    pjinfo.description = P->descr;
202
0
    if (P->iso_obj) {
203
0
        auto identifiedObj =
204
0
            dynamic_cast<NS_PROJ::common::IdentifiedObject *>(P->iso_obj.get());
205
        // cppcheck-suppress knownConditionTrueFalse
206
0
        if (identifiedObj) {
207
0
            pjinfo.description = identifiedObj->nameStr().c_str();
208
0
        }
209
0
    }
210
211
    // accuracy
212
0
    if (P->iso_obj) {
213
0
        auto conv = dynamic_cast<const NS_PROJ::operation::Conversion *>(
214
0
            P->iso_obj.get());
215
        // cppcheck-suppress knownConditionTrueFalse
216
0
        if (conv) {
217
0
            pjinfo.accuracy = 0.0;
218
0
        } else {
219
0
            auto op =
220
0
                dynamic_cast<const NS_PROJ::operation::CoordinateOperation *>(
221
0
                    P->iso_obj.get());
222
            // cppcheck-suppress knownConditionTrueFalse
223
0
            if (op) {
224
0
                const auto &accuracies = op->coordinateOperationAccuracies();
225
0
                if (!accuracies.empty()) {
226
0
                    try {
227
0
                        pjinfo.accuracy = std::stod(accuracies[0]->value());
228
0
                    } catch (const std::exception &) {
229
0
                    }
230
0
                }
231
0
            }
232
0
        }
233
0
    }
234
235
    /* projection definition */
236
0
    if (P->def_full)
237
0
        def = P->def_full;
238
0
    else
239
0
        def = pj_get_def(P, 0); /* pj_get_def takes a non-const PJ pointer */
240
0
    if (nullptr == def)
241
0
        pjinfo.definition = empty;
242
0
    else
243
0
        pjinfo.definition = pj_shrink(def);
244
    /* Make proj_destroy clean this up eventually */
245
0
    P->def_full = def;
246
247
0
    pjinfo.has_inverse = pj_has_inverse(P);
248
0
    return pjinfo;
249
0
}