Skip to content

Commit f3ee04a

Browse files
committed
Add hack to support N42 messages embedded with another XML message from a specific RSI system.
1 parent e6e6093 commit f3ee04a

File tree

2 files changed

+117
-4
lines changed

2 files changed

+117
-4
lines changed

SpecUtils/SpecFile.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,8 +500,16 @@ bool is_candidate_n42_file( const char * const data, const char * const data_end
500500
@TODO move this function, and similar ones to a N42 utils header/source
501501
*/
502502
char *convert_n42_utf16_xml_to_utf8( char * data, char * const data_end );
503-
504-
503+
504+
/** Function converts XML files that look like
505+
`<MessageEnvelope... <n42:RadInstrumentData>...</n42:RadInstrumentData></MessageEnvelope>`
506+
to
507+
`<RadInstrumentData>...<RadInstrumentData>`
508+
So they can be parsed as N42 files.
509+
*/
510+
bool rsi_portal_xml_to_n42_hack( char* &data, char* &data_end );
511+
512+
505513
/** @TODO move this function, and similar ones to a N42 utils header/source
506514
507515
*/

src/SpecFile_n42.cpp

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4714,7 +4714,111 @@ namespace SpecUtils
47144714

47154715
return new_data_end;
47164716
}//convert_n42_utf16_xml_to_utf8
4717-
4717+
4718+
4719+
bool rsi_portal_xml_to_n42_hack( char* &data, char* &data_end )
4720+
{
4721+
assert( data <= data_end );
4722+
if( data_end < data )
4723+
throw logic_error( "Invalid start-end of data" ); //shouldnt ever happen
4724+
4725+
const size_t orig_len = (data_end - data);
4726+
if( orig_len < 1024 )
4727+
return false;
4728+
4729+
// If '<MessageEnvelope' is not found within the first 512 characters, then return false
4730+
// if '<n42:RadInstrumentData>' is not found within the first 8192 characters, return false.
4731+
// Go through and replace all instances of "<n42:" with " <"
4732+
// Go through and replace all instances of "</n42:" with " </"
4733+
// Make `data` point at the first instance of "<RadInstrumentData>"
4734+
// Make `data_end` point one position past the first following "</RadInstrumentData>"
4735+
4736+
// Define string literals
4737+
const char message_envelope[] = "<MessageEnvelope";
4738+
const size_t message_envelope_len = (sizeof(message_envelope) / sizeof(message_envelope[0])) - 1;
4739+
4740+
const char rad_instrument_data[] = "<n42:RadInstrumentData>";
4741+
const size_t rad_instrument_data_len = (sizeof(rad_instrument_data) / sizeof(rad_instrument_data[0])) - 1;
4742+
4743+
const char rad_instrument_data_start[] = "<RadInstrumentData>";
4744+
const size_t rad_instrument_data_start_len = (sizeof(rad_instrument_data_start) / sizeof(rad_instrument_data_start[0])) - 1;
4745+
4746+
const char rad_instrument_data_end[] = "</RadInstrumentData>";
4747+
const size_t rad_instrument_data_end_len = (sizeof(rad_instrument_data_end) / sizeof(rad_instrument_data_end[0])) - 1;
4748+
4749+
const char n42_open[] = "<n42:";
4750+
const size_t n42_open_len = (sizeof(n42_open) / sizeof(n42_open[0])) - 1;
4751+
const char n42_close[] = "</n42:";
4752+
const size_t n42_close_len = (sizeof(n42_close) / sizeof(n42_close[0])) - 1;
4753+
const char replacement_open[] = " <";
4754+
const size_t replacement_open_len = (sizeof(replacement_open) / sizeof(replacement_open[0])) - 1;
4755+
const char replacement_close[] = " </";
4756+
const size_t replacement_close_len = (sizeof(replacement_close) / sizeof(replacement_close[0])) - 1;
4757+
4758+
static_assert( sizeof(n42_open) == sizeof(replacement_open), "Mismatch on n42 open str len" );
4759+
static_assert( sizeof(n42_close) == sizeof(replacement_close), "Mismatch on n42 open str len" );
4760+
4761+
// Check for '<MessageEnvelope' within the first 512 characters
4762+
const size_t envelope_search_len = std::min(size_t(512), orig_len);
4763+
char * const message_envelope_pos = std::search( data, data + envelope_search_len,
4764+
message_envelope, message_envelope + message_envelope_len);
4765+
if( message_envelope_pos == (data + envelope_search_len) )
4766+
return false;
4767+
4768+
// Check for '<n42:RadInstrumentData>' within the first 8192 characters
4769+
const size_t rad_instrument_search_len = std::min(size_t(8192), orig_len);
4770+
char *rad_instrument_pos = std::search(data, data + rad_instrument_search_len,
4771+
rad_instrument_data, rad_instrument_data + rad_instrument_data_len);
4772+
if( rad_instrument_pos == (data + rad_instrument_search_len) )
4773+
return false;
4774+
4775+
// If we are here, we are probably in the target rsi portal file
4776+
4777+
// Replace all instances of "<n42:" with " <"
4778+
char *pos = data;
4779+
while( pos < (data_end - n42_open_len) )
4780+
{
4781+
pos = std::search(pos, data_end, n42_open, n42_open + n42_open_len);
4782+
if( pos == data_end )
4783+
break; // No more occurrences
4784+
std::memcpy(pos, replacement_open, replacement_open_len);
4785+
pos += n42_open_len; // Move past the replaced substring
4786+
}
4787+
4788+
4789+
// Replace all instances of "</n42:" with " <"
4790+
pos = data;
4791+
while( pos < (data_end - n42_close_len) )
4792+
{
4793+
pos = std::search(pos, data_end, n42_close, n42_close + n42_close_len);
4794+
if( pos == data_end )
4795+
break; // No more occurrences
4796+
std::memcpy(pos, replacement_close, replacement_close_len);
4797+
pos += n42_close_len; // Move past the replaced substring
4798+
}
4799+
4800+
// Make `data` point at the first instance of "<RadInstrumentData>"
4801+
char *rad_data_start = std::search(data, data_end,
4802+
rad_instrument_data_start, rad_instrument_data_start + rad_instrument_data_start_len);
4803+
assert( rad_data_start < data_end );
4804+
4805+
if( rad_data_start == data_end )
4806+
return false; // "<RadInstrumentData>" not found
4807+
4808+
data = rad_data_start;
4809+
4810+
// Make `data_end` point one position past the first following "</RadInstrumentData>"
4811+
char *rad_data_end = std::search(rad_data_start, data_end,
4812+
rad_instrument_data_end, rad_instrument_data_end + rad_instrument_data_end_len);
4813+
if( rad_data_end == data_end )
4814+
return false; // "</RadInstrumentData>" not found
4815+
4816+
data_end = rad_data_end + rad_instrument_data_end_len;
4817+
4818+
return true;
4819+
}//bool rsi_portal_xml_to_n42_hack( char* &data, char* &data_end )
4820+
4821+
47184822
bool SpecFile::load_from_N42( std::istream &input )
47194823
{
47204824
std::unique_lock<std::recursive_mutex> scoped_lock( mutex_ );
@@ -8867,10 +8971,11 @@ namespace SpecUtils
88678971
reset();
88688972

88698973
data_end = convert_n42_utf16_xml_to_utf8( data, data_end );
8974+
rsi_portal_xml_to_n42_hack( data, data_end );
88708975

88718976
// Some times a bunch of null characters can get appended to the end
88728977
// of the file - lets remove them, or rapidxml::parse will fail.
8873-
// TODO: bet yet, we should look for the last '>' character, or even better, the last valid closing tag
8978+
// TODO: better yet, we should look for the last '>' character, or even better, the last valid closing tag
88748979
while( ((data_end - data) > 2) && ((*(data_end - 1)) == '\0') )
88758980
--data_end;
88768981

0 commit comments

Comments
 (0)