E-MailRelay
gxtext.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gxtext.cpp
19///
20
21#include "gdef.h"
22#include "gxtext.h"
23#include "gstr.h"
24#include "gassert.h"
25#include <array>
26
27namespace G
28{
29 namespace XtextImp
30 {
31 inline char hex( unsigned int n )
32 {
33 static constexpr std::array<char,17> map {{ "0123456789ABCDEF" }} ;
34 //static_assert( map[15] == 'F' , "" ) ;
35 return map[n] ;
36 }
37 inline bool ishex( char c , bool allow_lowercase )
38 {
39 return
40 ( c >= '0' && c <= '9' ) ||
41 ( allow_lowercase && c >= 'a' && c <= 'f' ) ||
42 ( c >= 'A' && c <= 'F' ) ;
43 }
44 inline unsigned int unhex( char c )
45 {
46 unsigned int rc = 0U ;
47 switch( c ) // NOLINT
48 {
49 case '0': rc = 0U ; break ;
50 case '1': rc = 1U ; break ;
51 case '2': rc = 2U ; break ;
52 case '3': rc = 3U ; break ;
53 case '4': rc = 4U ; break ;
54 case '5': rc = 5U ; break ;
55 case '6': rc = 6U ; break ;
56 case '7': rc = 7U ; break ;
57 case '8': rc = 8U ; break ;
58 case '9': rc = 9U ; break ;
59 case 'A': rc = 10U ; break ;
60 case 'B': rc = 11U ; break ;
61 case 'C': rc = 12U ; break ;
62 case 'D': rc = 13U ; break ;
63 case 'E': rc = 14U ; break ;
64 case 'F': rc = 15U ; break ;
65 case 'a': rc = 10U ; break ;
66 case 'b': rc = 11U ; break ;
67 case 'c': rc = 12U ; break ;
68 case 'd': rc = 13U ; break ;
69 case 'e': rc = 14U ; break ;
70 case 'f': rc = 15U ; break ;
71 }
72 return rc ;
73 }
74 }
75}
76
77bool G::Xtext::valid( std::string_view s , bool strict )
78{
79 namespace imp = XtextImp ;
80 if( !Str::isPrintableAscii(s) || ( strict && s.find_first_of("= ") != std::string::npos ) )
81 {
82 return false ;
83 }
84 else
85 {
86 std::size_t pos = s.find('+') ;
87 for( ; pos != std::string::npos ; pos = ((pos+1U)==s.size()?std::string::npos:s.find('+',pos+1U)) )
88 {
89 if( (pos+2U) >= s.size() ) return false ;
90 if( !imp::ishex(s.at(pos+1U),!strict) ) return false ;
91 if( !imp::ishex(s.at(pos+2U),!strict) ) return false ;
92 }
93 return true ;
94 }
95}
96
97std::string G::Xtext::encode( std::string_view s )
98{
99 namespace imp = XtextImp ;
100 std::string result ;
101 for( char c : s )
102 {
103 if( c >= '!' && c <= '~' && c != '=' && c != '+' )
104 {
105 result.append( 1U , c ) ;
106 }
107 else
108 {
109 unsigned int n = static_cast<unsigned char>(c) ;
110 result.append( 1U , '+' ) ;
111 result.append( 1U , imp::hex( n >> 4U ) ) ;
112 result.append( 1U , imp::hex( n & 0x0f ) ) ;
113 }
114 }
115 G_ASSERT( decode(result) == s ) ;
116 return result ;
117}
118
119std::string G::Xtext::decode( std::string_view s )
120{
121 namespace imp = XtextImp ;
122 std::string result ;
123 result.reserve( s.size() ) ;
124 for( auto p = s.begin() ; p != s.end() ; ++p ) // NOLINT
125 {
126 if( *p == '+' )
127 {
128 ++p ; if( p == s.end() ) break ;
129 char h1 = *p++ ; if( p == s.end() ) break ;
130 char h2 = *p ;
131 unsigned int c = ( imp::unhex(h1) << 4U ) | imp::unhex(h2) ;
132 result.append( 1U , static_cast<char>(static_cast<unsigned char>(c)) ) ;
133 }
134 else
135 {
136 result.append( 1U , *p ) ;
137 }
138 }
139 return result ;
140}
141
static bool isPrintableAscii(std::string_view s) noexcept
Returns true if every character is between 0x20 and 0x7e inclusive.
Definition: gstr.cpp:413
static std::string encode(std::string_view)
Encodes the given string.
Definition: gxtext.cpp:97
static std::string decode(std::string_view)
Decodes the given string.
Definition: gxtext.cpp:119
static bool valid(std::string_view, bool strict=false)
Returns true if a valid encoding, or empty.
Definition: gxtext.cpp:77
Low-level classes.
Definition: garg.h:36