mirror of
https://github.com/subsurface/subsurface.git
synced 2024-12-02 23:20:20 +00:00
Planner: Fix Warning from Coverity.
Fix an interger overflow warning when parsing setpoints. @bstoeger: In the end it turned out that this parser was only used in one place in the planner UI, and it was simplest to switch this to using `QVariant.toFloat()` in the model itself, which is consistent how the rest of the input values is parsed and validated. Signed-off-by: Michael Keller <github@ike.ch>
This commit is contained in:
parent
cc55c442a3
commit
33bb39f1ca
3 changed files with 22 additions and 148 deletions
128
core/planner.cpp
128
core/planner.cpp
|
@ -1102,131 +1102,3 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
|
||||||
|
|
||||||
return decodive;
|
return decodive;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Get a value with a given number of decimals:
|
|
||||||
* - get_decimals("10.2", &"10.2", 1) == 102
|
|
||||||
* - get_decimals("9", &"9", 1) = 90
|
|
||||||
* - get_decimals("1.35", &"1.35", 2) == 135))
|
|
||||||
*
|
|
||||||
* Return negative for errors.
|
|
||||||
*/
|
|
||||||
static int get_decimals(const char *begin, const char **endp, const unsigned decimals)
|
|
||||||
{
|
|
||||||
char *end;
|
|
||||||
int value = strtol(begin, &end, 10);
|
|
||||||
|
|
||||||
if (begin == end)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Fraction? We only look at the first digit */
|
|
||||||
if (*end == '.')
|
|
||||||
end++;
|
|
||||||
|
|
||||||
unsigned fraction = 0;
|
|
||||||
for (unsigned i = 0; i < decimals; i++) {
|
|
||||||
value *= 10;
|
|
||||||
|
|
||||||
unsigned digit = 0;
|
|
||||||
if (isdigit(*end)) {
|
|
||||||
digit = *end - '0';
|
|
||||||
|
|
||||||
end++;
|
|
||||||
} else if (*end != '\0') {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fraction = 10 * fraction + digit;
|
|
||||||
|
|
||||||
}
|
|
||||||
value += fraction;
|
|
||||||
|
|
||||||
do {
|
|
||||||
end++;
|
|
||||||
} while (isdigit(*end));
|
|
||||||
|
|
||||||
*endp = end;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_permille(const char *begin, const char **end)
|
|
||||||
{
|
|
||||||
int value = get_decimals(begin, end, 1);
|
|
||||||
if (value >= 0) {
|
|
||||||
/* Allow a percentage sign */
|
|
||||||
if (**end == '%')
|
|
||||||
++*end;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int validate_gas(const char *text, struct gasmix *gas)
|
|
||||||
{
|
|
||||||
int o2, he;
|
|
||||||
|
|
||||||
if (!text)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
while (isspace(*text))
|
|
||||||
text++;
|
|
||||||
|
|
||||||
if (!*text)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!strcasecmp(text, translate("gettextFromC", "air"))) {
|
|
||||||
o2 = O2_IN_AIR;
|
|
||||||
he = 0;
|
|
||||||
text += strlen(translate("gettextFromC", "air"));
|
|
||||||
} else if (!strcasecmp(text, translate("gettextFromC", "oxygen"))) {
|
|
||||||
o2 = 1000;
|
|
||||||
he = 0;
|
|
||||||
text += strlen(translate("gettextFromC", "oxygen"));
|
|
||||||
} else if (!strncasecmp(text, translate("gettextFromC", "ean"), 3)) {
|
|
||||||
o2 = get_permille(text + 3, &text);
|
|
||||||
he = 0;
|
|
||||||
} else {
|
|
||||||
o2 = get_permille(text, &text);
|
|
||||||
he = 0;
|
|
||||||
if (*text == '/')
|
|
||||||
he = get_permille(text + 1, &text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We don't want any extra crud */
|
|
||||||
while (isspace(*text))
|
|
||||||
text++;
|
|
||||||
if (*text)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Validate the gas mix */
|
|
||||||
if (*text || o2 < 1 || o2 > 1000 || he < 0 || o2 + he > 1000)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Let it rip */
|
|
||||||
gas->o2.permille = o2;
|
|
||||||
gas->he.permille = he;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int validate_po2(const char *text, int *mbar_po2)
|
|
||||||
{
|
|
||||||
int po2;
|
|
||||||
|
|
||||||
if (!text)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
po2 = get_decimals(text, &text, 2);
|
|
||||||
if (po2 < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
while (isspace(*text))
|
|
||||||
text++;
|
|
||||||
if (*text)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
*mbar_po2 = po2 * 10;
|
|
||||||
|
|
||||||
if (*mbar_po2 < 160)
|
|
||||||
*mbar_po2 = 160;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
|
@ -40,8 +40,6 @@ typedef enum {
|
||||||
PLAN_ERROR_INAPPROPRIATE_GAS,
|
PLAN_ERROR_INAPPROPRIATE_GAS,
|
||||||
} planner_error_t;
|
} planner_error_t;
|
||||||
|
|
||||||
extern int validate_gas(const char *text, struct gasmix *gas);
|
|
||||||
extern int validate_po2(const char *text, int *mbar_po2);
|
|
||||||
extern int get_cylinderid_at_time(struct dive *dive, struct divecomputer *dc, duration_t time);
|
extern int get_cylinderid_at_time(struct dive *dive, struct divecomputer *dc, duration_t time);
|
||||||
extern bool diveplan_empty(struct diveplan *diveplan);
|
extern bool diveplan_empty(struct diveplan *diveplan);
|
||||||
extern void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_disclaimer, planner_error_t error);
|
extern void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_disclaimer, planner_error_t error);
|
||||||
|
|
|
@ -357,13 +357,15 @@ bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &v
|
||||||
if (role == Qt::EditRole) {
|
if (role == Qt::EditRole) {
|
||||||
divedatapoint &p = divepoints[index.row()];
|
divedatapoint &p = divepoints[index.row()];
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case DEPTH:
|
case DEPTH: {
|
||||||
if (value.toInt() >= 0) {
|
int depth = value.toInt();
|
||||||
p.depth = units_to_depth(value.toInt());
|
if (depth >= 0) {
|
||||||
|
p.depth = units_to_depth(depth);
|
||||||
if (updateMaxDepth())
|
if (updateMaxDepth())
|
||||||
cylinders.updateBestMixes();
|
cylinders.updateBestMixes();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case RUNTIME: {
|
case RUNTIME: {
|
||||||
int secs = value.toInt() * 60;
|
int secs = value.toInt() * 60;
|
||||||
i = index.row();
|
i = index.row();
|
||||||
|
@ -380,23 +382,25 @@ bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &v
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DURATION: {
|
case DURATION: {
|
||||||
int secs = value.toInt() * 60;
|
int secs = value.toInt() * 60;
|
||||||
if (!secs)
|
if (secs < 0)
|
||||||
secs = 10;
|
secs = 10;
|
||||||
i = index.row();
|
i = index.row();
|
||||||
if (i)
|
if (i)
|
||||||
shift = divepoints[i].time - divepoints[i - 1].time - secs;
|
shift = divepoints[i].time - divepoints[i - 1].time - secs;
|
||||||
else
|
else
|
||||||
shift = divepoints[i].time - secs;
|
shift = divepoints[i].time - secs;
|
||||||
while (i < divepoints.size())
|
while (i < divepoints.size())
|
||||||
divepoints[i++].time -= shift;
|
divepoints[i++].time -= shift;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CCSETPOINT: {
|
case CCSETPOINT: {
|
||||||
int po2 = 0;
|
bool ok;
|
||||||
QByteArray gasv = value.toByteArray();
|
int po2 = round(value.toFloat(&ok) * 100) * 10;
|
||||||
if (validate_po2(gasv.data(), &po2))
|
|
||||||
p.setpoint = po2;
|
if (ok)
|
||||||
|
p.setpoint = std::max(po2, 160);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GAS:
|
case GAS:
|
||||||
|
|
Loading…
Reference in a new issue