00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00020
00022
00031 #include "arts.h"
00032 #include "xml_io.h"
00033 #include "xml_io_private.h"
00034 #include "xml_io_types.h"
00035 #include "xml_io_instantiation.h"
00036 #include "bofstream.h"
00037 #include "bifstream.h"
00038 #include "file.h"
00039
00040 #ifdef ENABLE_ZLIB
00041 #include "gzstream.h"
00042 #endif
00043
00044
00046
00048
00050
00056 void
00057 ArtsXMLTag::check_name (const String& expected_name)
00058 {
00059 if (name != expected_name)
00060 {
00061 xml_parse_error ("Tag <" + expected_name + "> expected but <"
00062 + name + "> found.");
00063 }
00064
00065 }
00066
00067
00069
00074 void
00075 ArtsXMLTag::add_attribute (const String& aname, const String& value)
00076 {
00077 XMLAttribute attr;
00078
00079 attr.name = aname;
00080 attr.value = value;
00081 attribs.push_back (attr);
00082 }
00083
00084
00086
00091 void
00092 ArtsXMLTag::add_attribute (const String& aname, const Index& value)
00093 {
00094 ostringstream v;
00095
00096 v << value;
00097 add_attribute (aname, v.str ());
00098 }
00099
00100
00102
00110 void
00111 ArtsXMLTag::check_attribute (const String& aname, const String& value)
00112 {
00113 String actual_value;
00114
00115 get_attribute_value (aname, actual_value);
00116
00117 if (actual_value == "*not found*")
00118 {
00119 xml_parse_error ("Required attribute " + aname
00120 + " does not exist");
00121 }
00122 else if (actual_value != value)
00123 {
00124 xml_parse_error ("Attribute " + aname + " has value "
00125 + actual_value + " but "
00126 + value + " was expected.");
00127 }
00128 }
00129
00130
00132
00140 void
00141 ArtsXMLTag::get_attribute_value (const String& aname, String& value)
00142 {
00143 value = "";
00144
00145 Array<XMLAttribute>::iterator it = attribs.begin ();
00146 while (it != attribs.end ())
00147 {
00148 if (it->name == aname)
00149 {
00150 value = it->value;
00151 it = attribs.end ();
00152 }
00153 else
00154 {
00155 it++;
00156 }
00157 }
00158 }
00159
00160
00162
00170 void
00171 ArtsXMLTag::get_attribute_value (const String& aname, Index& value)
00172 {
00173 String attribute_value;
00174 istringstream strstr ("");
00175
00176 get_attribute_value (aname, attribute_value);
00177 strstr.str (attribute_value);
00178 strstr >> value;
00179 if (strstr.fail ())
00180 {
00181 xml_parse_error ("Error while parsing value of " + aname
00182 + " from <" + name + ">");
00183 }
00184 }
00185
00186
00187
00189
00194 void
00195 ArtsXMLTag::read_from_stream (istream& is)
00196 {
00197 String token;
00198 stringbuf tag;
00199 istringstream sstr ("");
00200 XMLAttribute attr;
00201 char ch;
00202
00203 attribs.clear ();
00204
00205 while (is.good () && isspace (is.peek ()))
00206 {
00207 is.get ();
00208 }
00209
00210 is >> ch;
00211
00212 if (ch != '<')
00213 {
00214 is >> token;
00215 token = ch + token;
00216
00217 xml_parse_error ("'<' expected but " + token + " found.");
00218 }
00219
00220 is.get (tag, '>');
00221
00222
00223 if (is.bad () || is.eof ())
00224 {
00225 xml_parse_error ("Unexpected end of file while looking for '>'");
00226 }
00227
00228 if (is.get () != '>')
00229 {
00230 xml_parse_error ("Closing > not found in tag: " + tag.str ());
00231 }
00232
00233 sstr.str (tag.str () + '>');
00234 out3 << "Read: " << sstr.str () << '\n';
00235
00236 sstr >> name;
00237
00238 if (name [name.length () - 1] == '>')
00239 {
00240
00241
00242 name.erase (name.length () - 1, 1);
00243 token = ">";
00244 }
00245 else
00246 {
00247
00248 sstr >> token;
00249 }
00250 out3 << "Name: " << name << '\n';
00251
00252
00253 while (token != ">")
00254 {
00255 String::size_type pos;
00256
00257 pos = token.find ("=", 0);
00258 if (pos == String::npos)
00259 {
00260 xml_parse_error ("Syntax error in tag: " + tag.str ());
00261 }
00262
00263 attr.name = token.substr (0, pos);
00264 token.erase (0, pos + 1);
00265
00266 if (token[0] != '\"')
00267 {
00268 xml_parse_error ("Missing \" in tag: " + tag.str ());
00269 }
00270
00271 while ((pos = token.find ("\"", 1)) == (String::size_type)String::npos && token != ">")
00272 {
00273 String ntoken;
00274 sstr >> ntoken;
00275 token += " " + ntoken;
00276 }
00277
00278 if (pos == (String::size_type)String::npos)
00279 {
00280 xml_parse_error ("Missing \" in tag: " + sstr.str ());
00281 }
00282
00283 if (pos == 1)
00284 attr.value = "";
00285 else
00286 attr.value = token.substr (1, pos - 1);
00287
00288 attribs.push_back (attr);
00289
00290 out3 << "Attr: " << attr.name << '\n';
00291 out3 << "Value: " << attr.value << '\n';
00292
00293 if (token[token.length () - 1] == '>')
00294 {
00295 token = ">";
00296 }
00297 else
00298 {
00299 sstr >> token;
00300 }
00301 }
00302
00303 out3 << '\n';
00304
00305
00306 if (name == "comment")
00307 {
00308 is.get (tag, '<');
00309
00310
00311 if (is.bad () || is.eof ())
00312 {
00313 xml_parse_error ("Unexpected end of file while looking for "
00314 "comment tag");
00315 }
00316
00317 read_from_stream (is);
00318 check_name ("/comment");
00319 read_from_stream (is);
00320 }
00321 }
00322
00323
00325
00330 void
00331 ArtsXMLTag::write_to_stream (ostream& os)
00332 {
00333
00334 os << "<" << name;
00335
00336 Array<XMLAttribute>::iterator it = attribs.begin ();
00337
00338 while (it != attribs.end ())
00339 {
00340 os << ' ' << it->name
00341 << "=\"" << it->value << '\"';
00342 it++;
00343 }
00344
00345 os << ">";
00346 }
00347
00348
00349
00351
00353
00355
00361 void
00362 filename_xml (String& filename,
00363 const String& varname )
00364 {
00365 if ("" == filename)
00366 {
00367 extern const String out_basename;
00368 filename = out_basename + "." + varname + ".xml";
00369 }
00370 }
00371
00372
00373
00375
00382 void
00383 filename_xml_with_index (
00384 String& filename,
00385 const Index& file_index,
00386 const String& varname )
00387 {
00388 Index dummy = file_index;
00389 dummy += 1;
00390
00391 if ("" == filename)
00392 {
00393 extern const String out_basename;
00394 ostringstream os;
00395 os << out_basename << "." << varname << "." << file_index << ".xml";
00396 filename = os.str();
00397 }
00398 else
00399 {
00400 ostringstream os;
00401 os << filename << "." << file_index << ".xml";
00402 filename = os.str();
00403 }
00404 }
00405
00406
00407
00409
00411
00413
00419 void
00420 xml_open_output_file (ofstream& file, const String& name)
00421 {
00422
00423
00424
00425
00426
00427 file.exceptions(ios::badbit |
00428 ios::failbit);
00429
00430
00431 try {
00432 file.open (name.c_str());
00433 } catch (ios::failure) {
00434 ostringstream os;
00435 os << "Cannot open output file: " << name << '\n'
00436 << "Maybe you don't have write access "
00437 << "to the directory or the file?";
00438 throw runtime_error(os.str());
00439 }
00440
00441
00442
00443
00444
00445
00446
00447 if (!file)
00448 {
00449 ostringstream os;
00450 os << "Cannot open output file: " << name << '\n'
00451 << "Maybe you don't have write access "
00452 << "to the directory or the file?";
00453 throw runtime_error(os.str());
00454 }
00455 }
00456
00457 #ifdef ENABLE_ZLIB
00458
00460
00466 void
00467 xml_open_output_file (ogzstream& file, const String& name)
00468 {
00469
00470
00471
00472
00473
00474 file.exceptions(ios::badbit |
00475 ios::failbit);
00476
00477
00478 String nname = name;
00479
00480 if (nname.substr (nname.length()-3, 3) != ".gz")
00481 {
00482 nname += ".gz";
00483 }
00484
00485 try {
00486 file.open (nname.c_str());
00487 } catch (ios::failure) {
00488 ostringstream os;
00489 os << "Cannot open output file: " << nname << '\n'
00490 << "Maybe you don't have write access "
00491 << "to the directory or the file?";
00492 throw runtime_error(os.str());
00493 }
00494
00495
00496
00497
00498
00499
00500
00501 if (!file)
00502 {
00503 ostringstream os;
00504 os << "Cannot open output file: " << nname << '\n'
00505 << "Maybe you don't have write access "
00506 << "to the directory or the file?";
00507 throw runtime_error(os.str());
00508 }
00509 }
00510
00511 #endif
00512
00514
00520 void
00521 xml_open_input_file (ifstream& ifs, const String& name)
00522 {
00523
00524
00525
00526
00527 ifs.exceptions (ios::badbit);
00528
00529
00530 try
00531 {
00532 ifs.open (name.c_str ());
00533 }
00534 catch (ios::failure)
00535 {
00536 ostringstream os;
00537 os << "Cannot open input file: " << name << '\n'
00538 << "Maybe the file does not exist?";
00539 throw runtime_error (os.str ());
00540 }
00541
00542
00543
00544
00545 if (!ifs)
00546 {
00547 ostringstream os;
00548 os << "Cannot open input file: " << name << '\n'
00549 << "Maybe the file does not exist?";
00550 throw runtime_error (os.str ());
00551 }
00552
00553 out3 << "- Reading input file " << name << "\n";
00554 }
00555
00556
00557 #ifdef ENABLE_ZLIB
00558
00560
00566 void
00567 xml_open_input_file (igzstream& ifs, const String& name)
00568 {
00569
00570
00571
00572
00573 ifs.exceptions (ios::badbit);
00574
00575
00576 try
00577 {
00578 ifs.open (name.c_str ());
00579 }
00580 catch (ios::failure)
00581 {
00582 ostringstream os;
00583 os << "Cannot open input file: " << name << '\n'
00584 << "Maybe the file does not exist?";
00585 throw runtime_error (os.str ());
00586 }
00587
00588
00589
00590
00591 if (!ifs)
00592 {
00593 ostringstream os;
00594 os << "Cannot open input file: " << name << '\n'
00595 << "Maybe the file does not exist?";
00596 throw runtime_error (os.str ());
00597 }
00598
00599 out3 << "- Reading input file " << name << "\n";
00600 }
00601
00602 #endif
00603
00604
00606
00608
00610
00616 void
00617 xml_parse_error (const String& str_error)
00618 {
00619 ostringstream os;
00620 os << "XML parse error: " << str_error << '\n'
00621 << "Check syntax of XML file\n";
00622 throw runtime_error (os.str ());
00623 }
00624
00625
00627
00634 void
00635 xml_data_parse_error (ArtsXMLTag& tag, String str_error)
00636 {
00637 ostringstream os;
00638 os << "XML data parse error: Error reading ";
00639 tag.write_to_stream (os);
00640 os << str_error << "\n"
00641 << "Check syntax of XML file. A possible cause is that the file "
00642 << "contains NaN or Inf values.\n";
00643 throw runtime_error (os.str ());
00644 }
00645
00646
00648
00657 void
00658 xml_read_header_from_stream (istream& is, FileType& ftype, NumericType& ntype,
00659 EndianType& etype)
00660 {
00661 char str[6];
00662 stringbuf strbuf;
00663 ArtsXMLTag tag;
00664 String strtype;
00665
00666 while (!is.fail () && isspace (is.peek())) is.get();
00667
00668 is.get (str, 6);
00669
00670 if (string(str) != "<?xml")
00671 {
00672 xml_parse_error ("Input file is not a valid xml file "
00673 "(<?xml not found)");
00674 }
00675
00676 is.get (strbuf, '>');
00677 is.get ();
00678
00679 if (is.fail ())
00680 {
00681 xml_parse_error ("Input file is not a valid xml file");
00682 }
00683
00684 tag.read_from_stream (is);
00685 tag.check_name ("arts");
00686
00687
00688 tag.get_attribute_value ("format", strtype);
00689 if (strtype == "binary")
00690 {
00691 ftype = FILE_TYPE_BINARY;
00692 }
00693 else
00694 {
00695 ftype = FILE_TYPE_ASCII;
00696 }
00697
00698
00699 tag.get_attribute_value ("endian_type", strtype);
00700 if (strtype == "little")
00701 {
00702 etype = ENDIAN_TYPE_LITTLE;
00703 }
00704 if (strtype == "big")
00705 {
00706 etype = ENDIAN_TYPE_BIG;
00707 }
00708 if (strtype == "")
00709 {
00710
00711
00712 etype = ENDIAN_TYPE_LITTLE;
00713 }
00714 else
00715 {
00716 ostringstream os;
00717 os << " Error: Unknown endian type \"" << strtype
00718 << "\" specified in XML file.\n";
00719 throw runtime_error(os.str());
00720 }
00721
00722
00723 tag.get_attribute_value ("numeric_type", strtype);
00724 if (strtype == "float")
00725 {
00726 ntype = NUMERIC_TYPE_FLOAT;
00727 }
00728 else if (strtype == "double")
00729 {
00730 ntype = NUMERIC_TYPE_DOUBLE;
00731 }
00732 else if (strtype == "")
00733 {
00734
00735
00736 ntype = NUMERIC_TYPE_DOUBLE;
00737 }
00738 else
00739 {
00740 ostringstream os;
00741 os << " Error: Unknown numeric type \"" << strtype
00742 << "\" specified in XML file.\n";
00743 throw runtime_error(os.str());
00744 }
00745
00746 }
00747
00748
00750
00755 void
00756 xml_read_footer_from_stream (istream& is)
00757 {
00758 ArtsXMLTag tag;
00759
00760 tag.read_from_stream (is);
00761 tag.check_name ("/arts");
00762 }
00763
00764
00766
00770 void
00771 xml_write_header_to_stream (ostream& os, FileType ftype)
00772 {
00773 ArtsXMLTag tag;
00774
00775 os << "<?xml version=\"1.0\"?>"
00776 << '\n';
00777
00778 tag.set_name ("arts");
00779 switch (ftype)
00780 {
00781 case FILE_TYPE_ASCII:
00782 case FILE_TYPE_ZIPPED_ASCII:
00783 tag.add_attribute ("format", "ascii");
00784 break;
00785 case FILE_TYPE_BINARY:
00786 tag.add_attribute ("format", "binary");
00787 break;
00788 }
00789
00790 tag.add_attribute ("version", "1");
00791
00792 tag.write_to_stream (os);
00793
00794 os << '\n';
00795
00796 }
00797
00798
00800
00803 void
00804 xml_write_footer_to_stream (ostream& os)
00805 {
00806 ArtsXMLTag tag;
00807
00808 tag.set_name ("/arts");
00809 tag.write_to_stream (os);
00810
00811 os << endl;
00812 }
00813
00814 void
00815 xml_set_stream_precision (ostream& os)
00816 {
00817
00818
00819 int precision;
00820 #ifdef USE_FLOAT
00821 precision = FLT_DIG;
00822 #else
00823 #ifdef USE_DOUBLE
00824 precision = DBL_DIG;
00825 #else
00826 #error Numeric must be double or float
00827 #endif
00828 #endif
00829
00830 os << setprecision (precision);
00831 }
00832
00833
00835
00837
00839
00846 template<typename T> void
00847 xml_read_from_file (const String& filename,
00848 T& type)
00849 {
00850 istream* ifs;
00851 FileType ftype;
00852 NumericType ntype;
00853 EndianType etype;
00854
00855 out2 << " Reading " << filename << '\n';
00856
00857 String xml_file = filename;
00858 bool found_file;
00859
00860 found_file = find_file (xml_file, ".xml");
00861 if (!found_file) found_file = find_file (xml_file, ".xml.gz");
00862 if (!found_file) found_file = find_file (xml_file, ".gz");
00863
00864
00865 if (xml_file.substr (xml_file.length () - 3, 3) == ".gz")
00866 #ifdef ENABLE_ZLIB
00867 {
00868 ifs = new igzstream();
00869 xml_open_input_file (*(igzstream *)ifs, xml_file);
00870 }
00871 #else
00872 {
00873 throw runtime_error (
00874 "This arts version was compiled without zlib support.\n"
00875 "Thus zipped xml files cannot be read.");
00876 }
00877 #endif
00878 else
00879 {
00880 ifs = new ifstream();
00881 xml_open_input_file (*(ifstream *)ifs, xml_file);
00882 }
00883
00884
00885
00886
00887
00888
00889
00890 try
00891 {
00892 xml_read_header_from_stream (*ifs, ftype, ntype, etype);
00893 if (ftype == FILE_TYPE_ASCII)
00894 {
00895 xml_read_from_stream (*ifs, type);
00896 }
00897 else
00898 {
00899 String bfilename = filename + ".bin";
00900 bifstream bifs (bfilename.c_str ());
00901 xml_read_from_stream (*ifs, type, &bifs);
00902 }
00903 xml_read_footer_from_stream (*ifs);
00904 }
00905 catch (runtime_error e)
00906 {
00907 delete ifs;
00908 ostringstream os;
00909 os << "Error reading file: " << filename << '\n'
00910 << e.what ();
00911 throw runtime_error (os.str ());
00912 }
00913
00914 delete ifs;
00915 }
00916
00917
00918 void
00919 xml_read_arts_catalogue_from_file (const String& filename,
00920 ArrayOfLineRecord& type,
00921 const Numeric& fmin,
00922 const Numeric& fmax)
00923 {
00924 istream* ifs;
00925 FileType ftype;
00926 NumericType ntype;
00927 EndianType etype;
00928
00929 out2 << " Reading " << filename << '\n';
00930
00931 String xml_file = filename;
00932 bool found_file;
00933
00934 found_file = find_file (xml_file, ".xml");
00935 if (!found_file) found_file = find_file (xml_file, ".xml.gz");
00936 if (!found_file) found_file = find_file (xml_file, ".gz");
00937
00938
00939 if (xml_file.substr (xml_file.length () - 3, 3) == ".gz")
00940 #ifdef ENABLE_ZLIB
00941 {
00942 ifs = new igzstream();
00943 xml_open_input_file (*(igzstream *)ifs, xml_file);
00944 }
00945 #else
00946 {
00947 throw runtime_error (
00948 "This arts version was compiled without zlib support.\n"
00949 "Thus zipped xml files cannot be read.");
00950 }
00951 #endif
00952 else
00953 {
00954 ifs = new ifstream();
00955 xml_open_input_file (*(ifstream *)ifs, xml_file);
00956 }
00957
00958
00959
00960
00961
00962
00963
00964 try
00965 {
00966 xml_read_header_from_stream (*ifs, ftype, ntype, etype);
00967 if (ftype == FILE_TYPE_ASCII)
00968 {
00969 xml_read_from_stream (*ifs, type, fmin, fmax);
00970 }
00971 else
00972 {
00973 String bfilename = filename + ".bin";
00974 bifstream bifs (bfilename.c_str ());
00975 xml_read_from_stream (*ifs, type, fmin, fmax, &bifs);
00976 }
00977 xml_read_footer_from_stream (*ifs);
00978 }
00979 catch (runtime_error e)
00980 {
00981 delete ifs;
00982 ostringstream os;
00983 os << "Error reading file: " << filename << '\n'
00984 << e.what ();
00985 throw runtime_error (os.str ());
00986 }
00987
00988 delete ifs;
00989 }
00990
00991
00993
01001 template<typename T> void
01002 xml_write_to_file (const String& filename,
01003 const T& type,
01004 const FileType ftype)
01005 {
01006 ostream* ofs;
01007
01008 out2 << " Writing " << filename << '\n';
01009 if (ftype == FILE_TYPE_ZIPPED_ASCII)
01010 #ifdef ENABLE_ZLIB
01011 {
01012 ofs = new ogzstream();
01013 xml_open_output_file(*(ogzstream *)ofs, filename);
01014 }
01015 #else
01016 {
01017 throw runtime_error (
01018 "This arts version was compiled without zlib support.\n"
01019 "Thus zipped xml files cannot be written.");
01020 }
01021 #endif
01022 else
01023 {
01024 ofs = new ofstream();
01025 xml_open_output_file(*(ofstream *)ofs, filename);
01026 }
01027
01028
01029 try
01030 {
01031 xml_write_header_to_stream (*ofs, ftype);
01032 if (ftype == FILE_TYPE_ASCII || ftype == FILE_TYPE_ZIPPED_ASCII)
01033 {
01034 xml_write_to_stream (*ofs, type);
01035 }
01036 else
01037 {
01038 String bfilename = filename + ".bin";
01039 bofstream bofs (bfilename.c_str ());
01040 xml_write_to_stream (*ofs, type, &bofs);
01041 }
01042
01043 xml_write_footer_to_stream (*ofs);
01044 }
01045 catch (runtime_error e)
01046 {
01047 delete ofs;
01048 ostringstream os;
01049 os << "Error writing file: " << filename << '\n'
01050 << e.what ();
01051 throw runtime_error (os.str ());
01052 }
01053
01054 delete ofs;
01055 }
01056