Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus-es / 2016-12

Problema con Base64

7 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Antonio Evora

Estimados compañeros.

Tengo código para codificar un stream usando base64 y para decodificarlo. Usando el método TnxcxEncoding.TestDataEncoding se hace una codificación en base64 de un stream "controlado" (una cadena fija de solo erres) y el resultado, si el tamaño del stream es inferior a 256 bytes, es correcto, pero si es superior faltan caracteres en el stream resultante (comprobado con una utilidad externa). No le encuentro lógica alguna.

Si alguien tiene alguna idea será bienvenida.

Un cordial saludo y gracias de antemano.

El código es:

unit cEncodingDecoding;
{$mode objfpc}{$H+}
interface
uses
   Classes, SysUtils;
type
   { TnxcxEncoding }
   TnxcxEncoding = class (TObject)
   public
     class function TestDataEncoding(): boolean;
     class function StreamToBase64(aStream: TStream): string;
   end;
   { TnxcxDecoding }
   TnxcxDecoding = class (TObject)
   public
     class function TestDatadecoding(): boolean;
     class function Base64ToStream(Base64: string; var aStream:
TStream): Boolean;
   end;
implementation
uses base64, Forms, Clipbrd;

{ TnxcxDecoding }

class function TnxcxDecoding.TestDatadecoding: boolean;
var
   Texto: string;
   TextoEncoded: string;
   aStream: TStringStream;
   Base64Str: string;
   n: integer;
begin
   Texto:='';
   for n:=1 to 125840 do //257 do //125840 do
   begin
     Texto:=Texto+'r';
   end;
   TextoEncoded:='';
   for n:=1 to 41946 do //257 do //125840 do
   begin
     TextoEncoded:=TextoEncoded+'cnJy';
   end;
   TextoEncoded:=TextoEncoded+'cnI=';
   aStream:=TStringStream.Create(Texto);
   try
     Base64Str:=TnxcxEncoding.StreamToBase64(aStream);
Application.MessageBox(pchar(inttostr(Length(Base64Str))+LineEnding+LineEnding+inttostr(Length(TextoEncoded))),'');
Application.MessageBox(pchar(StringReplace(TextoEncoded,Base64Str,'',[])),'');
     aStream.Position:=0;
     aStream.Size:=0;
     Base64ToStream(Base64Str,TStream(aStream));
Application.MessageBox(pchar(inttostr(Length(aStream.DataString))+LineEnding+LineEnding+inttostr(Length(Texto))),'');
Application.MessageBox(pchar(StringReplace(Texto,aStream.DataString,'',[])),'');
   finally
     aStream.Free;
   end;
Application.MessageBox(pchar(inttostr(Length(DecodeStringBase64(EncodeStringBase64(Texto))))),'');
end;
class function TnxcxDecoding.Base64ToStream(Base64: string; var aStream:
TStream
   ): Boolean;
var
   EncodedStream: TStringStream;
   Base64Decoder: TBase64DecodingStream;
begin
   Result:=False;
   EncodedStream:=TStringStream.Create(Base64);
   try
     try
       if EncodedStream.Size>0 then
       begin
Base64Decoder:=TBase64DecodingStream.Create(EncodedStream);
         try
           aStream.CopyFrom(Base64Decoder,Base64Decoder.Size);
           Result:=True;
         finally
           Base64Decoder.Free;
         end;
       end
       else
       begin
         Result:=True;
       end;
     except
       on e: Exception do
       begin
         exit;
       end;
     end;
   finally
     EncodedStream.Free;
   end;
end;

{ TnxcxEncoding }

class function TnxcxEncoding.TestDataEncoding: boolean;
begin
end;
class function TnxcxEncoding.StreamToBase64(aStream: TStream): string;
const
   BUFFERSIZE=4096;
var
   EncodedStream: TStringStream;
   Base64Encoder: TBase64EncodingStream;
   //aBuffer: array [0..BUFFERSIZE-1] of Byte;
   //Leido: LongInt;
   //TotalLeido: LongInt;
begin
   Result:='';
   EncodedStream:=TStringStream.Create('');
   try
     Base64Encoder:=TBase64EncodingStream.Create(EncodedStream);
     try
       //TotalLeido:=0;
       //
       //repeat
       //  Leido:=aStream.Read(aBuffer,BUFFERSIZE);
       //
       //  if Leido>0 then
       //  begin
       //    TotalLeido:=TotalLeido+Leido;
       //
       //    Base64Encoder.Write(aBuffer,Leido);
       //  end;
       //until Leido<BUFFERSIZE;
       Base64Encoder.CopyFrom(aStream,aStream.Size);
       //Clipboard.AsText:=inttostr(aStream.Size)+' -
'+inttostr(Length(EncodedStream.DataString))+' (167788)';
       Result:=EncodedStream.DataString;
     finally
       Base64Encoder.Free;
     end;
   finally
     EncodedStream.Free;
   end;
end;
end.

Reply by email

José Mejuto
to Antonio Evora
Antonio Evora wrote 9 lines
Estimados compañeros. Tengo código para codificar un stream usando base64 y para decodificarlo. Usando el método TnxcxEncoding.TestDataEncoding se hace una codificación en base64 de un stream "controlado" (una cadena fija de solo erres) y el resultado, si el tamaño del stream es inferior a 256 bytes, es correcto, pero si es superior faltan caracteres en el stream resultante (comprobado con una utilidad externa). No le encuentro lógica alguna.

[...]

Base64Encoder:=TBase64EncodingStream.Create(EncodedStream);
       Base64Encoder.Flush;
Base64Encoder.CopyFrom(aStream,aStream.Size);

Inténtalo con esa linea antes del copyfrom.

Reply by email

Antonio Evora
to José Mejuto

Buenas José.

Añadiendo lo que comentas mantiene el comportamiento anómalo.

Si te fijas al final de método del test codifico y decodifico con las dos funciones de la unidad base64, siendo el resultado correcto: Application.MessageBox(pchar(inttostr(Length(DecodeStringBase64(EncodeStringBase64(Texto))))),'');

Lo que pretendo es generalizar con cualquier stream y no comprendo que puede estar pasando.

Un cordial saludo.

José Mejuto wrote
Base64Encoder.Flush;

Reply by email

José Mejuto
to Antonio Evora
Antonio Evora wrote
Buenas José. Añadiendo lo que comentas mantiene el comportamiento anómalo.

Hola,

Lo siento, la linea es después del CopyFrom, no antes. El Flush has de ejecutarlo siempre antes de obtener los datos finales para indicar que no hay más datos a convertir, ya que si hay 1 byte en el buffer interno ha de añadir "===", si hay 2 "==", si hay 3 "=" y si hay 0, pues el flush no hace nada.

Reply by email

Antonio Evora
to José Mejuto

Efectivamente José, todo solucionado!!!!

Mil gracias.

PD: ¿Ese "Flush" no debería de hacerlo internamente cuando le pido el DataString (con o sin persistencia)?

José Mejuto wrote 13 lines
El 11/12/2016 a las 14:24, Antonio Evora via Lazarus-es escribió: > Buenas José. > > Añadiendo lo que comentas mantiene el comportamiento anómalo. Hola, Lo siento, la linea es después del CopyFrom, no antes. El Flush has de ejecutarlo siempre antes de obtener los datos finales para indicar que no hay más datos a convertir, ya que si hay 1 byte en el buffer interno ha de añadir "===", si hay 2 "==", si hay 3 "=" y si hay 0, pues el flush no hace nada.

Reply by email

José Mejuto
to Antonio Evora
Antonio Evora wrote 6 lines
Efectivamente José, todo solucionado!!!! Mil gracias. PD: ¿Ese "Flush" no debería de hacerlo internamente cuando le pido el DataString (con o sin persistencia)?

Hola,

No porque un stream es un flujo continuo de datos y DataString sólo pertenece TStringStream y es una capa interna de datos. Podría hacerlo automáticamente el stream de encode64 al pedir el DataString, pero la verdad es que todos los streams funcionan del mismo modo, y todos aquellos que necesitan que les indiques el final usan un flush. Si lo hiciera automáticamente también tendría que hacerlo cada vez que haces un "Read", "CopyFrom", etc, lo cual complicaría sobremanera el stream y podría generar situaciones extrañas, como (pseudo código):

Stream.Write('A',1);
Stream.Position:=0;
Stream.Read(A,1);
Stream.Position:=0;
Stream.Write('B',1);
Stream.Position:=0;
Stream.Read(B,Stream.size);
C:=A+B;

Esperamos que C sea igual a "AB" pero en este caso sería algo como:

"A===B==="

Si se hiciera el flush automático.

Reply by email

Antonio Evora
to José Mejuto

Excelente explicación. Yo pensaba que al pedirle la cadena resultante (con DataString) era interpretado como que el proceso había concluido, y visto lo visto nada mas lejos de la realidad ;-)

Un cordial saludo y gracias reiteradas.

José Mejuto wrote 35 lines
El 12/12/2016 a las 9:12, Antonio Evora via Lazarus-es escribió: > Efectivamente José, todo solucionado!!!! > > Mil gracias. > > PD: ¿Ese "Flush" no debería de hacerlo internamente cuando le pido el > DataString (con o sin persistencia)? Hola, No porque un stream es un flujo continuo de datos y DataString sólo pertenece TStringStream y es una capa interna de datos. Podría hacerlo automáticamente el stream de encode64 al pedir el DataString, pero la verdad es que todos los streams funcionan del mismo modo, y todos aquellos que necesitan que les indiques el final usan un flush. Si lo hiciera automáticamente también tendría que hacerlo cada vez que haces un "Read", "CopyFrom", etc, lo cual complicaría sobremanera el stream y podría generar situaciones extrañas, como (pseudo código): Stream.Write('A',1); Stream.Position:=0; Stream.Read(A,1); Stream.Position:=0; Stream.Write('B',1); Stream.Position:=0; Stream.Read(B,Stream.size); C:=A+B; Esperamos que C sea igual a "AB" pero en este caso sería algo como: "A===B===" Si se hiciera el flush automático.

Reply by email