------------------------------------------------------------------------------
-- Copyright (c) 2016-2017, Natacha Porté --
-- --
-- Permission to use, copy, modify, and distribute this software for any --
-- purpose with or without fee is hereby granted, provided that the above --
-- copyright notice and this permission notice appear in all copies. --
-- --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --
-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --
------------------------------------------------------------------------------
with Natools.Smaz_Implementations.Base_64_Tools;
package body Natools.Smaz_Implementations.Base_4096 is
package Tools renames Natools.Smaz_Implementations.Base_64_Tools;
use type Ada.Streams.Stream_Element_Offset;
procedure Read_Code
(Input : in Ada.Streams.Stream_Element_Array;
Offset : in out Ada.Streams.Stream_Element_Offset;
Code : out Base_4096_Digit);
procedure Read_Code_Or_End
(Input : in Ada.Streams.Stream_Element_Array;
Offset : in out Ada.Streams.Stream_Element_Offset;
Code : out Base_4096_Digit;
Finished : out Boolean);
-- Read two base-64 symbols and assemble them into a base-4096 number
------------------------------
-- Local Helper Subprograms --
------------------------------
procedure Read_Code
(Input : in Ada.Streams.Stream_Element_Array;
Offset : in out Ada.Streams.Stream_Element_Offset;
Code : out Base_4096_Digit)
is
Low, High : Tools.Base_64_Digit;
begin
Tools.Next_Digit (Input, Offset, Low);
Tools.Next_Digit (Input, Offset, High);
Code := Base_4096_Digit (Low) + Base_4096_Digit (High) * 64;
end Read_Code;
procedure Read_Code_Or_End
(Input : in Ada.Streams.Stream_Element_Array;
Offset : in out Ada.Streams.Stream_Element_Offset;
Code : out Base_4096_Digit;
Finished : out Boolean)
is
Low, High : Tools.Base_64_Digit;
begin
Tools.Next_Digit_Or_End (Input, Offset, Low, Finished);
if Finished then
return;
end if;
Tools.Next_Digit (Input, Offset, High);
Code := Base_4096_Digit (Low) + Base_4096_Digit (High) * 64;
end Read_Code_Or_End;
----------------------
-- Public Interface --
----------------------
procedure Read_Code
(Input : in Ada.Streams.Stream_Element_Array;
Offset : in out Ada.Streams.Stream_Element_Offset;
Code : out Base_4096_Digit;
Verbatim_Length : out Natural;
Last_Code : in Base_4096_Digit;
Variable_Length_Verbatim : in Boolean)
is
Finished : Boolean;
begin
Read_Code_Or_End (Input, Offset, Code, Finished);
if Finished then
Code := Base_4096_Digit'Last;
Verbatim_Length := 0;
return;
end if;
if Code <= Last_Code then
Verbatim_Length := 0;
elsif not Variable_Length_Verbatim then
Verbatim_Length := Positive (Base_4096_Digit'Last - Code + 1);
Code := 0;
elsif Code < Base_4096_Digit'Last then
Verbatim_Length := Positive (Base_4096_Digit'Last - Code);
Code := 0;
else
Read_Code (Input, Offset, Code);
Verbatim_Length
:= Natural (Code) + Natural (Base_4096_Digit'Last - Last_Code);
Code := 0;
end if;
end Read_Code;
procedure Read_Verbatim
(Input : in Ada.Streams.Stream_Element_Array;
Offset : in out Ada.Streams.Stream_Element_Offset;
Output : out String) is
begin
Tools.Decode (Input, Offset, Output);
end Read_Verbatim;
procedure Skip_Verbatim
(Input : in Ada.Streams.Stream_Element_Array;
Offset : in out Ada.Streams.Stream_Element_Offset;
Verbatim_Length : in Positive)
is
Code : Tools.Base_64_Digit;
begin
for I in 1 .. Tools.Image_Length (Verbatim_Length) loop
Tools.Next_Digit (Input, Offset, Code);
end loop;
end Skip_Verbatim;
function Verbatim_Size
(Input_Length : in Positive;
Last_Code : in Base_4096_Digit;
Variable_Length_Verbatim : in Boolean)
return Ada.Streams.Stream_Element_Count
is
Verbatim1_Max_Size : constant Natural
:= Natural (Base_4096_Digit'Last - Last_Code)
- Boolean'Pos (Variable_Length_Verbatim);
Verbatim2_Max_Size : constant Natural
:= Natural (Base_4096_Digit'Last) + Verbatim1_Max_Size + 1;
Input_Index : Natural := 0;
Remaining_Length, Block_Length : Positive;
Result : Ada.Streams.Stream_Element_Count := 0;
begin
while Input_Index < Input_Length loop
Remaining_Length := Input_Length - Input_Index;
if Variable_Length_Verbatim
and then Remaining_Length > Verbatim1_Max_Size
then
Block_Length := Positive'Min
(Remaining_Length, Verbatim2_Max_Size);
Result := Result + 4;
else
Block_Length := Positive'Min
(Remaining_Length, Verbatim1_Max_Size);
Result := Result + 2;
end if;
Result := Result + Tools.Image_Length (Block_Length);
Input_Index := Input_Index + Block_Length;
end loop;
return Result;
end Verbatim_Size;
procedure Write_Code
(Output : in out Ada.Streams.Stream_Element_Array;
Offset : in out Ada.Streams.Stream_Element_Offset;
Code : in Base_4096_Digit)
is
Low : constant Tools.Base_64_Digit := Tools.Base_64_Digit (Code mod 64);
High : constant Tools.Base_64_Digit := Tools.Base_64_Digit (Code / 64);
begin
Output (Offset + 0) := Tools.Image (Low);
Output (Offset + 1) := Tools.Image (High);
Offset := Offset + 2;
end Write_Code;
procedure Write_Verbatim
(Output : in out Ada.Streams.Stream_Element_Array;
Offset : in out Ada.Streams.Stream_Element_Offset;
Input : in String;
Last_Code : in Base_4096_Digit;
Variable_Length_Verbatim : in Boolean)
is
Verbatim1_Max_Size : constant Natural
:= Natural (Base_4096_Digit'Last - Last_Code)
- Boolean'Pos (Variable_Length_Verbatim);
Verbatim2_Max_Size : constant Natural
:= Natural (Base_4096_Digit'Last) + Verbatim1_Max_Size + 1;
Input_Index : Positive := Input'First;
Remaining_Length, Block_Length : Positive;
begin
while Input_Index in Input'Range loop
Remaining_Length := Input'Last - Input_Index + 1;
if Variable_Length_Verbatim
and then Remaining_Length > Verbatim1_Max_Size
then
Block_Length := Positive'Min
(Remaining_Length, Verbatim2_Max_Size);
Write_Code (Output, Offset, Base_4096_Digit'Last);
Write_Code (Output, Offset, Base_4096_Digit
(Block_Length - Verbatim1_Max_Size - 1));
else
Block_Length := Positive'Min
(Remaining_Length, Verbatim1_Max_Size);
Write_Code (Output, Offset, Base_4096_Digit
(Base_4096_Digit'Last - Base_4096_Digit (Block_Length)
+ 1 - Boolean'Pos (Variable_Length_Verbatim)));
end if;
Tools.Encode
(Input (Input_Index .. Input_Index + Block_Length - 1),
Output, Offset);
Input_Index := Input_Index + Block_Length;
end loop;
end Write_Verbatim;
end Natools.Smaz_Implementations.Base_4096;