@@ -13,6 +13,7 @@ interface
1313 SbpIBaseStreamCoder,
1414 SbpINonAllocatingBaseCoder,
1515 SbpStreamUtilities,
16+ SbpCodingAlphabet,
1617 SbpBase16Alphabet;
1718
1819type
@@ -41,6 +42,9 @@ TBase16 = class(TInterfacedObject, IBase16, IBaseStreamCoder, INonAllocatingBa
4142 class procedure InternalEncode (const AInput: TSimpleBaseLibByteArray;
4243 const AOutput: TSimpleBaseLibCharArray; const AAlphabet: String); static;
4344
45+ function InternalDecode (const AInput: String;
46+ const AOutput: TSimpleBaseLibByteArray; out ABytesWritten: Int32): Boolean;
47+
4448 public
4549 class constructor Create;
4650
@@ -141,23 +145,24 @@ class function TBase16.GetModHex: IBase16;
141145
142146function TBase16.Decode (const AText: String): TSimpleBaseLibByteArray;
143147var
144- LTextLen: Int32;
145- LSafeCount: Int32;
146- LBytesWritten: Int32;
148+ LSafeCount, LBytesWritten: Int32;
147149begin
148- LTextLen := System.Length(AText);
149- if LTextLen = 0 then
150+ if System.Length(AText) = 0 then
150151 begin
151152 Result := nil ;
152153 Exit;
153154 end ;
154155
155156 LSafeCount := GetSafeByteCountForDecoding(AText);
156- System.SetLength(Result, LSafeCount);
157+ if LSafeCount = 0 then
158+ begin
159+ raise EArgumentSimpleBaseLibException.Create(' Invalid text length' );
160+ end ;
157161
158- if not TryDecode(AText, Result, LBytesWritten) then
162+ System.SetLength(Result, LSafeCount);
163+ if not InternalDecode(AText, Result, LBytesWritten) then
159164 begin
160- raise EArgumentSimpleBaseLibException.Create(' Invalid text ' );
165+ raise EArgumentSimpleBaseLibException.Create(' Invalid character in input ' );
161166 end ;
162167end ;
163168
@@ -193,56 +198,30 @@ function TBase16.TryDecode(const AText: String;
193198 const AOutput: TSimpleBaseLibByteArray;
194199 out ABytesWritten: Int32): Boolean;
195200var
196- LTextLen, LI, LO, LByte1, LByte2, LOutputLen: Int32;
197- LChar1, LChar2: Char;
201+ LTextLen, LOutputLen: Int32;
198202begin
203+ ABytesWritten := 0 ;
199204 LTextLen := System.Length(AText);
200205 if LTextLen = 0 then
201206 begin
202- ABytesWritten := 0 ;
203207 Result := True;
204208 Exit;
205209 end ;
206210
207211 if (LTextLen and 1 ) <> 0 then
208212 begin
209- ABytesWritten := 0 ;
210213 Result := False;
211214 Exit;
212215 end ;
213216
214217 LOutputLen := LTextLen div 2 ;
215218 if System.Length(AOutput) < LOutputLen then
216219 begin
217- ABytesWritten := 0 ;
218220 Result := False;
219221 Exit;
220222 end ;
221223
222- LO := 0 ;
223- LI := 1 ;
224- while LI <= LTextLen do
225- begin
226- LChar1 := AText[LI];
227- LChar2 := AText[LI + 1 ];
228-
229- LByte1 := FAlphabet.ReverseLookupTable[Ord(LChar1)] - 1 ;
230- LByte2 := FAlphabet.ReverseLookupTable[Ord(LChar2)] - 1 ;
231-
232- if (LByte1 < 0 ) or (LByte2 < 0 ) then
233- begin
234- ABytesWritten := LO;
235- Result := False;
236- Exit;
237- end ;
238-
239- AOutput[LO] := Byte((LByte1 * 16 ) or LByte2);
240- Inc(LO);
241- Inc(LI, 2 );
242- end ;
243-
244- ABytesWritten := LO;
245- Result := True;
224+ Result := InternalDecode(AText, AOutput, ABytesWritten);
246225end ;
247226
248227function TBase16.Encode (const ABytes: TSimpleBaseLibByteArray): String;
@@ -260,9 +239,9 @@ function TBase16.Encode(const ABytes: TSimpleBaseLibByteArray): String;
260239
261240 LAlphabet := FAlphabet.Value ;
262241 LSafeCount := GetSafeCharCountForEncoding(ABytes);
263- SetLength(LOutput, LSafeCount);
242+ System. SetLength(LOutput, LSafeCount);
264243 InternalEncode(ABytes, LOutput, LAlphabet);
265- SetString(Result, PChar(@LOutput[0 ]), Length(LOutput));
244+ SetString(Result, PChar(@LOutput[0 ]), System. Length(LOutput));
266245end ;
267246
268247function TBase16.TryEncode (const ABytes: TSimpleBaseLibByteArray;
@@ -271,20 +250,18 @@ function TBase16.TryEncode(const ABytes: TSimpleBaseLibByteArray;
271250 LLen, LOutputLen: Int32;
272251 LAlphabet: String;
273252begin
253+ ACharsWritten := 0 ;
274254 LLen := System.Length(ABytes);
275- LOutputLen := LLen * 2 ;
276-
277- if System.Length(AOutput) < LOutputLen then
255+ if LLen = 0 then
278256 begin
279- ACharsWritten := 0 ;
280- Result := False;
257+ Result := True;
281258 Exit;
282259 end ;
283260
284- if LOutputLen = 0 then
261+ LOutputLen := LLen * 2 ;
262+ if System.Length(AOutput) < LOutputLen then
285263 begin
286- ACharsWritten := 0 ;
287- Result := True;
264+ Result := False;
288265 Exit;
289266 end ;
290267
@@ -295,6 +272,39 @@ function TBase16.TryEncode(const ABytes: TSimpleBaseLibByteArray;
295272 Result := True;
296273end ;
297274
275+ function TBase16.InternalDecode (const AInput: String;
276+ const AOutput: TSimpleBaseLibByteArray; out ABytesWritten: Int32): Boolean;
277+ var
278+ LTextLen, LI, LO, LByte1, LByte2: Int32;
279+ LChar1, LChar2: Char;
280+ LTable: TSimpleBaseLibByteArray;
281+ begin
282+ LTable := FAlphabet.ReverseLookupTable;
283+ LTextLen := System.Length(AInput);
284+ LO := 0 ;
285+ LI := 1 ;
286+ while LI <= LTextLen do
287+ begin
288+ LChar1 := AInput[LI];
289+ LChar2 := AInput[LI + 1 ];
290+
291+ if (not TCodingAlphabet.TryLookup(LTable, LChar1, LByte1)) or
292+ (not TCodingAlphabet.TryLookup(LTable, LChar2, LByte2)) then
293+ begin
294+ ABytesWritten := LO;
295+ Result := False;
296+ Exit;
297+ end ;
298+
299+ AOutput[LO] := Byte((LByte1 * 16 ) or LByte2);
300+ Inc(LO);
301+ Inc(LI, 2 );
302+ end ;
303+
304+ ABytesWritten := LO;
305+ Result := True;
306+ end ;
307+
298308class procedure TBase16.InternalEncode (const AInput: TSimpleBaseLibByteArray;
299309 const AOutput: TSimpleBaseLibCharArray; const AAlphabet: String);
300310var
0 commit comments