1------------------------------------------------------------------------------
2--                     XML/Ada - An XML suite for Ada95                     --
3--                                                                          --
4--                     Copyright (C) 2001-2017, AdaCore                     --
5--                                                                          --
6-- This library is free software;  you can redistribute it and/or modify it --
7-- under terms of the  GNU General Public License  as published by the Free --
8-- Software  Foundation;  either version 3,  or (at your  option) any later --
9-- version. This library is distributed in the hope that it will be useful, --
10-- but WITHOUT ANY WARRANTY;  without even the implied warranty of MERCHAN- --
11-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE.                            --
12--                                                                          --
13-- As a special exception under Section 7 of GPL version 3, you are granted --
14-- additional permissions described in the GCC Runtime Library Exception,   --
15-- version 3.1, as published by the Free Software Foundation.               --
16--                                                                          --
17-- You should have received a copy of the GNU General Public License and    --
18-- a copy of the GCC Runtime Library Exception along with this program;     --
19-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
20-- <http://www.gnu.org/licenses/>.                                          --
21--                                                                          --
22------------------------------------------------------------------------------
23
24--  This package is the root hierarchy for the Core part of the DOM
25--  interface.
26--  It is in fact made of several subpackages, since DOM provides
27--  two views of the tree: Object-oriented throught the Element, Document,...
28--  types; and direct access through the Node interface.
29
30pragma Ada_05;
31
32with Unicode.CES;
33with Ada.Unchecked_Deallocation;
34with Sax.HTable;
35with Sax.Symbols;
36with Sax.Utils;
37
38package DOM.Core is
39
40   Default_Node_List_Growth_Factor : constant Float := 1.0;
41   --  Set to 1.0 the buffer is doubled in size (growth factor is 100%).
42   --  If set to 0.0 only a single empty items is added.
43   --  The higher this factor, the less memory allocations will be required
44   --  (and thus the faster your program will run).
45   --  Setting this to 0.0 will require more allocations, but will save memory,
46   --  since no empty node will remain in the final tree.
47
48   subtype DOM_String is Unicode.CES.Byte_Sequence;
49   --  A simple redefinition of the strings, to be compatible with the
50   --  standard DOM interface
51   --  See the package Encodings for the exact encoding used for DOM_Strings
52
53   subtype DOM_String_Access is Unicode.CES.Byte_Sequence_Access;
54
55   -----------
56   -- Nodes --
57   -----------
58   --  This is the base type for all DOM.Core types. It is declared in this
59   --  package for visibility reasons, so that all DOM.Core.* packages have
60   --  access to the components.
61
62   type Node_Types is
63     (Element_Node,
64      Attribute_Node,
65      Cdata_Section_Node,
66      Entity_Reference_Node,
67      Entity_Node,
68      Processing_Instruction_Node,
69      Text_Node,
70      Comment_Node,
71      Document_Node,
72      Document_Type_Node,
73      Document_Fragment_Node,
74      Notation_Node);
75
76   subtype Character_Data_Types is Node_Types range Text_Node .. Comment_Node;
77
78   type Node_Record (Node_Type : Node_Types) is private;
79   type Node is access Node_Record;
80
81   subtype Character_Data is Node;
82   subtype Element is Node (Element_Node);
83   subtype Attr is Node (Attribute_Node);
84   subtype Cdata_Section is Character_Data (Cdata_Section_Node);
85   subtype Entity_Reference is Node (Entity_Reference_Node);
86   subtype Entity is Node (Entity_Node);
87   subtype Processing_Instruction is Node (Processing_Instruction_Node);
88   subtype Text is Character_Data (Text_Node);
89   subtype Comment is Character_Data (Comment_Node);
90   subtype Document is Node (Document_Node);
91   subtype Document_Type is Node (Document_Type_Node);
92   subtype Document_Fragment is Node (Document_Fragment_Node);
93   subtype Notation is Node (Notation_Node);
94
95   type Node_List is private;
96   --  A simple ordered list of nodes (see DOM.Core.Nodes for subprograms)
97
98   type Named_Node_Map is private;
99   --  A collection of nodes accessible by their names.
100   --  This is unordered.
101
102   procedure Free (List : in out Node_List);
103   --  Free the memory occupied by the list. The items contained in the list
104   --  are not freed, since they still exist in the XML tree.
105
106   ------------------------
107   -- Dom implementation --
108   ------------------------
109   --  This provides a number of methods for performing operations that are
110   --  independent of any particular instance of the document object model.
111
112   type DOM_Implementation is private;
113   --  There are multiple implementations of DOM.
114   --  They can be specialized for some special cases (HTML, Stylesheets,...)
115
116   function Has_Feature
117     (Implementation : DOM_Implementation;
118      Feature        : DOM_String;
119      Version        : String := "2.0") return Boolean;
120   --  Return TRUE if this implementation of DOM has the Feature.
121
122   function Create_Document
123     (Implementation : DOM_Implementation;
124      NameSpace_URI  : DOM_String := "";
125      Qualified_Name : DOM_String := "";
126      Doc_Type       : Node := null;
127      Symbols        : Sax.Utils.Symbol_Table := Sax.Utils.No_Symbol_Table)
128      return Node;
129   --  Create an new document with its element.
130   --  Note that NameSpace_URI can be the empty string if you do not want
131   --  to use namespaces.
132   --  The Document Type Definition can be null if there is none associated
133   --  with the document.
134   --  Wrong_Document_Err is raised if Doc_Type has already been used for
135   --  another document.
136   --  Symbols should be used to specify the symbol table used by the parser
137   --  that generates the DOM. It is needed because the various string elements
138   --  in the tree are represented as symbols and the correct symbol table must
139   --  be specified. You can get it from the parser itself by using
140   --  Get_Symbol_Table. Optionally, you can pass an explicit No_Symbol_Table
141   --  to create one automatically. It is recommended to share the table with
142   --  the parser whenever possible for maximum efficient.
143   --  In general, the document is created from the Start_Document callback
144   --  of a tree_reader, so the simplest is to call the inherited
145   --  Start_Document.
146
147   procedure Set_Node_List_Growth_Factor (Factor : Float);
148   --  Set the growth factor, see Default_Node_List_Growth_Factor
149
150   --------------------
151   -- Dom exceptions --
152   --------------------
153   --  The following exceptions are declared in the DOM interface. If we
154   --  were to follow exactly the interface, we should a single exception to
155   --  which we associate an integer code. It seems easier to provide one
156   --  exception for each case. However, we kept the standard names.
157
158   Index_Size_Err : exception;
159   --  If Index or size is invalid (negative or greated than max value).
160
161   Domstring_Size_Err : exception;
162   --  If the specified range of text does not fit into a DomString.
163
164   Hierarchy_Request_Err : exception;
165   --  If a node is inserted somewhere it doesn't belong.
166
167   Wrong_Document_Err : exception;
168   --  If a node is used with a document other than its own.
169
170   Invalid_Character_Err : exception;
171   --  If an invalid character is used, for instance in a name.
172
173   No_Data_Allowed_Err : exception;
174   --  If data is specified for a node that doesn't support data.
175
176   No_Modification_Allowed_Err : exception;
177   --  If an attempt is made to modify a read-only object.
178
179   Not_Found_Err : exception;
180   --  If an attempt is made to reference a node in a concept where it doesn't
181   --  exist.
182
183   Not_Supported_Err : exception;
184   --  If the implementation does not support the type of object requested.
185
186   Inuse_Attribute_Err : exception;
187   --  If an attempt is made to add an attribute that is already used.
188
189   Invalid_State_Err : exception;
190   --  If an attempt is made to use an object that is not or no longer
191   --  available.
192
193   Syntax_Err : exception;
194   --  If an invalid string is specified.
195
196   Invalid_Modification_Err : exception;
197   --  If an attempt is made to modify the type of the underlying object.
198
199   Namespace_Err : exception;
200   --  If an attempt is made to create or modify an object in a way
201   --  incompatible with the namespace.
202
203   Invalid_Access_Err : exception;
204   --  If a parameter or an operation is not supported by the underlying
205   --  object.
206
207private
208
209   type DOM_Implementation is null record;
210
211   type Node_Array is array (Natural range <>) of Node;
212   type Node_Array_Access is access Node_Array;
213
214   procedure Free is new Ada.Unchecked_Deallocation
215     (Node_Array, Node_Array_Access);
216
217   type Node_List is record
218      Items  : Node_Array_Access := null;
219      Last   : Integer := -1;
220      --  The index of the last significant element in Items
221   end record;
222
223   Null_List : constant Node_List := (null, -1);
224
225   --  Not the most efficient way to implement a hash-table, but these are
226   --  generally short lists anyway (attributes,...)
227   type Named_Node_Map is new Node_List;
228   Null_Node_Map : constant Named_Node_Map := (null, -1);
229
230   ------------------
231   -- Nodes htable --
232   ------------------
233
234   type Node_String is record
235      N   : Node;
236      Key : Sax.Symbols.Symbol;
237   end record;
238   No_Node_String : constant Node_String := (null, Sax.Symbols.No_Symbol);
239
240   procedure Free (N : in out Node_String);
241   function Get_Key (N : Node_String) return Sax.Symbols.Symbol;
242   pragma Inline (Free, Get_Key);
243
244   package Nodes_Htable is new Sax.HTable
245     (Element       => Node_String,
246      Empty_Element => No_Node_String,
247      Free          => Free,
248      Key           => Sax.Symbols.Symbol,
249      Get_Key       => Get_Key,
250      Hash          => Sax.Symbols.Hash,
251      Equal         => Sax.Symbols."=");
252   type Nodes_Htable_Access is access Nodes_Htable.HTable;
253
254   -------------------
255   -- Node_Name_Def --
256   -------------------
257   --  Attributes and Elements share the same kind description. These are
258   --  grouped in the same type for ease of use
259
260   type Node_Name_Def is record
261      Prefix     : Sax.Symbols.Symbol;
262      Local_Name : Sax.Symbols.Symbol;
263      Namespace  : Sax.Symbols.Symbol;
264   end record;
265   No_Node_Name : constant Node_Name_Def :=
266     (Prefix     => Sax.Symbols.No_Symbol,
267      Local_Name => Sax.Symbols.No_Symbol,
268      Namespace  => Sax.Symbols.No_Symbol);
269
270   function Qualified_Name (N : Node_Name_Def) return DOM_String;
271   pragma Inline (Qualified_Name);
272   --  Return the qualified name of N
273
274   procedure Set_Prefix
275     (N : in out Node_Name_Def; Prefix : Sax.Symbols.Symbol);
276   pragma Inline (Set_Prefix);
277   --  Return or set the prefix of N
278
279   function From_Qualified_Name
280     (Doc       : Document;
281      Symbols   : Sax.Utils.Symbol_Table;
282      Name      : Sax.Symbols.Symbol;
283      Namespace : Sax.Symbols.Symbol := Sax.Symbols.No_Symbol)
284      return Node_Name_Def;
285   --  Build a node name from its qualified name. This is shared if
286   --  Shared_Node_Names is True.
287   --  Symbols is the symbol table in which Name and Namespace were created.
288
289   -----------------
290   -- Node_Record --
291   -----------------
292
293   type Node_Record (Node_Type : Node_Types) is record
294      Parent_Is_Owner : Boolean;
295      --  If True, the Parent node points to the owner document, not to the
296      --  real parent in the tree (which is null).
297      --  This boolean doesn't increase the size of this record, since because
298      --  of alignment issues Node_Type already occupies more space than it
299      --  really needs.
300
301      Parent   : Node;
302      case Node_Type is
303         when Element_Node =>
304            Name       : Node_Name_Def;
305            Children   : Node_List;
306            Attributes : Named_Node_Map;
307
308         when Attribute_Node =>
309            Attr_Name       : Node_Name_Def;
310            Attr_Value      : Sax.Symbols.Symbol;
311
312            Owner_Element   : Node;
313            --  Generally an Element, but it can be a Document if the attribute
314            --  hasn't been associated yet.
315
316            Is_Id           : Boolean := False;
317            Specified       : Boolean := False;
318            --   ??? In fact, attributes can have children (text or
319            --   entity_reference).
320
321         when Text_Node =>
322            Text : DOM_String_Access;
323
324         when Cdata_Section_Node =>
325            Cdata : DOM_String_Access;
326
327         when Entity_Reference_Node =>
328            Entity_Reference_Name : Sax.Symbols.Symbol;
329
330         when Entity_Node =>
331            Entity_Name : Sax.Symbols.Symbol;
332            --  ??? Allows children for the substitution of the entity
333
334         when Processing_Instruction_Node =>
335            Target  : Sax.Symbols.Symbol;
336            Pi_Data : Sax.Symbols.Symbol;
337
338         when Comment_Node =>
339            Comment : DOM_String_Access;
340
341         when Document_Node =>
342            Symbols        : Sax.Utils.Symbol_Table;
343            --  Keep a handle on the symbol table to ensure the symbols remain
344            --  valid while the tree exists
345
346            Doc_Children   : Node_List;
347            Doc_Type       : Node;
348            Implementation : DOM_Implementation;
349            Ids            : Nodes_Htable_Access;
350
351         when Document_Type_Node =>
352            Document_Type_Name : DOM_String_Access;
353            Doc_Type_Children  : Node_List;
354
355         when Document_Fragment_Node =>
356            Doc_Frag_Children : Node_List;
357
358         when Notation_Node =>
359            Public_ID : DOM_String_Access;
360            System_ID : DOM_String_Access;
361      end case;
362   end record;
363
364   procedure Append (List : in out Node_List; N : Node);
365   --  Insert N as the last element in List
366
367   procedure Remove (List : in out Node_List; N : Node);
368   --  Remove N from the list
369   --  N must be an element of List, this is not checked.
370
371   procedure Document_Add_Id
372     (Doc  : Document;
373      Id   : Sax.Symbols.Symbol;
374      Elem : Element);
375   --  Store in the document as fast access to Elem by its ID
376
377   procedure Document_Remove_Id
378     (Doc  : Document;
379      Id   : Sax.Symbols.Symbol);
380   --  Remove an ID associated with Elem in the fast htable access
381
382end DOM.Core;
383