-- -- -- package Copyright (c) Dmitry A. Kazakov -- -- GNAT.Sockets.Connection_State_Machine. Luebeck -- -- ASN1.Dates Spring, 2019 -- -- Implementation -- -- Last revision : 13:37 03 Aug 2019 -- -- -- -- This library is free software; you can redistribute it and/or -- -- modify it under the terms of the GNU General Public License as -- -- published by the Free Software Foundation; either version 2 of -- -- the License, or (at your option) any later version. This library -- -- is distributed in the hope that it will be useful, but WITHOUT -- -- ANY WARRANTY; without even the implied warranty of -- -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- -- General Public License for more details. You should have -- -- received a copy of the GNU General Public License along with -- -- this library; if not, write to the Free Software Foundation, -- -- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- -- -- -- As a special exception, if other files instantiate generics from -- -- this unit, or you link this unit with other files to produce an -- -- executable, this unit does not by itself cause the resulting -- -- executable to be covered by the GNU General Public License. This -- -- exception does not however invalidate any other reasons why the -- -- executable file might be covered by the GNU Public License. -- --____________________________________________________________________-- with Ada.Exceptions; use Ada.Exceptions; with Ada.IO_Exceptions; use Ada.IO_Exceptions; with Strings_Edit.Integers; use Strings_Edit.Integers; with Strings_Edit.Floats; use Strings_Edit.Floats; with Ada.Calendar.Formatting; with Strings_Edit.ISO_8601; with GNAT.Sockets.Connection_State_Machine.ASN1.Lengths; use GNAT.Sockets.Connection_State_Machine.ASN1.Lengths; package body GNAT.Sockets.Connection_State_Machine.ASN1.Dates is use GNAT.Sockets.Connection_State_Machine.ASN1.Strings; Invalid_Time : constant String := "Invalid ASN.1 time"; procedure Explicit_Put_Date is new Generic_Put (Time, Put_Date); procedure Encode ( Item : Date_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Explicit_Put_Date (Data, Pointer, Date_Tag, Item.Value); end Encode; procedure Explicit_Put_Date_Time is new Generic_Put (Time, Put_Date_Time); procedure Encode ( Item : Date_Time_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Explicit_Put_Date_Time (Data, Pointer, Date_Time_Tag, Item.Value); end Encode; procedure Explicit_Put_Duration is new Generic_Put (Duration, Put_Duration); procedure Encode ( Item : Duration_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Explicit_Put_Duration (Data, Pointer, Duration_Tag, Item.Value); end Encode; procedure Explicit_Put is new Generic_Put (Time); procedure Encode ( Item : Generalized_Time_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Explicit_Put (Data, Pointer, Generalized_Time_Tag, Item.Value); end Encode; procedure Encode ( Item : Implicit_Date_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Put_Date (Data, Pointer, Item.Value); end Encode; procedure Encode ( Item : Implicit_Date_Time_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Put_Date_Time (Data, Pointer, Item.Value); end Encode; procedure Encode ( Item : Implicit_Duration_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Put_Duration (Data, Pointer, Item.Value); end Encode; procedure Encode ( Item : Implicit_Generalized_Time_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Put (Data, Pointer, Item.Value); end Encode; procedure Encode ( Item : Implicit_Time_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Put (Data, Pointer, Item.Value); end Encode; procedure Encode ( Item : Implicit_UTC_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Put_UTC (Data, Pointer, Item.Value); end Encode; procedure Encode ( Item : Implicit_Time_Of_Day_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Put_Time_Of_Day (Data, Pointer, Item.Value); end Encode; procedure Explicit_Put_Time is new Generic_Put (Time, Put_Time); procedure Encode ( Item : Time_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Explicit_Put_Time (Data, Pointer, Time_Tag, Item.Value); end Encode; procedure Explicit_Put_Time_Of_Day is new Generic_Put (Day_Duration, Put_Time_Of_Day); procedure Encode ( Item : Time_Of_Day_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Explicit_Put_Time_Of_Day ( Data, Pointer, Time_Of_Day_Tag, Item.Value ); end Encode; procedure Explicit_Put_UTC is new Generic_Put (Time, Put_UTC); procedure Encode ( Item : UTC_Data_Item; Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset ) is begin Explicit_Put_UTC (Data, Pointer, UTC_Time_Tag, Item.Value); end Encode; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Date_Data_Item ) is begin Enumerate (Stream, Public_Time_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Date_Time_Data_Item ) is begin Enumerate (Stream, Public_Time_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Duration_Data_Item ) is begin Enumerate (Stream, Public_Duration_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Generalized_Time_Data_Item ) is begin Enumerate (Stream, Public_Time_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Implicit_Date_Data_Item ) is begin Enumerate (Stream, Public_Time_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Implicit_Date_Time_Data_Item ) is begin Enumerate (Stream, Public_Time_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Implicit_Duration_Data_Item ) is begin Enumerate (Stream, Public_Duration_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Implicit_Generalized_Time_Data_Item ) is begin Enumerate (Stream, Public_Time_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Implicit_Time_Data_Item ) is begin Enumerate (Stream, Public_Time_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Implicit_Time_Of_Day_Data_Item ) is begin Enumerate (Stream, Public_Duration_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Implicit_UTC_Data_Item ) is begin Enumerate (Stream, Public_Time_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Time_Data_Item ) is begin Enumerate (Stream, Public_Time_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : Time_Of_Day_Data_Item ) is begin Enumerate (Stream, Public_Duration_Data_Item (Item)); end Enumerate; procedure Enumerate ( Stream : access Root_Stream_Type'Class; Item : UTC_Data_Item ) is begin Enumerate (Stream, Public_Time_Data_Item (Item)); end Enumerate; procedure Feed ( Item : in out Date_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Get_Date (Get_Value (Item.Text)); end Feed; procedure Feed ( Item : in out Date_Time_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Get_Date_Time (Get_Value (Item.Text)); end Feed; procedure Feed ( Item : in out Duration_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Strings_Edit.ISO_8601.Value (Get_Value (Item.Text)); end Feed; procedure Feed ( Item : in out Generalized_Time_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Get (Get_Value (Item.Text), False); end Feed; procedure Feed ( Item : in out Implicit_Date_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Get_Date (Get_Value (Item.Text)); end Feed; procedure Feed ( Item : in out Implicit_Date_Time_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Get_Date_Time (Get_Value (Item.Text)); end Feed; procedure Feed ( Item : in out Implicit_Duration_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Strings_Edit.ISO_8601.Value (Get_Value (Item.Text)); end Feed; procedure Feed ( Item : in out Implicit_Generalized_Time_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Get (Get_Value (Item.Text), False); end Feed; procedure Feed ( Item : in out Implicit_Time_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Strings_Edit.ISO_8601.Value (Get_Value (Item.Text)); end Feed; procedure Feed ( Item : in out Implicit_Time_Of_Day_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Get_Time_Of_Day (Get_Value (Item.Text)); end Feed; procedure Feed ( Item : in out Implicit_UTC_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Get (Get_Value (Item.Text), True); end Feed; procedure Feed ( Item : in out Time_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Strings_Edit.ISO_8601.Value (Get_Value (Item.Text)); end Feed; procedure Feed ( Item : in out Time_Of_Day_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Get_Time_Of_Day (Get_Value (Item.Text)); end Feed; procedure Feed ( Item : in out UTC_Data_Item; Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Client : in out State_Machine'Class; State : in out Stream_Element_Offset ) is begin Feed ( Item => Item.Text, Data => Data, Pointer => Pointer, Client => Client, State => State ); if State /= 0 then return; end if; Item.Value := Get (Get_Value (Item.Text), True); end Feed; function Get_Hour (Source : String) return Integer is begin return Value (Source => Source, First => 0, Last => 24); end Get_Hour; function Get_Minute (Source : String) return Integer is begin return Value (Source => Source, First => 0, Last => 59); end Get_Minute; function Get_Second (Source : String) return Integer is begin return Value (Source => Source, First => 0, Last => 59); end Get_Second; procedure Get_Second ( Source : String; Pointer : in out Integer; Seconds : out Day_Duration ) is Index : Integer := Pointer; Result : Float; begin while Index <= Source'Last loop case Source (Index) is when ',' | '.' | '0'..'9' => Index := Index + 1; when others => exit; end case; end loop; if Index = Pointer then Seconds := 0.0; return; end if; declare Fraction : String := Source (Pointer..Index - 1); begin for This in Fraction'Range loop if Fraction (This) = ',' then Fraction (This) := '.'; end if; end loop; Result := Value ( Source => Fraction, First => 0.0, Last => Float'Pred (60.0) ); exception when End_Error => raise Data_Error; end; begin Seconds := Day_Duration (Result); exception when Constraint_Error => Seconds := Day_Duration'Last; end; Pointer := Index; end Get_Second; function Get (Source : String; Short : Boolean) return Time is use Ada.Calendar.Time_Zones; Year : Integer; Month : Integer; Day : Integer; Hour : Integer; Minute : Integer := 0; Seconds : Day_Duration := 0.0; Index : Integer := Source'First; begin if Short then if Source'Length < 2+2+2 then raise Data_Error; end if; else if Source'Length < 4+2+2 then raise Data_Error; end if; end if; if Short then if Index > Source'Last - 1 then raise Data_Error; end if; Year := Value (Source (Index..Index + 1)); if Year > 50 then Year := Year + 1900; else Year := Year + 2000; end if; Index := Index + 2; else if Index > Source'Last - 3 then raise Data_Error; end if; Year := Value (Source (Index..Index + 3)); Index := Index + 4; end if; if Index > Source'Last - 1 then raise Data_Error; end if; Month := Value (Source (Index..Index + 1)); Index := Index + 2; if Index > Source'Last - 1 then raise Data_Error; end if; Day := Value (Source (Index..Index + 1)); Index := Index + 2; if Index > Source'Last - 1 then raise Data_Error; end if; Hour := Get_Hour (Source (Index..Index + 1)); Index := Index + 2; if Index <= Source'Last then case Source (Index) is when '0'..'9' => if Index > Source'Last - 1 then raise Data_Error; end if; Minute := Value (Source (Index..Index + 1)); Index := Index + 2; if Index <= Source'Last then case Source (Index) is when '0'..'9' => if Short then if Index > Source'Last - 1 then raise Data_Error; end if; Seconds := Day_Duration ( Integer' ( Value (Source (Index..Index + 1)) ) ); Index := Index + 2; else Get_Second (Source, Index, Seconds); end if; when others => null; end case; end if; Seconds := Seconds + Duration (Minute * 60); when others => null; end case; end if; if Hour = 24 and then Seconds /= 0.0 then raise Data_Error; end if; return Get_Zoned_Time ( Source => Source (Index..Source'Last), Year => Year, Month => Month, Day => Day, Seconds => Duration (Hour * 60) * 60.0 + Seconds ); exception when others => Raise_Exception (Data_Error'Identity, Invalid_Time); end Get; function Get (Source : String) return Day_Duration is Result : Integer; Index : Integer := Source'First; Minute : Integer := 0; begin if Source'Length < 2+2+2 then raise Data_Error; end if; Result := Get_Hour (Source (Index..Index + 1)) * 3_600; Index := Index + 2; if Source (Index) = ':' then Index := Index + 1; end if; Result := Result + Get_Minute (Source (Index..Index + 1)) * 60; Index := Index + 2; if Source (Index) = ':' then Index := Index + 1; end if; if Index > Source'Last - 1 then raise Data_Error; end if; Result := Result + Get_Second (Source (Index..Index + 1)); Index := Index + 1; if Index /= Source'Last then raise Data_Error; end if; return Duration (Result); exception when others => Raise_Exception (Data_Error'Identity, Invalid_Time); end Get; procedure Get ( Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Length : Stream_Element_Offset; Value : out Time ) is begin if Data'Last - Pointer < Length - 1 then Raise_Exception (End_Error'Identity, Non_Terminated); elsif Length > Maximum_Time_Length then Raise_Exception (Constraint_Error'Identity, Too_Large); end if; Value := Get (To_String (Data (Pointer..Pointer + Length - 1)), False); Pointer := Pointer + Length; end Get; procedure Get ( Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Length : Stream_Element_Offset; Value : out Duration ) is begin if Data'Last - Pointer < Length - 1 then Raise_Exception (End_Error'Identity, Non_Terminated); elsif Length > 8 then Raise_Exception (Constraint_Error'Identity, Too_Large); end if; Value := Get (To_String (Data (Pointer..Pointer + Length - 1))); Pointer := Pointer + Length; end Get; function Get_ASN1_Type (Item : Date_Data_Item) return ASN1_Type is begin return Date_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Date_Time_Data_Item ) return ASN1_Type is begin return Date_Time_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Duration_Data_Item ) return ASN1_Type is begin return Duration_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Generalized_Time_Data_Item ) return ASN1_Type is begin return Generalized_Time_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Implicit_Date_Data_Item ) return ASN1_Type is begin return Date_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Implicit_Date_Time_Data_Item ) return ASN1_Type is begin return Date_Time_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Implicit_Duration_Data_Item ) return ASN1_Type is begin return Duration_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Implicit_Generalized_Time_Data_Item ) return ASN1_Type is begin return Generalized_Time_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Implicit_Time_Data_Item ) return ASN1_Type is begin return Time_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Implicit_Time_Of_Day_Data_Item ) return ASN1_Type is begin return Time_Of_Day_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Implicit_UTC_Data_Item ) return ASN1_Type is begin return UTC_Time_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Time_Data_Item ) return ASN1_Type is begin return Time_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : Time_Of_Day_Data_Item ) return ASN1_Type is begin return Time_Of_Day_Tag; end Get_ASN1_Type; function Get_ASN1_Type ( Item : UTC_Data_Item ) return ASN1_Type is begin return UTC_Time_Tag; end Get_ASN1_Type; procedure Get_Date ( Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Length : Stream_Element_Offset; Value : out Time ) is begin if Data'Last - Pointer < Length - 1 then Raise_Exception (End_Error'Identity, Non_Terminated); elsif Length /= 10 then Raise_Exception (Constraint_Error'Identity, Invalid_Length); end if; Value := Get_Date (To_String (Data (Pointer..Pointer + Length - 1))); Pointer := Pointer + Length; end Get_Date; function Get_Date (Source : String) return Time is use Ada.Calendar.Time_Zones; Year : Integer; Month : Integer; Day : Integer; Index : Integer := Source'First; begin if Source'Length /= 10 then raise Data_Error; end if; Year := Value (Source (Index..Index + 3)); Index := Index + 4; if Source (Index) /= '-' then raise Data_Error; end if; Index := Index + 1; Month := Value (Source (Index..Index + 1)); Index := Index + 2; if Source (Index) /= '-' then raise Data_Error; end if; Index := Index + 1; Day := Value (Source (Index..Index + 1)); return Ada.Calendar.Time_Of ( Year => Year_Number (Year), Month => Month_Number (Month), Day => Day_Number (Day), Seconds => 0.0 ); exception when others => Raise_Exception (Data_Error'Identity, Invalid_Time); end Get_Date; procedure Get_Date_Time ( Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Length : Stream_Element_Offset; Value : out Time ) is begin if Data'Last - Pointer < Length - 1 then Raise_Exception (End_Error'Identity, Non_Terminated); elsif Length /= 19 then Raise_Exception (Constraint_Error'Identity, Invalid_Length); end if; Value := Get_Date_Time ( To_String (Data (Pointer..Pointer + Length - 1)) ); Pointer := Pointer + Length; end Get_Date_Time; function Get_Date_Time (Source : String) return Time is use Ada.Calendar.Time_Zones; Year : Integer; Month : Integer; Day : Integer; Hour : Integer; Minute : Integer; Second : Integer; Index : Integer := Source'First; begin if Source'Length /= 19 then raise Data_Error; end if; Year := Value (Source (Index..Index + 3)); Index := Index + 4; if Source (Index) /= '-' then raise Data_Error; end if; Index := Index + 1; Month := Value (Source (Index..Index + 1)); Index := Index + 2; if Source (Index) /= '-' then raise Data_Error; end if; Index := Index + 1; Day := Value (Source (Index..Index + 1)); Index := Index + 2; if Source (Index) /= 'T' then raise Data_Error; end if; Index := Index + 1; Hour := Get_Hour (Source (Index..Index + 1)); Index := Index + 2; if Source (Index) /= ':' then raise Data_Error; end if; Index := Index + 1; Minute := Get_Minute (Source (Index..Index + 1)); Index := Index + 2; if Source (Index) /= ':' then raise Data_Error; end if; Index := Index + 1; Second := Get_Second (Source (Index..Index + 1)); return Ada.Calendar.Time_Of ( Year => Year_Number (Year), Month => Month_Number (Month), Day => Day_Number (Day), Seconds => Duration ( Float (Hour) * 3_600.0 + Float (Minute * 60) + Float (Second) ) ); exception when others => Raise_Exception (Data_Error'Identity, Invalid_Time); end Get_Date_Time; procedure Get_Duration ( Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Length : Stream_Element_Offset; Value : out Duration ) is begin if Data'Last - Pointer < Length - 1 then Raise_Exception (End_Error'Identity, Non_Terminated); elsif Length > Maximum_Time_Length then Raise_Exception (Constraint_Error'Identity, Too_Large); end if; Value := Strings_Edit.ISO_8601.Value ( To_String (Data (Pointer..Pointer + Length - 1)) ); Pointer := Pointer + Length; end Get_Duration; function Get_Duration ( Item : Public_Duration_Data_Item ) return Duration is begin return Item.Value; end Get_Duration; function Get_Time ( Item : Public_Time_Data_Item ) return Time is begin return Item.Value; end Get_Time; procedure Get_Time ( Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Length : Stream_Element_Offset; Value : out Time ) is begin if Data'Last - Pointer < Length - 1 then Raise_Exception (End_Error'Identity, Non_Terminated); elsif Length > Maximum_Time_Length then Raise_Exception (Constraint_Error'Identity, Too_Large); end if; Value := Strings_Edit.ISO_8601.Value ( To_String (Data (Pointer..Pointer + Length - 1)) ); Pointer := Pointer + Length; end Get_Time; function Get_Time_Of_Day (Source : String) return Day_Duration is Result : Day_Duration; Index : Integer := Source'First; begin if Source'Length /= 8 then raise Data_Error; end if; Result := Day_Duration (Integer'(Value (Source (Index..Index + 1)))); Index := Index + 2; if Source (Index) /= ':' then raise Data_Error; end if; Index := Index + 1; Result := ( Result * 60.0 + Day_Duration (Integer'(Value (Source (Index..Index + 1)))) ); Index := Index + 2; if Source (Index) /= ':' then raise Data_Error; end if; Index := Index + 1; Result := ( Result * 60.0 + Day_Duration (Integer'(Value (Source (Index..Index + 1)))) ); return Result; exception when others => Raise_Exception (Data_Error'Identity, Invalid_Time); end Get_Time_Of_Day; procedure Get_Time_Of_Day ( Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Length : Stream_Element_Offset; Value : out Day_Duration ) is begin if Data'Last - Pointer < Length - 1 then Raise_Exception (End_Error'Identity, Non_Terminated); elsif Length /= 8 then Raise_Exception (Constraint_Error'Identity, Invalid_Length); end if; Value := Get_Time_Of_Day ( To_String (Data (Pointer..Pointer + Length - 1)) ); Pointer := Pointer + Length; end Get_Time_Of_Day; procedure Get_UTC ( Data : Stream_Element_Array; Pointer : in out Stream_Element_Offset; Length : Stream_Element_Offset; Value : out Time ) is begin if Data'Last - Pointer < Length - 1 then Raise_Exception (End_Error'Identity, Non_Terminated); elsif Length > Maximum_Time_Length then Raise_Exception (Constraint_Error'Identity, Too_Large); end if; Value := Get (To_String (Data (Pointer..Pointer + Length - 1)), True); Pointer := Pointer + Length; end Get_UTC; function Get_Zoned_Time ( Source : String; Year : Integer; Month : Integer; Day : Integer; Seconds : Duration ) return Time is use Ada.Calendar.Time_Zones; Hour : Integer; Minute : Integer := 0; Index : Integer := Source'First; begin if Index > Source'Last then return Ada.Calendar.Time_Of ( Year => Year_Number (Year), Month => Month_Number (Month), Day => Day_Number (Day), Seconds => Seconds ); end if; if Source (Index) = 'Z' then Index := Index + 1; if Index <= Source'Last then raise Data_Error; end if; return Ada.Calendar.Formatting.Time_Of ( Year => Year_Number (Year), Month => Month_Number (Month), Day => Day_Number (Day), Seconds => Seconds, Time_Zone => 0 ); end if; case Source (Index) is when '-' | '+' => Index := Index + 1; if Index > Source'Last - 1 then raise Data_Error; end if; when others => raise Data_Error; end case; if Index > Source'Last - 1 then raise Data_Error; end if; Hour := Get_Hour (Source (Index..Index + 1)); Index := Index + 2; if Index <= Source'Last then if Source (Index) = ':' then Index := Index + 1; if Index > Source'Last then raise Data_Error; end if; end if; if Index > Source'Last - 1 then raise Data_Error; end if; Minute := Get_Minute (Source (Index..Index + 1)); Index := Index + 2; if Index <= Source'Last then raise Data_Error; end if; end if; return Ada.Calendar.Formatting.Time_Of ( Year => Year_Number (Year), Month => Month_Number (Month), Day => Day_Number (Day), Seconds => Seconds, Time_Zone => Time_Offset (Hour * 60 + Minute) ); end Get_Zoned_Time; function Is_Implicit (Item : Date_Data_Item) return Boolean is begin return False; end Is_Implicit; function Is_Implicit (Item : Date_Time_Data_Item) return Boolean is begin return False; end Is_Implicit; function Is_Implicit (Item : Duration_Data_Item) return Boolean is begin return False; end Is_Implicit; function Is_Implicit (Item : Generalized_Time_Data_Item) return Boolean is begin return False; end Is_Implicit; function Is_Implicit (Item : Implicit_Date_Data_Item) return Boolean is begin return True; end Is_Implicit; function Is_Implicit (Item : Implicit_Date_Time_Data_Item) return Boolean is begin return True; end Is_Implicit; function Is_Implicit (Item : Implicit_Duration_Data_Item) return Boolean is begin return True; end Is_Implicit; function Is_Implicit (Item : Implicit_Generalized_Time_Data_Item) return Boolean is begin return True; end Is_Implicit; function Is_Implicit (Item : Implicit_Time_Data_Item) return Boolean is begin return True; end Is_Implicit; function Is_Implicit (Item : Implicit_Time_Of_Day_Data_Item) return Boolean is begin return True; end Is_Implicit; function Is_Implicit (Item : Implicit_UTC_Data_Item) return Boolean is begin return True; end Is_Implicit; function Is_Implicit (Item : Time_Data_Item) return Boolean is begin return False; end Is_Implicit; function Is_Implicit (Item : Time_Of_Day_Data_Item) return Boolean is begin return False; end Is_Implicit; function Is_Implicit (Item : UTC_Data_Item) return Boolean is begin return False; end Is_Implicit; procedure Put ( Destination : in out String; Pointer : in out Integer; Short : Boolean; Value : Time ) is use Strings_Edit; Year : Year_Number; Month : Month_Number; Day : Day_Number; Hour : Ada.Calendar.Formatting.Hour_Number; Minute : Ada.Calendar.Formatting.Minute_Number; Second : Ada.Calendar.Formatting.Second_Number; Fraction : Ada.Calendar.Formatting.Second_Duration; Index : Integer := Pointer; begin Ada.Calendar.Formatting.Split ( Date => Value, Year => Year, Month => Month, Day => Day, Hour => Hour, Minute => Minute, Second => Second, Sub_Second => Fraction ); if Short then Put ( Destination => Destination, Pointer => Index, Value => Integer (Year) mod 100, Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); else Put ( Destination => Destination, Pointer => Index, Value => Integer (Year), Justify => Strings_Edit.Right, Fill => '0', Field => 4 ); end if; Put ( Destination => Destination, Pointer => Index, Value => Integer (Month), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Day), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => Hour, Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => Minute, Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => Second, Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); if not Short and then Fraction > 0.0 then Strings_Edit.Put ( Destination => Destination, Pointer => Index, Value => "." ); Put ( Destination => Destination, Pointer => Index, Value => Second, Justify => Strings_Edit.Right, Fill => '0', Field => 6 ); end if; Put ( Destination => Destination, Pointer => Index, Value => "Z" ); Pointer := Index; end Put; procedure Put ( Destination : in out String; Pointer : in out Integer; Value : Day_Duration ) is use Ada.Calendar.Formatting; use Strings_Edit; Hour : Hour_Number; Minute : Minute_Number; Second : Second_Number; Fraction : Second_Duration; Index : Integer := Pointer; begin Ada.Calendar.Formatting.Split ( Seconds => Value, Hour => Hour, Minute => Minute, Second => Second, Sub_Second => Fraction ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Hour), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Minute), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Second), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Pointer := Index; end Put; procedure Put ( Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset; Value : Time ) is Buffer : String (1..Maximum_Time_Length); Index : Integer := 1; begin Put (Buffer, Index, False, Value); Put (Data, Pointer, Buffer (1..Index - 1)); end Put; procedure Put ( Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset; Value : Day_Duration ) is Buffer : String (1..6); Index : Integer := 1; begin Put (Buffer, Index, Value); Put (Data, Pointer, Buffer); end Put; procedure Put_Date ( Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset; Value : Time ) is Buffer : String (1..10); Index : Integer := 1; begin Put_Date (Buffer, Index, Value); Put (Data, Pointer, Buffer); end Put_Date; procedure Put_Date ( Destination : in out String; Pointer : in out Integer; Value : Time ) is use Strings_Edit; Year : Year_Number; Month : Month_Number; Day : Day_Number; Seconds : Day_Duration; Index : Integer := Pointer; begin Ada.Calendar.Split ( Date => Value, Year => Year, Month => Month, Day => Day, Seconds => Seconds ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Year), Justify => Strings_Edit.Right, Fill => '0', Field => 4 ); Put ( Destination => Destination, Pointer => Index, Value => "-" ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Month), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => "-" ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Day), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Pointer := Index; end Put_Date; procedure Put_Date_Time ( Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset; Value : Time ) is Buffer : String (1..19); Index : Integer := 1; begin Put_Date_Time (Buffer, Index, Value); Put (Data, Pointer, Buffer); end Put_Date_Time; procedure Put_Date_Time ( Destination : in out String; Pointer : in out Integer; Value : Time ) is use Strings_Edit; use Ada.Calendar.Formatting; Year : Year_Number; Month : Month_Number; Day : Day_Number; Hour : Hour_Number; Minute : Minute_Number; Second : Second_Number; Seconds : Day_Duration; Fraction : Second_Duration; Index : Integer := Pointer; begin Ada.Calendar.Split ( Date => Value, Year => Year, Month => Month, Day => Day, Seconds => Seconds ); Ada.Calendar.Formatting.Split ( Seconds => Seconds, Hour => Hour, Minute => Minute, Second => Second, Sub_Second => Fraction ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Year), Justify => Strings_Edit.Right, Fill => '0', Field => 4 ); Put ( Destination => Destination, Pointer => Index, Value => "-" ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Month), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => "-" ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Day), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => "T" ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Hour), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => ":" ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Minute), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => ":" ); Put ( Destination => Destination, Pointer => Index, Value => Integer (Second), Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Pointer := Index; end Put_Date_Time; procedure Divide ( Value : in out Duration; Interval : Duration; Result : out Integer ) is begin Result := Integer (Value / Interval); if Duration (Result) * Interval > Value then Result := Result - 1; end if; Value := Value - Duration (Result) * Interval; end Divide; procedure Put_Duration ( Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset; Value : Duration ) is begin Put (Data, Pointer, Strings_Edit.ISO_8601.Image (Value, 6)); end Put_Duration; procedure Put_Time ( Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset; Value : Time ) is begin Put (Data, Pointer, Strings_Edit.ISO_8601.Image (Value, 6)); end Put_Time; procedure Put_Time_Of_Day ( Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset; Value : Day_Duration ) is Buffer : String (1..8); Index : Integer := 1; begin Put_Time_Of_Day (Buffer, Index, Value); Put (Data, Pointer, Buffer); end Put_Time_Of_Day; procedure Put_Time_Of_Day ( Destination : in out String; Pointer : in out Integer; Value : Day_Duration ) is use Strings_Edit; Seconds : constant Integer := Integer (Value); Index : Integer := Pointer; begin Put ( Destination => Destination, Pointer => Index, Value => Seconds / 3_600, Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => ":" ); Put ( Destination => Destination, Pointer => Index, Value => (Seconds / 60) mod 60, Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Put ( Destination => Destination, Pointer => Index, Value => ":" ); Put ( Destination => Destination, Pointer => Index, Value => Seconds mod 60, Justify => Strings_Edit.Right, Fill => '0', Field => 2 ); Pointer := Index; end Put_Time_Of_Day; procedure Put_UTC ( Data : in out Stream_Element_Array; Pointer : in out Stream_Element_Offset; Value : Time ) is Buffer : String (1..Maximum_Time_Length); Index : Integer := 1; begin Put (Buffer, Index, True, Value); Put (Data, Pointer, Buffer (1..Index - 1)); end Put_UTC; procedure Set_Duration ( Item : in out Public_Duration_Data_Item; Value : Duration ) is begin Item.Value := Value; end Set_Duration; procedure Set_Duration ( Item : in out Implicit_Time_Of_Day_Data_Item; Value : Duration ) is begin if Value not in Day_Duration then raise Constraint_Error; end if; Item.Value := Value; end Set_Duration; procedure Set_Duration ( Item : in out Time_Of_Day_Data_Item; Value : Duration ) is begin if Value not in Day_Duration then raise Constraint_Error; end if; Item.Value := Value; end Set_Duration; procedure Set_Implicit_Tag ( Item : in out Implicit_Date_Data_Item; Tag : Tag_Type; Length : Stream_Element_Offset ) is begin Set_Implicit_Tag (Item.Text, Tag, Length); end Set_Implicit_Tag; procedure Set_Implicit_Tag ( Item : in out Implicit_Date_Time_Data_Item; Tag : Tag_Type; Length : Stream_Element_Offset ) is begin Set_Implicit_Tag (Item.Text, Tag, Length); end Set_Implicit_Tag; procedure Set_Implicit_Tag ( Item : in out Implicit_Duration_Data_Item; Tag : Tag_Type; Length : Stream_Element_Offset ) is begin Set_Implicit_Tag (Item.Text, Tag, Length); end Set_Implicit_Tag; procedure Set_Implicit_Tag ( Item : in out Implicit_Generalized_Time_Data_Item; Tag : Tag_Type; Length : Stream_Element_Offset ) is begin Set_Implicit_Tag (Item.Text, Tag, Length); end Set_Implicit_Tag; procedure Set_Implicit_Tag ( Item : in out Implicit_Time_Data_Item; Tag : Tag_Type; Length : Stream_Element_Offset ) is begin Set_Implicit_Tag (Item.Text, Tag, Length); end Set_Implicit_Tag; procedure Set_Implicit_Tag ( Item : in out Implicit_Time_Of_Day_Data_Item; Tag : Tag_Type; Length : Stream_Element_Offset ) is begin Set_Implicit_Tag (Item.Text, Tag, Length); end Set_Implicit_Tag; procedure Set_Implicit_Tag ( Item : in out Implicit_UTC_Data_Item; Tag : Tag_Type; Length : Stream_Element_Offset ) is begin Set_Implicit_Tag (Item.Text, Tag, Length); end Set_Implicit_Tag; procedure Set_Time ( Item : in out Public_Time_Data_Item; Value : Time ) is begin Item.Value := Value; end Set_Time; end GNAT.Sockets.Connection_State_Machine.ASN1.Dates;