root/win32/xsd-3.1.0-i686/libxsd/xsd/cxx/parser/non-validating/xml-schema-pimpl.txx @ 111

Revision 111, 45.2 kB (checked in by mido, 16 years ago)

pridana knihovna XSD (a jeji chlebodarkyne XERCES), v ramci Win32 zprovoznen priklad tests/test_xsd_hello.cxx

Line 
1// file      : xsd/cxx/parser/non-validating/xml-schema-pimpl.txx
2// author    : Boris Kolpackov <boris@codesynthesis.com>
3// copyright : Copyright (c) 2005-2008 Code Synthesis Tools CC
4// license   : GNU GPL v2 + exceptions; see accompanying LICENSE file
5
6#include <limits>
7#include <locale>
8
9#include <xsd/cxx/zc-istream.hxx>
10
11namespace xsd
12{
13  namespace cxx
14  {
15    namespace parser
16    {
17      namespace non_validating
18      {
19        // Note that most of the types implemented here cannot have
20        // whitespaces in the value. As result we don't need to waste
21        // time collapsing whitespaces. All we need to do is trim the
22        // string representation which can be done without copying.
23        //
24
25        // any_type
26        //
27
28        template <typename C>
29        void any_type_pimpl<C>::
30        post_any_type ()
31        {
32        }
33
34        // any_simple_type
35        //
36
37        template <typename C>
38        void any_simple_type_pimpl<C>::
39        post_any_simple_type ()
40        {
41        }
42
43        // boolean
44        //
45        template <typename C>
46        void boolean_pimpl<C>::
47        _pre ()
48        {
49          str_.clear ();
50        }
51
52        template <typename C>
53        void boolean_pimpl<C>::
54        _characters (const ro_string<C>& s)
55        {
56          str_ += s;
57        }
58
59        template <typename C>
60        bool boolean_pimpl<C>::
61        post_boolean ()
62        {
63          std::basic_string<C> tmp;
64          tmp.swap (str_);
65
66          ro_string<C> str (tmp);
67          trim (str);
68
69          return str == bits::true_<C> () || str == bits::one<C> ();
70        }
71
72        // byte
73        //
74
75        template <typename C>
76        void byte_pimpl<C>::
77        _pre ()
78        {
79          str_.clear ();
80        }
81
82        template <typename C>
83        void byte_pimpl<C>::
84        _characters (const ro_string<C>& s)
85        {
86          str_ += s;
87        }
88
89        template <typename C>
90        signed char byte_pimpl<C>::
91        post_byte ()
92        {
93          std::basic_string<C> tmp;
94          tmp.swap (str_);
95
96          ro_string<C> str (tmp);
97          trim (str);
98
99          short t;
100          zc_istream<C> is (str);
101          is >> t;
102
103          return static_cast<signed char> (t);
104        }
105
106        // unsigned_byte
107        //
108
109        template <typename C>
110        void unsigned_byte_pimpl<C>::
111        _pre ()
112        {
113          str_.clear ();
114        }
115
116        template <typename C>
117        void unsigned_byte_pimpl<C>::
118        _characters (const ro_string<C>& s)
119        {
120          str_ += s;
121        }
122
123        template <typename C>
124        unsigned char unsigned_byte_pimpl<C>::
125        post_unsigned_byte ()
126        {
127          std::basic_string<C> tmp;
128          tmp.swap (str_);
129
130          ro_string<C> str (tmp);
131          trim (str);
132
133          unsigned short t;
134          zc_istream<C> is (str);
135          is >> t;
136
137          return static_cast<unsigned char> (t);
138        }
139
140        // short
141        //
142
143        template <typename C>
144        void short_pimpl<C>::
145        _pre ()
146        {
147          str_.clear ();
148        }
149
150        template <typename C>
151        void short_pimpl<C>::
152        _characters (const ro_string<C>& s)
153        {
154          str_ += s;
155        }
156
157        template <typename C>
158        short short_pimpl<C>::
159        post_short ()
160        {
161          std::basic_string<C> tmp;
162          tmp.swap (str_);
163
164          ro_string<C> str (tmp);
165          trim (str);
166
167          short t;
168          zc_istream<C> is (str);
169          is >> t;
170
171          return t;
172        }
173
174        // unsigned_short
175        //
176
177        template <typename C>
178        void unsigned_short_pimpl<C>::
179        _pre ()
180        {
181          str_.clear ();
182        }
183
184        template <typename C>
185        void unsigned_short_pimpl<C>::
186        _characters (const ro_string<C>& s)
187        {
188          str_ += s;
189        }
190
191        template <typename C>
192        unsigned short unsigned_short_pimpl<C>::
193        post_unsigned_short ()
194        {
195          std::basic_string<C> tmp;
196          tmp.swap (str_);
197
198          ro_string<C> str (tmp);
199          trim (str);
200
201          unsigned short t;
202          zc_istream<C> is (str);
203          is >> t;
204
205          return t;
206        }
207
208        // int
209        //
210
211        template <typename C>
212        void int_pimpl<C>::
213        _pre ()
214        {
215          str_.clear ();
216        }
217
218        template <typename C>
219        void int_pimpl<C>::
220        _characters (const ro_string<C>& s)
221        {
222          str_ += s;
223        }
224
225        template <typename C>
226        int int_pimpl<C>::
227        post_int ()
228        {
229          std::basic_string<C> tmp;
230          tmp.swap (str_);
231
232          ro_string<C> str (tmp);
233          trim (str);
234
235          int t;
236          zc_istream<C> is (str);
237          is >> t;
238
239          return t;
240        }
241
242        // unsigned_int
243        //
244
245        template <typename C>
246        void unsigned_int_pimpl<C>::
247        _pre ()
248        {
249          str_.clear ();
250        }
251
252        template <typename C>
253        void unsigned_int_pimpl<C>::
254        _characters (const ro_string<C>& s)
255        {
256          str_ += s;
257        }
258
259        template <typename C>
260        unsigned int unsigned_int_pimpl<C>::
261        post_unsigned_int ()
262        {
263          std::basic_string<C> tmp;
264          tmp.swap (str_);
265
266          ro_string<C> str (tmp);
267          trim (str);
268
269          unsigned int t;
270          zc_istream<C> is (str);
271          is >> t;
272
273          return t;
274        }
275
276        // long
277        //
278        template <typename C>
279        void long_pimpl<C>::
280        _pre ()
281        {
282          str_.clear ();
283        }
284
285        template <typename C>
286        void long_pimpl<C>::
287        _characters (const ro_string<C>& s)
288        {
289          str_ += s;
290        }
291
292        template <typename C>
293        long long long_pimpl<C>::
294        post_long ()
295        {
296          std::basic_string<C> tmp;
297          tmp.swap (str_);
298
299          ro_string<C> str (tmp);
300          trim (str);
301
302          long long t;
303          zc_istream<C> is (str);
304          is >> t;
305
306          return t;
307        }
308
309        // unsigned_long
310        //
311        template <typename C>
312        void unsigned_long_pimpl<C>::
313        _pre ()
314        {
315          str_.clear ();
316        }
317
318        template <typename C>
319        void unsigned_long_pimpl<C>::
320        _characters (const ro_string<C>& s)
321        {
322          str_ += s;
323        }
324
325        template <typename C>
326        unsigned long long unsigned_long_pimpl<C>::
327        post_unsigned_long ()
328        {
329          std::basic_string<C> tmp;
330          tmp.swap (str_);
331
332          ro_string<C> str (tmp);
333          trim (str);
334
335          unsigned long long t;
336          zc_istream<C> is (str);
337          is >> t;
338
339          return t;
340        }
341
342        // integer
343        //
344        template <typename C>
345        void integer_pimpl<C>::
346        _pre ()
347        {
348          str_.clear ();
349        }
350
351        template <typename C>
352        void integer_pimpl<C>::
353        _characters (const ro_string<C>& s)
354        {
355          str_ += s;
356        }
357
358        template <typename C>
359        long long integer_pimpl<C>::
360        post_integer ()
361        {
362          std::basic_string<C> tmp;
363          tmp.swap (str_);
364
365          ro_string<C> str (tmp);
366          trim (str);
367
368          long long t;
369          zc_istream<C> is (str);
370          is >> t;
371
372          return t;
373        }
374
375        // negative_integer
376        //
377        template <typename C>
378        void negative_integer_pimpl<C>::
379        _pre ()
380        {
381          str_.clear ();
382        }
383
384        template <typename C>
385        void negative_integer_pimpl<C>::
386        _characters (const ro_string<C>& s)
387        {
388          str_ += s;
389        }
390
391        template <typename C>
392        long long negative_integer_pimpl<C>::
393        post_negative_integer ()
394        {
395          std::basic_string<C> tmp;
396          tmp.swap (str_);
397
398          ro_string<C> str (tmp);
399          trim (str);
400
401          long long t;
402          zc_istream<C> is (str);
403          is >> t;
404
405          return t;
406        }
407
408        // non_positive_integer
409        //
410        template <typename C>
411        void non_positive_integer_pimpl<C>::
412        _pre ()
413        {
414          str_.clear ();
415        }
416
417        template <typename C>
418        void non_positive_integer_pimpl<C>::
419        _characters (const ro_string<C>& s)
420        {
421          str_ += s;
422        }
423
424        template <typename C>
425        long long non_positive_integer_pimpl<C>::
426        post_non_positive_integer ()
427        {
428          std::basic_string<C> tmp;
429          tmp.swap (str_);
430
431          ro_string<C> str (tmp);
432          trim (str);
433
434          long long t;
435          zc_istream<C> is (str);
436          is >> t;
437
438          return t;
439        }
440
441        // positive_integer
442        //
443        template <typename C>
444        void positive_integer_pimpl<C>::
445        _pre ()
446        {
447          str_.clear ();
448        }
449
450        template <typename C>
451        void positive_integer_pimpl<C>::
452        _characters (const ro_string<C>& s)
453        {
454          str_ += s;
455        }
456
457        template <typename C>
458        unsigned long long positive_integer_pimpl<C>::
459        post_positive_integer ()
460        {
461          std::basic_string<C> tmp;
462          tmp.swap (str_);
463
464          ro_string<C> str (tmp);
465          trim (str);
466
467          unsigned long long t;
468          zc_istream<C> is (str);
469          is >> t;
470
471          return t;
472        }
473
474        // non_negative_integer
475        //
476        template <typename C>
477        void non_negative_integer_pimpl<C>::
478        _pre ()
479        {
480          str_.clear ();
481        }
482
483        template <typename C>
484        void non_negative_integer_pimpl<C>::
485        _characters (const ro_string<C>& s)
486        {
487          str_ += s;
488        }
489
490        template <typename C>
491        unsigned long long non_negative_integer_pimpl<C>::
492        post_non_negative_integer ()
493        {
494          std::basic_string<C> tmp;
495          tmp.swap (str_);
496
497          ro_string<C> str (tmp);
498          trim (str);
499
500          unsigned long long t;
501          zc_istream<C> is (str);
502          is >> t;
503
504          return t;
505        }
506
507        // float
508        //
509        template <typename C>
510        void float_pimpl<C>::
511        _pre ()
512        {
513          str_.clear ();
514        }
515
516        template <typename C>
517        void float_pimpl<C>::
518        _characters (const ro_string<C>& s)
519        {
520          str_ += s;
521        }
522
523        template <typename C>
524        float float_pimpl<C>::
525        post_float ()
526        {
527          std::basic_string<C> tmp;
528          tmp.swap (str_);
529
530          ro_string<C> str (tmp);
531          trim (str);
532
533          if (str == bits::positive_inf<C> ())
534            return std::numeric_limits<float>::infinity ();
535
536          if (str == bits::negative_inf<C> ())
537            return -std::numeric_limits<float>::infinity ();
538
539          if (str == bits::nan<C> ())
540            return std::numeric_limits<float>::quiet_NaN ();
541
542          float t;
543          zc_istream<C> is (str);
544          is.imbue (std::locale::classic ());
545          is >> t;
546
547          return t;
548        }
549
550        // double
551        //
552        template <typename C>
553        void double_pimpl<C>::
554        _pre ()
555        {
556          str_.clear ();
557        }
558
559        template <typename C>
560        void double_pimpl<C>::
561        _characters (const ro_string<C>& s)
562        {
563          str_ += s;
564        }
565
566        template <typename C>
567        double double_pimpl<C>::
568        post_double ()
569        {
570          std::basic_string<C> tmp;
571          tmp.swap (str_);
572
573          ro_string<C> str (tmp);
574          trim (str);
575
576          if (str == bits::positive_inf<C> ())
577            return std::numeric_limits<double>::infinity ();
578
579          if (str == bits::negative_inf<C> ())
580            return -std::numeric_limits<double>::infinity ();
581
582          if (str == bits::nan<C> ())
583            return std::numeric_limits<double>::quiet_NaN ();
584
585          double t;
586          zc_istream<C> is (str);
587          is.imbue (std::locale::classic ());
588          is >> t;
589
590          return t;
591        }
592
593        // decimal
594        //
595        template <typename C>
596        void decimal_pimpl<C>::
597        _pre ()
598        {
599          str_.clear ();
600        }
601
602        template <typename C>
603        void decimal_pimpl<C>::
604        _characters (const ro_string<C>& s)
605        {
606          str_ += s;
607        }
608
609        template <typename C>
610        double decimal_pimpl<C>::
611        post_decimal ()
612        {
613          std::basic_string<C> tmp;
614          tmp.swap (str_);
615
616          ro_string<C> str (tmp);
617          trim (str);
618
619          double t;
620          zc_istream<C> is (str);
621          is.imbue (std::locale::classic ());
622          is >> t;
623
624          return t;
625        }
626
627
628        // string
629        //
630        template <typename C>
631        void string_pimpl<C>::
632        _pre ()
633        {
634          str_.clear ();
635        }
636
637        template <typename C>
638        void string_pimpl<C>::
639        _characters (const ro_string<C>& s)
640        {
641          str_ += s;
642        }
643
644        template <typename C>
645        std::basic_string<C> string_pimpl<C>::
646        post_string ()
647        {
648          std::basic_string<C> r;
649          r.swap (str_);
650          return r;
651        }
652
653        // normalized_string
654        //
655        template <typename C>
656        void normalized_string_pimpl<C>::
657        _pre ()
658        {
659          str_.clear ();
660        }
661
662        template <typename C>
663        void normalized_string_pimpl<C>::
664        _characters (const ro_string<C>& s)
665        {
666          str_ += s;
667        }
668
669        template <typename C>
670        std::basic_string<C> normalized_string_pimpl<C>::
671        post_normalized_string ()
672        {
673          typedef typename std::basic_string<C>::size_type size_type;
674
675          size_type size (str_.size ());
676
677          for (size_type i (0); i < size; ++i)
678          {
679            C& c = str_[i];
680
681            if (c == C (0x0A) || c == C (0x0D) || c == C (0x09))
682              c = C (0x20);
683          }
684
685          std::basic_string<C> r;
686          r.swap (str_);
687          return r;
688        }
689
690        // token
691        //
692        template <typename C>
693        void token_pimpl<C>::
694        _pre ()
695        {
696          str_.clear ();
697        }
698
699        template <typename C>
700        void token_pimpl<C>::
701        _characters (const ro_string<C>& s)
702        {
703          if (str_.size () == 0)
704          {
705            ro_string<C> tmp (s.data (), s.size ());
706
707            if (trim_left (tmp) != 0)
708              str_ += tmp;
709          }
710          else
711            str_ += s;
712        }
713
714        template <typename C>
715        std::basic_string<C> token_pimpl<C>::
716        post_token ()
717        {
718          typedef typename std::basic_string<C>::size_type size_type;
719
720          size_type size (str_.size ());
721          size_type j (0);
722
723          bool subs (false);
724
725          for (size_type i (0); i < size; ++i)
726          {
727            C c = str_[i];
728
729            if (c == C (0x20) || c == C (0x0A) ||
730                c == C (0x0D) || c == C (0x09))
731            {
732              subs = true;
733            }
734            else
735            {
736              if (subs)
737              {
738                subs = false;
739                str_[j++] = C (0x20);
740              }
741
742              str_[j++] = c;
743            }
744          }
745
746          str_.resize (j);
747
748          std::basic_string<C> r;
749          r.swap (str_);
750          return r;
751        }
752
753        // name
754        //
755        template <typename C>
756        void name_pimpl<C>::
757        _pre ()
758        {
759          str_.clear ();
760        }
761
762        template <typename C>
763        void name_pimpl<C>::
764        _characters (const ro_string<C>& s)
765        {
766          if (str_.size () == 0)
767          {
768            ro_string<C> tmp (s.data (), s.size ());
769
770            if (trim_left (tmp) != 0)
771              str_ += tmp;
772          }
773          else
774            str_ += s;
775        }
776
777        template <typename C>
778        std::basic_string<C> name_pimpl<C>::
779        post_name ()
780        {
781          ro_string<C> tmp (str_);
782          str_.resize (trim_right (tmp));
783
784          std::basic_string<C> r;
785          r.swap (str_);
786          return r;
787        }
788
789        // nmtoken
790        //
791        template <typename C>
792        void nmtoken_pimpl<C>::
793        _pre ()
794        {
795          str_.clear ();
796        }
797
798        template <typename C>
799        void nmtoken_pimpl<C>::
800        _characters (const ro_string<C>& s)
801        {
802          if (str_.size () == 0)
803          {
804            ro_string<C> tmp (s.data (), s.size ());
805
806            if (trim_left (tmp) != 0)
807              str_ += tmp;
808          }
809          else
810            str_ += s;
811        }
812
813        template <typename C>
814        std::basic_string<C> nmtoken_pimpl<C>::
815        post_nmtoken ()
816        {
817          ro_string<C> tmp (str_);
818          str_.resize (trim_right (tmp));
819
820          std::basic_string<C> r;
821          r.swap (str_);
822          return r;
823        }
824
825        // nmtokens
826        //
827        template <typename C>
828        void nmtokens_pimpl<C>::
829        _pre ()
830        {
831          nmtokens_pskel<C>::_pre ();
832          seq_.clear ();
833        }
834
835        template <typename C>
836        string_sequence<C> nmtokens_pimpl<C>::
837        post_nmtokens ()
838        {
839          string_sequence<C> r;
840          r.swap (seq_);
841          return r;
842        }
843
844        template <typename C>
845        void nmtokens_pimpl<C>::
846        _xsd_parse_item (const ro_string<C>& s)
847        {
848          parser_.pre ();
849          parser_._pre ();
850          parser_._characters (s);
851          parser_._post ();
852          seq_.push_back (parser_.post_nmtoken ());
853        }
854
855        // ncname
856        //
857        template <typename C>
858        void ncname_pimpl<C>::
859        _pre ()
860        {
861          str_.clear ();
862        }
863
864        template <typename C>
865        void ncname_pimpl<C>::
866        _characters (const ro_string<C>& s)
867        {
868          if (str_.size () == 0)
869          {
870            ro_string<C> tmp (s.data (), s.size ());
871
872            if (trim_left (tmp) != 0)
873              str_ += tmp;
874          }
875          else
876            str_ += s;
877        }
878
879        template <typename C>
880        std::basic_string<C> ncname_pimpl<C>::
881        post_ncname ()
882        {
883          ro_string<C> tmp (str_);
884          str_.resize (trim_right (tmp));
885
886          std::basic_string<C> r;
887          r.swap (str_);
888          return r;
889        }
890
891        // id
892        //
893        template <typename C>
894        std::basic_string<C> id_pimpl<C>::
895        post_id ()
896        {
897          return this->post_ncname ();
898        }
899
900        // idref
901        //
902        template <typename C>
903        std::basic_string<C> idref_pimpl<C>::
904        post_idref ()
905        {
906          return this->post_ncname ();
907        }
908
909        // idrefs
910        //
911        template <typename C>
912        void idrefs_pimpl<C>::
913        _pre ()
914        {
915          idrefs_pskel<C>::_pre ();
916          seq_.clear ();
917        }
918
919        template <typename C>
920        string_sequence<C> idrefs_pimpl<C>::
921        post_idrefs ()
922        {
923          string_sequence<C> r;
924          r.swap (seq_);
925          return r;
926        }
927
928        template <typename C>
929        void idrefs_pimpl<C>::
930        _xsd_parse_item (const ro_string<C>& s)
931        {
932          parser_.pre ();
933          parser_._pre ();
934          parser_._characters (s);
935          parser_._post ();
936          seq_.push_back (parser_.post_idref ());
937        }
938
939        // language
940        //
941        template <typename C>
942        void language_pimpl<C>::
943        _pre ()
944        {
945          str_.clear ();
946        }
947
948        template <typename C>
949        void language_pimpl<C>::
950        _characters (const ro_string<C>& s)
951        {
952          if (str_.size () == 0)
953          {
954            ro_string<C> tmp (s.data (), s.size ());
955
956            if (trim_left (tmp) != 0)
957              str_ += tmp;
958          }
959          else
960            str_ += s;
961        }
962
963        template <typename C>
964        std::basic_string<C> language_pimpl<C>::
965        post_language ()
966        {
967          ro_string<C> tmp (str_);
968          str_.resize (trim_right (tmp));
969
970          std::basic_string<C> r;
971          r.swap (str_);
972          return r;
973        }
974
975        // uri
976        //
977        template <typename C>
978        void uri_pimpl<C>::
979        _pre ()
980        {
981          str_.clear ();
982        }
983
984        template <typename C>
985        void uri_pimpl<C>::
986        _characters (const ro_string<C>& s)
987        {
988          if (str_.size () == 0)
989          {
990            ro_string<C> tmp (s.data (), s.size ());
991
992            if (trim_left (tmp) != 0)
993              str_ += tmp;
994          }
995          else
996            str_ += s;
997        }
998
999        template <typename C>
1000        std::basic_string<C> uri_pimpl<C>::
1001        post_uri ()
1002        {
1003          ro_string<C> tmp (str_);
1004          str_.resize (trim_right (tmp));
1005
1006          std::basic_string<C> r;
1007          r.swap (str_);
1008          return r;
1009        }
1010
1011        // qname
1012        //
1013        template <typename C>
1014        void qname_pimpl<C>::
1015        _pre ()
1016        {
1017          str_.clear ();
1018        }
1019
1020        template <typename C>
1021        void qname_pimpl<C>::
1022        _characters (const ro_string<C>& s)
1023        {
1024          if (str_.size () == 0)
1025          {
1026            ro_string<C> tmp (s.data (), s.size ());
1027
1028            if (trim_left (tmp) != 0)
1029              str_ += tmp;
1030          }
1031          else
1032            str_ += s;
1033        }
1034
1035        template <typename C>
1036        qname<C> qname_pimpl<C>::
1037        post_qname ()
1038        {
1039          typedef typename ro_string<C>::size_type size_type;
1040
1041          ro_string<C> tmp (str_);
1042          size_type size (trim_right (tmp));
1043          size_type pos (tmp.find (C (':')));
1044
1045          if (pos != ro_string<C>::npos)
1046          {
1047            std::basic_string<C> prefix (tmp.data (), pos++);
1048            std::basic_string<C> name (tmp.data () + pos, size - pos);
1049            return qname<C> (prefix, name);
1050          }
1051          else
1052          {
1053            str_.resize (size);
1054            return qname<C> (str_);
1055          }
1056        }
1057
1058        // base64_binary
1059        //
1060        template <typename C>
1061        void base64_binary_pimpl<C>::
1062        _pre ()
1063        {
1064          str_.clear ();
1065        }
1066
1067        template <typename C>
1068        void base64_binary_pimpl<C>::
1069        _characters (const ro_string<C>& s)
1070        {
1071          if (str_.size () == 0)
1072          {
1073            ro_string<C> tmp (s.data (), s.size ());
1074
1075            if (trim_left (tmp) != 0)
1076              str_ += tmp;
1077          }
1078          else
1079            str_ += s;
1080        }
1081
1082        namespace bits
1083        {
1084          template <typename C>
1085          inline unsigned char
1086          base64_decode (C c)
1087          {
1088            unsigned char r (0xFF);
1089
1090            if (c >= C('A') && c <= C ('Z'))
1091              r = static_cast<unsigned char> (c - C ('A'));
1092            else if (c >= C('a') && c <= C ('z'))
1093              r = static_cast<unsigned char> (c - C ('a') + 26);
1094            else if (c >= C('0') && c <= C ('9'))
1095              r = static_cast<unsigned char> (c - C ('0') + 52);
1096            else if (c == C ('+'))
1097              r = 62;
1098            else if (c == C ('/'))
1099              r = 63;
1100
1101            return r;
1102          }
1103        }
1104
1105        template <typename C>
1106        std::auto_ptr<buffer> base64_binary_pimpl<C>::
1107        post_base64_binary ()
1108        {
1109          typedef typename std::basic_string<C>::size_type size_type;
1110
1111          size_type size (str_.size ());
1112          const C* src (str_.c_str ());
1113
1114          // Remove all whitespaces.
1115          //
1116          {
1117            size_type j (0);
1118
1119            bool subs (false);
1120
1121            for (size_type i (0); i < size; ++i)
1122            {
1123              C c = str_[i];
1124
1125              if (c == C (0x20) || c == C (0x0A) ||
1126                  c == C (0x0D) || c == C (0x09))
1127              {
1128                subs = true;
1129              }
1130              else
1131              {
1132                if (subs)
1133                  subs = false;
1134
1135                str_[j++] = c;
1136              }
1137            }
1138
1139            size = j;
1140            str_.resize (size);
1141          }
1142
1143          // Our length should be a multiple of four.
1144          //
1145          size_type quad_count (size / 4);
1146          size_type capacity (quad_count * 3 + 1);
1147
1148          std::auto_ptr<buffer> buf (new buffer (capacity, capacity));
1149          char* dst (buf->data ());
1150
1151          size_type si (0), di (0); // Source and destination indexes.
1152
1153          // Process all quads except the last one.
1154          //
1155          unsigned char b1, b2, b3, b4;
1156
1157          for (size_type q (0); q < quad_count - 1; ++q)
1158          {
1159            b1 = bits::base64_decode (src[si++]);
1160            b2 = bits::base64_decode (src[si++]);
1161            b3 = bits::base64_decode (src[si++]);
1162            b4 = bits::base64_decode (src[si++]);
1163
1164            dst[di++] = (b1 << 2) | (b2 >> 4);
1165            dst[di++] = (b2 << 4) | (b3 >> 2);
1166            dst[di++] = (b3 << 6) | b4;
1167          }
1168
1169          // Process the last quad. The first two octets are always there.
1170          //
1171          b1 = bits::base64_decode (src[si++]);
1172          b2 = bits::base64_decode (src[si++]);
1173
1174          C e3 (src[si++]);
1175          C e4 (src[si++]);
1176
1177          if (e4 == C ('='))
1178          {
1179            if (e3 == C ('='))
1180            {
1181              // Two pads. Last 4 bits in b2 should be zero.
1182              //
1183              dst[di++] = (b1 << 2) | (b2 >> 4);
1184            }
1185            else
1186            {
1187              // One pad. Last 2 bits in b3 should be zero.
1188              //
1189              b3 = bits::base64_decode (e3);
1190
1191              dst[di++] = (b1 << 2) | (b2 >> 4);
1192              dst[di++] = (b2 << 4) | (b3 >> 2);
1193            }
1194          }
1195          else
1196          {
1197            // No pads.
1198            //
1199            b3 = bits::base64_decode (e3);
1200            b4 = bits::base64_decode (e4);
1201
1202            dst[di++] = (b1 << 2) | (b2 >> 4);
1203            dst[di++] = (b2 << 4) | (b3 >> 2);
1204            dst[di++] = (b3 << 6) | b4;
1205          }
1206
1207          // Set the real size.
1208          //
1209          buf->size (di);
1210
1211          return buf;
1212        }
1213
1214        // hex_binary
1215        //
1216        template <typename C>
1217        void hex_binary_pimpl<C>::
1218        _pre ()
1219        {
1220          str_.clear ();
1221        }
1222
1223        template <typename C>
1224        void hex_binary_pimpl<C>::
1225        _characters (const ro_string<C>& s)
1226        {
1227          if (str_.size () == 0)
1228          {
1229            ro_string<C> tmp (s.data (), s.size ());
1230
1231            if (trim_left (tmp) != 0)
1232              str_ += tmp;
1233          }
1234          else
1235            str_ += s;
1236        }
1237
1238        namespace bits
1239        {
1240          template <typename C>
1241          inline unsigned char
1242          hex_decode (C c)
1243          {
1244            unsigned char r (0xFF);
1245
1246            if (c >= C('0') && c <= C ('9'))
1247              r = static_cast<unsigned char> (c - C ('0'));
1248            else if (c >= C ('A') && c <= C ('F'))
1249              r = static_cast<unsigned char> (10 + (c - C ('A')));
1250            else if (c >= C ('a') && c <= C ('f'))
1251              r = static_cast<unsigned char> (10 + (c - C ('a')));
1252
1253            return r;
1254          }
1255        }
1256
1257        template <typename C>
1258        std::auto_ptr<buffer> hex_binary_pimpl<C>::
1259        post_hex_binary ()
1260        {
1261          typedef typename ro_string<C>::size_type size_type;
1262
1263          ro_string<C> tmp (str_);
1264          size_type size (trim_right (tmp));
1265
1266          buffer::size_t n (size / 2);
1267          std::auto_ptr<buffer> buf (new buffer (n));
1268
1269          const C* src (tmp.data ());
1270          char* dst (buf->data ());
1271
1272          for (buffer::size_t i (0); i < n; ++i)
1273          {
1274            unsigned char h (bits::hex_decode (src[2 * i]));
1275            unsigned char l (bits::hex_decode (src[2 * i + 1]));
1276            dst[i] = (h << 4) | l;
1277          }
1278
1279          return buf;
1280        }
1281
1282        // time_zone
1283        //
1284        namespace bits
1285        {
1286          // Datatypes 3.2.7.3.
1287          //
1288          template <typename C>
1289          void
1290          parse_tz (const C* s,
1291                    typename std::basic_string<C>::size_type n,
1292                    short& h, short& m)
1293          {
1294            // time_zone := Z|(+|-)HH:MM
1295            //
1296            if (n == 0)
1297            {
1298              return;
1299            }
1300            else if (s[0] == 'Z')
1301            {
1302              h = 0;
1303              m = 0;
1304            }
1305            else if (n == 6)
1306            {
1307              // Parse hours.
1308              //
1309              h = 10 * (s[1] - '0') + (s[2] - '0');
1310
1311              // Parse minutes.
1312              //
1313              m = 10 * (s[4] - '0') + (s[5] - '0');
1314
1315              if (s[0] == '-')
1316              {
1317                h = -h;
1318                m = -m;
1319              }
1320            }
1321          }
1322        }
1323
1324        // gday
1325        //
1326        template <typename C>
1327        void gday_pimpl<C>::
1328        _pre ()
1329        {
1330          str_.clear ();
1331        }
1332
1333        template <typename C>
1334        void gday_pimpl<C>::
1335        _characters (const ro_string<C>& s)
1336        {
1337          if (str_.size () == 0)
1338          {
1339            ro_string<C> tmp (s.data (), s.size ());
1340
1341            if (trim_left (tmp) != 0)
1342              str_ += tmp;
1343          }
1344          else
1345            str_ += s;
1346        }
1347
1348        template <typename C>
1349        gday gday_pimpl<C>::
1350        post_gday ()
1351        {
1352          typedef typename ro_string<C>::size_type size_type;
1353
1354          ro_string<C> tmp (str_);
1355          size_type size (trim_right (tmp));
1356          const C* s (tmp.data ());
1357
1358          unsigned short day (0);
1359          bool z (false);
1360          short zh, zm;
1361
1362          // gday := ---DD[Z|(+|-)HH:MM]
1363          //
1364          if (size >= 5)
1365          {
1366            day = 10 * (s[3] - '0') + (s[4] - '0');
1367
1368            if (size > 5)
1369            {
1370              bits::parse_tz (s + 5, size - 5, zh, zm);
1371              z = true;
1372            }
1373          }
1374
1375          return z ? gday (day, zh, zm) : gday (day);
1376        }
1377
1378        // gmonth
1379        //
1380        template <typename C>
1381        void gmonth_pimpl<C>::
1382        _pre ()
1383        {
1384          str_.clear ();
1385        }
1386
1387        template <typename C>
1388        void gmonth_pimpl<C>::
1389        _characters (const ro_string<C>& s)
1390        {
1391          if (str_.size () == 0)
1392          {
1393            ro_string<C> tmp (s.data (), s.size ());
1394
1395            if (trim_left (tmp) != 0)
1396              str_ += tmp;
1397          }
1398          else
1399            str_ += s;
1400        }
1401
1402        template <typename C>
1403        gmonth gmonth_pimpl<C>::
1404        post_gmonth ()
1405        {
1406          typedef typename ro_string<C>::size_type size_type;
1407
1408          ro_string<C> tmp (str_);
1409          size_type size (trim_right (tmp));
1410          const C* s (tmp.data ());
1411
1412          unsigned short month (0);
1413          bool z (false);
1414          short zh, zm;
1415
1416          // gmonth := --MM[Z|(+|-)HH:MM]
1417          //
1418          if (size >= 4)
1419          {
1420            month = 10 * (s[2] - '0') + (s[3] - '0');
1421
1422            if (size > 4)
1423            {
1424              bits::parse_tz (s + 4, size - 4, zh, zm);
1425              z = true;
1426            }
1427          }
1428
1429          return z ? gmonth (month, zh, zm) : gmonth (month);
1430        }
1431
1432        // gyear
1433        //
1434        template <typename C>
1435        void gyear_pimpl<C>::
1436        _pre ()
1437        {
1438          str_.clear ();
1439        }
1440
1441        template <typename C>
1442        void gyear_pimpl<C>::
1443        _characters (const ro_string<C>& s)
1444        {
1445          if (str_.size () == 0)
1446          {
1447            ro_string<C> tmp (s.data (), s.size ());
1448
1449            if (trim_left (tmp) != 0)
1450              str_ += tmp;
1451          }
1452          else
1453            str_ += s;
1454        }
1455
1456        template <typename C>
1457        gyear gyear_pimpl<C>::
1458        post_gyear ()
1459        {
1460          typedef typename ro_string<C>::size_type size_type;
1461
1462          ro_string<C> tmp (str_);
1463          size_type size (trim_right (tmp));
1464          const C* s (tmp.data ());
1465
1466          int year (0);
1467          bool z (false);
1468          short zh, zm;
1469
1470          // gyear := [-]CCYY[N]*[Z|(+|-)HH:MM]
1471          //
1472
1473          if (size >= 4)
1474          {
1475            // Find the end of the year token.
1476            //
1477            size_type pos (4);
1478            for (; pos < size; ++pos)
1479            {
1480              C c (s[pos]);
1481
1482              if (c == C ('Z') || c == C ('+') || c == C ('-'))
1483                break;
1484            }
1485
1486            ro_string<C> year_fragment (s, pos);
1487            zc_istream<C> is (year_fragment);
1488            is >> year;
1489
1490            if (pos < size)
1491            {
1492              bits::parse_tz (s + pos, size - pos, zh, zm);
1493              z = true;
1494            }
1495          }
1496
1497          return z ? gyear (year, zh, zm) : gyear (year);
1498        }
1499
1500        // gmonth_day
1501        //
1502        template <typename C>
1503        void gmonth_day_pimpl<C>::
1504        _pre ()
1505        {
1506          str_.clear ();
1507        }
1508
1509        template <typename C>
1510        void gmonth_day_pimpl<C>::
1511        _characters (const ro_string<C>& s)
1512        {
1513          if (str_.size () == 0)
1514          {
1515            ro_string<C> tmp (s.data (), s.size ());
1516
1517            if (trim_left (tmp) != 0)
1518              str_ += tmp;
1519          }
1520          else
1521            str_ += s;
1522        }
1523
1524        template <typename C>
1525        gmonth_day gmonth_day_pimpl<C>::
1526        post_gmonth_day ()
1527        {
1528          typedef typename ro_string<C>::size_type size_type;
1529
1530          ro_string<C> tmp (str_);
1531          size_type size (trim_right (tmp));
1532          const C* s (tmp.data ());
1533
1534          unsigned short month (0), day (0);
1535          bool z (false);
1536          short zh, zm;
1537
1538          // gmonth_day := --MM-DD[Z|(+|-)HH:MM]
1539          //
1540          if (size >= 7)
1541          {
1542            month = 10 * (s[2] - '0') + (s[3] - '0');
1543            day = 10 * (s[5] - '0') + (s[6] - '0');
1544
1545            if (size > 7)
1546            {
1547              bits::parse_tz (s + 7, size - 7, zh, zm);
1548              z = true;
1549            }
1550          }
1551
1552          return z
1553            ? gmonth_day (month, day, zh, zm)
1554            : gmonth_day (month, day);
1555        }
1556
1557        // gyear_month
1558        //
1559        template <typename C>
1560        void gyear_month_pimpl<C>::
1561        _pre ()
1562        {
1563          str_.clear ();
1564        }
1565
1566        template <typename C>
1567        void gyear_month_pimpl<C>::
1568        _characters (const ro_string<C>& s)
1569        {
1570          if (str_.size () == 0)
1571          {
1572            ro_string<C> tmp (s.data (), s.size ());
1573
1574            if (trim_left (tmp) != 0)
1575              str_ += tmp;
1576          }
1577          else
1578            str_ += s;
1579        }
1580
1581        template <typename C>
1582        gyear_month gyear_month_pimpl<C>::
1583        post_gyear_month ()
1584        {
1585          typedef typename ro_string<C>::size_type size_type;
1586
1587          ro_string<C> tmp (str_);
1588          size_type size (trim_right (tmp));
1589          const C* s (tmp.data ());
1590
1591          int year (0);
1592          unsigned short month (0);
1593          bool z (false);
1594          short zh, zm;
1595
1596          // gyear_month := [-]CCYY[N]*-MM[Z|(+|-)HH:MM]
1597          //
1598
1599          if (size >= 7)
1600          {
1601            // Find the end of the year token.
1602            //
1603            size_type pos (tmp.find (C ('-'), 4));
1604
1605            if (pos != ro_string<C>::npos && (size - pos - 1) >= 2)
1606            {
1607              ro_string<C> year_fragment (s, pos);
1608              zc_istream<C> yis (year_fragment);
1609              yis >> year;
1610
1611              month = 10 * (s[pos + 1] - '0') + (s[pos + 2] - '0');
1612
1613              pos += 3;
1614
1615              if (pos < size)
1616              {
1617                bits::parse_tz (s + pos, size - pos, zh, zm);
1618                z = true;
1619              }
1620            }
1621          }
1622
1623          return z
1624            ? gyear_month (year, month, zh, zm)
1625            : gyear_month (year, month);
1626        }
1627
1628        // date
1629        //
1630        template <typename C>
1631        void date_pimpl<C>::
1632        _pre ()
1633        {
1634          str_.clear ();
1635        }
1636
1637        template <typename C>
1638        void date_pimpl<C>::
1639        _characters (const ro_string<C>& s)
1640        {
1641          if (str_.size () == 0)
1642          {
1643            ro_string<C> tmp (s.data (), s.size ());
1644
1645            if (trim_left (tmp) != 0)
1646              str_ += tmp;
1647          }
1648          else
1649            str_ += s;
1650        }
1651
1652        template <typename C>
1653        date date_pimpl<C>::
1654        post_date ()
1655        {
1656          typedef typename ro_string<C>::size_type size_type;
1657
1658          ro_string<C> tmp (str_);
1659          size_type size (trim_right (tmp));
1660          const C* s (tmp.data ());
1661
1662          int year (0);
1663          unsigned short month (0), day (0);
1664          bool z (false);
1665          short zh, zm;
1666
1667          // date := [-]CCYY[N]*-MM-DD[Z|(+|-)HH:MM]
1668          //
1669
1670          if (size >= 10)
1671          {
1672            // Find the end of the year token.
1673            //
1674            size_type pos (tmp.find (C ('-'), 4));
1675
1676            if (pos != ro_string<C>::npos && (size - pos - 1) >= 5)
1677            {
1678              ro_string<C> year_fragment (s, pos);
1679              zc_istream<C> yis (year_fragment);
1680              yis >> year;
1681
1682              month = 10 * (s[pos + 1] - '0') + (s[pos + 2] - '0');
1683              day = 10 * (s[pos + 4] - '0') + (s[pos + 5] - '0');
1684
1685              pos += 6;
1686
1687              if (pos < size)
1688              {
1689                bits::parse_tz (s + pos, size - pos, zh, zm);
1690                z = true;
1691              }
1692            }
1693          }
1694
1695          return z
1696            ? date (year, month, day, zh, zm)
1697            : date (year, month, day);
1698        }
1699
1700        // time
1701        //
1702        template <typename C>
1703        void time_pimpl<C>::
1704        _pre ()
1705        {
1706          str_.clear ();
1707        }
1708
1709        template <typename C>
1710        void time_pimpl<C>::
1711        _characters (const ro_string<C>& s)
1712        {
1713          if (str_.size () == 0)
1714          {
1715            ro_string<C> tmp (s.data (), s.size ());
1716
1717            if (trim_left (tmp) != 0)
1718              str_ += tmp;
1719          }
1720          else
1721            str_ += s;
1722        }
1723
1724        template <typename C>
1725        time time_pimpl<C>::
1726        post_time ()
1727        {
1728          typedef typename ro_string<C>::size_type size_type;
1729
1730          ro_string<C> tmp (str_);
1731          size_type size (trim_right (tmp));
1732          const C* s (tmp.data ());
1733
1734          unsigned short hours (0), minutes (0);
1735          double seconds (0.0);
1736          bool z (false);
1737          short zh, zm;
1738
1739          // time := HH:MM:SS[.S+][Z|(+|-)HH:MM]
1740          //
1741
1742          if (size >= 8)
1743          {
1744            hours = 10 * (s[0] - '0') + (s[1] - '0');
1745            minutes = 10 * (s[3] - '0') + (s[4] - '0');
1746
1747            // Find the end of the seconds fragment.
1748            //
1749            size_type pos (8);
1750            for (; pos < size; ++pos)
1751            {
1752              C c (s[pos]);
1753
1754              if (c == C ('Z') || c == C ('+') || c == C ('-'))
1755                break;
1756            }
1757
1758            ro_string<C> seconds_fragment (s + 6, pos - 6);
1759            zc_istream<C> sis (seconds_fragment);
1760            sis >> seconds;
1761
1762            if (pos < size)
1763            {
1764              bits::parse_tz (s + pos, size - pos, zh, zm);
1765              z = true;
1766            }
1767          }
1768
1769          return z
1770            ? time (hours, minutes, seconds, zh, zm)
1771            : time (hours, minutes, seconds);
1772        }
1773
1774
1775        // date_time
1776        //
1777        template <typename C>
1778        void date_time_pimpl<C>::
1779        _pre ()
1780        {
1781          str_.clear ();
1782        }
1783
1784        template <typename C>
1785        void date_time_pimpl<C>::
1786        _characters (const ro_string<C>& s)
1787        {
1788          if (str_.size () == 0)
1789          {
1790            ro_string<C> tmp (s.data (), s.size ());
1791
1792            if (trim_left (tmp) != 0)
1793              str_ += tmp;
1794          }
1795          else
1796            str_ += s;
1797        }
1798
1799        template <typename C>
1800        date_time date_time_pimpl<C>::
1801        post_date_time ()
1802        {
1803          typedef typename ro_string<C>::size_type size_type;
1804
1805          ro_string<C> tmp (str_);
1806          size_type size (trim_right (tmp));
1807          const C* s (tmp.data ());
1808
1809          int year (0);
1810          unsigned short month (0), day (0), hours (0), minutes (0);
1811          double seconds (0.0);
1812          bool z (false);
1813          short zh, zm;
1814
1815          // date_time := [-]CCYY[N]*-MM-DDTHH:MM:SS[.S+][Z|(+|-)HH:MM]
1816          //
1817
1818          if (size >= 19)
1819          {
1820            // Find the end of the year token.
1821            //
1822            size_type pos (tmp.find (C ('-'), 4));
1823
1824            if (pos != ro_string<C>::npos && (size - pos - 1) >= 14)
1825            {
1826              ro_string<C> year_fragment (s, pos);
1827              zc_istream<C> yis (year_fragment);
1828              yis >> year;
1829
1830              month = 10 * (s[pos + 1] - '0') + (s[pos + 2] - '0');
1831              day = 10 * (s[pos + 4] - '0') + (s[pos + 5] - '0');
1832
1833              pos += 7; // Point to the first H.
1834
1835              hours = 10 * (s[pos] - '0') + (s[pos + 1] - '0');
1836              minutes = 10 * (s[pos + 3] - '0') + (s[pos + 4] - '0');
1837
1838              // Find the end of the seconds fragment.
1839              //
1840              pos += 6; // Point to the first S.
1841
1842              size_type sec_end (pos + 2);
1843              for (; sec_end < size; ++sec_end)
1844              {
1845                C c (s[sec_end]);
1846
1847                if (c == C ('Z') || c == C ('+') || c == C ('-'))
1848                  break;
1849              }
1850
1851              ro_string<C> seconds_fragment (s + pos, sec_end - pos);
1852              zc_istream<C> sis (seconds_fragment);
1853              sis >> seconds;
1854
1855              if (sec_end < size)
1856              {
1857                bits::parse_tz (s + sec_end, size - sec_end, zh, zm);
1858                z = true;
1859              }
1860            }
1861          }
1862
1863          return z
1864            ? date_time (year, month, day, hours, minutes, seconds, zh, zm)
1865            : date_time (year, month, day, hours, minutes, seconds);
1866        }
1867
1868        // duration
1869        //
1870        template <typename C>
1871        void duration_pimpl<C>::
1872        _pre ()
1873        {
1874          str_.clear ();
1875        }
1876
1877        template <typename C>
1878        void duration_pimpl<C>::
1879        _characters (const ro_string<C>& s)
1880        {
1881          if (str_.size () == 0)
1882          {
1883            ro_string<C> tmp (s.data (), s.size ());
1884
1885            if (trim_left (tmp) != 0)
1886              str_ += tmp;
1887          }
1888          else
1889            str_ += s;
1890        }
1891
1892        namespace bits
1893        {
1894          template <typename C>
1895          inline typename ro_string<C>::size_type
1896          duration_delim (const C* s,
1897                          typename ro_string<C>::size_type pos,
1898                          typename ro_string<C>::size_type size)
1899          {
1900            const C* p (s + pos);
1901            for (; p < (s + size); ++p)
1902            {
1903              if (*p == C ('Y') || *p == C ('D') || *p == C ('M') ||
1904                  *p == C ('H') || *p == C ('M') || *p == C ('S') ||
1905                  *p == C ('T'))
1906                break;
1907            }
1908
1909            return p - s;
1910          }
1911        }
1912
1913        template <typename C>
1914        duration duration_pimpl<C>::
1915        post_duration ()
1916        {
1917          typedef typename ro_string<C>::size_type size_type;
1918
1919          ro_string<C> tmp (str_);
1920          size_type size (trim_right (tmp));
1921
1922          bool negative (false);
1923          unsigned int years (0), months (0), days (0), hours (0), minutes (0);
1924          double seconds (0.0);
1925
1926          // duration := [-]P[nY][nM][nD][TnHnMn[.n+]S]
1927          //
1928          const C* s (tmp.data ());
1929
1930          if (size >= 3)
1931          {
1932            size_type pos (0);
1933
1934            if (s[0] == C ('-'))
1935            {
1936              negative = true;
1937              pos++;
1938            }
1939
1940            pos++; // Skip 'P'.
1941
1942            size_type del (bits::duration_delim (s, pos, size));
1943
1944            if (del != size && s[del] == C ('Y'))
1945            {
1946              ro_string<C> fragment (s + pos, del - pos);
1947              zc_istream<C> is (fragment);
1948              is >> years;
1949
1950              pos = del + 1;
1951              del = bits::duration_delim (s, pos, size);
1952            }
1953
1954            if (del != size && s[del] == C ('M'))
1955            {
1956              ro_string<C> fragment (s + pos, del - pos);
1957              zc_istream<C> is (fragment);
1958              is >> months;
1959
1960              pos = del + 1;
1961              del = bits::duration_delim (s, pos, size);
1962            }
1963
1964            if (del != size && s[del] == C ('D'))
1965            {
1966              ro_string<C> fragment (s + pos, del - pos);
1967              zc_istream<C> is (fragment);
1968              is >> days;
1969
1970              pos = del + 1;
1971              del = bits::duration_delim (s, pos, size);
1972            }
1973
1974            if (del != size && s[del] == C ('T'))
1975            {
1976              pos = del + 1;
1977              del = bits::duration_delim (s, pos, size);
1978
1979              if (del != size && s[del] == C ('H'))
1980              {
1981                ro_string<C> fragment (s + pos, del - pos);
1982                zc_istream<C> is (fragment);
1983                is >> hours;
1984
1985                pos = del + 1;
1986                del = bits::duration_delim (s, pos, size);
1987              }
1988
1989              if (del != size && s[del] == C ('M'))
1990              {
1991                ro_string<C> fragment (s + pos, del - pos);
1992                zc_istream<C> is (fragment);
1993                is >> minutes;
1994
1995                pos = del + 1;
1996                del = bits::duration_delim (s, pos, size);
1997              }
1998
1999              if (del != size && s[del] == C ('S'))
2000              {
2001                ro_string<C> fragment (s + pos, del - pos);
2002                zc_istream<C> is (fragment);
2003                is >> seconds;
2004              }
2005            }
2006          }
2007
2008          return duration (
2009            negative, years, months, days, hours, minutes, seconds);
2010        }
2011      }
2012    }
2013  }
2014}
Note: See TracBrowser for help on using the browser.