Which is the best method to detect if a string is Base64Encoded or not (using Delphi)?
Best you can do is try to decode it. If the decode fails then the input was not base64 encoded. It the string successfully decodes then the input might have been base64 encoded.
You can check if the string only contains Base64 valids chars
function StringIsBase64(const InputString : String ) : Boolean;
const
Base64Chars: Set of AnsiChar = ['A'..'Z','a'..'z','0'..'9','+','/','='];
var
i : integer;
begin
Result:=True;
for i:=1 to Length(InputString) do
{$IFDEF UNICODE}
if not CharInSet(InputString[i],Base64Chars) then
{$ELSE}
if not (InputString[i] in Base64Chars) then
{$ENDIF}
begin
Result:=False;
break;
end;
end;
The = char is used for padding so you can add an aditional valiation to the function for padded base64 strings checking if the length of the string is mod 4
In addition to RRUZ answer you can also check the length of the string (is it a multiple of 4).
function IsValidBase64(const aValue: string): Boolean;
var
i: Integer;
lValidChars: set of Char;
begin
Result := aValue <> '';
lValidChars := ['a'..'z', 'A'..'Z', '0'..'9', '/', '+'];
//length of string should be multiple of 4
if Length(aValue) mod 4 > 0 then
Result := False
else
for i := 1 to Length(aValue) do
begin
if aValue[i] = '=' then
begin
if i < Length(aValue) - 1 then
begin
Result := False;
Exit;
end
else
lValidChars := ['='];
end
else if not (aValue[i] in lValidChars) then
begin
Result := False;
Break;
end;
end;
end;
Please note that this code is Delphi 7 code and not adjusted for Unicode use.
As was already told here, there is no reliable verification if a certain string is Base64 encoded or not, so even when you consider the input as a valid Base64 encoded string, it doesn't mean the string is actually encoded that way. I'm posting here just another version of a validation function, which according to RFC 4648 verifies:
if the input string is not empty and its length is multiple of 4
if the input string contains at most two padding characters and only at the end of the string
if the input string contains only characters from the Base64 alphabet (see the Page 5, Table 1)
function IsValidBase64EncodedString(const AValue: string): Boolean;
const
Base64Alphabet = ['A'..'Z', 'a'..'z', '0'..'9', '+', '/'];
var
I: Integer;
ValLen: Integer;
begin
ValLen := Length(AValue);
Result := (ValLen > 0) and (ValLen mod 4 = 0);
if Result then
begin
while (AValue[ValLen] = '=') and (ValLen > Length(AValue) - 2) do
Dec(ValLen);
for I := ValLen downto 1 do
if not (AValue[I] in Base64Alphabet) then
begin
Result := False;
Break;
end;
end;
end;
Related
var
btof: boolean;
const
allowed = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
begin
btof:= false;
for i := 1 to length(sfilename) do
begin
if (sfilename[i] in [allowed[1] .. allowed[length(allowed)]])
then
btof := true;
end;
end;
I've been staring at this for the past hour trying to see the problem, but I just can't find it...
btof is always false, no matter the input.
The set notation [allowed[1] .. allowed[length(allowed)] boils down to a set of char ['a'..'9']. As the literal '9' has a lesser value than the literal 'a', the resulting set is just empty.
That is not how you check if a character is in an string. Actually you check if the character is between 'a' and '9'. That's not really what you intent to do.
Here is an implementation that works:
// Check if a filename contain any illegal character
function CheckIllegal(const SFilename : String) : Boolean;
var
C : Char;
const
Allowed = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
begin
Result := FALSE;
for C in SFilename do begin
if Pos(C, Allowed) < 1 then begin
Result := TRUE;
break;
end;
end;
end;
By the way, your list of allowed characters in a filename is incomplete, at least if you think about Windows OS.
var
bAllowed: boolean;
sfilename: string;
i, x: Integer;
C: Integer;
const
allowed = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
begin
bAllowed := true;
sfilename := edtInput.Text;
i := Length(sfilename);
x := 1;
while ((x <= i) and (bAllowed)) do
begin
bAllowed := Pos(sfilename[x], allowed) > 0;
Inc(x);
end;
if bAllowed then
ShowMessage('The string is valid')
else
ShowMessage('The string isn''t valid');
This is a more optimized version of the code. I take it that the purpose of the code that you gave was to determine if the string is valid and return a bool. Thus it only has to check up and till the point that it finds an illegal char in the string.
Note that I have changed it that if the string is valid it returns a true and invalid a false.
function HexToDec(Str: string): Integer;
var
i, M: Integer;
begin
Result:=0;
M:=1;
Str:=AnsiUpperCase(Str);
for i:=Length(Str) downto 1 do
begin
case Str[i] of
'1'..'9': Result:=Result+(Ord(Str[i])-Ord('0'))*M;
'A'..'F': Result:=Result+(Ord(Str[i])-Ord('A')+10)*M;
end;
M:=M shl 4;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if Edit1.Text<>'' then
Label2.Caption:=IntToStr(HexToDec(Edit1.Text));
end;
How to using it without function, because i want to call the result again in other line, and how about hexa to octal ? am i must conver from hexa to dec and then dec to octal?
Delphi can do this already, so you don't need to write a function parsing the number. It is quite simple, actually:
function HexToDec(const Str: string): Integer;
begin
if (Str <> '') and ((Str[1] = '-') or (Str[1] = '+')) then
Result := StrToInt(Str[1] + '$' + Copy(Str, 2, MaxInt))
else
Result := StrToInt('$' + Str);
end;
Note that that also handles negative hex numbers, or numbers like +$1234.
How to using it without function, because i want to call the result again in other line ?
If you want to re-use the value, assign the result of HexToDec to a variable and use that in IntToStr.
FWIW, in your function, there is no need to call AnsiUpperCase, because all hex digits fall in the ASCII range anyway. A much simpler UpperCase should work too.
My first comment would be that you are not converting hex to decimal with your function (although you are converting to decimal as an intermediate) but rather hex to integer. IntToStr then converts integer to base 10, effectively. To generalise what you want then I would create two functions - strBaseToInt and IntToStrBase where Base is meant to imply e.g. 16 for hex, 10 for dec, 8 for octal, etc., and assuming the convention adopted by hex that A=10, and so on but to (possibly) Z = 35 making the maximum base possible 36.
I don't handle + or - but that could be added easily.
In the reverse funtion, again for simplicity of illustration I have ommitted supporting negative values.
Edit
Thanks to Rudy for this improvement
Edit 2 - Overflow test added, as per comments
function StrBaseToInt(const Str: string; const Base : integer): Integer;
var
i, iVal, iTest: Longword;
begin
if (Base > 36) or (Base < 2) then raise Exception.Create('Invalid Base');
Result:=0;
iTest := 0;
for i:=1 to Length(Str) do
begin
case Str[i] of
'0'..'9': iVal := (Ord(Str[i])-Ord('0'));
'A'..'Z': iVal := (Ord(Str[i])-Ord('A')+10);
'a'..'z': iVal := (Ord(Str[i])-Ord('a')+10);
else raise Exception.Create( 'Illegal character found');
end;
if iVal < Base then
begin
Result:=Result * Base + iVal;
if Result < iTest then // overflow test!
begin
raise Exception.Create( 'Overflow occurred');
end
else
begin
iTest := Result;
end;
end
else
begin
raise Exception.Create( 'Illegal character found');
end;
end;
end;
Then, for example your HexToOct function would look like this
function HexToOct( Value : string ) : string;
begin
Result := IntToStrBase( StrBaseToInt( Value, 16), 8 );
end;
Additional
A general function would be
function BaseToBase( const Value : string; const FromBase, ToBase : integer ) : string;
begin
Result := IntToStrBase( StrBaseToInt( Value, FromBase ),ToBase );
end;
I want to convert a string of integers in hexadecimal (and the opposite).
I've seen the IntToHex functions, but it uses a small integer.
For example, I need to convert the number:
999888777666555444 in hexadecimal
and then the opposite:
hexadecimal number in 999888777666555444
If you need to convert more than 8-bytes values, you can represent your very-long-integer as array of byte, word, dword or something. In that case you should just convert any particular item and concatenate results. Opposite is the same (only thing you should remember is value should be considered as right-aligned).
converting a arbitrary length buffer to hex:
function HexDump(const _Buffer; _Len: integer): string;
type
PByte = ^Byte;
var
i: integer;
p: PByte;
begin
p := #_Buffer;
Result := '';
for i := 0 to _Len - 1 do begin
Result := Result + Long2Hex2(p^);
Inc(p);
end;
end;
And the utility functions used by this:
const
/// <summary>
/// String containing all characters that can be used as digits
/// </summary>
DIGIT_CHARS: string = '0123456789ABCDEFGHIJKlMNOPQRSTUVWXYZ';
function Long2Num(_l: ULong; _Base: Byte; _MinWidth: Integer = 1): string;
var
m: Byte;
begin
Result := '';
while _l > 0 do begin
m := _l mod _Base;
_l := _l div _Base;
Result := DIGIT_CHARS[m + 1] + Result;
end;
while Length(Result) < _MinWidth do
Result := '0' + Result;
end;
function Long2Hex(_l: ULong): string;
begin
Result := Long2Num(_l, 16);
end;
function Long2Hex2(_l: ULong): string;
begin
Result := Long2Hex(_l);
if Length(Result) < 2 then
Result := '0' + Result;
end;
These functions are part of my dzlib.
Note: This does not generate the hex numbers as you might expect them, e.g. if you pass an integer to the function like this:
var
IntValue: integer;
begin
IntValue := $12345678;
s := HexDump(IntValue, SizeOf(IntValue));
end;
You end up with s = '78563412' because Intel processors store integers in little endian format.
Unfortunately the other way round is more difficult, because there is no standard arbitrary length integer type in Delphi. There are some implementations of such a type though.
I am trying to validate a string, where by it can contain all alphebetical and numerical characters, aswell as the underline ( _ ) symbol.
This is what I tried so far:
var
S: string;
const
Allowed = ['A'..'Z', 'a'..'z', '0'..'9', '_'];
begin
S := 'This_is_my_string_0123456789';
if Length(S) > 0 then
begin
if (Pos(Allowed, S) > 0 then
ShowMessage('Ok')
else
ShowMessage('string contains invalid symbols');
end;
end;
In Lazarus this errors with:
Error: Incompatible type for arg no. 1: Got "Set Of Char", expected
"Variant"
Clearly my use of Pos is all wrong and I am not sure if my approach is even the correct way of going about it or not?
Thanks.
You will have to check every single character of the string, if it's contained in Allowed
e.g.:
var
S: string;
const
Allowed = ['A' .. 'Z', 'a' .. 'z', '0' .. '9', '_'];
Function Valid: Boolean;
var
i: Integer;
begin
Result := Length(s) > 0;
i := 1;
while Result and (i <= Length(S)) do
begin
Result := Result AND (S[i] in Allowed);
inc(i);
end;
if Length(s) = 0 then Result := true;
end;
begin
S := 'This_is_my_string_0123456789';
if Valid then
ShowMessage('Ok')
else
ShowMessage('string contains invalid symbols');
end;
TYPE TCharSet = SET OF CHAR;
FUNCTION ValidString(CONST S : STRING ; CONST ValidChars : TCharSet) : BOOLEAN;
VAR
I : Cardinal;
BEGIN
Result:=FALSE;
FOR I:=1 TO LENGTH(S) DO IF NOT (S[I] IN ValidChars) THEN EXIT;
Result:=TRUE
END;
If you are using a Unicode version of Delphi (as you seem to be), beware that a SET OF CHAR cannot contain all valid characters in the Unicode character set. Then perhaps this function will be useful instead:
FUNCTION ValidString(CONST S,ValidChars : STRING) : BOOLEAN;
VAR
I : Cardinal;
BEGIN
Result:=FALSE;
FOR I:=1 TO LENGTH(S) DO IF POS(S[I],ValidChars)=0 THEN EXIT;
Result:=TRUE
END;
but then again, not all characters (actually Codepoints) in Unicode can be expressed by a single character, and some characters can be expressed in more than one way (both as a single character and as a multi-character).
But as long as you constrain yourself within these limitations, one of the above functions should be useful. You can even include both, if you add an "OVERLOAD;" directive to the end of each function declaration, as in:
FUNCTION ValidString(CONST S : STRING ; CONST ValidChars : TCharSet) : BOOLEAN; OVERLOAD;
FUNCTION ValidString(CONST S,ValidChars : STRING) : BOOLEAN; OVERLOAD;
Lazarus/Free Pascal doesn't overload pos for that but has "posset" variants in unit strutils for that;
http://www.freepascal.org/docs-html/rtl/strutils/posset.html
Regarding Andreas' (IMHO correct ) remark, you can use isemptystr for that. It was meant to check for strings that only contain whitespace, but it basically checks if a string only contains characters in a set.
http://www.freepascal.org/docs-html/rtl/strutils/isemptystr.html
You can use Regular Expressions:
uses System.RegularExpressions;
if not TRegEx.IsMatch(S, '^[_a-zA-Z0-9]+$') then
ShowMessage('string contains invalid symbols');
Is there a method in Delphi to check if a string is a number without raising an exception?
its for int parsing.
and an exception will raise if one use the
try
StrToInt(s);
except
//exception handling
end;
function TryStrToInt(const S: string; out Value: Integer): Boolean;
TryStrToInt converts the string S, which represents an integer-type number in either decimal or hexadecimal notation, into a number, which is assigned to Value. If S does not represent a valid number, TryStrToInt returns false; otherwise TryStrToInt returns true.
To accept decimal but not hexadecimal values in the input string, you may use code like this:
function TryDecimalStrToInt( const S: string; out Value: Integer): Boolean;
begin
result := ( pos( '$', S ) = 0 ) and TryStrToInt( S, Value );
end;
var
s: String;
iValue, iCode: Integer;
...
val(s, iValue, iCode);
if iCode = 0 then
ShowMessage('s has a number')
else
ShowMessage('s has not a number');
Try this function StrToIntDef()
From help
Converts a string that represents an integer (decimal or hex notation) to a number with error default.
Pascal
function StrToIntDef(const S: string; Default: Integer): Integer;
Edit
Just now checked the source of TryStrToInt() function in Delphi 2007. If Delphi 7 dont have this function you can write like this. Its just a polished code to da-soft answer
function TryStrToInt(const S: string; out Value: Integer): Boolean;
var
E: Integer;
begin
Val(S, Value, E);
Result := E = 0;
end;
XE4 and newer:
for ch in s do
TCharacter.IsNumber(ch);
Don't forget:
uses System.Character
In delphi 7 you can use the Val procedure. From the help:
Unit: System
Delphi syntax: procedure Val(S; var V; var Code: Integer);
S is a string-type expression; it must be a sequence of characters that form a signed real number.
V is an integer-type or real-type variable. If V is an integer-type variable, S must form a whole number.
Code is a variable of type Integer.
If the string is invalid, the index of the offending character is stored in Code; otherwise, Code is set to zero. For a null-terminated string, the error position returned in Code is one larger than the actual zero-based index of the character in error.
use this function
function IsNumber(N : String) : Boolean;
var
I : Integer;
begin
Result := True;
if Trim(N) = '' then
Exit(False);
if (Length(Trim(N)) > 1) and (Trim(N)[1] = '0') then
Exit(False);
for I := 1 to Length(N) do
begin
if not (N[I] in ['0'..'9']) then
begin
Result := False;
Break;
end;
end;
end;
For older Delphi versions from delphi 5 help example:
uses Dialogs;
var
I, Code: Integer;
begin
{ Get text from TEdit control }
Val(Edit1.Text, I, Code);
{ Error during conversion to integer? }
if Code <> 0 then
MessageDlg('Error at position: ' + IntToStr(Code), mtWarning, [mbOk], 0);
else
Canvas.TextOut(10, 10, 'Value = ' + IntToStr(I));
end;
In some languages decimal separators are different (for example, '.' is used in English and ',' is used in Russian). For these cases to convert string to real number the following procedure is proposed:
function TryStrToFloatMultiLang(const S : String; out Value : Extended) : Boolean;
var
dc : char;
begin
Result := false;
dc := DecimalSeparator;
DecimalSeparator := '.';
try
Result := TryStrToFloat(S, Value);
except
DecimalSeparator := ',';
Result := TryStrToFloat(S, Value);
end;
DecimalSeparator := dc;
end;
Update
As #Pep mentioned TryStrToFloat catch exceptions, but it returns boolean value. So the correct code is:
function TryStrToFloatMultiLang(const S : String; out Value : Extended) : Boolean;
var
dc : char;
begin
Result := false;
dc := DecimalSeparator;
DecimalSeparator := '.';
Result := TryStrToFloat(S, Value);
if not Result then begin
DecimalSeparator := ',';
Result := TryStrToFloat(S, Value);
end;
DecimalSeparator := dc;
end;
When you using procedure
val(s, i, iCode);
and set value xd ....
val('xd', i, iCode)
as a result we obtain: 13
standard unit Variants
function VarIsNumeric(v:Variant):Boolean