00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "Message_AMOS.hh"
00011 #include <cstdio>
00012 using namespace AMOS;
00013 using namespace std;
00014 using namespace HASHMAP;
00015
00016 #define FIELD_SEPARATOR ':'
00017 #define FIELD_TERMINATOR '.'
00018
00019
00020
00021
00022
00023
00024 inline bool skipto (istream & in, char ch)
00025 {
00026 static const int chunk = 1024;
00027
00028 while ( true )
00029 {
00030 in . ignore (chunk, ch);
00031
00032 if ( !in . good( ) )
00033 return false;
00034 if ( in . gcount( ) != chunk )
00035 return true;
00036
00037 in . unget( );
00038 }
00039 }
00040
00041
00042
00043 bool Message_t::read (istream & in)
00044 {
00045 int i;
00046 char ch;
00047 string data;
00048 string chunk;
00049 string name (NCODE_SIZE, NULL_CHAR);
00050
00051
00052 if ( !skipto (in, '{') )
00053 return NULL_NCODE;
00054
00055
00056 clear( );
00057
00058 try {
00059
00060
00061 for ( i = 0; i < NCODE_SIZE; i ++ )
00062 name [i] = in . get( );
00063 if ( in . get( ) != NL_CHAR )
00064 AMOS_THROW_IO ("Could not parse message NCode: " + name);
00065 setMessageCode (name);
00066
00067
00068 while ( true )
00069 {
00070
00071 ch = in . peek( );
00072
00073
00074 if ( ch == EOF )
00075 AMOS_THROW_IO ("Unbalanced message nesting");
00076
00077 else if ( ch == '{' )
00078 {
00079 subs_m . push_back (Message_t ( ));
00080 subs_m . back( ) . read (in);
00081 continue;
00082 }
00083
00084 else if ( ch == '}' )
00085 {
00086 skipto (in, NL_CHAR);
00087 break;
00088 }
00089
00090 else if ( ch == NL_CHAR )
00091 {
00092 in . get( );
00093 continue;
00094 }
00095
00096
00097 for ( i = 0; i < NCODE_SIZE; i ++ )
00098 name [i] = in . get( );
00099 if ( in . get( ) != FIELD_SEPARATOR )
00100 AMOS_THROW_IO ("Could not parse field code in '" +
00101 Decode (mcode_m) + "' message");
00102
00103
00104 getline (in, data);
00105 if ( !in . good( ) )
00106 AMOS_THROW_IO ("Could not parse single-line field data in '" +
00107 Decode (mcode_m) + "' message");
00108
00109
00110 if ( data . empty( ) )
00111 {
00112 getline (in, data, FIELD_TERMINATOR);
00113
00114
00115 while ( in . peek( ) != NL_CHAR ||
00116 (!data . empty( ) && *(data . rbegin( )) != NL_CHAR) )
00117 {
00118 if ( !in . good( ) )
00119 AMOS_THROW_IO ("Unterminated multi-line field in '" +
00120 Decode (mcode_m) + "' message");
00121
00122 data . push_back (FIELD_TERMINATOR);
00123 getline (in, chunk, FIELD_TERMINATOR);
00124 data . append (chunk);
00125 }
00126 in . get( );
00127
00128 if ( !in . good( ) )
00129 AMOS_THROW_IO ("Could not parse multi-line field data in '" +
00130 Decode (mcode_m) + "' message");
00131 }
00132
00133
00134 setField (name, data);
00135 }
00136 }
00137 catch (Exception_t) {
00138
00139
00140 clear( );
00141 throw;
00142 }
00143
00144 return true;
00145 }
00146
00147
00148
00149 void Message_t::setField (NCode_t fcode, const string & data)
00150 {
00151 if ( data . empty( ) )
00152 return;
00153
00154
00155 string::size_type nlpos = data . rfind (NL_CHAR);
00156 if ( nlpos != string::npos && nlpos != data . size( ) - 1 )
00157 AMOS_THROW_ARGUMENT ("Invalid multi-line message field format");
00158
00159
00160 fields_m [fcode] = data;
00161 }
00162
00163
00164
00165 NCode_t Message_t::skip (istream & in)
00166 {
00167 int i;
00168 char ch;
00169 string name (NCODE_SIZE, NULL_CHAR);
00170
00171
00172 if ( !skipto (in, '{') )
00173 return NULL_NCODE;
00174
00175
00176 for ( i = 0; i < NCODE_SIZE; i ++ )
00177 name [i] = in . get( );
00178 if ( in . get( ) != NL_CHAR )
00179 AMOS_THROW_IO ("Could not parse message header: " + name);
00180
00181
00182 i = 1;
00183 while ( i != 0 )
00184 {
00185
00186 ch = in . get( );
00187 if ( !in . good( ) )
00188 AMOS_THROW_IO ("Unbalanced message nesting");
00189
00190
00191 if ( ch == '{' )
00192 i ++;
00193 else if ( ch == '}' )
00194 i --;
00195
00196
00197 if ( ch != NL_CHAR )
00198 skipto (in, NL_CHAR);
00199 }
00200
00201 return Encode (name);
00202 }
00203
00204
00205
00206 void Message_t::write (ostream & out) const
00207 {
00208 bool mline = false;
00209
00210
00211 out << '{' << Decode (mcode_m) << endl;
00212
00213
00214 hash_map<NCode_t,string>::const_iterator mi;
00215 for ( mi = fields_m . begin( ); mi != fields_m . end( ); mi ++ )
00216 {
00217
00218 mline = *(mi -> second . rbegin( )) == NL_CHAR ? true : false;
00219
00220 out << Decode (mi -> first) << FIELD_SEPARATOR;
00221 if ( mline )
00222 out . put (NL_CHAR);
00223 out << mi -> second;
00224 if ( mline )
00225 out . put (FIELD_TERMINATOR);
00226 out . put (NL_CHAR);
00227 }
00228
00229
00230 vector<Message_t>::const_iterator vi;
00231 for ( vi = subs_m . begin( ); vi != subs_m . end( ); vi ++ )
00232 vi -> write (out);
00233
00234
00235 out << '}' << endl;
00236
00237
00238 if ( !out . good( ) )
00239 AMOS_THROW_IO ("Message write failure");
00240 }