git-svn-id: https://pdfsharp.svn.codeplex.com/svn@39620 56d0cb2f-6006-4f69-a5a2-94740...
[pdfsharp:pdfsharp.git] / PDFsharp / code / PdfSharp / PdfSharp.Pdf / PdfOutline.cs
1 #region PDFsharp - A .NET library for processing PDF\r
2 //\r
3 // Authors:\r
4 //   Stefan Lange (mailto:Stefan.Lange@pdfsharp.com)\r
5 //\r
6 // Copyright (c) 2005-2009 empira Software GmbH, Cologne (Germany)\r
7 //\r
8 // http://www.pdfsharp.com\r
9 // http://sourceforge.net/projects/pdfsharp\r
10 //\r
11 // Permission is hereby granted, free of charge, to any person obtaining a\r
12 // copy of this software and associated documentation files (the "Software"),\r
13 // to deal in the Software without restriction, including without limitation\r
14 // the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
15 // and/or sell copies of the Software, and to permit persons to whom the\r
16 // Software is furnished to do so, subject to the following conditions:\r
17 //\r
18 // The above copyright notice and this permission notice shall be included\r
19 // in all copies or substantial portions of the Software.\r
20 //\r
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
24 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
26 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \r
27 // DEALINGS IN THE SOFTWARE.\r
28 #endregion\r
29 \r
30 using System;\r
31 using System.Collections.Generic;\r
32 using System.Diagnostics;\r
33 using System.Collections;\r
34 using System.Text;\r
35 using System.IO;\r
36 using PdfSharp.Drawing;\r
37 using PdfSharp.Internal;\r
38 using PdfSharp.Pdf.IO;\r
39 using PdfSharp.Pdf.Internal;\r
40 \r
41 namespace PdfSharp.Pdf\r
42 {\r
43   /// <summary>\r
44   /// Represents an outline item in the outlines tree. An outline is also knows as a bookmark.\r
45   /// </summary>\r
46   public sealed class PdfOutline : PdfDictionary\r
47   {\r
48     /// <summary>\r
49     /// Initializes a new instance of the <see cref="PdfOutline"/> class.\r
50     /// </summary>\r
51     public PdfOutline()\r
52     {\r
53       //this.outlines = new PdfOutlineCollection(this);\r
54     }\r
55 \r
56     /// <summary>\r
57     /// Initializes a new instance of the <see cref="PdfOutline"/> class.\r
58     /// </summary>\r
59     /// <param name="document">The document.</param>\r
60     internal PdfOutline(PdfDocument document)\r
61       : base(document)\r
62     {\r
63       //this.outlines = new PdfOutlineCollection(this);\r
64     }\r
65 \r
66     /// <summary>\r
67     /// Initializes a new instance from an existing dictionary. Used for object type transformation.\r
68     /// </summary>\r
69     public PdfOutline(PdfDictionary dict)\r
70       : base(dict)\r
71     { }\r
72 \r
73     /// <summary>\r
74     /// Initializes a new instance of the <see cref="PdfOutline"/> class.\r
75     /// </summary>\r
76     /// <param name="title">The outline text.</param>\r
77     /// <param name="destinationPage">The destination page.</param>\r
78     /// <param name="opened">Specifies whether the node is displayed expanded (opened) or collapsed.</param>\r
79     /// <param name="style">The font style used to draw the outline text.</param>\r
80     /// <param name="textColor">The color used to draw the outline text.</param>\r
81     public PdfOutline(string title, PdfPage destinationPage, bool opened, PdfOutlineStyle style, XColor textColor)\r
82     {\r
83       Title = title;\r
84       DestinationPage = destinationPage;\r
85       Opened = opened;\r
86       Style = style;\r
87       TextColor = textColor;\r
88     }\r
89 \r
90     /// <summary>\r
91     /// Initializes a new instance of the <see cref="PdfOutline"/> class.\r
92     /// </summary>\r
93     /// <param name="title">The outline text.</param>\r
94     /// <param name="destinationPage">The destination page.</param>\r
95     /// <param name="opened">Specifies whether the node is displayed expanded (opened) or collapsed.</param>\r
96     /// <param name="style">The font style used to draw the outline text.</param>\r
97     public PdfOutline(string title, PdfPage destinationPage, bool opened, PdfOutlineStyle style)\r
98     {\r
99       Title = title;\r
100       DestinationPage = destinationPage;\r
101       Opened = opened;\r
102       Style = style;\r
103     }\r
104 \r
105     /// <summary>\r
106     /// Initializes a new instance of the <see cref="PdfOutline"/> class.\r
107     /// </summary>\r
108     /// <param name="title">The outline text.</param>\r
109     /// <param name="destinationPage">The destination page.</param>\r
110     /// <param name="opened">Specifies whether the node is displayed expanded (opened) or collapsed.</param>\r
111     public PdfOutline(string title, PdfPage destinationPage, bool opened)\r
112     {\r
113       Title = title;\r
114       DestinationPage = destinationPage;\r
115       Opened = opened;\r
116     }\r
117 \r
118     /// <summary>\r
119     /// Initializes a new instance of the <see cref="PdfOutline"/> class.\r
120     /// </summary>\r
121     /// <param name="title">The outline text.</param>\r
122     /// <param name="destinationPage">The destination page.</param>\r
123     public PdfOutline(string title, PdfPage destinationPage)\r
124     {\r
125       Title = title;\r
126       DestinationPage = destinationPage;\r
127     }\r
128 \r
129     internal int Count\r
130     {\r
131       get { return this.count; }\r
132       set { this.count = value; }\r
133     }\r
134     int count;\r
135 \r
136     /// <summary>\r
137     /// The total number of open descendants at all lower levels.\r
138     /// </summary>\r
139     internal int openCount;\r
140 \r
141     //internal int CountOpen()\r
142     //{\r
143     //  int count = this.opened ? 1 : 0;\r
144     //  if (this.outlines != null)\r
145     //    count += this.outlines.CountOpen();\r
146     //  return count;\r
147     //}\r
148 \r
149     internal PdfOutline Parent\r
150     {\r
151       get { return this.parent; }\r
152       set { this.parent = value; }\r
153     }\r
154     PdfOutline parent;\r
155 \r
156     /// <summary>\r
157     /// Gets or sets the title.\r
158     /// </summary>\r
159     public string Title\r
160     {\r
161       get { return Elements.GetString(Keys.Title); }\r
162       set\r
163       {\r
164         PdfString s = new PdfString(value, PdfStringEncoding.PDFDocEncoding);\r
165         Elements.SetValue(Keys.Title, s);\r
166       }\r
167     }\r
168 \r
169     /// <summary>\r
170     /// Gets or sets the destination page.\r
171     /// </summary>\r
172     public PdfPage DestinationPage\r
173     {\r
174       get { return this.destinationPage; }\r
175       set { this.destinationPage = value; }\r
176     }\r
177     PdfPage destinationPage;\r
178 \r
179     /// <summary>\r
180     /// Gets or sets whether the outline item is opened (or expanded).\r
181     /// </summary>\r
182     public bool Opened\r
183     {\r
184       get { return this.opened2; }\r
185       set { this.opened2 = value; }\r
186       // TODO: adjust openCount of ascendant...\r
187 #if false\r
188       set \r
189       {\r
190         if (this.opened != value)\r
191         {\r
192           this.opened = value;\r
193           int sign = value ? 1 : -1;\r
194           PdfOutline parent = this.parent;\r
195           if (this.opened)\r
196           {\r
197             while (parent != null)\r
198             {\r
199               parent.openCount += 1 + this.openCount;\r
200             }\r
201           }\r
202           else\r
203           {\r
204           }\r
205         }\r
206       }\r
207 #endif\r
208     }\r
209     bool opened2;\r
210 \r
211     /// <summary>\r
212     /// Gets or sets the style.\r
213     /// </summary>\r
214     public PdfOutlineStyle Style\r
215     {\r
216       get { return (PdfOutlineStyle)Elements.GetInteger(Keys.F); }\r
217       set { Elements.SetInteger(Keys.F, (int)value); }\r
218     }\r
219 \r
220     /// <summary>\r
221     /// Gets or sets the color of the text.\r
222     /// </summary>\r
223     /// <value>The color of the text.</value>\r
224     public XColor TextColor\r
225     {\r
226       get { return this.textColor; }\r
227       set { this.textColor = value; }\r
228     }\r
229     XColor textColor;\r
230 \r
231     /// <summary>\r
232     /// Gets the outline collection of this node.\r
233     /// </summary>\r
234     public PdfOutlineCollection Outlines\r
235     {\r
236       get\r
237       {\r
238         if (this.outlines == null)\r
239           this.outlines = new PdfOutlineCollection(this.Owner, this);\r
240         return this.outlines;\r
241       }\r
242     }\r
243     PdfOutlineCollection outlines;\r
244 \r
245     /// <summary>\r
246     /// Creates key/values pairs according to the object structure.\r
247     /// </summary>\r
248     internal override void PrepareForSave()\r
249     {\r
250       bool hasKids = this.outlines != null && this.outlines.Count > 0;\r
251       if (this.parent != null || hasKids)\r
252       {\r
253         if (this.parent == null)\r
254         {\r
255           // This is the outline dictionary (the root)\r
256           Elements[Keys.First] = this.outlines[0].Reference;\r
257           Elements[Keys.Last] = this.outlines[this.outlines.Count - 1].Reference;\r
258 \r
259           // TODO: /Count - the meaning is not completely clear to me\r
260           if (this.openCount > 0)\r
261             Elements[Keys.Count] = new PdfInteger(this.openCount);\r
262         }\r
263         else\r
264         {\r
265           // This is an outline item dictionary\r
266           Elements[Keys.Parent] = this.parent.Reference;\r
267 \r
268           int count = this.parent.outlines.Count;\r
269           int index = this.parent.outlines.IndexOf(this);\r
270           Debug.Assert(index != -1);\r
271 \r
272           if (DestinationPage != null)\r
273             Elements[Keys.Dest] = new PdfArray(this.Owner,\r
274               DestinationPage.Reference,\r
275               new PdfLiteral("/XYZ null null 0"));\r
276 \r
277           if (index > 0)\r
278             Elements[Keys.Prev] = this.parent.outlines[index - 1].Reference;\r
279 \r
280           if (index < count - 1)\r
281             Elements[Keys.Next] = this.parent.outlines[index + 1].Reference;\r
282 \r
283           if (hasKids)\r
284           {\r
285             Elements[Keys.First] = this.outlines[0].Reference;\r
286             Elements[Keys.Last] = this.outlines[this.outlines.Count - 1].Reference;\r
287           }\r
288           // TODO: /Count - the meaning is not completely clear to me\r
289           if (this.openCount > 0)\r
290             Elements[Keys.Count] = new PdfInteger((this.opened2 ? 1 : -1) * this.openCount);\r
291 \r
292           if (this.textColor != XColor.Empty && this.Owner.HasVersion("1.4"))\r
293             Elements[Keys.C] = new PdfLiteral("[{0}]", PdfEncoders.ToString(this.textColor, PdfColorMode.Rgb));\r
294 \r
295           // if (this.Style != PdfOutlineStyle.Regular && this.Document.HasVersion("1.4"))\r
296           //  //pdf.AppendFormat("/F {0}\n", (int)this.style);\r
297           //  Elements[Keys.F] = new PdfInteger((int)this.style);\r
298         }\r
299         // Prepare kids\r
300         if (hasKids)\r
301           foreach (PdfOutline outline in this.outlines)\r
302             outline.PrepareForSave();\r
303       }\r
304     }\r
305 \r
306     internal override void WriteObject(PdfWriter writer)\r
307     {\r
308       bool hasKids = this.outlines != null && this.outlines.Count > 0;\r
309       if (this.parent != null || hasKids)\r
310       {\r
311         // Everything done in PrepareForSave\r
312         if (this.parent == null)\r
313         {\r
314           // This is the outline dictionary (the root)\r
315         }\r
316         else\r
317         {\r
318           // This is an outline item dictionary\r
319         }\r
320         base.WriteObject(writer);\r
321       }\r
322     }\r
323 \r
324     /// <summary>\r
325     /// Represents a collection of outlines.\r
326     /// </summary>\r
327     public class PdfOutlineCollection : PdfObject, IEnumerable\r
328     {\r
329       internal PdfOutlineCollection(PdfDocument document, PdfOutline parent)\r
330         : base(document)\r
331       {\r
332         this.parent = parent;\r
333       }\r
334 \r
335       /// <summary>\r
336       /// Indicates whether the outline has at least one entry.\r
337       /// </summary>\r
338       public bool HasOutline\r
339       {\r
340         get { return this.outlines != null && this.outlines.Count > 0; }\r
341       }\r
342 \r
343       /// <summary>\r
344       /// Gets the number of entries in this collection.\r
345       /// </summary>\r
346       public int Count\r
347       {\r
348         get { return this.outlines.Count; }\r
349       }\r
350 \r
351       //internal int CountOpen()\r
352       //{\r
353       //  int count = 0;\r
354       //  foreach (PdfOutline outline in this.outlines)\r
355       //    count += outline.CountOpen();\r
356       //  return count;\r
357       //}\r
358 \r
359       /// <summary>\r
360       /// Adds the specified outline.\r
361       /// </summary>\r
362       public void Add(PdfOutline outline)\r
363       {\r
364         if (outline == null)\r
365           throw new ArgumentNullException("outline");\r
366 \r
367         if (!Object.ReferenceEquals(Owner, outline.DestinationPage.Owner))\r
368           throw new ArgumentException("Destination page must belong to this document.");\r
369 \r
370         // TODO check the parent problems...\r
371         outline.Document = Owner;\r
372         outline.parent = this.parent;\r
373 \r
374 \r
375         this.outlines.Add(outline);\r
376         this.Owner.irefTable.Add(outline);\r
377 \r
378         if (outline.Opened)\r
379         {\r
380           outline = this.parent;\r
381           while (outline != null)\r
382           {\r
383             outline.openCount++;\r
384             outline = outline.parent;\r
385           }\r
386         }\r
387       }\r
388 \r
389       /// <summary>\r
390       /// Adds the specified outline entry.\r
391       /// </summary>\r
392       /// <param name="title">The outline text.</param>\r
393       /// <param name="destinationPage">The destination page.</param>\r
394       /// <param name="opened">Specifies whether the node is displayed expanded (opened) or collapsed.</param>\r
395       /// <param name="style">The font style used to draw the outline text.</param>\r
396       /// <param name="textColor">The color used to draw the outline text.</param>\r
397       public PdfOutline Add(string title, PdfPage destinationPage, bool opened, PdfOutlineStyle style, XColor textColor)\r
398       {\r
399         PdfOutline outline = new PdfOutline(title, destinationPage, opened, style, textColor);\r
400         Add(outline);\r
401         return outline;\r
402       }\r
403 \r
404       /// <summary>\r
405       /// Adds the specified outline entry.\r
406       /// </summary>\r
407       /// <param name="title">The outline text.</param>\r
408       /// <param name="destinationPage">The destination page.</param>\r
409       /// <param name="opened">Specifies whether the node is displayed expanded (opened) or collapsed.</param>\r
410       /// <param name="style">The font style used to draw the outline text.</param>\r
411       public PdfOutline Add(string title, PdfPage destinationPage, bool opened, PdfOutlineStyle style)\r
412       {\r
413         PdfOutline outline = new PdfOutline(title, destinationPage, opened, style);\r
414         Add(outline);\r
415         return outline;\r
416       }\r
417 \r
418       /// <summary>\r
419       /// Adds the specified outline entry.\r
420       /// </summary>\r
421       /// <param name="title">The outline text.</param>\r
422       /// <param name="destinationPage">The destination page.</param>\r
423       /// <param name="opened">Specifies whether the node is displayed expanded (opened) or collapsed.</param>\r
424       public PdfOutline Add(string title, PdfPage destinationPage, bool opened)\r
425       {\r
426         PdfOutline outline = new PdfOutline(title, destinationPage, opened);\r
427         Add(outline);\r
428         return outline;\r
429       }\r
430 \r
431       /// <summary>\r
432       /// Adds the specified outline entry.\r
433       /// </summary>\r
434       /// <param name="title">The outline text.</param>\r
435       /// <param name="destinationPage">The destination page.</param>\r
436       public PdfOutline Add(string title, PdfPage destinationPage)\r
437       {\r
438         PdfOutline outline = new PdfOutline(title, destinationPage);\r
439         Add(outline);\r
440         return outline;\r
441       }\r
442 \r
443       /// <summary>\r
444       /// Gets the index of the specified outline.\r
445       /// </summary>\r
446       public int IndexOf(PdfOutline item)\r
447       {\r
448         return this.outlines.IndexOf(item);\r
449       }\r
450 \r
451       /// <summary>\r
452       /// Gets the <see cref="PdfSharp.Pdf.PdfOutline"/> at the specified index.\r
453       /// </summary>\r
454       public PdfOutline this[int index]\r
455       {\r
456         get\r
457         {\r
458           if (index < 0 || index >= this.outlines.Count)\r
459             throw new ArgumentOutOfRangeException("index", index, PSSR.OutlineIndexOutOfRange);\r
460           return (PdfOutline)this.outlines[index];\r
461         }\r
462         //set\r
463         //{\r
464         //  if (index < 0 || index >= this.outlines.Count)\r
465         //    throw new ArgumentOutOfRangeException("index", index, PSSR.OutlineIndexOutOfRange);\r
466         //  this.outlines[index] = value;\r
467         //}\r
468       }\r
469 \r
470       /// <summary>\r
471       /// Returns an enumerator that iterates through a collection.\r
472       /// </summary>\r
473       public IEnumerator GetEnumerator()\r
474       {\r
475         return outlines.GetEnumerator();\r
476       }\r
477 \r
478       private PdfOutline parent;\r
479       private List<PdfOutline> outlines = new List<PdfOutline>();\r
480     }\r
481 \r
482     /// <summary>\r
483     /// Predefined keys of this dictionary.\r
484     /// </summary>\r
485     internal sealed class Keys : KeysBase\r
486     {\r
487       /// <summary>\r
488       /// (Optional) The type of PDF object that this dictionary describes; if present,\r
489       /// must be Outlines for an outline dictionary.\r
490       /// </summary>\r
491       [KeyInfo(KeyType.Name | KeyType.Optional, FixedValue = "Outlines")]\r
492       public const string Type = "/Type";\r
493 \r
494       // Outline and outline item are combined\r
495       ///// <summary>\r
496       ///// (Required if there are any open or closed outline entries; must be an indirect reference)\r
497       ///// An outline item dictionary representing the first top-level item in the outline.\r
498       ///// </summary>\r
499       //[KeyInfo(KeyType.Dictionary)]\r
500       //public const string First = "/First";\r
501       //\r
502       ///// <summary>\r
503       ///// (Required if there are any open or closed outline entries; must be an indirect reference)\r
504       ///// An outline item dictionary representing the last top-level item in the outline.\r
505       ///// </summary>\r
506       //[KeyInfo(KeyType.Dictionary)]\r
507       //public const string Last = "/Last";\r
508       //\r
509       ///// <summary>\r
510       ///// (Required if the document has any open outline entries) The total number of open items at all\r
511       ///// levels of the outline. This entry should be omitted if there are no open outline items.\r
512       ///// </summary>\r
513       //[KeyInfo(KeyType.Integer)]\r
514       //public const string Count = "/Count";\r
515 \r
516       /// <summary>\r
517       /// (Required) The text to be displayed on the screen for this item.\r
518       /// </summary>\r
519       [KeyInfo(KeyType.String | KeyType.Required)]\r
520       public const string Title = "/Title";\r
521 \r
522       /// <summary>\r
523       /// (Required; must be an indirect reference) The parent of this item in the outline hierarchy.\r
524       /// The parent of a top-level item is the outline dictionary itself.\r
525       /// </summary>\r
526       [KeyInfo(KeyType.Dictionary | KeyType.Required)]\r
527       public const string Parent = "/Parent";\r
528 \r
529       /// <summary>\r
530       /// (Required for all but the first item at each level; must be an indirect reference)\r
531       /// The previous item at this outline level.\r
532       /// </summary>\r
533       [KeyInfo(KeyType.Dictionary | KeyType.Required)]\r
534       public const string Prev = "/Prev";\r
535 \r
536       /// <summary>\r
537       /// (Required for all but the last item at each level; must be an indirect reference)\r
538       /// The next item at this outline level.\r
539       /// </summary>\r
540       [KeyInfo(KeyType.Dictionary | KeyType.Required)]\r
541       public const string Next = "/Next";\r
542 \r
543       /// <summary>\r
544       /// (Required if the item has any descendants; must be an indirect reference)\r
545       ///  The first of this item\92s immediate children in the outline hierarchy.\r
546       /// </summary>\r
547       [KeyInfo(KeyType.Dictionary | KeyType.Required)]\r
548       public const string First = "/First";\r
549 \r
550       /// <summary>\r
551       /// (Required if the item has any descendants; must be an indirect reference)\r
552       /// The last of this item\92s immediate children in the outline hierarchy.\r
553       /// </summary>\r
554       [KeyInfo(KeyType.Dictionary | KeyType.Required)]\r
555       public const string Last = "/Last";\r
556 \r
557       /// <summary>\r
558       /// (Required if the item has any descendants) If the item is open, the total number of its \r
559       /// open descendants at all lower levels of the outline hierarchy. If the item is closed, a \r
560       /// negative integer whose absolute value specifies how many descendants would appear if the \r
561       /// item were reopened.\r
562       /// </summary>\r
563       [KeyInfo(KeyType.Integer | KeyType.Required)]\r
564       public const string Count = "/Count";\r
565 \r
566       /// <summary>\r
567       /// (Optional; not permitted if an A entry is present) The destination to be displayed when this \r
568       /// item is activated.\r
569       /// </summary>\r
570       [KeyInfo(KeyType.ArrayOrNameOrString | KeyType.Optional)]\r
571       public const string Dest = "/Dest";\r
572 \r
573       /// <summary>\r
574       /// (Optional; not permitted if an A entry is present) The destination to be displayed when \r
575       /// this item is activated.\r
576       /// </summary>\r
577       [KeyInfo(KeyType.Dictionary | KeyType.Optional)]\r
578       public const string A = "/A";\r
579 \r
580       /// <summary>\r
581       /// (Optional; PDF 1.3; must be an indirect reference) The structure element to which the item \r
582       /// refers.\r
583       /// Note: The ability to associate an outline item with a structure element (such as the beginning \r
584       /// of a chapter) is a PDF 1.3 feature. For backward compatibility with earlier PDF versions, such\r
585       /// an item should also specify a destination (Dest) corresponding to an area of a page where the\r
586       /// contents of the designated structure element are displayed.\r
587       /// </summary>\r
588       [KeyInfo(KeyType.Dictionary | KeyType.Optional)]\r
589       public const string SE = "/SE";\r
590 \r
591       /// <summary>\r
592       /// (Optional; PDF 1.4) An array of three numbers in the range 0.0 to 1.0, representing the \r
593       /// components in the DeviceRGB color space of the color to be used for the outline entry\92s text.\r
594       /// Default value: [0.0 0.0 0.0].\r
595       /// </summary>\r
596       [KeyInfo(KeyType.Array | KeyType.Optional)]\r
597       public const string C = "/C";\r
598 \r
599       /// <summary>\r
600       /// (Optional; PDF 1.4) A set of flags specifying style characteristics for displaying the outline\r
601       /// item\92s text. Default value: 0.\r
602       /// </summary>\r
603       [KeyInfo(KeyType.Integer | KeyType.Optional)]\r
604       public const string F = "/F";\r
605 \r
606       /// <summary>\r
607       /// Gets the KeysMeta for these keys.\r
608       /// </summary>\r
609       public static DictionaryMeta Meta\r
610       {\r
611         get\r
612         {\r
613           if (Keys.meta == null)\r
614             Keys.meta = CreateMeta(typeof(Keys));\r
615           return Keys.meta;\r
616         }\r
617       }\r
618       static DictionaryMeta meta;\r
619     }\r
620 \r
621     /// <summary>\r
622     /// Gets the KeysMeta of this dictionary type.\r
623     /// </summary>\r
624     internal override DictionaryMeta Meta\r
625     {\r
626       get { return Keys.Meta; }\r
627     }\r
628   }\r
629 }\r