-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathLightCore.EncodeMime.pas
More file actions
197 lines (156 loc) · 6.08 KB
/
LightCore.EncodeMime.pas
File metadata and controls
197 lines (156 loc) · 6.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
UNIT LightCore.EncodeMime;
{=============================================================================================================
2026.01.30
www.GabrielMoraru.com
Github.com/GabrielOnDelphi/Delphi-LightSaber/blob/main/System/Copyright.txt
==============================================================================================================
MIME/BASE64 ENCODING LIB
Provides functions for MIME (Base64) encoding/decoding of strings.
This unit wraps Soap.EncdDecd to provide simpler, safer string-based operations.
Two variants are provided:
- MimeString/DeMimeString: For Unicode strings (uses UTF-8 encoding internally)
- MimeStringA/DeMimeStringA: For AnsiString (raw byte operations)
Don't use EncdDecd directly - it was updated for Unicode:
http://stackoverflow.com/questions/21883152/how-to-encode-strings-with-encddec-library/21883731#21883731
=============================================================================================================}
INTERFACE
USES
System.Classes, System.SysUtils, Soap.EncdDecd, System.NetEncoding;
{ Unicode string encoding - handles UTF-8 conversion automatically }
function MimeString (CONST Input: string): string;
function DeMimeString (CONST Input: string): string;
{ AnsiString encoding - raw byte operations, no character set conversion }
function MimeStringA (CONST Input: AnsiString): AnsiString;
function DeMimeStringA (CONST Input: AnsiString): AnsiString;
IMPLEMENTATION
USES
LightCore.StreamMem;
{--------------------------------------------------------------------------------------------------
UNICODE STRING MIME ENCODING
These functions handle Unicode strings by converting to/from UTF-8 internally.
The Base64 output is ASCII-safe and can be transmitted through any text channel.
Example:
Encoded:= MimeString('Hello World'); // Returns 'SGVsbG8gV29ybGQ='
Original:= DeMimeString(Encoded); // Returns 'Hello World'
--------------------------------------------------------------------------------------------------}
{ Encodes a Unicode string to Base64.
The input is first converted to UTF-8 bytes, then those bytes are Base64-encoded.
Returns an empty string if Input is empty.
Solution credit: David Heffernan (StackOverflow) }
function MimeString(CONST Input: string): string;
var
InStr, OutStr: TStringStream;
begin
if Input = '' then EXIT('');
InStr:= TStringStream.Create(Input, TEncoding.UTF8);
try
OutStr:= TStringStream.Create('');
try
EncodeStream(InStr, OutStr);
Result:= OutStr.DataString;
finally
FreeAndNil(OutStr);
end;
finally
FreeAndNil(InStr);
end;
end;
{ Decodes a Base64 string back to Unicode.
The Base64 input is decoded to bytes, then interpreted as UTF-8 to produce the result.
Returns an empty string if Input is empty. }
function DeMimeString(CONST Input: string): string;
var
InStr, OutStr: TStringStream;
begin
if Input = '' then EXIT('');
InStr:= TStringStream.Create(Input);
try
OutStr:= TStringStream.Create('', TEncoding.UTF8);
try
DecodeStream(InStr, OutStr);
Result:= OutStr.DataString;
finally
FreeAndNil(OutStr);
end;
finally
FreeAndNil(InStr);
end;
end;
{--------------------------------------------------------------------------------------------------
ANSISTRING MIME ENCODING
These functions handle raw AnsiString bytes without any character set conversion.
Useful for binary data or legacy systems that work with AnsiString.
Used by: cpCertificate.pas
Implementation note:
WriteChars writes raw bytes without a length prefix.
ReadCharsA reads raw bytes without expecting a length prefix.
These must be paired correctly (both use count-based, not length-prefixed operations).
--------------------------------------------------------------------------------------------------}
{ Encodes an AnsiString to Base64.
The raw bytes of the input are Base64-encoded without any character set conversion.
Returns an empty string if Input is empty. }
function MimeStringA(CONST Input: AnsiString): AnsiString;
var
InStr, OutStr: TCubicMemStream;
begin
if Input = '' then EXIT('');
InStr:= TCubicMemStream.Create;
try
InStr.WriteChars(Input);
InStr.Position:= 0;
OutStr:= TCubicMemStream.Create;
try
EncodeStream(InStr, OutStr);
{ ReadCharsA reads raw bytes without expecting a length prefix.
This matches WriteChars which also doesn't write a length prefix.
We pass OutStr.Size as SafetyLimit since we know the exact data size. }
OutStr.Position:= 0;
Result:= OutStr.ReadCharsA(OutStr.Size, OutStr.Size);
finally
FreeAndNil(OutStr);
end;
finally
FreeAndNil(InStr);
end;
end;
{ Decodes a Base64 AnsiString back to raw bytes.
Returns an empty string if Input is empty.
Raises exception for invalid Base64 input. }
function DeMimeStringA(CONST Input: AnsiString): AnsiString;
var
InStr, OutStr: TCubicMemStream;
i: Integer;
c: AnsiChar;
begin
if Input = '' then EXIT('');
{ Validate Base64 characters before attempting to decode }
for i:= 1 to Length(Input) do
begin
c:= Input[i];
if NOT (((c >= 'A') AND (c <= 'Z')) OR
((c >= 'a') AND (c <= 'z')) OR
((c >= '0') AND (c <= '9')) OR
(c = '+') OR (c = '/') OR (c = '=') OR
(c = #13) OR (c = #10) OR (c = ' ')) { Allow whitespace }
then raise EEncodingError.Create('Invalid Base64 character in input');
end;
InStr:= TCubicMemStream.Create;
try
InStr.WriteChars(Input);
InStr.Position:= 0;
OutStr:= TCubicMemStream.Create;
try
DecodeStream(InStr, OutStr);
{ ReadCharsA reads raw bytes without expecting a length prefix.
This matches WriteChars which also doesn't write a length prefix.
We pass OutStr.Size as SafetyLimit since we know the exact data size. }
OutStr.Position:= 0;
Result:= OutStr.ReadCharsA(OutStr.Size, OutStr.Size);
finally
FreeAndNil(OutStr);
end;
finally
FreeAndNil(InStr);
end;
end;
end.