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
eaa0a228
Commit
eaa0a228
authored
Jun 27, 2023
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add utility for UTF-8 validation
parent
fc6e3818
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 @
eaa0a228
...
...
@@ -131,6 +131,7 @@ caf_add_component(
src/detail/print.cpp
src/detail/private_thread.cpp
src/detail/private_thread_pool.cpp
src/detail/rfc3629.cpp
src/detail/ripemd_160.cpp
src/detail/set_thread_name.cpp
src/detail/stream_bridge.cpp
...
...
@@ -271,6 +272,7 @@ caf_add_component(
detail.parser.read_timespan
detail.parser.read_unsigned_integer
detail.private_thread_pool
detail.rfc3629
detail.ringbuffer
detail.ripemd_160
detail.type_id_list_builder
...
...
libcaf_core/caf/detail/rfc3629.hpp
0 → 100644
View file @
eaa0a228
// 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 @
eaa0a228
// 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 @
eaa0a228
// 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