// base/io-funcs.cc // Copyright 2009-2011 Microsoft Corporation; Saarland University // See ../../COPYING for clarification regarding multiple authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, // MERCHANTABLITY OR NON-INFRINGEMENT. // See the Apache 2 License for the specific language governing permissions and // limitations under the License. #include "base/io-funcs.h" #include "base/kaldi-math.h" namespace kaldi { template<> void WriteBasicType(std::ostream &os, bool binary, bool b) { os << (b ? "T":"F"); if (!binary) os << " "; if (os.fail()) KALDI_ERR << "Write failure in WriteBasicType"; } template<> void ReadBasicType(std::istream &is, bool binary, bool *b) { KALDI_PARANOID_ASSERT(b != NULL); if (!binary) is >> std::ws; // eat up whitespace. char c = is.peek(); if (c == 'T') { *b = true; is.get(); } else if (c == 'F') { *b = false; is.get(); } else { KALDI_ERR << "Read failure in ReadBasicType, file position is " << is.tellg() << ", next char is " << CharToString(c); } } template<> void WriteBasicType(std::ostream &os, bool binary, float f) { if (binary) { char c = sizeof(f); os.put(c); os.write(reinterpret_cast(&f), sizeof(f)); } else { os << f << " "; } } template<> void WriteBasicType(std::ostream &os, bool binary, double f) { if (binary) { char c = sizeof(f); os.put(c); os.write(reinterpret_cast(&f), sizeof(f)); } else { os << f << " "; } } template<> void ReadBasicType(std::istream &is, bool binary, float *f) { KALDI_PARANOID_ASSERT(f != NULL); if (binary) { double d; int c = is.peek(); if (c == sizeof(*f)) { is.get(); is.read(reinterpret_cast(f), sizeof(*f)); } else if (c == sizeof(d)) { ReadBasicType(is, binary, &d); *f = d; } else { KALDI_ERR << "ReadBasicType: expected float, saw " << is.peek() << ", at file position " << is.tellg(); } } else { is >> *f; } if (is.fail()) { KALDI_ERR << "ReadBasicType: failed to read, at file position " << is.tellg(); } } template<> void ReadBasicType(std::istream &is, bool binary, double *d) { KALDI_PARANOID_ASSERT(d != NULL); if (binary) { float f; int c = is.peek(); if (c == sizeof(*d)) { is.get(); is.read(reinterpret_cast(d), sizeof(*d)); } else if (c == sizeof(f)) { ReadBasicType(is, binary, &f); *d = f; } else { KALDI_ERR << "ReadBasicType: expected float, saw " << is.peek() << ", at file position " << is.tellg(); } } else { is >> *d; } if (is.fail()) { KALDI_ERR << "ReadBasicType: failed to read, at file position " << is.tellg(); } } void CheckToken(const char *token) { if (*token == '\0') KALDI_ERR << "Token is empty (not a valid token)"; const char *orig_token = token; while (*token != '\0') { if (::isspace(*token)) KALDI_ERR << "Token is not a valid token (contains space): '" << orig_token << "'"; token++; } } void WriteToken(std::ostream &os, bool binary, const char *token) { // binary mode is ignored; // we use space as termination character in either case. KALDI_ASSERT(token != NULL); CheckToken(token); // make sure it's valid (can be read back) os << token << " "; if (os.fail()) { KALDI_ERR << "Write failure in WriteToken."; } } int Peek(std::istream &is, bool binary) { if (!binary) is >> std::ws; // eat up whitespace. return is.peek(); } void WriteToken(std::ostream &os, bool binary, const std::string & token) { WriteToken(os, binary, token.c_str()); } void ReadToken(std::istream &is, bool binary, std::string *str) { KALDI_ASSERT(str != NULL); if (!binary) is >> std::ws; // consume whitespace. is >> *str; if (is.fail()) { KALDI_ERR << "ReadToken, failed to read token at file position " << is.tellg(); } if (!isspace(is.peek())) { KALDI_ERR << "ReadToken, expected space after token, saw instead " << CharToString(static_cast(is.peek())) << ", at file position " << is.tellg(); } is.get(); // consume the space. } int PeekToken(std::istream &is, bool binary) { if (!binary) is >> std::ws; // consume whitespace. bool read_bracket; if (static_cast(is.peek()) == '<') { read_bracket = true; is.get(); } else { read_bracket = false; } int ans = is.peek(); if (read_bracket) { if (!is.unget()) { // Clear the bad bit. This code can be (and is in fact) reached, since the // C++ standard does not guarantee that a call to unget() must succeed. is.clear(); } } return ans; } void ExpectToken(std::istream &is, bool binary, const char *token) { int pos_at_start = is.tellg(); KALDI_ASSERT(token != NULL); CheckToken(token); // make sure it's valid (can be read back) if (!binary) is >> std::ws; // consume whitespace. std::string str; is >> str; is.get(); // consume the space. if (is.fail()) { KALDI_ERR << "Failed to read token [started at file position " << pos_at_start << "], expected " << token; } // The second half of the '&&' expression below is so that if we're expecting // "", we will accept "Foo>" instead. This is so that the model-reading // code will tolerate errors in PeekToken where is.unget() failed; search for // is.clear() in PeekToken() for an explanation. if (strcmp(str.c_str(), token) != 0 && !(token[0] == '<' && strcmp(str.c_str(), token + 1) == 0)) { KALDI_ERR << "Expected token \"" << token << "\", got instead \"" << str <<"\"."; } } void ExpectToken(std::istream &is, bool binary, const std::string &token) { ExpectToken(is, binary, token.c_str()); } } // end namespace kaldi