/* * Copyright (c) 2017, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "cm_include.h" #include "cm_printf_host.h" #include "cm_debug.h" #include "cm_mem.h" void PFParser::getToken(void) { m_prevToken = m_currToken; m_currToken = Token(); // This is a lexer that has 2 modes // Inside a conversion specification and outside while (*m_currLoc != '\0') { if (!m_inSpec) { // We're just picking off characters until we see a % m_currToken.tokenType = Token::String; while (*m_currLoc != '\0') { if (*m_currLoc == '%') { // Peek to check for %% if (*(m_currLoc+1) != '\0' && *(m_currLoc+1) != '%') { // This is definitely a directive, not a %% break; } // This IS %% so take another character off the input m_currToken.tokenString += *m_currLoc++; } m_currToken.tokenString += *m_currLoc++; } if (*m_currLoc == '%') m_inSpec = true; if (m_currToken.tokenString.length() > 0) return; } if (m_inSpec) { char currChar = *m_currLoc++; switch(currChar) { default: // We've had an unexpected character m_currToken.tokenType = Token::Error; m_currToken.tokenString += currChar; // Preserve the error char m_inSpec = false; // End of the format spec return; case '%': m_currToken.tokenType = Token::Percent; return; case '-': m_currToken.tokenType = Token::Minus; return; case '+': m_currToken.tokenType = Token::Plus; return; case ' ': m_currToken.tokenType = Token::Space; return; case '.': m_currToken.tokenType = Token::Period; return; case '#': m_currToken.tokenType = Token::Hash; return; case '*': m_currToken.tokenType = Token::Star; return; case 'h': // Have to deal with 'hh' if (*m_currLoc == 'h') { m_currLoc++; m_currToken.tokenType = Token::hh_Mod; return; } m_currToken.tokenType = Token::h_Mod; return; case 'l': // Have to deal with 'll' if (*m_currLoc == 'l') { m_currLoc++; m_currToken.tokenType = Token::ll_Mod; return; } m_currToken.tokenType = Token::l_Mod; return; case 'j': m_currToken.tokenType = Token::j_Mod; return; case 'z': m_currToken.tokenType = Token::z_Mod; return; case 't': m_currToken.tokenType = Token::t_Mod; return; case 'L': m_currToken.tokenType = Token::L_Mod; return; case 'c': m_currToken.tokenType = Token::c_Conv; m_inSpec = false; // End of the format spec return; case 's': m_currToken.tokenType = Token::s_Conv; m_inSpec = false; // End of the format spec return; case 'd': m_currToken.tokenType = Token::d_Conv; m_inSpec = false; // End of the format spec return; case 'i': m_currToken.tokenType = Token::i_Conv; m_inSpec = false; // End of the format spec return; case 'o': m_currToken.tokenType = Token::o_Conv; m_inSpec = false; // End of the format spec return; case 'x': m_currToken.tokenType = Token::x_Conv; m_inSpec = false; // End of the format spec return; case 'X': m_currToken.tokenType = Token::X_Conv; m_inSpec = false; // End of the format spec return; case 'u': m_currToken.tokenType = Token::u_Conv; m_inSpec = false; // End of the format spec return; case 'f': m_currToken.tokenType = Token::f_Conv; m_inSpec = false; // End of the format spec return; case 'F': m_currToken.tokenType = Token::F_Conv; m_inSpec = false; // End of the format spec return; case 'e': m_currToken.tokenType = Token::e_Conv; m_inSpec = false; // End of the format spec return; case 'E': m_currToken.tokenType = Token::E_Conv; m_inSpec = false; // End of the format spec return; case 'a': m_currToken.tokenType = Token::a_Conv; m_inSpec = false; // End of the format spec return; case 'A': m_currToken.tokenType = Token::A_Conv; m_inSpec = false; // End of the format spec return; case 'g': m_currToken.tokenType = Token::g_Conv; m_inSpec = false; // End of the format spec return; case 'G': m_currToken.tokenType = Token::G_Conv; m_inSpec = false; // End of the format spec return; case 'n': m_currToken.tokenType = Token::n_Conv; m_inSpec = false; // End of the format spec return; case 'p': m_currToken.tokenType = Token::p_Conv; m_inSpec = false; // End of the format spec return; case '0': if (*m_currLoc < '1' || *m_currLoc > '9') { // Next character not part of a larger integer m_currToken.tokenType = Token::Zero; return; } // Deliberately drop through case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': m_currToken.tokenString += currChar; while (*m_currLoc >= '0' && *m_currLoc <= '9') { m_currToken.tokenString += *m_currLoc++; } // Create integer // Since we've created this integer string and we know it is simple we can use // atoi knowing that it won't throw an error m_currToken.tokenString = atoi(m_currToken.tokenString.c_str()); m_currToken.tokenType = Token::Integer; return; } } } m_currToken.tokenType = Token::End; } bool PFParser::accept(PFParser::Token::TokenType s) { if (m_currToken == s) { getToken(); return true; } return false; } bool PFParser::expect(Token::TokenType s) { if (accept(s)) return true; error(); return false; } int PFParser::format(void) { if (m_currToken == Token::_None_) { getToken(); } while(m_currToken != Token::End && m_currToken != Token::Error) { if (accept(Token::String)) { } else if (accept(Token::Percent)) { return directive(); } } return 0; } int PFParser::directive(void) { int numArgs = 0; flags(); numArgs += width(); numArgs += precision(); length_modifier(); int numConvArgs = conversion(); if (numConvArgs == 0) { // Not expecting ANY arguments // Ignore any previous directives (width, precision etc.) numArgs = 0; } else { numArgs += numConvArgs; } return numArgs; } void PFParser::flags(void) { if (accept(Token::Minus)) { } if (accept(Token::Plus)) { } if (accept(Token::Space)) { } if (accept(Token::Zero)) { } if (accept(Token::Hash)) { } } int PFParser::width(void) { if (accept(Token::Integer)) { return 0; } else if (accept(Token::Star)) { return 1; } return 0; } int PFParser::precision(void) { if (accept(Token::Period)) { if (accept(Token::Integer)) { return 0; } else if (expect(Token::Star)) { return 1; } return 0; } return 0; } void PFParser::length_modifier(void) { if (accept(Token::hh_Mod)) { } else if (accept(Token::h_Mod)) { } else if (accept(Token::l_Mod)) { } else if (accept(Token::ll_Mod)) { } else if (accept(Token::j_Mod)) { m_unsupported = true; } else if (accept(Token::t_Mod)) { m_unsupported = true; } else if (accept(Token::z_Mod)) { m_unsupported = true; } else if (accept(Token::L_Mod)) { } } int PFParser::conversion(void) { int numArgs = 1; if (accept(Token::Percent)) { numArgs = 0; } else if (accept(Token::c_Conv)) { } else if (accept(Token::s_Conv)) { } else if (accept(Token::d_Conv)) { } else if (accept(Token::i_Conv)) { } else if (accept(Token::o_Conv)) { } else if (accept(Token::x_Conv)) { } else if (accept(Token::X_Conv)) { } else if (accept(Token::u_Conv)) { } else if (accept(Token::f_Conv)) { } else if (accept(Token::F_Conv)) { } else if (accept(Token::e_Conv)) { } else if (accept(Token::E_Conv)) { } else if (accept(Token::a_Conv)) { } else if (accept(Token::A_Conv)) { } else if (accept(Token::g_Conv)) { } else if (accept(Token::G_Conv)) { } else if (accept(Token::n_Conv)) { m_unsupported = true; } else if (expect(Token::p_Conv)) { } else { // Expect must have failed numArgs = 0; } return numArgs; } int CalcSizeFromHeader(unsigned char * memory) { PCM_PRINT_HEADER header = (PCM_PRINT_HEADER)memory; if((header->objectType == CM_PRINT_OBJECT_TYPE_MATRIX) || (header->objectType == CM_PRINT_OBJECT_TYPE_VECTOR)) { switch (header->dataType) { case CM_PRINT_DATA_TYPE_CHAR: return CM_PRINT_SIZE_WITH_PAYLOAD(header->height*header->width*sizeof(char )); case CM_PRINT_DATA_TYPE_UCHAR: return CM_PRINT_SIZE_WITH_PAYLOAD(header->height*header->width*sizeof(unsigned char )); case CM_PRINT_DATA_TYPE_INT: return CM_PRINT_SIZE_WITH_PAYLOAD(header->height*header->width*sizeof(int )); case CM_PRINT_DATA_TYPE_UINT: return CM_PRINT_SIZE_WITH_PAYLOAD(header->height*header->width*sizeof(unsigned int )); case CM_PRINT_DATA_TYPE_FLOAT: return CM_PRINT_SIZE_WITH_PAYLOAD(header->height*header->width*sizeof(float )); case CM_PRINT_DATA_TYPE_SHORT: return CM_PRINT_SIZE_WITH_PAYLOAD(header->height*header->width*sizeof(short )); case CM_PRINT_DATA_TYPE_USHORT: return CM_PRINT_SIZE_WITH_PAYLOAD(header->height*header->width*sizeof(unsigned short )); case CM_PRINT_DATA_TYPE_QWORD: return CM_PRINT_SIZE_WITH_PAYLOAD(header->height*header->width*sizeof(long long )); case CM_PRINT_DATA_TYPE_UQWORD: return CM_PRINT_SIZE_WITH_PAYLOAD(header->height*header->width*sizeof(unsigned long long )); case CM_PRINT_DATA_TYPE_DOUBLE: return CM_PRINT_SIZE_WITH_PAYLOAD(header->height*header->width*sizeof(double )); default: CmAssert(0); } return PRINT_HEADER_SIZE; } else if(header->objectType == CM_PRINT_OBJECT_TYPE_STRING || header->objectType == CM_PRINT_OBJECT_TYPE_FORMAT) { return PRINT_HEADER_SIZE + PRINT_FORMAT_STRING_SIZE; } else if(header->objectType == CM_PRINT_OBJECT_TYPE_SCALAR) { if(!((header->dataType == CM_PRINT_DATA_TYPE_CHAR) || (header->dataType == CM_PRINT_DATA_TYPE_UCHAR) || (header->dataType == CM_PRINT_DATA_TYPE_UINT) || (header->dataType == CM_PRINT_DATA_TYPE_INT) || (header->dataType == CM_PRINT_DATA_TYPE_USHORT) || (header->dataType == CM_PRINT_DATA_TYPE_SHORT) || (header->dataType == CM_PRINT_DATA_TYPE_DOUBLE) || (header->dataType == CM_PRINT_DATA_TYPE_QWORD) || (header->dataType == CM_PRINT_DATA_TYPE_UQWORD) || (header->dataType == CM_PRINT_DATA_TYPE_FLOAT))) { CmAssert(0); } return PRINT_HEADER_SIZE; } else { CmAssert(0); return PRINT_HEADER_SIZE; } } void PFParser::Flush(void) { if (m_inputStart && m_currLoc) { if (m_currToken != Token::End && m_currToken != Token::_None_) { // Tidy up any remaining characters // Any characters that remain to be flushed need to be check for illegal directives (e.g. %n // will cause an exception if attempted to be printed with no argument) int numArgs = format(); if (m_unsupported) { CM_PRINTF(m_streamOut,"Unsupported (but valid C++11) format string used : %s", m_inputStart); reset(); } else if (m_error) { CM_PRINTF(m_streamOut,"Error in printf format string : %s", m_inputStart); reset(); } else if (numArgs > 0) { // Not enough arguments provided for remaining directives CM_PRINTF(m_streamOut,"Not enough (no) arguments supplied for format string : %s", m_inputStart); reset(); } else { CM_PRINTF(m_streamOut,"%s", m_inputStart); } } reset(); } } PRINT_FMT_STATUS PFParser::GetNextFmtToken(char* tkn, size_t size) { memset(tkn, 0, size); if (m_numMultArg) { if (!m_argsExpected) { // Copy the whole of the format string into the token if ((size_t)(m_currLoc - m_inputStart) <= size) { CmSafeMemCopy(tkn, m_inputStart, m_currLoc - m_inputStart); tkn[m_currLoc - m_inputStart] = '\0'; return PF_SUCCESS; } return PF_FAIL; } // Still processing input arguments return PF_SUCCESS; } int numArgs = format(); switch (numArgs) { default: return PF_FAIL; // Something has gone wrong case 0: case 1: // Copy the whole of the format string into the token if ((size_t)(m_currLoc - m_inputStart) <= size) { CmSafeMemCopy(tkn, m_inputStart, m_currLoc - m_inputStart); tkn[m_currLoc - m_inputStart] = '\0'; return PF_SUCCESS; } return PF_FAIL; case 2: case 3: m_numMultArg = numArgs - 1; m_argsExpected = numArgs - 1; return PF_SUCCESS; } } bool PFParser::outputToken(const char *tkn, PCM_PRINT_HEADER header) { if (m_numMultArg && m_argsExpected) { // Processing items for multi-arg directives if (header->objectType == CM_PRINT_OBJECT_TYPE_SCALAR && header->dataType != CM_PRINT_DATA_TYPE_FLOAT && header->dataType != CM_PRINT_DATA_TYPE_DOUBLE && header->dataType != CM_PRINT_DATA_TYPE_QWORD && header->dataType != CM_PRINT_DATA_TYPE_UQWORD) { // Received an int type argument as expected switch (header->dataType) { case CM_PRINT_DATA_TYPE_INT: { int* scalar_int = reinterpret_cast(&header->scalar64); m_args[m_numMultArg - m_argsExpected] = *scalar_int; } break; case CM_PRINT_DATA_TYPE_UINT: { unsigned int* scalar_uint = reinterpret_cast(&header->scalar64); m_args[m_numMultArg - m_argsExpected] = *scalar_uint; } break; case CM_PRINT_DATA_TYPE_CHAR: m_args[m_numMultArg - m_argsExpected] = *((char* )&(header->scalar64)); break; case CM_PRINT_DATA_TYPE_UCHAR: m_args[m_numMultArg - m_argsExpected] = *((unsigned char* )&(header->scalar64)); break; case CM_PRINT_DATA_TYPE_SHORT: { short* scalar_short = reinterpret_cast(&header->scalar64); m_args[m_numMultArg - m_argsExpected] = *scalar_short; } break; case CM_PRINT_DATA_TYPE_USHORT: { unsigned short* scalar_ushort = reinterpret_cast(&header->scalar64); m_args[m_numMultArg - m_argsExpected] = *scalar_ushort; } break; } m_argsExpected -= 1; return true; } else { // Not received the expected argument // Dump what is in the format string and attempt to recover as well as possible return false; } } // Inform the user that they've used an unsupported format string if that is the case // (e.g. %jd, %td etc.) if (m_unsupported) { CM_PRINTF(m_streamOut,"Unsupported (but valid C++11) printf format string : %s", tkn); reset(); return true; } // Inform the user that they've got an error (illegal format string) if (m_error) { CM_PRINTF(m_streamOut, "Error in printf format string : %s", tkn); reset(); return true; } // Output as appropriate if (!m_numMultArg) { switch (header->dataType) { case CM_PRINT_DATA_TYPE_INT: { int* scalar_int = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut, tkn, *scalar_int); } break; case CM_PRINT_DATA_TYPE_UINT: { unsigned int* scalar_uint = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut, tkn, *scalar_uint); } break; case CM_PRINT_DATA_TYPE_CHAR: CM_PRINTF(m_streamOut, tkn, *((char*)&(header->scalar64))); break; case CM_PRINT_DATA_TYPE_UCHAR: CM_PRINTF(m_streamOut, tkn, *((unsigned char*)&(header->scalar64))); break; case CM_PRINT_DATA_TYPE_FLOAT: { float* scalar_float = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut, tkn, *scalar_float); } break; case CM_PRINT_DATA_TYPE_SHORT: { short* scalar_short = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut, tkn, *scalar_short); } break; case CM_PRINT_DATA_TYPE_USHORT: { unsigned short* scalar_ushort = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut, tkn, *scalar_ushort); } break; case CM_PRINT_DATA_TYPE_DOUBLE: { double* scalar_double = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut, tkn, *scalar_double); } break; case CM_PRINT_DATA_TYPE_QWORD: CM_PRINTF(m_streamOut, tkn, *((long long*)&(header->scalar64))); break; case CM_PRINT_DATA_TYPE_UQWORD: CM_PRINTF(m_streamOut, tkn, *((unsigned long long*)&(header->scalar64))); break; } } else if (m_numMultArg == 1) { switch (header->dataType) { case CM_PRINT_DATA_TYPE_INT: { int* scalar_int = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], *scalar_int); } break; case CM_PRINT_DATA_TYPE_UINT: { unsigned int* scalar_uint = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], *scalar_uint); } break; case CM_PRINT_DATA_TYPE_CHAR: CM_PRINTF(m_streamOut,tkn, m_args[0], *((char* )&(header->scalar64))); break; case CM_PRINT_DATA_TYPE_UCHAR: CM_PRINTF(m_streamOut,tkn, m_args[0], *((unsigned char* )&(header->scalar64))); break; case CM_PRINT_DATA_TYPE_FLOAT: { float* scalar_float = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], *scalar_float); } break; case CM_PRINT_DATA_TYPE_SHORT: { short* scalar_short = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], *scalar_short); } break; case CM_PRINT_DATA_TYPE_USHORT: { unsigned short* scalar_ushort = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], *scalar_ushort); } break; case CM_PRINT_DATA_TYPE_DOUBLE: { double* scalar_double = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], *scalar_double); } break; case CM_PRINT_DATA_TYPE_QWORD: CM_PRINTF(m_streamOut,tkn, m_args[0], *((long long* )&(header->scalar64))); break; case CM_PRINT_DATA_TYPE_UQWORD: CM_PRINTF(m_streamOut,tkn, m_args[0], *((unsigned long long* )&(header->scalar64))); break; } } else if (m_numMultArg == 2) { switch (header->dataType) { case CM_PRINT_DATA_TYPE_INT: { int* scalar_int = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], m_args[1], *scalar_int); } break; case CM_PRINT_DATA_TYPE_UINT: { unsigned int* scalar_uint = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], m_args[1], *scalar_uint); } break; case CM_PRINT_DATA_TYPE_CHAR: CM_PRINTF(m_streamOut,tkn, m_args[0], m_args[1], *((char* )&(header->scalar64))); break; case CM_PRINT_DATA_TYPE_UCHAR: CM_PRINTF(m_streamOut,tkn, m_args[0], m_args[1], *((unsigned char* )&(header->scalar64))); break; case CM_PRINT_DATA_TYPE_FLOAT: { float* scalar_float = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], m_args[1], *scalar_float); } break; case CM_PRINT_DATA_TYPE_SHORT: { short* scalar_short = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], m_args[1], *scalar_short); } break; case CM_PRINT_DATA_TYPE_USHORT: { unsigned short* scalar_ushort = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], m_args[1], *scalar_ushort); } break; case CM_PRINT_DATA_TYPE_DOUBLE: { double* scalar_double = reinterpret_cast(&header->scalar64); CM_PRINTF(m_streamOut,tkn, m_args[0], m_args[1], *scalar_double); } break; case CM_PRINT_DATA_TYPE_QWORD: CM_PRINTF(m_streamOut,tkn, m_args[0], m_args[1], *((long long* )&(header->scalar64))); break; case CM_PRINT_DATA_TYPE_UQWORD: CM_PRINTF(m_streamOut,tkn, m_args[0], m_args[1], *((unsigned long long* )&(header->scalar64))); break; } } reset(); return true; } void PFParser::DumpMemory(unsigned char * memory) { PCM_PRINT_HEADER header = (PCM_PRINT_HEADER)memory; memory += PRINT_HEADER_SIZE; int threadid = header->tid; if(!m_numMultArg && header->objectType == CM_PRINT_OBJECT_TYPE_MATRIX ) { CM_PRINTF(m_streamOut,"\n Thread id %d, Matrix , Width %d, Height %d \n", threadid, header->width, header->height); } else if(!m_numMultArg && header->objectType == CM_PRINT_OBJECT_TYPE_VECTOR) { CM_PRINTF(m_streamOut, " \n Thread id %d, Vector , Width %d\n", threadid, header->width); } else if(!m_numMultArg && header->objectType == CM_PRINT_OBJECT_TYPE_FORMAT) { // Flush any remaining characters from existing format string (if any) Flush(); SetStart((char *)memory); } else if(!m_numMultArg && header->objectType == CM_PRINT_OBJECT_TYPE_STRING) { char tkn[PRINT_FORMAT_STRING_SIZE]; PRINT_FMT_STATUS status = GetNextFmtToken(tkn, PRINT_FORMAT_STRING_SIZE); if (status == PF_SUCCESS) { // Inform the user that they've used an unsupported format string if that is the case // (e.g. %jd, %td etc.) if (m_unsupported) { CM_PRINTF(m_streamOut, "Unsupported (but valid C++11) format string used : %s", tkn); } // Inform the user that they've got an error (illegal format string) if (m_error) { CM_PRINTF(m_streamOut, "Error in printf format string : %s", tkn); } if (m_unsupported || m_error) { reset(); return; } CM_PRINTF(m_streamOut, tkn, (char*)memory); reset(); } return; } else if(header->objectType == CM_PRINT_OBJECT_TYPE_SCALAR) { char tkn[PRINT_FORMAT_STRING_SIZE]; PRINT_FMT_STATUS status = GetNextFmtToken(tkn, PRINT_FORMAT_STRING_SIZE); if (status == PF_SUCCESS) { if (!outputToken(tkn, header)) { // Something has gone wrong // Reset multi-arg at least CM_PRINTF(m_streamOut, "Problem outputting with format string %s\n", tkn); m_numMultArg = m_argsExpected = 0; } } return; } else { if (m_numMultArg) { // Something has gone wrong in multi-arg so reset CM_PRINTF(m_streamOut, "Error in multi-arg directive\n"); m_numMultArg = 0; m_argsExpected = 0; } else { CM_PRINTF(m_streamOut, "Unknown TYPE\n"); } return; } } void DumpAllThreadOutput(FILE *streamOut, unsigned char * dumpMem, size_t buffersize) { unsigned int offsetFromHeader = 0; unsigned int off = PRINT_BUFFER_HEADER_SIZE; PFParser pState(streamOut); while(1) { if((off + PRINT_HEADER_SIZE) >= buffersize) break; if(off >= (*(unsigned int *)dumpMem)) break; offsetFromHeader = CalcSizeFromHeader(dumpMem + off); if( (off + offsetFromHeader) >= buffersize ) break; pState.DumpMemory(dumpMem + off); off += offsetFromHeader; } // Flush any remaining characters in the format buffer pState.Flush(); }