Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
5d11121f
Unverified
Commit
5d11121f
authored
Jun 29, 2023
by
Dominik Charousset
Committed by
GitHub
Jun 29, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1460
Add utility for UTF-8 validation
parents
4f20d587
eaa0a228
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
285 additions
and
0 deletions
+285
-0
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+2
-0
libcaf_core/caf/detail/rfc3629.hpp
libcaf_core/caf/detail/rfc3629.hpp
+27
-0
libcaf_core/src/detail/rfc3629.cpp
libcaf_core/src/detail/rfc3629.cpp
+102
-0
libcaf_core/test/detail/rfc3629.cpp
libcaf_core/test/detail/rfc3629.cpp
+154
-0
No files found.
libcaf_core/CMakeLists.txt
View file @
5d11121f
...
@@ -131,6 +131,7 @@ caf_add_component(
...
@@ -131,6 +131,7 @@ caf_add_component(
src/detail/print.cpp
src/detail/print.cpp
src/detail/private_thread.cpp
src/detail/private_thread.cpp
src/detail/private_thread_pool.cpp
src/detail/private_thread_pool.cpp
src/detail/rfc3629.cpp
src/detail/ripemd_160.cpp
src/detail/ripemd_160.cpp
src/detail/set_thread_name.cpp
src/detail/set_thread_name.cpp
src/detail/stream_bridge.cpp
src/detail/stream_bridge.cpp
...
@@ -271,6 +272,7 @@ caf_add_component(
...
@@ -271,6 +272,7 @@ caf_add_component(
detail.parser.read_timespan
detail.parser.read_timespan
detail.parser.read_unsigned_integer
detail.parser.read_unsigned_integer
detail.private_thread_pool
detail.private_thread_pool
detail.rfc3629
detail.ringbuffer
detail.ringbuffer
detail.ripemd_160
detail.ripemd_160
detail.type_id_list_builder
detail.type_id_list_builder
...
...
libcaf_core/caf/detail/rfc3629.hpp
0 → 100644
View file @
5d11121f
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/byte_span.hpp"
#include "caf/detail/core_export.hpp"
#include <cstddef>
namespace
caf
::
detail
{
/// Wraps functions for processing RFC 3629 encoding, i.e., UTF-8. See
/// https://datatracker.ietf.org/doc/html/rfc3629 for details.
class
CAF_CORE_EXPORT
rfc3629
{
public:
/// Checks whether `bytes` is a valid UTF-8 string.
static
bool
valid
(
const_byte_span
bytes
)
noexcept
;
/// Checks whether `str` is a valid UTF-8 string.
static
bool
valid
(
std
::
string_view
str
)
noexcept
{
return
valid
(
as_bytes
(
make_span
(
str
)));
}
};
}
// namespace caf::detail
libcaf_core/src/detail/rfc3629.cpp
0 → 100644
View file @
5d11121f
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/detail/rfc3629.hpp"
namespace
{
// Convenient literal for std::byte.
constexpr
std
::
byte
operator
""
_b
(
unsigned
long
long
x
)
{
return
static_cast
<
std
::
byte
>
(
x
);
}
// Takes the first N bits of `value`.
template
<
size_t
N
>
constexpr
std
::
byte
head
(
std
::
byte
value
)
noexcept
{
if
constexpr
(
N
==
1
)
{
return
value
&
0b1000
'
0000
_b
;
}
else
if
constexpr
(
N
==
2
)
{
return
value
&
0b1100
'
0000
_b
;
}
else
if
constexpr
(
N
==
3
)
{
return
value
&
0b1110
'
0000
_b
;
}
else
if
constexpr
(
N
==
4
)
{
return
value
&
0b1111
'
0000
_b
;
}
else
if
constexpr
(
N
==
5
)
{
return
value
&
0b1111
'
1000
_b
;
}
else
if
constexpr
(
N
==
6
)
{
return
value
&
0b1111
'
1100
_b
;
}
else
{
static_assert
(
N
==
7
);
return
value
&
0b1111
'
1110
_b
;
}
}
// Checks whether `value` is an UTF-8 continuation byte.
constexpr
bool
is_continuation_byte
(
std
::
byte
value
)
noexcept
{
return
head
<
2
>
(
value
)
==
0b1000
'
0000
_b
;
}
// The following code is based on the algorithm described in
// http://unicode.org/mail-arch/unicode-ml/y2003-m02/att-0467/01-The_Algorithm_to_Valide_an_UTF-8_String
bool
validate_rfc3629
(
const
std
::
byte
*
first
,
const
std
::
byte
*
last
)
{
while
(
first
!=
last
)
{
auto
x
=
*
first
++
;
// Null byte (terminator) is not allowed.
if
(
x
==
0
_b
)
return
false
;
// First bit is zero: ASCII character.
if
(
head
<
1
>
(
x
)
==
0b0000
'
0000
_b
)
continue
;
// 110b'xxxx: 2-byte sequence.
if
(
head
<
3
>
(
x
)
==
0b1100
'
0000
_b
)
{
// No non-shortest form.
if
(
head
<
7
>
(
x
)
==
0b1100
'
0000
_b
)
return
false
;
if
(
first
==
last
||
!
is_continuation_byte
(
*
first
++
))
return
false
;
continue
;
}
// 1110'xxxx: 3-byte sequence.
if
(
head
<
4
>
(
x
)
==
0b1110
'
0000
_b
)
{
if
(
first
==
last
||
!
is_continuation_byte
(
*
first
))
return
false
;
// No non-shortest form.
if
(
x
==
0b1110
'
0000
_b
&&
head
<
3
>
(
*
first
)
==
0b1000
'
0000
_b
)
return
false
;
// No surrogate characters.
if
(
x
==
0b1110
'
1101
_b
&&
head
<
3
>
(
*
first
)
==
0b1010
'
0000
_b
)
return
false
;
++
first
;
if
(
first
==
last
||
!
is_continuation_byte
(
*
first
++
))
return
false
;
continue
;
}
// 1111'0bxx: 4-byte sequence.
if
(
head
<
5
>
(
x
)
==
0b1111
'
0000
_b
)
{
if
(
first
==
last
||
!
is_continuation_byte
(
*
first
))
return
false
;
// No non-shortest form.
if
(
x
==
0b1111
'
0000
_b
&&
head
<
4
>
(
*
first
)
==
0b1000
'
0000
_b
)
return
false
;
++
first
;
if
(
first
==
last
||
!
is_continuation_byte
(
*
first
++
))
return
false
;
if
(
first
==
last
||
!
is_continuation_byte
(
*
first
++
))
return
false
;
continue
;
}
return
false
;
}
return
true
;
}
}
// namespace
namespace
caf
::
detail
{
bool
rfc3629
::
valid
(
const_byte_span
bytes
)
noexcept
{
return
validate_rfc3629
(
bytes
.
begin
(),
bytes
.
end
());
}
}
// namespace caf::detail
libcaf_core/test/detail/rfc3629.cpp
0 → 100644
View file @
5d11121f
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE detail.rfc3629
#include "caf/detail/rfc3629.hpp"
#include "core-test.hpp"
using
namespace
caf
;
namespace
{
bool
valid_utf8
(
const_byte_span
bytes
)
noexcept
{
return
detail
::
rfc3629
::
valid
(
bytes
);
}
bool
valid_utf8
(
std
::
string_view
bytes
)
noexcept
{
return
detail
::
rfc3629
::
valid
(
bytes
);
}
constexpr
std
::
byte
operator
""
_b
(
unsigned
long
long
x
)
{
return
static_cast
<
std
::
byte
>
(
x
);
}
// Missing continuation byte.
constexpr
std
::
byte
invalid_two_byte_1
[]
=
{
0xc8
_b
};
// Illegal non-shortest form (1).
constexpr
std
::
byte
invalid_two_byte_2
[]
=
{
0xc0
_b
,
0x80
_b
};
// Illegal non-shortest form (2).
constexpr
std
::
byte
invalid_two_byte_3
[]
=
{
0xc1
_b
,
0x80
_b
};
// Invalid continuation byte.
constexpr
std
::
byte
invalid_two_byte_4
[]
=
{
0xc8
_b
,
0x0f
_b
};
// Missing continuation bytes.
constexpr
std
::
byte
invalid_three_byte_1
[]
=
{
0xe8
_b
};
// Missing continuation byte.
constexpr
std
::
byte
invalid_three_byte_2
[]
=
{
0xe8
_b
,
0x80
_b
};
// Invalid continuation byte (1).
constexpr
std
::
byte
invalid_three_byte_3
[]
=
{
0xe8
_b
,
0x0f
_b
,
0x80
_b
};
// Invalid continuation byte (2).
constexpr
std
::
byte
invalid_three_byte_4
[]
=
{
0xe8
_b
,
0x80
_b
,
0x0f
_b
};
// Illegal non-shortest form (1).
constexpr
std
::
byte
invalid_three_byte_5
[]
=
{
0xe0
_b
,
0x80
_b
,
0x80
_b
};
// Illegal non-shortest form (2).
constexpr
std
::
byte
invalid_three_byte_6
[]
=
{
0xe0
_b
,
0x9f
_b
,
0x8f
_b
};
// Illegal surrogate (smallest).
constexpr
std
::
byte
invalid_three_byte_7
[]
=
{
0xed
_b
,
0xa0
_b
,
0x80
_b
};
// Illegal surrogate (largest).
constexpr
std
::
byte
invalid_three_byte_8
[]
=
{
0xed
_b
,
0xbf
_b
,
0xbf
_b
};
// Missing continuation bytes.
constexpr
std
::
byte
invalid_four_byte_1
[]
=
{
0xf1
_b
};
// Missing continuation bytes 3 and 4.
constexpr
std
::
byte
invalid_four_byte_2
[]
=
{
0xf1
_b
,
0xbc
_b
};
// Missing continuation byte 4.
constexpr
std
::
byte
invalid_four_byte_3
[]
=
{
0xf1
_b
,
0xbc
_b
,
0xbc
_b
};
// Invalid continuation byte (1).
constexpr
std
::
byte
invalid_four_byte_4
[]
=
{
0xf1
_b
,
0x08
_b
,
0x80
_b
,
0x80
_b
};
// Invalid continuation byte (2).
constexpr
std
::
byte
invalid_four_byte_5
[]
=
{
0xf1
_b
,
0x80
_b
,
0x08
_b
,
0x80
_b
};
// Invalid continuation byte (3).
constexpr
std
::
byte
invalid_four_byte_6
[]
=
{
0xf1
_b
,
0x80
_b
,
0x80
_b
,
0x08
_b
};
// Illegal non-shortest form.
constexpr
std
::
byte
invalid_four_byte_7
[]
=
{
0xf0
_b
,
0x8f
_b
,
0x8f
_b
,
0x8f
_b
};
// Illegal start of a sequence.
constexpr
std
::
byte
invalid_four_byte_8
[]
=
{
0xf8
_b
,
0x80
_b
,
0x80
_b
,
0x80
_b
};
// Smallest valid 2-byte sequence.
constexpr
std
::
byte
valid_two_byte_1
[]
=
{
0xc2
_b
,
0x80
_b
};
// Largest valid 2-byte sequence.
constexpr
std
::
byte
valid_two_byte_2
[]
=
{
0xdf
_b
,
0xbf
_b
};
// Smallest valid 3-byte sequence.
constexpr
std
::
byte
valid_three_byte_1
[]
=
{
0xe0
_b
,
0xa0
_b
,
0x80
_b
};
// Largest valid 3-byte sequence.
constexpr
std
::
byte
valid_three_byte_2
[]
=
{
0xef
_b
,
0xbf
_b
,
0xbf
_b
};
// Smallest valid 4-byte sequence.
constexpr
std
::
byte
valid_four_byte_1
[]
=
{
0xf0
_b
,
0x90
_b
,
0x80
_b
,
0x80
_b
};
// Largest valid 4-byte sequence.
constexpr
std
::
byte
valid_four_byte_2
[]
=
{
0xf7
_b
,
0xbf
_b
,
0xbf
_b
,
0xbf
_b
};
// Single line ASCII text.
constexpr
std
::
string_view
ascii_1
=
"Hello World!"
;
// Multi-line ASCII text.
constexpr
std
::
string_view
ascii_2
=
R"__(
* ____ _ _____ *
* / ___| / \ | ___| CAF *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
)__"
;
}
// namespace
TEST_CASE
(
"ASCII input"
)
{
CHECK
(
valid_utf8
(
ascii_1
));
CHECK
(
valid_utf8
(
ascii_2
));
}
TEST_CASE
(
"valid UTF-8 input"
)
{
CHECK
(
valid_utf8
(
valid_two_byte_1
));
CHECK
(
valid_utf8
(
valid_two_byte_2
));
CHECK
(
valid_utf8
(
valid_three_byte_1
));
CHECK
(
valid_utf8
(
valid_three_byte_2
));
CHECK
(
valid_utf8
(
valid_four_byte_1
));
CHECK
(
valid_utf8
(
valid_four_byte_2
));
}
TEST_CASE
(
"invalid UTF-8 input"
)
{
CHECK
(
!
valid_utf8
(
invalid_two_byte_1
));
CHECK
(
!
valid_utf8
(
invalid_two_byte_2
));
CHECK
(
!
valid_utf8
(
invalid_two_byte_3
));
CHECK
(
!
valid_utf8
(
invalid_two_byte_4
));
CHECK
(
!
valid_utf8
(
invalid_three_byte_1
));
CHECK
(
!
valid_utf8
(
invalid_three_byte_2
));
CHECK
(
!
valid_utf8
(
invalid_three_byte_3
));
CHECK
(
!
valid_utf8
(
invalid_three_byte_4
));
CHECK
(
!
valid_utf8
(
invalid_three_byte_5
));
CHECK
(
!
valid_utf8
(
invalid_three_byte_6
));
CHECK
(
!
valid_utf8
(
invalid_three_byte_7
));
CHECK
(
!
valid_utf8
(
invalid_three_byte_8
));
CHECK
(
!
valid_utf8
(
invalid_four_byte_1
));
CHECK
(
!
valid_utf8
(
invalid_four_byte_2
));
CHECK
(
!
valid_utf8
(
invalid_four_byte_3
));
CHECK
(
!
valid_utf8
(
invalid_four_byte_4
));
CHECK
(
!
valid_utf8
(
invalid_four_byte_5
));
CHECK
(
!
valid_utf8
(
invalid_four_byte_6
));
CHECK
(
!
valid_utf8
(
invalid_four_byte_7
));
CHECK
(
!
valid_utf8
(
invalid_four_byte_8
));
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment