aboutsummaryrefslogtreecommitdiff
path: root/printer/src
diff options
context:
space:
mode:
Diffstat (limited to 'printer/src')
-rw-r--r--printer/src/mipi_syst_collateral.cpp331
-rw-r--r--printer/src/mipi_syst_decode.cpp874
-rw-r--r--printer/src/mipi_syst_main.cpp265
-rw-r--r--printer/src/mipi_syst_message.cpp371
-rw-r--r--printer/src/mipi_syst_printf.cpp435
5 files changed, 2276 insertions, 0 deletions
diff --git a/printer/src/mipi_syst_collateral.cpp b/printer/src/mipi_syst_collateral.cpp
new file mode 100644
index 0000000..a421808
--- /dev/null
+++ b/printer/src/mipi_syst_collateral.cpp
@@ -0,0 +1,331 @@
+/*
+ Copyright (c) 2018, MIPI Alliance, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Contributors:
+ * Norbert Schulz (Intel Corporation) - Initial API and implementation
+ */
+
+#include <iomanip>
+#include <sstream>
+#include <iostream>
+#include <type_traits>
+
+#include "mipi_syst_collateral.h"
+#include "mipi_syst_guid.h"
+
+MIPI_SYST_NAMESPACE_BEGIN
+
+const char tagCollateral[] = "syst:Collateral";
+const char tagClient[] = "syst:Client";
+const char tagGuids[] = "syst:Guids";
+const char tagGuid[] = "syst:Guid";
+const char tagBuilds[] = "syst:Builds";
+const char tagBuild[] = "syst:Build";
+const char tagCatalog32[] = "syst:Catalog32";
+const char tagCatalog64[] = "syst:Catalog64";
+const char tagSourceFiles[] = "syst:SourceFiles";
+const char tagFile[] = "syst:File";
+const char tagShort32[] = "syst:Short32";
+const char tagShort64[] = "syst:Short64";
+const char tagWrite[] = "syst:Write";
+const char tagProtocol[] = "syst:Protocol";
+const char tagModules[] = "syst:Modules";
+const char tagModule[] = "syst:Module";
+const char tagID[] = "ID";
+const char tagMask[] = "Mask";
+const char tagFileAttr[] = "File";
+const char tagLine[] = "Line";
+const char tagFormat[] = "syst:Format";
+
+
+std::vector<collateral*> collateral::parseXml(const std::string& filename)
+{
+ pugi::xml_document doc;
+ pugi::xml_parse_result scan_result(doc.load_file(filename.c_str()));
+ std::stringstream sstr;
+
+ if (!scan_result) {
+ sstr
+ << "XML parser error on file "
+ << filename
+ << " : "
+ << scan_result.description();
+
+ throw std::invalid_argument(sstr.str());
+ }
+
+ std::vector<collateral*> result;
+
+ for(auto client(doc.child(tagCollateral).child(tagClient));
+ client;
+ client = client.next_sibling(tagClient))
+ {
+ result.push_back(new collateral(client, filename));
+ }
+ return result;
+}
+
+
+collateral::collateral(pugi::xml_node& node, const std::string& file) :
+ m_file(file),
+ m_name(node.attribute("Name").as_string())
+{
+ // Scan id <-> item mappings
+ //
+ parseMaskedItems(node.child(tagGuids), tagGuid, m_guids);
+ parseMaskedItems(node.child(tagBuilds), tagBuild, m_builds);
+ parseMaskedItems(node.child(tagSourceFiles), tagFile, m_files);
+ parseMaskedItems(node.child(tagModules), tagModule, m_modules);
+ parseMaskedItems(node.child(tagCatalog32), tagFormat, m_msgs32);
+ parseMaskedItems(node.child(tagCatalog64), tagFormat, m_msgs64);
+ parseMaskedItems(node.child(tagShort32), tagFormat, m_shorts32);
+ parseMaskedItems(node.child(tagShort64), tagFormat, m_shorts64);
+ parseMaskedItems(node.child(tagWrite), tagProtocol, m_writeTypes);
+}
+
+bool collateral::match(const guid& g, uint64_t build) const
+{
+ for (auto& it : m_guids) {
+ if ((g & it.mask()) == (it.key() & it.mask()))
+ {
+ if (build != 0x0) {
+ // find collateral with matching build number
+ //
+ if (m_builds.find(build) != m_builds.end())
+ {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+template<> const collateral::catalogentry<uint32_t> * collateral::getCatalogEntry<>(uint32_t id) const
+{
+ auto hit = m_msgs32.find(id);
+ return (hit != m_msgs32.end()) ? &hit->value() : nullptr;
+}
+
+template<> const collateral::catalogentry<uint64_t> * collateral::getCatalogEntry<>(uint64_t id) const
+{
+ auto hit = m_msgs64.find(id);
+ return (hit != m_msgs64.end()) ? &hit->value() : nullptr;
+}
+const std::string * collateral::getSourceFile(uint32_t id) const
+{
+ auto hit = m_files.find(id);
+ return (hit != m_files.end()) ? &hit->value() : nullptr;
+}
+
+const std::string * collateral::getWriteType(uint8_t id) const
+{
+ auto hit(m_writeTypes.find(id));
+ return (hit != m_writeTypes.end()) ? &hit->value() : nullptr;
+}
+
+template<> const collateral::catalogentry<uint32_t> * collateral::getShortEntry<>(uint32_t id) const
+{
+ auto hit(m_shorts32.find(id));
+ return (hit != m_shorts32.end()) ? &hit->value() : nullptr;
+}
+template<> const collateral::catalogentry<uint64_t> * collateral::getShortEntry<>(uint64_t id) const
+{
+ auto hit(m_shorts64.find(id));
+ return (hit != m_shorts64.end()) ? &hit->value() : nullptr;
+}
+
+template<typename K> bool parse(K& dest, const std::string& s)
+{
+ return stringToNum<K>(s, dest);
+}
+
+template<> bool parse<guid>(guid& g, const std::string& s)
+{
+ return g.parse(s);
+}
+
+template<typename K> K nomask() { return (K)-1; }
+template<> guid nomask<guid>() { return guid("{ffffffff-ffff-ffff-ffff-ffffffffffff}"); }
+
+template<typename T> std::ostream & operator<<(std::ostream &os, const collateral::catalogentry<T>& p)
+{
+ return os << p.msg;
+}
+
+template<typename K, typename V>
+void collateral::parseMaskedItems(
+ pugi::xml_node root, const char * tag, masked_vector<K, V>& dest)
+{
+ for (pugi::xml_node item(root.child(tag));
+ item;
+ item = item.next_sibling(tag))
+ {
+ masked_item<K, V> data;
+
+ std::string keyStr(item.attribute(tagID).as_string());
+ std::string val(item.child_value());
+
+ if (!parse<K>(data.key(), keyStr)) {
+ std::stringstream what;
+ what <<
+ "Malformed " << tag << "entry ID=\"" << keyStr <<
+ "\" value =\"" << val << "\"" <<
+ " for catalog " << m_name;
+ throw std::invalid_argument(what.str());
+ }
+
+ std::string maskStr(item.attribute(tagMask).as_string());
+ if (!maskStr.empty()) {
+ if (!parse<K>(data.mask(), maskStr)) {
+ std::stringstream what;
+ what <<
+ "Malformed " << tag << "entry Mask=\"" << maskStr <<
+ "\" value =\"" << val << "\"" <<
+ " for catalog " << m_name;
+ throw std::invalid_argument(what.str());
+ }
+ } else {
+ data.mask() = nomask<K>();
+ }
+
+ data.value() = val;
+
+ // scan option file/line data if value supports source positions
+ //
+ if (std::is_base_of<catalogentry<K>, V>::value) {
+ catalogentry<K> * entry((catalogentry<K>*)&data.value());
+ entry->mask = data.mask();
+
+ std::string file(item.attribute(tagFileAttr).as_string());
+ std::string line(item.attribute(tagLine).as_string());
+
+ if (!file.empty()) {
+ if (!parse(entry->m_file, file)) {
+ std::stringstream what;
+ what <<
+ "Malformed File attribute " << file <<
+ "in section " << tag <<
+ " for catalog " << m_name;
+ throw std::invalid_argument(what.str());
+ }
+ }
+
+ if (!line.empty()) {
+ if (!parse(entry->m_line, line)) {
+ std::stringstream what;
+ what <<
+ "Malformed Line attribute " << line <<
+ "in section " << tag <<
+ " for catalog " << m_name;
+ throw std::invalid_argument(what.str());
+ }
+ }
+ }
+
+ auto it = dest.find(data.key());
+ if (it != dest.end() && it->value() != val) {
+ std::cerr <<
+ "Overwriting ID" << data.key() << " -> " << val <<
+ " old value: " << it->value() << std::endl;
+ *it = data;
+ }
+ else {
+ dest.push_back(data);
+ }
+ }
+}
+
+/** Helper to parse a GUID "{...}" string into the binary representation.
+* @param str GUID ascii string "{xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
+* @param guid resulting guid
+* @return true if guid could be parserd
+*/
+bool guid::parse(const std::string& str)
+{
+ if (
+ (str.length() != sizeof("{00000000-0000-0000-0000-000000000000}")-1) ||
+ str[0]!= '{' ||str[37] != '}' ||
+ str[9] != '-' || str[14] != '-' || str[19] != '-' || str[24] != '-'
+ )
+ {
+ return false;
+ }
+
+ // parse the byte values;
+ //
+ const char * p(str.c_str()+1);
+
+ for (int i(0); i < 16; ++i, p += 2) {
+ if (i == 4 || i == 6|| i == 8 || i == 10) {
+ p++; // skip "-"
+ }
+ std::stringstream sstr(std::string(p, 2));
+ uint16_t temp;
+
+ if (! (sstr >> std::hex >>temp)) {
+ return false;
+ }
+ u.b[i] = (uint8_t)(temp);
+ }
+
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const guid& g)
+{
+ auto flags(os.flags());
+
+
+ os << '{';
+
+ for (int i(0); i < 16; ++i) {
+ os << std::setfill('0') << std::noshowbase << std::hex << std::setw(2)
+ << (uint16_t)g.u.b[i];
+
+ if (i == 3 || i == 5|| i == 7 || i == 9) {
+ os << '-';
+ }
+ }
+
+ os << '}';
+
+ os.flags(flags);
+ return os;
+}
+
+MIPI_SYST_NAMESPACE_END \ No newline at end of file
diff --git a/printer/src/mipi_syst_decode.cpp b/printer/src/mipi_syst_decode.cpp
new file mode 100644
index 0000000..1c9b1d8
--- /dev/null
+++ b/printer/src/mipi_syst_decode.cpp
@@ -0,0 +1,874 @@
+/*
+ Copyright (c) 2018, MIPI Alliance, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Contributors:
+ * Norbert Schulz (Intel Corporation) - Initial API and implementation
+ */
+#include<sstream>
+#include <iomanip>
+
+#include "mipi_syst_decode.h"
+#include "mipi_syst_printf.h"
+
+MIPI_SYST_NAMESPACE_BEGIN
+
+/// Helper to extract string from byte array,
+//
+// @param dest where to write bytes to
+// @param offset where to start from
+// @param data byte array
+// @param len number of bytes in array
+//
+// @return bytes consumed or < 0 if no null byte found
+//
+static int32_t bytes2String(std::string& dest, const uint8_t * data, uint32_t len)
+{
+ uint32_t i(0);
+
+ while(i <len)
+ {
+ if (!data[i]) {
+ break; // null byte found
+ }
+ dest += data[i++];
+ }
+
+ if (i == len && data[i - 1]) {
+ return -1;
+ }
+
+ return (uint32_t)dest.size();
+}
+
+// Helper for printf formating
+//
+static std::string printfFormat(
+ const std::string& fmt,
+ bool is32Bit,
+ const void * data,
+ uint32_t len)
+{
+ msgprintf printer(is32Bit);
+ std::string result;
+ if (len > 0) {
+ printer.format(fmt, data, len, result);
+ }
+ else {
+ printer.format(fmt, NULL, 0, result);
+ }
+ return result;
+}
+
+void decoder::setBuildNumber(uint64_t id, const guid& g) const
+{
+ // cache guid <-> id association
+ // TODO: A production quality implementation should add a sanity check here
+ // and issue a warning if the ID changes compared to an earlier one.
+ //
+ if (build_by_guid.find(g) != build_by_guid.end()) {
+ build_by_guid[g] = id;
+ }
+
+ // Remove an eventually earlier cached collateral to guid mapping. We recompute
+ // next time with the now known build id.
+ //
+ auto cache_hit(collateral_by_guid.find(g));
+ if (cache_hit != collateral_by_guid.end()) {
+ collateral_by_guid.erase(cache_hit);
+ }
+}
+
+
+// Decode single SyS-T message
+//
+bool decoder::decode(message& dest, const std::vector<uint8_t>& data, const decode_context * ctx) const
+{
+ bool rt(false);
+
+ try {
+ // header
+ //
+ if (data.size() < sizeof(uint32_t)) throw tooshort_exception();
+ message::header hdr(bytes2ValLE<uint32_t>(&data[0]));
+
+ // short message ?
+ //
+ if (message::isShort(hdr)) {
+ rt = decodeShortMessage(dest, &data[0], (uint32_t)data.size(), ctx);
+ } else {
+ rt = decodeNormalMessage(dest, &data[0], (uint32_t)data.size(), ctx);
+ }
+
+ if (rt && dest.getHeader().field.type == message::BUILD) {
+ // found build message, store build number for later
+ //
+ setBuildNumber(dest.getBuild(), dest.getGuid());
+ }
+ } catch (decode_exception& de) {
+ dest.setStatus(de.get_state());
+
+ // decode failed, show raw byte dump as payload
+ //
+ std::stringstream sstr;
+ sstr << std::hex << std::uppercase << std::setfill('0') << std::setw(2);
+ for (auto uc : data) {
+ sstr << (uint16_t)uc;
+ }
+ dest.setPayload(sstr.str());
+ }
+ return rt;
+}
+
+
+template<class T> void decodeShortPayload(message & m, T v)
+{
+ const collateral * coll(m.getCollateral());
+ const collateral::catalogentry<T> * entry(
+ coll ? coll->getShortEntry(v) : nullptr);
+
+ if (entry) {
+ std::stringstream dest;
+ hostPrintf(dest, entry->msg, v & (~entry->mask), std::vector<int>());
+ m.setPayload(dest.str());
+ } else {
+ m.setPayload(toHexValue(v));
+ }
+}
+
+bool decoder::decodeShortMessage(
+ message& dest,
+ const uint8_t *data, uint32_t length,
+ const decode_context * ctx) const
+{
+ if (length < sizeof(uint32_t)) throw tooshort_exception();
+
+ uint32_t type(data[0] & 0x0F); // Bit 0..3 = type
+ uint32_t subtype(data[3] & 0x3F); // Bit 24..29 = subtype
+
+ dest.setHeader(0); // all optional fields off
+ dest.setType(type);
+ dest.setLength(length);
+ dest.setCollateral(ctx ? findCollateral(ctx->getGuid()) : nullptr);
+ dest.setContextTS(ctx ? ctx->getTS() : 0);
+
+ switch (type) {
+ case message::type::SHORT32:
+ decodeShortPayload(dest, bytes2ValLE<uint32_t>(data) >> 4);
+ break;
+
+ case message::type::SHORT64:
+ if (length < sizeof(uint64_t)) throw tooshort_exception();
+ decodeShortPayload(dest, bytes2ValLE<uint64_t>(data) >> 4);
+ break;
+
+ case message::type::BUILD:
+ dest.setSubType(subtype);
+ switch (subtype) {
+ case message::subtype_build::BUILD_COMPACT32:
+ {
+ uint32_t val(bytes2ValLE<uint32_t>(data));
+ val = ((val & 0x00FFFFF0) >> 4) | ((val & 0x30000000) >> 10);
+ dest.setBuild(val);
+ dest.setPayload(toHexValue(val));
+ break;
+ }
+ case message::subtype_build::BUILD_COMPACT64:
+ {
+ if (length < sizeof(uint64_t)) throw tooshort_exception();
+
+ uint64_t val(bytes2ValLE<uint64_t>(data));
+ val = ((val & 0x0000000000FFFFF0ull) >> 4) |
+ ((val & 0xFFFFFFFF30000000ull) >> 10);
+ dest.setBuild(val);
+ dest.setPayload(toHexValue(val));
+
+ break;
+ }
+ default:
+ throw unknown_type_exception();
+ }
+ break;
+ default:
+ throw unknown_type_exception();
+ }
+
+ dest.setStatus(message::decode_state::OK);
+
+ return true;
+}
+
+// Decode "normal" SyS-T message data
+//
+bool decoder::decodeNormalMessage(message& dest, const uint8_t * data, uint32_t length, const decode_context * ctx) const
+{
+ uint32_t offset(0);
+
+ dest.setContextTS(ctx ? ctx->getTS() : 0);
+ dest.setLength(length);
+
+ // header
+ //
+ if (length < (offset + sizeof(uint32_t))) throw tooshort_exception();
+ dest.setHeader(bytes2ValLE<uint32_t>(data+offset));
+ offset += sizeof(uint32_t);
+
+ // checksum at the end ?
+ //
+ if (dest.getHeader().field.chksum) {
+ if (length < offset + sizeof(uint32_t)) throw tooshort_exception();
+ length -= sizeof(uint32_t);
+ dest.setCrc(bytes2ValLE<uint32_t>(data+length));
+ }
+
+ // guid
+ //
+ if (dest.getHeader().field.guid) {
+ if (length < (offset + sizeof(uint64_t[2]))) throw tooshort_exception();
+
+ dest.setGuid(guid(data+offset));
+ offset += sizeof(uint64_t[2]);
+ } else {
+ dest.setGuid(generatePseudoGuid(dest.getHeaderOrigin()));
+ }
+
+ // location
+ //
+ if (dest.getHeader().field.location) {
+ if (length < offset + sizeof(uint8_t)) throw tooshort_exception();
+ uint32_t tag(data[offset++]);
+ if (tag & 0x1) {
+ // 64 bit
+ if (length < offset + sizeof(uint64_t)) throw tooshort_exception();
+ if (tag & 0x2) { // addr
+ uint64_t addr(bytes2ValLE<uint64_t>(data+offset));
+ dest.setLocAddr64(addr);
+ } else {
+ uint32_t file(bytes2ValLE<uint32_t>(data + offset));
+ uint32_t line(bytes2ValLE<uint32_t>(data + offset + 4));
+ dest.setLocFileLine(file, line);
+ }
+ offset += sizeof(uint64_t);
+ } else {
+ // 32 bit
+ if (length < offset + sizeof(uint32_t)) throw tooshort_exception();
+ if (tag & 0x2) { // addr
+ uint32_t addr(bytes2ValLE<uint32_t>(data + offset));
+ dest.setLocAddr32(addr);
+ } else {
+ uint16_t file(bytes2ValLE<uint16_t>(data + offset));
+ uint16_t line(bytes2ValLE<uint16_t>(data + offset + 2));
+ dest.setLocFileLine(file, line);
+ }
+ offset += sizeof(uint32_t);
+ }
+ }
+
+ // length
+ //
+ uint32_t payload_len(length - offset);
+
+ if (dest.getHeader().field.length) {
+ if (length < offset + sizeof(uint16_t)) throw tooshort_exception();
+ payload_len = bytes2ValLE<uint16_t>(data + offset);
+ offset += sizeof(uint16_t);
+ }
+
+ // timestamp
+ //
+ if (dest.getHeader().field.timestamp) {
+ if (length < offset + sizeof(uint64_t)) throw tooshort_exception();
+ dest.setMessageTS(bytes2ValLE<uint64_t>(data + offset));
+ offset += sizeof(uint64_t);
+ }
+
+ if (dest.getHeader().field.length) {
+ // length given, compare with remaining payload length
+ //
+ int diff(length - offset - payload_len);
+ if (diff < 0) {
+ throw tooshort_exception();
+ } else if (diff > 0) {
+ throw toolong_exception();
+ }
+ }
+
+ // check CRC32 if set
+ //
+ if (dest.getHeader().field.chksum) {
+ uint32_t crc = getCrc32(data, length);
+ if (crc != dest.getCrc()) {
+ throw crc_error_exception();
+ }
+ }
+
+ // Check for collateral information
+ //
+ const collateral* coll = findCollateral(dest.getGuid());
+ dest.setCollateral(coll);
+
+ // Set client name based on collateral (or use raw guid/origin from message)
+ //
+ if (coll != nullptr) {
+ dest.setClientName(coll->getName());
+ }
+ else {
+ std::stringstream sstr;
+ if (dest.getHeader().field.guid) {
+ sstr << dest.getGuid();
+ } else {
+ sstr << dest.getHeaderOrigin();
+ }
+ dest.setClientName(sstr.str());
+ }
+
+ // Payload decode depening on type
+ //
+ (this->*payloadDecode[dest.getHeader().field.type])(dest, data+offset, length - offset);
+
+ dest.setStatus(message::decode_state::OK);
+ return true;
+}
+
+void decoder::decodeInvalidType(message& dest, const uint8_t * data, uint32_t len) const
+{
+ (void)dest;
+ (void)data;
+ (void)len;
+
+ throw unknown_type_exception();
+}
+
+void decoder::decodeBuildPayload(message& dest, const uint8_t * data, uint32_t len) const
+{
+ std::stringstream sstr;
+
+ switch (dest.getHeader().field.subtype) {
+ case message::subtype_build::BUILD_LONG:
+ if (len < sizeof(uint64_t)) throw tooshort_exception();
+
+ dest.setBuild(bytes2ValLE<uint64_t>(data));
+ sstr << toHexValue(dest.getBuild());
+
+ data += sizeof(uint64_t);
+ len -= sizeof(uint64_t);
+
+ if (0 != len) { // string follows ....
+ std::string payload;
+ if (bytes2String(payload, data, len) > 0) {
+ sstr << " " << payload;
+ } else {
+ throw tooshort_exception();
+ }
+ }
+ break;
+ default:
+ throw unknown_type_exception();
+ break;
+ }
+
+ dest.setPayload(sstr.str());
+}
+
+void decoder::decodeStringPayload(message& dest, const uint8_t * data, uint32_t len) const
+{
+ std::string format;
+ int fmtlen;
+
+ if (!len || (fmtlen = bytes2String(format, data, len)) <= 0) {
+ throw tooshort_exception();
+ }
+
+ std::stringstream sstr;
+
+ switch (dest.getHeader().field.subtype) {
+ case message::subtype_string::STRING_PRINTF_32:
+ case message::subtype_string::STRING_PRINTF_64:
+ sstr << printfFormat(
+ format,
+ dest.getHeader().field.subtype ==
+ message::subtype_string::STRING_PRINTF_32,
+ &data[fmtlen+1],
+ len - fmtlen - 1);
+ break;
+
+ case message::subtype_string::STRING_ASSERT:
+ case message::subtype_string::STRING_FUNCTIONENTER:
+ case message::subtype_string::STRING_FUNCTIONEXIT:
+ case message::subtype_string::STRING_GENERIC:
+ case message::subtype_string::STRING_INVALIDPARAM:
+ sstr << format;
+ break;
+ default:
+ throw unknown_type_exception();
+ break;
+ }
+
+ dest.setPayload(sstr.str());
+}
+
+void decoder::decodeCatalogPayload(message& dest, const uint8_t * data, uint32_t len) const
+{
+ const collateral * coll(dest.getCollateral());
+ if (coll == nullptr) throw missing_collateral_exception();
+
+ std::stringstream sstr;
+ bool is32Bit(false);
+ const collateral::sourcepos * srcpos(nullptr);
+ const std::string * fmt(nullptr);
+
+ switch (dest.getHeader().field.subtype) {
+ case message::subtype_catalog::CATALOG_ID32_P32:
+ is32Bit = true;
+ // fall through
+
+ case message::subtype_catalog::CATALOG_ID32_P64:
+ {
+ if (len < sizeof(uint32_t)) throw tooshort_exception();
+ const collateral::catalogentry<uint32_t> * entry(nullptr);
+
+ if ((entry = coll->getCatalogEntry(bytes2ValLE<uint32_t>(data))) == nullptr) {
+ sstr
+ << "Undefined catalog id 0x"
+ << toHexValue(bytes2ValLE<uint32_t>(data));
+ } else {
+ fmt = &entry->msg;
+ srcpos = entry;
+ }
+ data += sizeof(uint32_t);
+ len -= sizeof(uint32_t);
+ break;
+ }
+ case message::subtype_catalog::CATALOG_ID64_P32:
+ is32Bit = true;
+ // fall through
+ case message::subtype_catalog::CATALOG_ID64_P64:
+ {
+ if (len < sizeof(uint64_t)) throw tooshort_exception();
+ const collateral::catalogentry<uint64_t> * entry(nullptr);
+
+ if ((entry = coll->getCatalogEntry(bytes2ValLE<uint64_t>(data))) == nullptr) {
+ sstr
+ << "Undefined catalog id 0x"
+ << toHexValue(bytes2ValLE<uint64_t>(data));
+ } else {
+ fmt = &entry->msg;
+ srcpos = entry;
+ }
+ data += sizeof(uint64_t);
+ len -= sizeof(uint64_t);
+ break;
+ }
+ default:
+ throw unknown_type_exception();
+ break;
+ }
+
+ if (fmt != nullptr) {
+ sstr << printfFormat(*fmt, is32Bit, data, len);
+
+ // if current message has no file attribute from payload, but the catalog entry
+ // does provides one, use the one from the catalog
+ //
+ if (0 != srcpos->m_file && 0 == (dest.getLocation().tag & message::IDANDLINE))
+ {
+ dest.setLocFileLine(srcpos->m_file, srcpos->m_line);
+ }
+ }
+
+ dest.setPayload(sstr.str());
+}
+
+void decoder::decodeRawPayload(message& dest, const uint8_t * data, uint32_t len) const
+{
+ std::stringstream sstr;
+
+ while (len--) {
+ sstr << std::setfill('0') << std::setw(2) << std::hex << (uint16_t)*data++;
+ }
+
+ dest.setPayload(sstr.str());
+}
+
+void decoder::loadCollateral(const std::string& filename)
+{
+ for (auto items : collateral::parseXml(filename)) {
+ collaterals.insert(collaterals.end(), items);
+ }
+}
+
+guid decoder::generatePseudoGuid(uint8_t origin)
+{
+ // A pseudo-guid is defined by storing the origin value into
+ // bits [7..0] of the guid[8] byte. The highest bit is forced
+ // to zero, which distiquishes it from an RFC4122 compliant
+ // GUID.
+ // This example code has no additional transport data for
+ // identifying the message client. All other values are
+ // set to 0.
+ //
+ uint8_t pseudo_guid_data[16] = {
+ 0,0,0,0,
+ 0,0,0,origin,
+ 0,0,0,0,
+ 0,0,0,0
+ };
+ return guid(pseudo_guid_data);
+}
+
+collateral * decoder::findCollateral(const guid& g) const
+{
+ // do we already know the catalog for this GUID ?
+ //
+ auto cache_hit(collateral_by_guid.find(g));
+ if (cache_hit != collateral_by_guid.end()) {
+ return cache_hit->second;
+ }
+
+ uint64_t build(0);
+ auto build_hit(build_by_guid.find(g));
+ if (build_hit != build_by_guid.end()) {
+ build = build_hit->second;
+ }
+
+ // search all catalogs
+ //
+ auto match = std::find_if(collaterals.begin(), collaterals.end(),
+ [&g,build](const collateral* v)
+ {
+ return (v->match(g, build));
+ });
+
+ if (match != collaterals.end()) {
+ collateral_by_guid[g] = *match;
+ return *match;
+ }
+ return nullptr;
+}
+
+// Message type dependend payload decode handlers
+//
+decoder::decode_payload_f decoder::payloadDecode[] = {
+ &decoder::decodeBuildPayload, // [0]
+ &decoder::decodeInvalidType, // [1]
+ &decoder::decodeStringPayload, // [2]
+ &decoder::decodeCatalogPayload, // [3]
+ &decoder::decodeInvalidType, // [4]
+ &decoder::decodeInvalidType, // [5]
+ &decoder::decodeRawPayload, // [6]
+ &decoder::decodeInvalidType, // [7]
+ &decoder::decodeInvalidType, // [8]
+ &decoder::decodeInvalidType, // [9]
+ &decoder::decodeInvalidType, // [10]
+ &decoder::decodeInvalidType, // [11]
+ &decoder::decodeInvalidType, // [12]
+ &decoder::decodeInvalidType, // [13]
+ &decoder::decodeInvalidType, // [14]
+ &decoder::decodeInvalidType // [15]
+};
+
+// Build CRC over a byte buffer (Castagnoli CRC-32C)
+//
+uint32_t decoder::getCrc32(const uint8_t * data, size_t len)
+{
+ uint32_t crc(0xFFFFFFFF);
+
+ while (len--) {
+ crc = crc32c_table[((int)crc ^ (*data++)) & 0xFF] ^ (crc >> 8);
+ }
+ return crc ^ 0xFFFFFFFF;
+}
+
+// Pre-computed CRC-C values for all byte values using the
+// polynomial 0x1EDC6F41 (Castagnoli).
+//
+const uint32_t decoder::crc32c_table[256] = {
+ 0x00000000,
+ 0xF26B8303,
+ 0xE13B70F7,
+ 0x1350F3F4,
+ 0xC79A971F,
+ 0x35F1141C,
+ 0x26A1E7E8,
+ 0xD4CA64EB,
+ 0x8AD958CF,
+ 0x78B2DBCC,
+ 0x6BE22838,
+ 0x9989AB3B,
+ 0x4D43CFD0,
+ 0xBF284CD3,
+ 0xAC78BF27,
+ 0x5E133C24,
+ 0x105EC76F,
+ 0xE235446C,
+ 0xF165B798,
+ 0x030E349B,
+ 0xD7C45070,
+ 0x25AFD373,
+ 0x36FF2087,
+ 0xC494A384,
+ 0x9A879FA0,
+ 0x68EC1CA3,
+ 0x7BBCEF57,
+ 0x89D76C54,
+ 0x5D1D08BF,
+ 0xAF768BBC,
+ 0xBC267848,
+ 0x4E4DFB4B,
+ 0x20BD8EDE,
+ 0xD2D60DDD,
+ 0xC186FE29,
+ 0x33ED7D2A,
+ 0xE72719C1,
+ 0x154C9AC2,
+ 0x061C6936,
+ 0xF477EA35,
+ 0xAA64D611,
+ 0x580F5512,
+ 0x4B5FA6E6,
+ 0xB93425E5,
+ 0x6DFE410E,
+ 0x9F95C20D,
+ 0x8CC531F9,
+ 0x7EAEB2FA,
+ 0x30E349B1,
+ 0xC288CAB2,
+ 0xD1D83946,
+ 0x23B3BA45,
+ 0xF779DEAE,
+ 0x05125DAD,
+ 0x1642AE59,
+ 0xE4292D5A,
+ 0xBA3A117E,
+ 0x4851927D,
+ 0x5B016189,
+ 0xA96AE28A,
+ 0x7DA08661,
+ 0x8FCB0562,
+ 0x9C9BF696,
+ 0x6EF07595,
+ 0x417B1DBC,
+ 0xB3109EBF,
+ 0xA0406D4B,
+ 0x522BEE48,
+ 0x86E18AA3,
+ 0x748A09A0,
+ 0x67DAFA54,
+ 0x95B17957,
+ 0xCBA24573,
+ 0x39C9C670,
+ 0x2A993584,
+ 0xD8F2B687,
+ 0x0C38D26C,
+ 0xFE53516F,
+ 0xED03A29B,
+ 0x1F682198,
+ 0x5125DAD3,
+ 0xA34E59D0,
+ 0xB01EAA24,
+ 0x42752927,
+ 0x96BF4DCC,
+ 0x64D4CECF,
+ 0x77843D3B,
+ 0x85EFBE38,
+ 0xDBFC821C,
+ 0x2997011F,
+ 0x3AC7F2EB,
+ 0xC8AC71E8,
+ 0x1C661503,
+ 0xEE0D9600,
+ 0xFD5D65F4,
+ 0x0F36E6F7,
+ 0x61C69362,
+ 0x93AD1061,
+ 0x80FDE395,
+ 0x72966096,
+ 0xA65C047D,
+ 0x5437877E,
+ 0x4767748A,
+ 0xB50CF789,
+ 0xEB1FCBAD,
+ 0x197448AE,
+ 0x0A24BB5A,
+ 0xF84F3859,
+ 0x2C855CB2,
+ 0xDEEEDFB1,
+ 0xCDBE2C45,
+ 0x3FD5AF46,
+ 0x7198540D,
+ 0x83F3D70E,
+ 0x90A324FA,
+ 0x62C8A7F9,
+ 0xB602C312,
+ 0x44694011,
+ 0x5739B3E5,
+ 0xA55230E6,
+ 0xFB410CC2,
+ 0x092A8FC1,
+ 0x1A7A7C35,
+ 0xE811FF36,
+ 0x3CDB9BDD,
+ 0xCEB018DE,
+ 0xDDE0EB2A,
+ 0x2F8B6829,
+ 0x82F63B78,
+ 0x709DB87B,
+ 0x63CD4B8F,
+ 0x91A6C88C,
+ 0x456CAC67,
+ 0xB7072F64,
+ 0xA457DC90,
+ 0x563C5F93,
+ 0x082F63B7,
+ 0xFA44E0B4,
+ 0xE9141340,
+ 0x1B7F9043,
+ 0xCFB5F4A8,
+ 0x3DDE77AB,
+ 0x2E8E845F,
+ 0xDCE5075C,
+ 0x92A8FC17,
+ 0x60C37F14,
+ 0x73938CE0,
+ 0x81F80FE3,
+ 0x55326B08,
+ 0xA759E80B,
+ 0xB4091BFF,
+ 0x466298FC,
+ 0x1871A4D8,
+ 0xEA1A27DB,
+ 0xF94AD42F,
+ 0x0B21572C,
+ 0xDFEB33C7,
+ 0x2D80B0C4,
+ 0x3ED04330,
+ 0xCCBBC033,
+ 0xA24BB5A6,
+ 0x502036A5,
+ 0x4370C551,
+ 0xB11B4652,
+ 0x65D122B9,
+ 0x97BAA1BA,
+ 0x84EA524E,
+ 0x7681D14D,
+ 0x2892ED69,
+ 0xDAF96E6A,
+ 0xC9A99D9E,
+ 0x3BC21E9D,
+ 0xEF087A76,
+ 0x1D63F975,
+ 0x0E330A81,
+ 0xFC588982,
+ 0xB21572C9,
+ 0x407EF1CA,
+ 0x532E023E,
+ 0xA145813D,
+ 0x758FE5D6,
+ 0x87E466D5,
+ 0x94B49521,
+ 0x66DF1622,
+ 0x38CC2A06,
+ 0xCAA7A905,
+ 0xD9F75AF1,
+ 0x2B9CD9F2,
+ 0xFF56BD19,
+ 0x0D3D3E1A,
+ 0x1E6DCDEE,
+ 0xEC064EED,
+ 0xC38D26C4,
+ 0x31E6A5C7,
+ 0x22B65633,
+ 0xD0DDD530,
+ 0x0417B1DB,
+ 0xF67C32D8,
+ 0xE52CC12C,
+ 0x1747422F,
+ 0x49547E0B,
+ 0xBB3FFD08,
+ 0xA86F0EFC,
+ 0x5A048DFF,
+ 0x8ECEE914,
+ 0x7CA56A17,
+ 0x6FF599E3,
+ 0x9D9E1AE0,
+ 0xD3D3E1AB,
+ 0x21B862A8,
+ 0x32E8915C,
+ 0xC083125F,
+ 0x144976B4,
+ 0xE622F5B7,
+ 0xF5720643,
+ 0x07198540,
+ 0x590AB964,
+ 0xAB613A67,
+ 0xB831C993,
+ 0x4A5A4A90,
+ 0x9E902E7B,
+ 0x6CFBAD78,
+ 0x7FAB5E8C,
+ 0x8DC0DD8F,
+ 0xE330A81A,
+ 0x115B2B19,
+ 0x020BD8ED,
+ 0xF0605BEE,
+ 0x24AA3F05,
+ 0xD6C1BC06,
+ 0xC5914FF2,
+ 0x37FACCF1,
+ 0x69E9F0D5,
+ 0x9B8273D6,
+ 0x88D28022,
+ 0x7AB90321,
+ 0xAE7367CA,
+ 0x5C18E4C9,
+ 0x4F48173D,
+ 0xBD23943E,
+ 0xF36E6F75,
+ 0x0105EC76,
+ 0x12551F82,
+ 0xE03E9C81,
+ 0x34F4F86A,
+ 0xC69F7B69,
+ 0xD5CF889D,
+ 0x27A40B9E,
+ 0x79B737BA,
+ 0x8BDCB4B9,
+ 0x988C474D,
+ 0x6AE7C44E,
+ 0xBE2DA0A5,
+ 0x4C4623A6,
+ 0x5F16D052,
+ 0xAD7D5351
+};
+
+MIPI_SYST_NAMESPACE_END \ No newline at end of file
diff --git a/printer/src/mipi_syst_main.cpp b/printer/src/mipi_syst_main.cpp
new file mode 100644
index 0000000..32f6aeb
--- /dev/null
+++ b/printer/src/mipi_syst_main.cpp
@@ -0,0 +1,265 @@
+/*
+ Copyright (c) 2018, MIPI Alliance, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Contributors:
+ * Norbert Schulz (Intel Corporation) - Initial API and implementation
+ */
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string>
+#include <memory>
+
+#include "mipi_syst_decode.h"
+#include "mipi_syst_guid.h"
+
+// print program usage banner
+//
+static void usage(const std::string& details)
+{
+ std::cerr << "usage: systprint [-p] [-c <collateralXML>...] [-g short-message-guid] [-o output] [inputfile(s)...]" << std::endl;
+ std::cerr << " -p / --payload_only only print payload (default is CSV)" << std::endl;
+ std::cerr << " -c / --colateral filename load given SyS-T collateral XML" << std::endl;
+ std::cerr << " -g / --short_guid guid guid value for short messages" << std::endl;
+ std::cerr << " -o / --output file output file name (default stdout)" << std::endl;
+ std::cerr << " inputfile(s)... file(s) with example library platform output or '-' for stdin" << std::endl;
+ std::cerr << std::endl;
+
+ if (!details.empty()) {
+ std::cerr << details << std::endl;
+ }
+ exit(1);
+}
+
+
+// ASCII char -> HEX nibble value, or 0xFF if invalid
+//
+static const uint8_t hexCharVal[] =
+{
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+
+// Convert ASCII hex string into byte array, fail if string is not a
+// sequence of 0..(2*n) hex characters
+//
+static bool hex2bin(const std::string& hexStr, std::vector<uint8_t>& dest)
+{
+ size_t nibbles(hexStr.size());
+
+ if (nibbles % 2) { // 2 chars needed for 1 value
+ return false;
+ }
+ dest.clear();
+
+ for(auto hexChar(hexStr.c_str()); nibbles ; nibbles -= 2)
+ {
+ auto high(hexCharVal[(uint8_t)*hexChar++]);
+ auto low(hexCharVal[(uint8_t)*hexChar++]);
+ if (high == 0xFF || low == 0xFF) {
+ return false;
+ }
+ dest.push_back((high << 4) | low);
+ }
+ return true;
+}
+
+
+// Scan input file that is assumed to come from the SyS-T library example platform.
+// Extract the raw event HEX data lines that look like this
+//
+// SYS-T RAW DATA: 4202000B0...
+//
+// Then parse the hex portion of the line and try to decode it as a SyS-T message.
+//
+static void readAndPrint(std::istream& is, std::ostream& os,
+ bool payload_only,
+ const mipi::syst::decode_context * ctx,
+ const mipi::syst::decoder& decoder)
+{
+ static const std::string pattern("SYS-T RAW DATA: ");
+ std::string line;
+
+ while (getline(is, line)) {
+ if (line.compare(0, pattern.size(), pattern)) {
+ continue; // not a raw dump of a SyS-T message
+ }
+
+ // sanitize line endings
+ //
+ while (line.size() &&
+ (line[line.size()-1] == '\r' ||
+ line[line.size()-1] == '\n'))
+ {
+ line.erase(line.size()-1);
+ }
+ std::vector<uint8_t> bytes;
+ if (!hex2bin(line.substr(pattern.size()), bytes)) {
+ continue;
+ }
+ mipi::syst::message msg;
+
+ decoder.decode(msg, bytes, ctx);
+ if (payload_only) {
+ os << msg.getPayload() << std::endl;
+ } else {
+ os << msg;
+ }
+ }
+}
+
+/// Simple GUID context wrapper
+//
+// This class implements a trivial decode context provider by just
+// wrapping a guid set from the command line. A real implementation would
+// encapsulate transport information here to build client identifying
+// information. @see mipi::syst::decode_context
+//
+class short_guid_context : public mipi::syst::decode_context {
+public:
+ short_guid_context(const mipi::syst::guid& g) : m_guid(g), m_fakeTS(0) {}
+
+ const mipi::syst::guid& getGuid() const {
+ return m_guid;
+ }
+
+ uint64_t getTS() const {
+ return m_fakeTS++; // replace with transport TS
+ }
+private:
+ mipi::syst::guid m_guid;
+ mutable uint64_t m_fakeTS;
+};
+
+
+int main(int argc, char ** argv)
+{
+ std::vector<std::string> inputs;
+ std::string output;
+ bool payload_only(false);
+ std::shared_ptr<short_guid_context> short_ctx(nullptr); // guid to use for short messages
+
+ mipi::syst::decoder decoder;
+
+ // parse & check arguments
+ //
+ for (auto i = 1; i < argc; ++i) {
+ const std::string arg(argv[i]);
+ if (arg == "-c" || arg == "--collateral") {
+ if (++i >= argc) {
+ usage("missing collateral file argument");
+ }
+ try {
+ decoder.loadCollateral(argv[i]);
+ }
+ catch (std::exception& e) {
+ std::cerr << "error loading '" << argv[i] << "': " << e.what();
+ exit(1);
+ }
+ } else if (arg == "-p" || arg == "--payload_only") {
+ payload_only = true;
+ } else if (arg == "-g" || arg == "--short_guid") {
+ if (++i >= argc) {
+ usage("missing guid argument for -g/--short_guid option");
+ }
+ try {
+ short_ctx = std::make_shared<short_guid_context>(
+ mipi::syst::guid(argv[i]));
+ } catch (std::exception& e) {
+ std::cerr << e.what();
+ exit(1);
+ }
+ } else if (arg == "-o" || arg == "--output") {
+ if (++i >= argc) {
+ usage("missing filename argument for -o/--output option");
+ }
+ output = argv[i];
+ } else if (arg == "-") { //stdin
+ inputs.push_back(arg);
+ } else if (arg[0] == '-') {
+ usage(std::string("unknown argument : ") + arg);
+ } else {
+ inputs.push_back(arg);
+ }
+ }
+
+ if (inputs.empty()) {
+ usage("no input provided");
+ }
+
+ // set output destination (default stdout)
+ //
+ std::ostream * os(&std::cout);
+ std::ofstream ofs;
+
+ if (!output.empty()) {
+ ofs.open(output.c_str(), std::ofstream::out);
+ if (!ofs.is_open()) {
+ std::cerr << "unable to open output file : " << output << std::endl;
+ exit(1);
+ }
+ os = &ofs;
+ }
+
+ if (!payload_only) {
+ *os << mipi::syst::message::csvHeaderString << std::endl;
+ }
+ for (auto input : inputs) {
+ if (input == "-") {
+ readAndPrint(std::cin, *os, payload_only, short_ctx.get(), decoder);
+ } else {
+ std::ifstream ifs(input);
+ if (!ifs.is_open()) {
+ std::cerr << "unable to open input file : " << input << std::endl;
+ exit(1);
+ }
+ readAndPrint(ifs, *os, payload_only, short_ctx.get(), decoder);
+ ifs.close();
+ }
+ }
+
+ if (ofs.is_open()) {
+ ofs.close();
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/printer/src/mipi_syst_message.cpp b/printer/src/mipi_syst_message.cpp
new file mode 100644
index 0000000..f67c2b6
--- /dev/null
+++ b/printer/src/mipi_syst_message.cpp
@@ -0,0 +1,371 @@
+/*
+ Copyright (c) 2018, MIPI Alliance, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Contributors:
+ * Norbert Schulz (Intel Corporation) - Initial API and implementation
+ */
+
+#include<sstream>
+#include <iomanip>
+#include "mipi_syst_message.h"
+#include "mipi_syst_collateral.h"
+#include "mipi_syst_printf.h"
+
+MIPI_SYST_NAMESPACE_BEGIN
+
+// Code for storing and printing out decoded message content
+//
+
+void message::setLocAddr32(uint32_t addr)
+{
+ m_loc.tag |= location_type::ADDRESS32;
+ m_loc.tag &= ~location_type::ADDRESS64;
+ m_loc.address = addr;
+}
+
+void message::setLocAddr64(uint64_t addr)
+{
+ m_loc.tag |= location_type::ADDRESS64;
+ m_loc.tag &= ~location_type::ADDRESS32;
+ m_loc.address = addr;
+}
+
+void message::setLocFileLine(uint32_t file, uint32_t line)
+{
+ m_loc.tag |= location_type::IDANDLINE;
+ m_loc.file = file;
+ m_loc.line = line;
+}
+
+// Check type for short message
+//
+bool message::isShort(message::header hdr) {
+ switch (hdr.field.type) {
+ case message::type::SHORT32:
+ case message::type::SHORT64:
+ return true;
+
+ case message::type::BUILD:
+ switch (hdr.field.subtype) {
+ case message::subtype_build::BUILD_COMPACT32:
+ case message::subtype_build::BUILD_COMPACT64:
+ return true;
+ }
+ }
+ return false;
+}
+
+
+// Pretty print decode status value
+//
+static const char * status2string(const message& msg)
+{
+ switch (msg.getState()) {
+ case message::decode_state::OK:
+ return "OK";
+ case message::decode_state::UNKNOWN_TYPE:
+ return "UNKNOWN_TYPE";
+ case message::decode_state::TOO_SHORT:
+ return "TOO_SHORT";
+ case message::decode_state::CHECKSUM_ERROR:
+ return "CHECKSUM_ERROR";
+ case message::decode_state::MISSING_COLLATERAL:
+ return "MISSING_COLLATERAL";
+ default:
+ return "UNKNOWN_STATE";
+ }
+}
+
+// Pretty print sevrity values
+//
+static const char * severity2string[] = {
+ "MAX",
+ "FATAL",
+ "ERROR",
+ "WARNING",
+ "INFO",
+ "USER1",
+ "USER2",
+ "DEBUG"
+};
+
+// Pretty print type:subtype values
+//
+static const std::string type2string(
+ message::header hdr,
+ const collateral * coll)
+{
+ static const char * typenames[] = {
+ "BUILD",
+ "SHORT32",
+ "STRING",
+ "CATALOG",
+ "UNKNOWN(4)",
+ "UNKNOWN(5)",
+ "RAW",
+ "SHORT64",
+ "CLOCK",
+ "UNKNOWN(9)",
+ "UNKNOWN(10)",
+ "UNKNOWN(11)",
+ "UNKNOWN(12)",
+ "UNKNOWN(13)",
+ "UNKNOWN(14)",
+ "UNKNOWN(15)",
+ };
+
+ uint32_t type(hdr.field.type);
+ std::stringstream sstr;
+
+ sstr << typenames[type];
+
+ // compute subtype string
+ //
+ std::string subtype("??");
+
+ switch (type) {
+ case message::type::SHORT32:
+ case message::type::SHORT64:
+ subtype.clear(); // no subtype
+ break;
+
+ case message::type::BUILD:
+ switch (hdr.field.subtype) {
+ case message::subtype_build::BUILD_LONG:
+ subtype = "LONG";
+ break;
+ case message::subtype_build::BUILD_COMPACT32:
+ subtype = "COMPACT32";
+ break;
+ case message::subtype_build::BUILD_COMPACT64:
+ subtype = "COMPACT64";
+ break;
+ }
+ break;
+ case message::type::STRING:
+ switch (hdr.field.subtype) {
+ case message::subtype_string::STRING_GENERIC:
+ subtype = "GENERIC";
+ break;
+ case message::subtype_string::STRING_FUNCTIONENTER:
+ subtype = "ENTER";
+ break;
+ case message::subtype_string::STRING_FUNCTIONEXIT:
+ subtype = "EXIT";
+ break;
+ case message::subtype_string::STRING_INVALIDPARAM:
+ subtype = "INVPARAM";
+ break;
+ case message::subtype_string::STRING_ASSERT:
+ subtype = "ASSERT";
+ break;
+ case message::subtype_string::STRING_PRINTF_32:
+ subtype = "PRINTF32";
+ break;
+ case message::subtype_string::STRING_PRINTF_64:
+ subtype = "PRINTF64";
+ break;
+ }
+ break;
+ case message::type::CATALOG:
+ switch (hdr.field.subtype) {
+ case message::subtype_catalog::CATALOG_ID32_P32:
+ subtype = "ID32P32";
+ break;
+ case message::subtype_catalog::CATALOG_ID64_P32:
+ subtype = "ID64P32";
+ break;
+ case message::subtype_catalog::CATALOG_ID32_P64:
+ subtype = "ID32P64";
+ break;
+ case message::subtype_catalog::CATALOG_ID64_P64:
+ subtype = "ID64P64";
+ break;
+ }
+ break;
+ case message::type::RAW:
+ {
+ const std::string * name(nullptr);
+ if (coll && (name = coll->getWriteType(hdr.field.subtype)) != nullptr)
+ {
+ std::stringstream dest;
+ hostPrintf(dest, *name, hdr.field.subtype, std::vector<int>());
+ subtype = dest.str();
+ } else {
+ subtype = std::to_string(hdr.field.subtype);
+ }
+ } break;
+
+ case message::type::CLOCK:
+ switch (hdr.field.subtype) {
+ case message::subtype_clock::CLOCK_SYNC:
+ subtype = "SYNC";
+ break;
+ }
+ break;
+ }
+
+ if (!subtype.empty()) {
+ sstr << ':' << subtype;
+ }
+
+ return sstr.str();
+}
+
+// CSV double-quote escaping, replace " with "" and eliminate newlines
+//
+void csvQuoteString(std::ostream& os, const std::string& s)
+{
+ for (auto c : s) {
+ if (c == '\n') {
+ os << ' '; // newline not supported in CSV
+ } else if (c == '"') {
+ os << c << c;
+ } else {
+ os << c;
+ }
+ }
+}
+
+// location information printing
+//
+std::string location2string(
+ const message::location& loc,
+ const collateral * collateral)
+{
+ bool hasAddress(0!=(loc.tag & (message::ADDRESS32 | message::ADDRESS32)));
+ bool hasFileLine(0 != (loc.tag & message::IDANDLINE));
+
+ std::stringstream sstr;
+
+ if (hasFileLine) {
+ const std::string * fileName(
+ collateral != nullptr ?
+ collateral->getSourceFile(loc.file) : nullptr);
+
+ if (fileName != nullptr) {
+ sstr << (*fileName) << ':' << loc.line;
+ } else {
+ sstr << loc.file << ':' << loc.line;
+ }
+ if (hasAddress) sstr << ' ';
+ }
+
+ if (hasAddress) {
+ if (loc.tag & message::ADDRESS32) {
+ sstr << toHexValue((uint32_t)loc.address);
+ } else {
+ sstr << toHexValue(loc.address);
+ }
+ }
+
+ return sstr.str();
+}
+const char message::csvHeaderString[] = "Decode Status,Payload,Type,Severity,Origin,Unit,Message TimeStamp,Context TimeStamp,Location,Raw Length,Checksum,Collateral";
+
+// CSV line formatting of a message
+//
+std::ostream& operator << (std::ostream& os, const message& msg)
+{
+ char delimiter(',');
+ const collateral * coll(msg.getCollateral());
+
+ // turn volatile fields like timestamp/crc off when running unit testing
+ //
+ static bool unit_testing(getenv("SYST_UNITTESTING") != NULL);
+
+ // status
+ os << status2string(msg) << delimiter;
+
+ // payload
+ os << '"';
+ csvQuoteString(os, msg.getPayload());
+ os << '"' << delimiter;
+
+ if (msg.getState() != message::OK && msg.getState() != message::MISSING_COLLATERAL)
+ {
+ // decode failed, report other fields as empty. The data can't be trusted.
+ //
+ os << ",,,,," << std::endl;
+ return os;
+ }
+
+ // Type/Subtype
+ //
+ os << type2string(msg.getHeader(), msg.getCollateral()) << delimiter;
+
+ // Severity
+ //
+ os << severity2string[msg.getHeader().field.severity] << delimiter;
+
+ // client name and unit
+ //
+ os << msg.getClientName() << delimiter;
+ os << msg.getUnit() << delimiter;
+
+ // time stamps
+ if (msg.getHeader().field.timestamp) {
+ os << (unit_testing ?
+ "<--UNITTEST-HIDE_TS-->" : toHexValue(msg.getMessageTS()));
+ }
+ os << delimiter;
+
+ os << (unit_testing ?
+ "<--UNITTEST-HIDE_TS-->" : toHexValue(msg.getContextTS())) << delimiter;
+
+ // location
+ //
+ csvQuoteString(os, location2string(msg.getLocation(), coll));
+ os << delimiter;
+
+ // raw message length
+ //
+ os << std::to_string(msg.getLength()) << delimiter;
+
+ // crc
+ //
+ if (msg.getHeader().field.chksum) {
+ os << (unit_testing ? "<--UNITTEST-HIDE_CRC-->" : toHexValue(msg.getCrc()));
+ }
+ os << delimiter;
+
+ if (coll != nullptr) {
+ csvQuoteString(os, coll->getFileName());
+ }
+ os << std::endl;
+
+ return os;
+}
+
+MIPI_SYST_NAMESPACE_END \ No newline at end of file
diff --git a/printer/src/mipi_syst_printf.cpp b/printer/src/mipi_syst_printf.cpp
new file mode 100644
index 0000000..e0da037
--- /dev/null
+++ b/printer/src/mipi_syst_printf.cpp
@@ -0,0 +1,435 @@
+/*
+ Copyright (c) 2018, MIPI Alliance, Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Contributors:
+ * Norbert Schulz (Intel Corporation) - Initial API and implementation
+ */
+
+#include <sstream>
+#include "mipi_syst_printf.h"
+
+MIPI_SYST_NAMESPACE_BEGIN
+
+template<> double bytes2ValLE<double>(const void * data)
+{
+ union { uint64_t ll; double d; } u = { bytes2ValLE<uint64_t>(data) };
+ return u.d;
+}
+
+// Parse printf style format string into a sequence of text and format fragments
+//
+uint32_t
+fmtscanner::parse(const std::string& fmt, Args& args)
+{
+ uint32_t result(OK);
+
+ const char * p(fmt.c_str());
+ const char * eof(p + fmt.size());
+ FmtScanState state(START);
+ Modifier modifier(MOD_NONE);
+ size_t fmtPos = 0; // curremt position in format
+ size_t fragmentStart = 0; // where current fragment started
+ size_t lastPercentPos = 0; // where the last % fmt start was seen
+
+ args.clear();
+
+ while (p < eof) {
+ switch (state) {
+ case START:
+ fragmentStart = fmtPos;
+ modifier = MOD_NONE;
+
+ state = PLAINTEXT;
+ ; // deliberate fall through
+
+ case PLAINTEXT:
+ if (*p == '%') {
+ lastPercentPos = fmtPos;
+ state = PERCENT;
+ }
+ break;
+
+ case PERCENT:
+ if (*p == '%') {
+ lastPercentPos = 0; // '%%' is not a format, but the % char
+ state = PLAINTEXT;
+ } else {
+ // arg fmt definition is starting
+ //
+ if (lastPercentPos != fragmentStart) {
+ args.push_back(
+ ArgFragment(TEXT, 0,
+ fmt.substr(fragmentStart,
+ lastPercentPos - fragmentStart)));
+ }
+ fragmentStart = lastPercentPos;
+ state = FLAGS;
+ continue;
+ }
+ break;
+
+ case FLAGS:
+ switch (*p) {
+ case '-':
+ case '+':
+ case ' ':
+ case '#':
+ case '0':
+ break;
+ default:
+ state = WIDTH;
+ continue;
+ break;
+ }
+ break;
+
+ case WIDTH:
+ if (*p == '*') {
+ args.push_back(ArgFragment(STAR, SIZEOF_INT, ""));
+ state = PRECISION_DOT;
+ } else {
+ state = WIDTH_NUMBER;
+ continue;
+ }
+ break;
+
+ case WIDTH_NUMBER:
+ if (!isdigit(*p)) {
+ state = PRECISION_DOT;
+ continue;
+ }
+ break;
+
+ case PRECISION_DOT:
+ if (*p == '.') {
+ state = PRECISION_VAL;
+ } else {
+ state = MODIFIER;
+ continue;
+ }
+ break;
+
+ case PRECISION_VAL:
+ if (*p == '*') {
+ args.push_back(ArgFragment(STAR, SIZEOF_INT, std::string()));
+ state = MODIFIER;
+ } else {
+ state = PRECISION_NUMBER;
+ continue;
+ }
+ break;
+
+ case PRECISION_NUMBER:
+ if (!isdigit(*p)) {
+ state = MODIFIER;
+ continue;
+ }
+ break;
+
+ case MODIFIER:
+ state = SPECIFIER;
+
+ switch (*p) {
+ case 'h':
+ modifier = MOD_H;
+ state = MODIFIER_HALF;
+ break;
+ case 'l':
+ modifier = MOD_L;
+ state = MODIFIER_LONG;
+ break;
+ case 'j':
+ modifier = MOD_J;
+ break;
+ case 'z':
+ modifier = MOD_Z;
+ break;
+ case 't':
+ modifier = MOD_T;
+ break;
+ case 'L':
+ modifier = MOD_LD;
+ break;
+ default:
+ continue;
+ }
+ break;
+
+ case MODIFIER_HALF:
+ state = SPECIFIER;
+ if (*p == 'h') {
+ modifier = MOD_HH;
+ break;
+ } else {
+ continue;
+ }
+ break;
+
+
+ case MODIFIER_LONG:
+ state = SPECIFIER;
+ if (*p == 'l') {
+ modifier = MOD_LL;
+ break;
+ } else {
+ continue;
+ }
+
+ case SPECIFIER:
+ {
+ std::string fragment = fmt.substr(fragmentStart,
+ fmtPos - fragmentStart + 1);
+
+ switch (*p) {
+ case 'd':
+ case 'i':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ switch (modifier) {
+ case MOD_L:
+ // convert long to longlong if client is 64bit, but host 32bit
+ //
+ if ((SIZEOF_LONG == 8) && (sizeof(long) != 8)) {
+ size_t pos(fragment.find('l'));
+ if (pos != std::string::npos) {
+ fragment = fragment.insert(pos, "l");
+ }
+ }
+ args.push_back(ArgFragment(INTEGER, SIZEOF_LONG, fragment));
+ break;
+ case MOD_LL:
+ case MOD_J:
+ args.push_back(ArgFragment(INTEGER, SIZEOF_LONGLONG, fragment));
+ break;
+ case MOD_Z:
+ args.push_back(ArgFragment(INTEGER, SIZEOF_SIZEOF, fragment));
+ break;
+ default:
+ args.push_back(ArgFragment(INTEGER, SIZEOF_INT, fragment));
+ break;
+ }
+ state = START;
+ break;
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ case 'a':
+ case 'A':
+ args.push_back(ArgFragment(DOUBLE, SIZEOF_LONGLONG, fragment));
+ break;
+ case 'c':
+ args.push_back(ArgFragment(INTEGER, SIZEOF_INT, fragment));
+ break;
+ case 'p':
+ args.push_back(ArgFragment(POINTER, SIZEOF_PTR, fragment));
+ break;
+ case 's':
+ args.push_back(ArgFragment(STRING, SIZEOF_PTR, fragment));
+ break;
+ case 'n':
+ args.push_back(ArgFragment(PERCENT_N, SIZEOF_PTR, fragment));
+ break;
+ default: // unsupported format
+ args.push_back(ArgFragment(UNKNOWN, 0, fragment));
+ result |= UNKNOWN_FORMAT;
+ break;
+ }
+ state = START;
+ }
+ break;
+
+ default:
+ break;
+ }
+ ++p;
+ ++fmtPos;
+ }
+
+ // check if we have a tail plain text string at the end of the format
+ // and add it to arg list.
+ //
+ if (state == PLAINTEXT) {
+ args.push_back(ArgFragment(TEXT, 0,
+ fmt.substr(fragmentStart, fmtPos - fragmentStart + 1)));
+ state = START;
+ }
+
+ if (state != START) {
+ result |= INCOMPLETE_FORMAT;
+ }
+
+ return result;
+}
+
+
+fmtscanner::ArgFragment::ArgFragment(
+ ArgType type, size_t size, const std::string& text) :
+ _type(type), _size(size), _text(text)
+{}
+
+
+
+bool msgprintf::format(
+ const std::string& fmt,
+ const void * args, uint32_t size,
+ std::string& result)
+{
+ std::stringstream sstr; // where the result is build
+
+ // Parse the format string for the number of needed parameters
+ //
+ uint32_t parseResult;
+ if ((parseResult = _scanner.parse(fmt, _args)) != fmtscanner::OK) {
+ sstr << "invalid format string '" << fmt << "'";
+ result = sstr.str();
+ return false;
+ }
+
+ const char * bufPtr((const char *)args); //current byte from arg buffer
+ const void * eob((const char *)args + size); // end of buffer address
+ std::vector<int> starArgs; // '*' args like in "%*.*f"
+ bool success(true);
+
+ // Loop over the argument fragments to format each using local printf
+ // and then add it to the result string.
+ //
+ for (fmtscanner::Args::const_iterator it(_args.begin());
+ it != _args.end();
+ ++it)
+ {
+ size_t need(it->size()); // number of bytes needed for format
+ fmtscanner::ArgType type(it->type());
+
+ switch (type) {
+ case fmtscanner::INTEGER:
+ case fmtscanner::POINTER:
+ if (bufPtr + need <= eob) {
+ if (need == sizeof(uint64_t)) {
+ uint64_t val(bytes2ValLE<uint64_t>(bufPtr));
+ success = hostPrintf(sstr, it->text(), val, starArgs);
+ } else {
+ uint32_t val(bytes2ValLE<uint32_t>(bufPtr));
+ success = hostPrintf(sstr, it->text(), val, starArgs);
+ }
+ }
+ break;
+
+ case fmtscanner::DOUBLE:
+ if (bufPtr + need <= eob) {
+ double val(bytes2ValLE<double>(bufPtr));
+ success = hostPrintf(sstr, it->text(), val, starArgs);
+ }
+ break;
+
+ case fmtscanner::TEXT:
+ // copy text, but "%%" means "%" in printf format
+ //
+ for (const char *c = it->text().c_str(); *c; ++c) {
+ if ('%' == *c && '%' == *(c+1)) continue;
+ sstr << *c;
+ }
+
+ break;
+
+ case fmtscanner::STRING:
+ // String embedded in message buffer
+ // check if it is valid (zero terminated inside message) and
+ // then format it into result
+ //
+ {
+ const char * str(bufPtr);
+
+ // Hunt the null byte
+ //
+ for (need = 1; str <= eob && *str; ++str, ++need)
+ ;
+
+ if (str > eob) {
+ result = " - corrupt printf payload, missing argument string termination";
+ return false;
+ }
+
+ success = hostPrintf(sstr, it->text(), bufPtr, starArgs);
+ }
+ break;
+ case fmtscanner::PERCENT_N:
+ // %n is a nop . There is no usefull place to return the
+ // output to.
+ //
+ break;
+
+ case fmtscanner::STAR:
+ // A star argument was seen in fmt, put on the *-stack (can be up to 2)
+ //
+ if (bufPtr + need <= eob) {
+ starArgs.push_back(bytes2ValLE<uint32_t>(bufPtr));
+ }
+ break;
+
+ default:
+ sstr << "- printf internal error, unkown argtype in format '"
+ << fmt << "'";
+ success = false;
+ }
+
+ // Check for overflow in input buffer
+ //
+ if ((bufPtr + need) > eob) {
+ sstr << "- insufficient argument bytes for format '"
+ << fmt << "'";
+ success = false;
+ }
+
+ if (!success) {
+ result = sstr.str();
+ return false;
+ }
+
+ if (type != fmtscanner::STAR) {
+ starArgs.clear();
+ }
+ bufPtr += need;
+ }
+
+ result = sstr.str();
+
+ return true;
+}
+
+MIPI_SYST_NAMESPACE_END \ No newline at end of file