Skip to content

Commit

Permalink
gh-610 Configurable limits - Refactor current options
Browse files Browse the repository at this point in the history
  • Loading branch information
nolan-veed authored and gavv committed Nov 27, 2023
1 parent d7c2bcd commit 33112cd
Show file tree
Hide file tree
Showing 9 changed files with 325 additions and 162 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include "roc_core/parse_duration.h"
#include "roc_core/parse_units.h"
#include "roc_core/log.h"
#include "roc_core/stddefs.h"

Expand Down Expand Up @@ -84,5 +84,67 @@ bool parse_duration(const char* str, nanoseconds_t& result) {
return true;
}

bool parse_size(const char* str, size_t& result) {
if (str == NULL) {
roc_log(LogError, "parse size: string is null");
return false;
}

const size_t kibibyte = 1024;
const size_t mebibyte = 1024 * kibibyte;
const size_t gibibyte = 1024 * mebibyte;

size_t multiplier = 1;

const size_t str_len = strlen(str);
const char* suffix;

// suffix is optional.
if ((suffix = find_suffix(str, str_len, "G"))) {
multiplier = gibibyte;
} else if ((suffix = find_suffix(str, str_len, "M"))) {
multiplier = mebibyte;
} else if ((suffix = find_suffix(str, str_len, "K"))) {
multiplier = kibibyte;
}

if (!isdigit(*str)) {
roc_log(LogError,
"parse size: invalid format, not a number, expected <number>[<suffix>], "
"where suffix=<K|M|G>");
return false;
}

char* number_end = NULL;
unsigned long long number = strtoull(str, &number_end, 10);

if (number == ULLONG_MAX || (!suffix && *number_end != '\0')
|| (suffix && number_end != suffix)) {
roc_log(LogError,
"parse size: invalid format, can't parse number, expected "
"<number>[<suffix>], where suffix=<K|M|G>");
return false;
}

size_t number_converted = number;
if (number_converted < number) {
roc_log(LogError,
"parse size: too large, can't parse number, expected "
"<number>[<suffix>], where suffix=<K|M|G>");
return false;
}

size_t output = number_converted * multiplier;
if (output / multiplier != number_converted) {
roc_log(LogError,
"parse size: too large, can't parse number, expected "
"<number>[<suffix>], where suffix=<K|M|G>");
return false;
}

result = output;
return true;
}

} // namespace core
} // namespace roc
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

//! @file roc_core/parse_duration.h
//! @brief Parse duration.
//! @file roc_core/parse_units.h
//! @brief Parse units like duration, size, etc.

#ifndef ROC_CORE_PARSE_DURATION_H_
#define ROC_CORE_PARSE_DURATION_H_
#ifndef ROC_CORE_PARSE_UNITS_H_
#define ROC_CORE_PARSE_UNITS_H_

#include "roc_core/attributes.h"
#include "roc_core/time.h"
Expand All @@ -33,7 +33,20 @@ namespace core {
//! false if string can't be parsed.
ROC_ATTR_NODISCARD bool parse_duration(const char* string, nanoseconds_t& result);

//! Parse size from string.
//!
//! @remarks
//! The input string should be in one of the following forms:
//! - "<number>"
//! - "<number>K"
//! - "<number>M"
//! - "<number>G"
//!
//! @returns
//! false if string can't be parsed.
ROC_ATTR_NODISCARD bool parse_size(const char* string, size_t& result);

} // namespace core
} // namespace roc

#endif // ROC_CORE_PARSE_DURATION_H_
#endif // ROC_CORE_PARSE_UNITS_H_
57 changes: 0 additions & 57 deletions src/tests/roc_core/test_parse_duration.cpp

This file was deleted.

107 changes: 107 additions & 0 deletions src/tests/roc_core/test_parse_units.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2015 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include <CppUTest/TestHarness.h>

#include "roc_core/parse_units.h"
#include "roc_core/time.h"

namespace roc {
namespace core {

TEST_GROUP(parse_units) {};

TEST(parse_units, parse_duration_error) {
nanoseconds_t result = 0;

CHECK(!parse_duration(NULL, result));
CHECK(!parse_duration("", result));
CHECK(!parse_duration("1", result));
CHECK(!parse_duration("s", result));
CHECK(!parse_duration("1 s", result));
CHECK(!parse_duration(" 1s", result));
CHECK(!parse_duration("1s ", result));
CHECK(!parse_duration("!s", result));
CHECK(!parse_duration("s1", result));
CHECK(!parse_duration("1x", result));
}

TEST(parse_units, parse_duration) {
nanoseconds_t result = 0;

CHECK(parse_duration("123ns", result));
CHECK(result == 123 * Nanosecond);

CHECK(parse_duration("123us", result));
CHECK(result == 123 * Microsecond);

CHECK(parse_duration("123ms", result));
CHECK(result == 123 * Millisecond);

CHECK(parse_duration("123s", result));
CHECK(result == 123 * Second);

CHECK(parse_duration("123m", result));
CHECK(result == 123 * Minute);

CHECK(parse_duration("123h", result));
CHECK(result == 123 * Hour);
}

TEST(parse_units, parse_size_error) {
size_t result = 0;

CHECK(!parse_size(NULL, result));
CHECK(!parse_size("", result));
CHECK(!parse_size("K", result));
CHECK(!parse_size("1 K", result));
CHECK(!parse_size(" 1K", result));
CHECK(!parse_size("1K ", result));
CHECK(!parse_size("!K", result));
CHECK(!parse_size("K1", result));
CHECK(!parse_size("1x", result));
}

TEST(parse_units, parse_size) {
size_t result = 0;

const size_t kibibyte = 1024;
const size_t mebibyte = 1024 * kibibyte;
const size_t gibibyte = 1024 * mebibyte;

CHECK(parse_size("123", result));
CHECK(result == 123);

CHECK(parse_size("123K", result));
CHECK(result == 123 * kibibyte);

CHECK(parse_size("123M", result));
CHECK(result == 123 * mebibyte);

CHECK(parse_size("1G", result));
CHECK(result == 1 * gibibyte);
}

TEST(parse_units, parse_size_overflows_due_to_sizeof_size_t) {
if (SIZE_MAX < ULLONG_MAX) {
char s[32];
snprintf(s, 32, "%llu", ULLONG_MAX - 1);
size_t result = 0;
CHECK_FALSE(parse_size(s, result));
}
}

TEST(parse_units, parse_size_overflows_due_to_multiplier) {
char s[32];
snprintf(s, 32, "%zuK", SIZE_MAX - 1);
size_t result = 0;
CHECK_FALSE(parse_size(s, result));
}

} // namespace core
} // namespace roc
2 changes: 1 addition & 1 deletion src/tools/roc_copy/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include "roc_core/crash_handler.h"
#include "roc_core/heap_arena.h"
#include "roc_core/log.h"
#include "roc_core/parse_duration.h"
#include "roc_core/parse_units.h"
#include "roc_core/scoped_ptr.h"
#include "roc_pipeline/transcoder_sink.h"
#include "roc_sndio/backend_dispatcher.h"
Expand Down
15 changes: 9 additions & 6 deletions src/tools/roc_recv/cmdline.ggo
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ section "Options"
option "choppy-play-timeout" - "Choppy playback timeout, TIME units"
string optional

option "packet-limit" - "Maximum packet size, in bytes"
int optional
option "frame-len" - "Duration of the internal frames, TIME units"
typestr="TIME" string optional

option "frame-limit" - "Maximum internal frame size, in bytes"
int optional
option "max-packet-size" - "Maximum packet size, in SIZE units"
typestr="SIZE" string optional

option "frame-length" - "Duration of the internal frames, TIME units"
typestr="TIME" string optional
option "max-frame-size" - "Maximum internal frame size, in SIZE units"
typestr="SIZE" string optional

option "rate" - "Override output sample rate, Hz"
int optional
Expand Down Expand Up @@ -92,6 +92,9 @@ FILE_FORMAT is the output file format name, e.g.:
TIME is an integer number with a suffix, e.g.:
123ns; 123us; 123ms; 123s; 123m; 123h;

SIZE is an integer number with an optional suffix, e.g.:
123; 123K; 123M; 123G;

Use --list-supported option to print the list of the supported
URI schemes and file formats.

Expand Down
Loading

0 comments on commit 33112cd

Please sign in to comment.