text:
// *****************************************************************************
//
// © Copyright 2020, Septentrio NV/SA.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//    1. Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//    2. 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.
//    3. 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 HOLDER 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.
//
// *****************************************************************************

// *****************************************************************************
//
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:

// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// *****************************************************************************

//! 0x24 is ASCII for $ - 1st byte in each message
#ifndef NMEA_SYNC_BYTE_1
#define NMEA_SYNC_BYTE_1 0x24
#endif
//! 0x47 is ASCII for G - 2nd byte to indicate NMEA-type ASCII message
#ifndef NMEA_SYNC_BYTE_2_1
#define NMEA_SYNC_BYTE_2_1 0x47
#endif
//! 0x50 is ASCII for P - 2nd byte to indicate proprietary ASCII message
#ifndef NMEA_SYNC_BYTE_2_2
#define NMEA_SYNC_BYTE_2_2 0x50
#endif
//! 0x24 is ASCII for $ - 1st byte in each response from the Rx
#ifndef RESPONSE_SYNC_BYTE_1
#define RESPONSE_SYNC_BYTE_1 0x24
#endif
//! 0x52 is ASCII for R (for "Response") - 2nd byte in each response from the Rx
#ifndef RESPONSE_SYNC_BYTE_2
#define RESPONSE_SYNC_BYTE_2 0x52
#endif
//! 0x0D is ASCII for "Carriage Return", i.e. "Enter"
#ifndef CARRIAGE_RETURN
#define CARRIAGE_RETURN 0x0D
#endif
//! 0x0A is ASCII for "Line Feed", i.e. "New Line"
#ifndef LINE_FEED
#define LINE_FEED 0x0A
#endif
//! 0x3F is ASCII for ? - 3rd byte in the response message from the Rx in case the
//! command was invalid
#ifndef RESPONSE_SYNC_BYTE_3
#define RESPONSE_SYNC_BYTE_3 0x3F
#endif
//! 0x49 is ASCII for I - 1st character of connection descriptor sent by the Rx after
//! initiating TCP connection
#ifndef CONNECTION_DESCRIPTOR_BYTE_1
#define CONNECTION_DESCRIPTOR_BYTE_1 0x49
#endif
//! 0x50 is ASCII for P - 2nd character of connection descriptor sent by the Rx after
//! initiating TCP connection
#ifndef CONNECTION_DESCRIPTOR_BYTE_2
#define CONNECTION_DESCRIPTOR_BYTE_2 0x50
#endif

// C++ libraries
#include <cassert> // for assert
#include <cstddef>
#include <map>
#include <sstream>
// Boost includes
#include <boost/call_traits.hpp>
#include <boost/format.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/tokenizer.hpp>
// ROSaic includes
#include <septentrio_gnss_driver/abstraction/typedefs.hpp>
#include <septentrio_gnss_driver/crc/crc.h>
#include <septentrio_gnss_driver/parsers/nmea_parsers/gpgga.hpp>
#include <septentrio_gnss_driver/parsers/nmea_parsers/gpgsa.hpp>
#include <septentrio_gnss_driver/parsers/nmea_parsers/gpgsv.hpp>
#include <septentrio_gnss_driver/parsers/nmea_parsers/gprmc.hpp>
#include <septentrio_gnss_driver/parsers/string_utilities.h>

#ifndef RX_MESSAGE_HPP
#define RX_MESSAGE_HPP

/**
 * @file rx_message.hpp
 * @date 20/08/20
 * @brief Defines a class that reads messages handed over from the circular buffer
 */

extern bool g_read_cd;
extern uint32_t g_cd_count;

//! Settings struct
struct Settings
{
    //! Set logger level to DEBUG
    bool activate_debug_log;
    //! Device port
    std::string device;
    //! Delay in seconds between reconnection attempts to the connection type
    //! specified in the parameter connection_type
    float reconnect_delay_s;
    //! Baudrate
    uint32_t baudrate;
    //! HW flow control
    std::string hw_flow_control;
    //! In case of serial communication to Rx, rx_serial_port specifies Rx's
    //! serial port connected to, e.g. USB1 or COM1
    std::string rx_serial_port;
    //! Datum to be used
    std::string datum;
    //! Polling period for PVT-related SBF blocks
    uint32_t polling_period_pvt;
    //! Polling period for all other SBF blocks and NMEA messages
    uint32_t polling_period_rest;
    //! Marker-to-ARP offset in the eastward direction
    float delta_e;
    //! Marker-to-ARP offset in the northward direction
    float delta_n;
    //! Marker-to-ARP offset in the upward direction
    float delta_u;
    //! Main antenna type, from the list returned by the command "lstAntennaInfo,
    //! Overview"
    std::string ant_type;
    //! Aux1 antenna type, from the list returned by the command "lstAntennaInfo,
    //! Overview"
    std::string ant_aux1_type;
    //! Serial number of your particular Main antenna
    std::string ant_serial_nr;
    //! Serial number of your particular Aux1 antenna
    std::string ant_aux1_serial_nr;
    //! ROS axis orientation, body: front-left-up, geographic: ENU
    bool use_ros_axis_orientation;
    //! IMU orientation x-angle
    double theta_x;
    //! IMU orientation y-angle
    double theta_y;
    //! IMU orientation z-angle
    double theta_z;
    //! INS antenna lever arm x-offset
    double ant_lever_x;
    //! INS antenna lever arm y-offset
    double ant_lever_y;
    //! INS antenna lever arm z-offset
    double ant_lever_z;
    //! INS POI offset in x-dimension
    double poi_x;
    //! INS POI offset in y-dimension
    double poi_y;
    //! INS POI offset in z-dimension
    double poi_z;
    //! INS velocity sensor lever arm x-offset
    double vsm_x;
    //! INS velocity sensor lever arm y-offset
    double vsm_y;
    //! INS velocity sensor lever arm z-offset
    double vsm_z;
    //! Attitude offset determination in longitudinal direction
    double heading_offset;
    //! Attitude offset determination in latitudinal direction
    double pitch_offset;
    //! INS multiantenna
    bool multi_antenna;
    //! INS solution reference point
    bool ins_use_poi;
    //! For heading computation when unit is powered-cycled
    std::string ins_initial_heading;
    //! Attitude deviation mask
    float att_std_dev;
    //! Position deviation mask
    float pos_std_dev;
    //! Type of NTRIP connection
    std::string ntrip_mode;
    //! Hostname or IP address of the NTRIP caster to connect to
    std::string caster;
    //! IP port number of NTRIP caster to connect to
    uint32_t caster_port;
    //! Username for NTRIP service
    std::string ntrip_username;
    //! Password for NTRIP service
    std::string ntrip_password;
    //! Mountpoint for NTRIP service
    std::string mountpoint;
    //! NTRIP version for NTRIP service
    std::string ntrip_version;
    //! Whether Rx has internet or not
    bool rx_has_internet;
    //! RTCM version for NTRIP service (if Rx does not have internet)
    std::string rtcm_version;
    //! Rx TCP port number, e.g. 28785, on which Rx receives the corrections
    //! (can't be the same as main connection unless localhost concept is used)
    uint32_t rx_input_corrections_tcp;
    //! Rx serial port, e.g. USB2, on which Rx receives the corrections (can't be
    //! the same as main connection unless localhost concept is used)
    std::string rx_input_corrections_serial;
    //! Whether (and at which rate) or not to send GGA to the NTRIP caster
    std::string send_gga;
    //! Whether or not to publish the GGA message
    bool publish_gpgga;
    //! Whether or not to publish the RMC message
    bool publish_gprmc;
    //! Whether or not to publish the GSA message
    bool publish_gpgsa;
    //! Whether or not to publish the GSV message
    bool publish_gpgsv;
    //! Whether or not to publish the MeasEpoch message
    bool publish_measepoch;
    //! Whether or not to publish the PVTCartesianMsg
    //! message
    bool publish_pvtcartesian;
    //! Whether or not to publish the PVTGeodeticMsg message
    bool publish_pvtgeodetic;
    //! Whether or not to publish the PosCovCartesianMsg
    //! message
    bool publish_poscovcartesian;
    //! Whether or not to publish the PosCovGeodeticMsg
    //! message
    bool publish_poscovgeodetic;
    //! Whether or not to publish the VelCovGeodeticMsg
    //! message
    bool publish_velcovgeodetic;
    //! Whether or not to publish the AttEulerMsg message
    bool publish_atteuler;
    //! Whether or not to publish the AttCovEulerMsg message
    bool publish_attcoveuler;
    //! Whether or not to publish the INSNavCartMsg message
    bool publish_insnavcart;
    //! Whether or not to publish the INSNavGeodMsg message
    bool publish_insnavgeod;
    //! Whether or not to publish the IMUSetupMsg message
    bool publish_imusetup;
    //! Whether or not to publish the VelSensorSetupMsg message
    bool publish_velsensorsetup;
    //! Whether or not to publish the ExtEventINSNavGeodMsg message
    bool publish_exteventinsnavgeod;
    //! Whether or not to publish the ExtEventINSNavCartMsg message
    bool publish_exteventinsnavcart;
    //! Whether or not to publish the ExtSensorMeasMsg message
    bool publish_extsensormeas;
    //! Whether or not to publish the TimeReferenceMsg message with GPST
    bool publish_gpst;
    //! Whether or not to publish the NavSatFixMsg message
    bool publish_navsatfix;
    //! Whether or not to publish the GPSFixMsg message
    bool publish_gpsfix;
    //! Whether or not to publish the PoseWithCovarianceStampedMsg message
    bool publish_pose;
    //! Whether or not to publish the DiagnosticArrayMsg message
    bool publish_diagnostics;
    //! Whether or not to publish the ImuMsg message
    bool publish_imu;
    //! Whether or not to publish the LocalizationMsg message
    bool publish_localization;
    //! Whether or not to publish the tf of the localization
    bool publish_tf;
    //! Septentrio receiver type, either "gnss" or "ins"
    std::string septentrio_receiver_type;
    //! If true, the ROS message headers' unix time field is constructed from the TOW (in
    //! the SBF case) and UTC (in the NMEA case) data. If false, times are constructed
    //! within the driver via time(NULL) of the \<ctime\> library.
    bool use_gnss_time;
    //! The frame ID used in the header of every published ROS message
    std::string frame_id;
    //! The frame ID used in the header of published ROS Imu message
    std::string imu_frame_id;
    //! The frame ID used in the header of published ROS Localization message if poi is used
    std::string poi_frame_id;
    //! The frame ID of the velocity sensor
    std::string vsm_frame_id;
    //! The frame ID of the aux1 antenna
    std::string aux1_frame_id;
    //! The frame ID of the vehicle frame
    std::string vehicle_frame_id;
    //! Wether the UTM zone of the localization is locked
    bool lock_utm_zone;
    //! The number of leap seconds that have been inserted into the UTC time
    uint32_t leap_seconds;
    //! Whether or not we are reading from an SBF file
    bool read_from_sbf_log;
    //! Whether or not we are reading from a PCAP file
    bool read_from_pcap;
};

//! Enum for NavSatFix's status.status field, which is obtained from PVTGeodetic's
//! Mode field
enum TypeOfPVT_Enum
{
    evNoPVT,
    evStandAlone,
    evDGPS,
    evFixed,
    evRTKFixed,
    evRTKFloat,
    evSBAS,
    evMovingBaseRTKFixed,
    evMovingBaseRTKFloat,
    evPPP
};

//! Since switch only works with int (yet NMEA message IDs are strings), we need
//! enum. Note drawbacks: No variable can have a name which is already in some
//! enumeration, enums are not type safe etc..
enum RxID_Enum
{
    evNavSatFix,
    evINSNavSatFix,
    evGPSFix,
    evINSGPSFix,
    evPoseWithCovarianceStamped,
    evINSPoseWithCovarianceStamped,
    evGPGGA,
    evGPRMC,
    evGPGSA,
    evGPGSV,
    evGLGSV,
    evGAGSV,
    evPVTCartesian,
    evPVTGeodetic,
    evPosCovCartesian,
    evPosCovGeodetic,
    evAttEuler,
    evAttCovEuler,
    evINSNavCart,
    evINSNavGeod,
    evIMUSetup,
    evVelSensorSetup,
    evExtEventINSNavGeod,
    evExtEventINSNavCart,
    evExtSensorMeas,
    evGPST,
    evChannelStatus,
    evMeasEpoch,
    evDOP,
    evVelCovGeodetic,
    evDiagnosticArray,
    evLocalization,
    evReceiverStatus,
    evQualityInd,
    evReceiverSetup
};

namespace io_comm_rx {

    /**
     * @class RxMessage
     * @brief Can search buffer for messages, read/parse them, and so on
     */
    class RxMessage
    {
    public:
        /**
         * @brief Constructor of the RxMessage class
         *
         * One can always provide a non-const value where a const one was expected.
         * The const-ness of the argument just means the function promises not to
         * change it.. Recall: static_cast by the way can remove or add const-ness,
         * no other C++ cast is capable of removing it (not even reinterpret_cast)
         * @param[in] data Pointer to the buffer that is about to be analyzed
         * @param[in] size Size of the buffer (as handed over by async_read_some)
         */
        RxMessage(ROSaicNodeBase* node, Settings* settings) :
            node_(node),
            settings_(settings),
            unix_time_(0)
        {
            found_ = false;
            crc_check_ = false;
            message_size_ = 0;

            //! Pair of iterators to facilitate initialization of the map
            std::pair<uint16_t, TypeOfPVT_Enum> type_of_pvt_pairs[] = {
            std::make_pair(static_cast<uint16_t>(0), evNoPVT),
            std::make_pair(static_cast<uint16_t>(1), evStandAlone),
            std::make_pair(static_cast<uint16_t>(2), evDGPS),
            std::make_pair(static_cast<uint16_t>(3), evFixed),
            std::make_pair(static_cast<uint16_t>(4), evRTKFixed),
            std::make_pair(static_cast<uint16_t>(5), evRTKFloat),
            std::make_pair(static_cast<uint16_t>(6), evSBAS),
            std::make_pair(static_cast<uint16_t>(7), evMovingBaseRTKFixed),
            std::make_pair(static_cast<uint16_t>(8), evMovingBaseRTKFloat),
            std::make_pair(static_cast<uint16_t>(10), evPPP)};

            type_of_pvt_map = TypeOfPVTMap(type_of_pvt_pairs, type_of_pvt_pairs + evPPP + 1);

            //! Pair of iterators to facilitate initialization of the map
            std::pair<std::string, RxID_Enum> rx_id_pairs[] = {
            std::make_pair("NavSatFix", evNavSatFix),
            std::make_pair("INSNavSatFix", evINSNavSatFix),
            std::make_pair("GPSFix", evGPSFix),
            std::make_pair("INSGPSFix", evINSGPSFix),
            std::make_pair("PoseWithCovarianceStamped", evPoseWithCovarianceStamped),
            std::make_pair("INSPoseWithCovarianceStamped", evINSPoseWithCovarianceStamped),
            std::make_pair("$GPGGA", evGPGGA),
            std::make_pair("$GPRMC", evGPRMC),
            std::make_pair("$GPGSA", evGPGSA),
            std::make_pair("$GPGSV", evGPGSV),
            std::make_pair("$GLGSV", evGLGSV),
            std::make_pair("$GAGSV", evGAGSV),
            std::make_pair("4006", evPVTCartesian),
            std::make_pair("4007", evPVTGeodetic),
            std::make_pair("5905", evPosCovCartesian),
            std::make_pair("5906", evPosCovGeodetic),
            std::make_pair("5938", evAttEuler),
            std::make_pair("5939", evAttCovEuler),
            std::make_pair("GPST", evGPST),
            std::make_pair("4013", evChannelStatus),
            std::make_pair("4027", evMeasEpoch),
            std::make_pair("4001", evDOP),
            std::make_pair("5908", evVelCovGeodetic),
            std::make_pair("DiagnosticArray", evDiagnosticArray),
            std::make_pair("Localization", evLocalization),
            std::make_pair("4014", evReceiverStatus),
            std::make_pair("4082", evQualityInd),
            std::make_pair("5902", evReceiverSetup),
            std::make_pair("4225", evINSNavCart),
            std::make_pair("4226", evINSNavGeod),
            std::make_pair("4230", evExtEventINSNavGeod),
            std::make_pair("4229", evExtEventINSNavCart),
            std::make_pair("4224", evIMUSetup),
            std::make_pair("4244", evVelSensorSetup),
            std::make_pair("4050", evExtSensorMeas)
            };

            rx_id_map = RxIDMap(rx_id_pairs, rx_id_pairs + evReceiverSetup + 1);
        }

         /**
         * @brief Put new data
         * @param[in] recvTimestamp Timestamp of receiving buffer
         * @param[in] data Pointer to the buffer that is about to be analyzed
         * @param[in] size Size of the buffer (as handed over by async_read_some)
         */
        void newData(Timestamp recvTimestamp, const uint8_t* data, std::size_t& size)
        {
            recvTimestamp_ = recvTimestamp;
            data_ = data;
            count_ = size;
            found_ = false;
            crc_check_ = false;
            message_size_ = 0;
        }

        //! Determines whether data_ points to the SBF block with ID "ID", e.g. 5003
        bool isMessage(const uint16_t ID);
        //! Determines whether data_ points to the NMEA message with ID "ID", e.g.
        //! "$GPGGA"
        bool isMessage(std::string ID);
        //! Determines whether data_ currently points to an SBF block
        bool isSBF();
        //! Determines whether data_ currently points to an NMEA message
        bool isNMEA();
        //! Determines whether data_ currently points to an NMEA message
        bool isResponse();
        //! Determines whether data_ currently points to a connection descriptor
        //! (right after initiating a TCP connection)
        bool isConnectionDescriptor();
        //! Determines whether data_ currently points to an error message reply from
        //! the Rx
        bool isErrorMessage();
        //! Determines size of the message (also command reply) that data_ is
        //! currently pointing at
        std::size_t messageSize();
        //! Returns the message ID of the message where data_ is pointing at at the
        //! moment, SBF identifiers embellished with inverted commas, e.g. "5003"
        std::string messageID();

        /**
         * @brief Returns the count_ variable
         * @return The variable count_
         */
        std::size_t getCount() { return count_; };
        /**
         * @brief Searches the buffer for the beginning of the next message (NMEA or
         * SBF)
         * @return A pointer to the start of the next message.
         */
        const uint8_t* search();

        /**
         * @brief Gets the length of the SBF block
         *
         * It determines the length from the header of the SBF block. The block
         * length thus includes the header length.
         * @return The length of the SBF block
         */
        uint16_t getBlockLength();

        /**
         * @brief Gets the current position in the read buffer
         * @return The current position of the read buffer
         */
        const uint8_t* getPosBuffer();

        /**
         * @brief Gets the end position in the read buffer
         * @return A pointer pointing to just after the read buffer (matches
         * search()'s final pointer in case no valid message is found)
         */
        const uint8_t* getEndBuffer();

        /**
         * @brief Has an NMEA message, SBF block or command reply been found in the
         * buffer?
         * @returns True if a message with the correct header & length has been found
         */
        bool found();

        /**
         * @brief Goes to the start of the next message based on the calculated
         * length of current message
         */
        void next();

        /**
         * @brief Performs the CRC check (if SBF) and publishes ROS messages
         * @return True if read was successful, false otherwise
         */
        bool read(std::string message_key, bool search = false);

        /**
         * @brief Whether or not a message has been found
         */
        bool found_;

         /**
         * @brief Wether all blocks from GNSS have arrived for GpsFix Message
         */
        bool gnss_gpsfix_complete(uint32_t id);

        /**
         * @brief Wether all blocks from INS have arrived for GpsFix Message
         */
        bool ins_gpsfix_complete(uint32_t id);

        /**
         * @brief Wether all blocks from GNSS have arrived for NavSatFix Message
         */
        bool gnss_navsatfix_complete(uint32_t id);

        /**
         * @brief Wether all blocks from INS have arrived for NavSatFix Message
         */
        bool ins_navsatfix_complete(uint32_t id);

        /**
         * @brief Wether all blocks from GNSS have arrived for Pose Message
         */
        bool gnss_pose_complete(uint32_t id);

        /**
         * @brief Wether all blocks from INS have arrived for Pose Message
         */
        bool ins_pose_complete(uint32_t id);

        /**
         * @brief Wether all blocks have arrived for Diagnostics Message
         */
        bool diagnostics_complete(uint32_t id);

         /**
         * @brief Wether all blocks have arrived for Localization Message
         */
        bool ins_localization_complete(uint32_t id);

    private:
        /**
         * @brief Pointer to the node
         */
        ROSaicNodeBase* node_;

        /**
         * @brief Timestamp of receiving buffer
         */
        Timestamp recvTimestamp_;

        /**
         * @brief Pointer to the buffer of messages
         */
        const uint8_t* data_;

        /**
         * @brief Number of unread bytes in the buffer
         */
        std::size_t count_;

        /**
         * @brief Whether the CRC check as evaluated in the read() method was
         * successful or not is stored here
         */
        bool crc_check_;

        /**
         * @brief Helps to determine size of response message / NMEA message / SBF
         * block
         */
        std::size_t message_size_;

        /**
         * @brief Number of times the GPSFixMsg message has been published
         */
        uint32_t count_gpsfix_ = 0;

        /**
         * @brief Since NavSatFix etc. need PVTGeodetic, incoming PVTGeodetic blocks
         * need to be stored
         */
        PVTGeodeticMsg last_pvtgeodetic_;

        /**
         * @brief Since NavSatFix etc. need PosCovGeodetic, incoming PosCovGeodetic
         * blocks need to be stored
         */
        PosCovGeodeticMsg last_poscovgeodetic_;

        /**
         * @brief Since GPSFix etc. need AttEuler, incoming AttEuler blocks need to
         * be stored
         */
        AttEulerMsg last_atteuler_;

        /**
         * @brief Since GPSFix etc. need AttCovEuler, incoming AttCovEuler blocks
         * need to be stored
         */
        AttCovEulerMsg last_attcoveuler_;

        /**
         * @brief Since NavSatFix, GPSFix, Imu and Pose. need INSNavGeod, incoming INSNavGeod blocks
         * need to be stored
         */
        INSNavGeodMsg last_insnavgeod_;

         /**
         * @brief Since Imu needs ExtSensorMeas, incoming ExtSensorMeas blocks
         * need to be stored
         */
        ExtSensorMeasMsg last_extsensmeas_;

        /**
         * @brief Since GPSFix needs ChannelStatus, incoming ChannelStatus blocks
         * need to be stored
         */
        ChannelStatus last_channelstatus_;

        /**
         * @brief Since GPSFix needs MeasEpoch (for SNRs), incoming MeasEpoch blocks
         * need to be stored
         */
        MeasEpochMsg last_measepoch_;

        /**
         * @brief Since GPSFix needs DOP, incoming DOP blocks need to be stored
         */
        DOP last_dop_;

        /**
         * @brief Since GPSFix needs VelCovGeodetic, incoming VelCovGeodetic blocks
         * need to be stored
         */
        VelCovGeodeticMsg last_velcovgeodetic_;

        /**
         * @brief Since DiagnosticArray needs ReceiverStatus, incoming ReceiverStatus
         * blocks need to be stored
         */
        ReceiverStatus last_receiverstatus_;

        /**
         * @brief Since DiagnosticArray needs QualityInd, incoming QualityInd blocks
         * need to be stored
         */
        QualityInd last_qualityind_;

        /**
         * @brief Since DiagnosticArray needs ReceiverSetup, incoming ReceiverSetup
         * blocks need to be stored
         */
        ReceiverSetup last_receiversetup_;

        //! Shorthand for the map responsible for matching PVTGeodetic's Mode field
        //! to an enum value
        typedef std::map<uint16_t, TypeOfPVT_Enum> TypeOfPVTMap;

        /**
         * @brief All instances of the RxMessage class shall have access to the map
         * without reinitializing it, hence static
         */
        TypeOfPVTMap type_of_pvt_map;

        //! Shorthand for the map responsible for matching ROS message identifiers to
        //! an enum value
        typedef std::map<std::string, RxID_Enum> RxIDMap;

        /**
         * @brief All instances of the RxMessage class shall have access to the map
         * without reinitializing it, hence static
         *
         * This map is for mapping ROS message, SBF and NMEA identifiers to an
         * enumeration and makes the switch-case formalism in rx_message.hpp more
         * explicit.
         */
        RxIDMap rx_id_map;

        //! When reading from an SBF file, the ROS publishing frequency is governed by the
        //! time stamps found in the SBF blocks therein.
        Timestamp unix_time_;

        //! For GPSFix: Whether the ChannelStatus block of the current epoch has arrived or
        //! not
        bool channelstatus_has_arrived_gpsfix_ = false;

        //! For GPSFix: Whether the MeasEpoch block of the current epoch has arrived or not
        bool measepoch_has_arrived_gpsfix_ = false;

        //! For GPSFix: Whether the DOP block of the current epoch has arrived or not
        bool dop_has_arrived_gpsfix_ = false;

        //! For GPSFix: Whether the PVTGeodetic block of the current epoch has arrived or not
        bool pvtgeodetic_has_arrived_gpsfix_ = false;

        //! For GPSFix: Whether the PosCovGeodetic block of the current epoch has arrived or
        //! not
        bool poscovgeodetic_has_arrived_gpsfix_ = false;

        //! For GPSFix: Whether the VelCovGeodetic block of the current epoch has arrived or
        //! not
        bool velcovgeodetic_has_arrived_gpsfix_ = false;

        //! For GPSFix: Whether the AttEuler block of the current epoch has arrived or not
        bool atteuler_has_arrived_gpsfix_ = false;

        //! For GPSFix: Whether the AttCovEuler block of the current epoch has arrived or not
        bool attcoveuler_has_arrived_gpsfix_ = false;

        //! For GPSFix: Whether the INSNavGeod block of the current epoch has arrived or not
        bool insnavgeod_has_arrived_gpsfix_ = false;

        //! For NavSatFix: Whether the PVTGeodetic block of the current epoch has arrived or
        //! not
        bool pvtgeodetic_has_arrived_navsatfix_ = false;

        //! For NavSatFix: Whether the PosCovGeodetic block of the current epoch has arrived
        //! or not
        bool poscovgeodetic_has_arrived_navsatfix_ = false;

        //! For NavSatFix: Whether the INSNavGeod block of the current epoch has arrived
        //! or not
        bool insnavgeod_has_arrived_navsatfix_ = false;
        //! For PoseWithCovarianceStamped: Whether the PVTGeodetic block of the current epoch
        //! has arrived or not
        bool pvtgeodetic_has_arrived_pose_ = false;

        //! For PoseWithCovarianceStamped: Whether the PosCovGeodetic block of the current
        //! epoch has arrived or not
        bool poscovgeodetic_has_arrived_pose_ = false;

        //! For PoseWithCovarianceStamped: Whether the AttEuler block of the current epoch
        //! has arrived or not
        bool atteuler_has_arrived_pose_ = false;

        //! For PoseWithCovarianceStamped: Whether the AttCovEuler block of the current epoch
        //! has arrived or not
        bool attcoveuler_has_arrived_pose_ = false;

        //! For PoseWithCovarianceStamped: Whether the INSNavGeod block of the current epoch
        //! has arrived or not
        bool insnavgeod_has_arrived_pose_ = false;

        //! For DiagnosticArray: Whether the ReceiverStatus block of the current epoch has
        //! arrived or not
        bool receiverstatus_has_arrived_diagnostics_ = false;

        //! For DiagnosticArray: Whether the QualityInd block of the current epoch has
        //! arrived or not
        bool qualityind_has_arrived_diagnostics_ = false;

        //! For Localization: Whether the INSNavGeod block of the current epoch
        //! has arrived or not
        bool insnavgeod_has_arrived_localization_ = false;

        /**
         * @brief "Callback" function when constructing NavSatFix messages
         * @return A smart pointer to the ROS message NavSatFix just created
         */
        NavSatFixMsg NavSatFixCallback();

        /**
         * @brief "Callback" function when constructing GPSFix messages
         * @return A smart pointer to the ROS message GPSFix just created
         */
        GPSFixMsg GPSFixCallback();

        /**
         * @brief "Callback" function when constructing PoseWithCovarianceStamped
         * messages
         * @return A smart pointer to the ROS message PoseWithCovarianceStamped just
         * created
         */
        PoseWithCovarianceStampedMsg
        PoseWithCovarianceStampedCallback();

        /**
         * @brief "Callback" function when constructing
         * DiagnosticArrayMsg messages
         * @return A smart pointer to the ROS message
         * DiagnosticArrayMsg just created
         */
        DiagnosticArrayMsg DiagnosticArrayCallback();

        /**
         * @brief "Callback" function when constructing
         * ImuMsg messages
         * @return A smart pointer to the ROS message
         * ImuMsg just created
         */
        ImuMsg ImuCallback();

        /**
         * @brief "Callback" function when constructing
         * LocalizationUtmMsg messages
         * @return A smart pointer to the ROS message
         * LocalizationUtmMsg just created
         */
        LocalizationUtmMsg LocalizationUtmCallback();

         /**
         * @brief Waits according to time when reading from file
         */
        void wait(Timestamp time_obj);

        /**
         * @brief Wether all elements are true
         */
        bool allTrue(std::vector<bool>& vec, uint32_t id);

        /**
         * @brief Settings struct
         */
        Settings* settings_;

        /**
         * @brief Fixed UTM zone
         */
        std::shared_ptr<std::string> fixedUtmZone_;

        /**
         * @brief Calculates the timestamp, in the Unix Epoch time format
         * This is either done using the TOW as transmitted with the SBF block (if
         * "use_gnss" is true), or using the current time.
         * @param[in] tow (Time of Week) Number of milliseconds that elapsed since the
         * beginning of the current GPS week as transmitted by the SBF block
         * @param[in] wnc (Week Number Counter) counts the number of complete weeks
         * elapsed since January 6, 1980
         * @param[in] use_gnss If true, the TOW as transmitted with the SBF block is
         * used, otherwise the current time
         * @return Timestamp object containing seconds and nanoseconds since last epoch
         */
        Timestamp timestampSBF(uint32_t tow, uint16_t wnc, bool use_gnss_time);
    };
} // namespace io_comm_rx
#endif // for RX_MESSAGE_HPP

max_stars_repo_name: septentrio-gnss/rosaic

max_issues_repo_name: septentrio-gnss/rosaic

max_forks_repo_name: septentrio-gnss/rosaic


text:
#include "dsa_common.h"

#include "date_time.h"

#include <chrono>
#include <iomanip>

#include <time.h>

#ifdef __MINGW32__
#include <timezoneapi.h>
#include <cstring>
#endif

#if _MSC_VER
#define localtime_r(a, b) localtime_s(b, a)
#endif

#include <boost/date_time/posix_time/posix_time.hpp>
#include <climits>
#include <regex>

namespace dsa {

static const size_t TS_SIZE = sizeof("0000-00-00T00:00:00.000+00:00") - 1;

#ifndef __MINGW32__  // if not mingw

thread_local std::chrono::milliseconds _last_ms{0};
thread_local string_ _last_ts = "0000-00-00T00:00:00.000+00:00";

static void update_ts(std::chrono::system_clock::time_point now) {
  std::time_t t = std::chrono::system_clock::to_time_t(now);

  tm localt;
  localtime_r(&t, &localt);
  size_t str_size;
  char buf[32];

  str_size = std::strftime(buf, sizeof(buf), "%FT%T.000%z0", &localt);

  // string_ str(buf, str_size);

  // set milli second
  auto ms = _last_ms.count() % 1000;
  buf[20] = static_cast<char>((ms / 100) + '0');
  buf[21] = static_cast<char>(((ms % 100) / 10) + '0');
  buf[22] = static_cast<char>((ms % 10) + '0');

  // fix format of timezone;
  buf[28] = buf[27];
  buf[27] = buf[26];
  buf[26] = ':';

  std::copy(buf, buf + TS_SIZE, _last_ts.begin());
}

#else  // strftime doesn't work in mingw

static std::chrono::milliseconds _last_ms{0};
static string_ _last_ts = "0000-00-00T00:00:00.000+00:00";

// this is not 100% thread safe, might generate wrong timestamp in certain case
// but won't crash the application
static void update_ts(std::chrono::system_clock::time_point now) {
  std::time_t t = std::chrono::system_clock::to_time_t(now);

  tm localt;
  localtime_r(&t, &localt);
  size_t str_size;
  char buf[32];

  TIME_ZONE_INFORMATION TimeZoneInfo;
  GetTimeZoneInformation(&TimeZoneInfo);
  int hourOffset = TimeZoneInfo.Bias / 60;
  int minOffset = TimeZoneInfo.Bias % 60;
  bool posOffset = false;
  if (hourOffset < 0) {
    hourOffset *= -1;
    posOffset = true;
  }
  if (minOffset < 0) {
    minOffset *= -1;
  }

  char tz[5];
  sprintf(tz, "%s%02i:%02i", posOffset ? "+" : "-", hourOffset, minOffset);
  sprintf(buf, "%02i-%02i-%02iT%02i:%02i:%02i.%03lli%s", localt.tm_year + 1900,
          (localt.tm_mon + 1), localt.tm_mday, localt.tm_hour, localt.tm_min,
          localt.tm_sec,
          std::chrono::duration_cast<std::chrono::milliseconds>(
              now.time_since_epoch())
                  .count() %
              1000,
          tz);

  std::copy(buf, buf + TS_SIZE, _last_ts.begin());
}

#endif

const string_& DateTime::get_ts() {
  // only generate the string when time changed
  auto now = std::chrono::system_clock::now();
  auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
      now.time_since_epoch());
  if (ms > _last_ms) {
    _last_ms = ms;
    update_ts(now);
  }
  return _last_ts;
}

int64_t DateTime::ms_since_epoch() {
  auto now = std::chrono::system_clock::now();
  return std::chrono::duration_cast<std::chrono::milliseconds>(
             now.time_since_epoch())
      .count();
}

int64_t DateTime::parse_ts(const string_& ts) {
  // ISO8601 string
  static std::regex ts_regex(
      R"(^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(:(\d{2})(\.\d{3,10})?)?((\+|-)(\d{2}):(\d{2})|Z|z)?$)");
  auto it = std::sregex_iterator(ts.begin(), ts.end(), ts_regex);
  if (it == std::sregex_iterator()) {  // match is a empty iterator
    return LLONG_MIN;
  }
  auto& match = *it;
  int year = atoi(match[1].str().c_str());
  int month = atoi(match[2].str().c_str());
  int day = atoi(match[3].str().c_str());

  int hour = atoi(match[4].str().c_str());
  int minute = atoi(match[5].str().c_str());
  int second = 0;
  int ms = 0;
  if (match[6].matched) {
    second = atoi(match[7].str().c_str());
    if (match[8].matched) {
      ms = atoi(match[8].str().substr(1, 3).c_str());
    }
  }

  boost::posix_time::ptime ptime(
      boost::gregorian::date(year, month, day),
      boost::posix_time::time_duration(hour, minute, second));
  if (match[9].matched) {
    int64_t since_epoch = (int64_t) to_time_t(ptime) * 1000 + ms;
    if (match[10].matched) {
      int tz_hour = atoi(match[11].str().c_str());
      int tz_minute = atoi(match[12].str().c_str());
      int tz_off = (tz_hour * 60 + tz_minute) * 60000;
      if (*match[10].first == '-') {
        return since_epoch + tz_off;
      } else {
        return since_epoch - tz_off;
      }
    } else {
      // Z or z
      return since_epoch;
    }
  } else {
    // TODO implement local time conversion
    // for now use UTC
    return to_time_t(ptime) * 1000 + ms;
  }
}
}  // namespace dsa

ext: cc


text:
// Copyright (c) 2015 Elements of Programming Interviews. All rights reserved.

#include <boost/thread.hpp>
#include <boost/thread/sync_bounded_queue.hpp>
#include <cassert>
#include <chrono>
#include <chrono>
#include <functional>
#include <iostream>
#include <string>
#include <unordered_set>

using std::stoi;
using std::bind;
using std::ref;
using std::pair;
using std::make_pair;
using std::unordered_set;
using std::cout;
using std::endl;
using std::chrono::system_clock;
using std::chrono::milliseconds;
using std::chrono::duration_cast;
using boost::thread_group;
using boost::sync_bounded_queue;
using boost::queue_op_status;

typedef unsigned long long CollatzInt;
typedef sync_bounded_queue<pair<CollatzInt, CollatzInt>> QueueType;
void Worker(CollatzInt lower, CollatzInt upper);
bool CollatzCheck(CollatzInt x, unordered_set<CollatzInt>& visited);

// @include
void ThreadFunc(QueueType& q) {
  pair<CollatzInt, CollatzInt> args;
  while (q.wait_pull_front(args) == queue_op_status::success) {
    Worker(args.first, args.second);
  }
}

// Performs basic unit of work
void Worker(CollatzInt lower, CollatzInt upper) {
  for (CollatzInt i = lower; i <= upper; ++i) {
    assert(CollatzCheck(i, unordered_set<CollatzInt>()));
  }
  cout << '(' << lower << ',' << upper << ')' << endl;
}

// Checks an individual number
bool CollatzCheck(CollatzInt x, unordered_set<CollatzInt>& visited) {
  if (x == 1) {
    return true;
  }
  if (!visited.emplace(x).second) {
    return false;
  }
  if (x & 1) {  // odd number
    return CollatzCheck(3 * x + 1, visited);
  } else {  // even number
    return CollatzCheck(x >> 1, visited);  // divide by 2
  }
}
// @exclude

// @include

int main(int argc, char* argv[]) {
  CollatzInt N = 10000000;
  CollatzInt RANGESIZE = 1000000;
  int NTHREADS = 4;
  // @exclude
  if (argc > 1) {
    N = stoi(argv[1]);
  }
  if (argc > 2) {
    RANGESIZE = stoi(argv[2]);
  }
  if (argc > 3) {
    NTHREADS = stoi(argv[3]);
  }

  assert(CollatzCheck(1, unordered_set<CollatzInt>()));
  assert(CollatzCheck(3, unordered_set<CollatzInt>()));
  assert(CollatzCheck(8, unordered_set<CollatzInt>()));
  auto start_time = system_clock::now();

  // @include
  // Uses synchronized bounded queue for task assignment and load balancing
  QueueType q(NTHREADS);
  thread_group threads;
  for (int i = 0; i < NTHREADS; ++i) {
    threads.create_thread(bind(ThreadFunc, ref(q)));
  }
  for (CollatzInt i = 0; i < N / RANGESIZE; ++i) {
    q << make_pair(i * RANGESIZE + 1, (i + 1) * RANGESIZE);
  }
  q.close();
  threads.join_all();

  // @exclude
  cout << "Finished all threads" << endl;
  auto running_time =
      duration_cast<milliseconds>(system_clock::now() - start_time).count();
  cout << "time in milliseconds for checking to " << N << " is "
       << running_time << '(' << N / running_time << " per ms)";

  // @include
  return 0;
}
// @exclude

max_stars_repo_name: powernit/epicode

max_issues_repo_name: powernit/epicode

max_forks_repo_name: powernit/epicode


text:
/* (C) 2003-2013 Willem Jan Hengeveld <itsme@xs4all.nl>
 * Web: http://www.xs4all.nl/~itsme/
 *
 */
#include <fstream>
#include <iostream>
#include <iomanip>
#include <cassert>
#include <string>
#include <vector>

#include <boost/format.hpp>

#ifdef _WIN32
#include <windows.h>
#include <tlhelp32.h>
#endif

// headers from the idasdk
#include "pro.h"     // for basic types.
#include "ida.hpp"   // for ida constants and types.
#include "idp.hpp"   // for interface version
#include "dbg.hpp"   // for 'dbg' global variable
#include "netnode.hpp"  // for RootNode

#include "expr.hpp"  // for IDCFuncs

#if IDA_SDK_VERSION >= 700
typedef ext_idcfunc_t extfun_t;

struct funcset_t {
  int qnty;                     ///< Number of functions
  ext_idcfunc_t *f;                  ///< Function table
};
funcset_t *find_idcfuncs()
{
    uint64_t *p = (uint64_t*)&callui;
    uint64_t *pend = (uint64_t*)&dbg;
    p++;
    while (p<pend && *p==0)
        p++;
    uint64_t addr_fnlist = (uint64_t )p;

    while (p<pend) {
        if (0x100 < *p && *p < 0x1000) {
            if (p[1]!=addr_fnlist) {
                msg("expected to find addr list after count %lld\n", p[0]);
            }
            break;
        }
        if (*p==addr_fnlist) {
            msg("expected to find count %lld before fnlist\n", p[-1]);
            p--;
            break;
        }
        p++;
    }
    if (p==pend) {
        msg("could not find fset\n");
        return nullptr;
    }

    uint32_t *pd = (uint32_t *)(p+9);
#ifdef IDA70BETA3
    typedef size_t (*ea2str_fn)(ea_t ea, char *buf, size_t bufsize);
#else
    typedef size_t (*ea2str_fn)(char *buf, size_t bufsize, ea_t ea);
#endif

    msg("fnlist = %llx, ea2str = %llx\n", addr_fnlist, (uint64_t)ea2str_fn(ea2str));
    msg("found idcfuncs @%p: %lld,  %llx, %llx, %llx, %llx,  %lld,  %llx, %llx, %llx, %d, %d, %d, %d\n",
            p,  p[0],  p[1], p[2], p[3], p[4],  p[5],  p[6], p[7], p[8],  pd[0], pd[1], pd[2], pd[3]);
    return (funcset_t*)p;
}

// memlayout:
// _callui   = sub_...
// ext_idcfunc_t fnlist[0x1ef] = { { }, ... }
// funcset_t IDCFuncs { 0x1ef, fnlist, sub, sub, sub, 0, netnode_inited, ea2str, sub, (int)9, 10, 15, 18, 7 }
//

funcset_t dummyfuncs = {0, nullptr};
funcset_t &IDCFuncs = dummyfuncs;
#endif

typedef std::vector<char> CharVector;

typedef struct {
    char  *function_name;      // 00
    char  *end_function_name;  // 04
    uint32_t w1;                  // 08
    uint32_t w2;                  // 0c
    uint8_t *after_end_fnname;   // 10
    uint32_t w4;                  // 14
    uint32_t nrparams;            // 18
    uint8_t *body;               // 1c
    uint8_t *end_body;           // 20
    uint32_t w5;                  // 24
    uint32_t w6;                  // 28
    uint32_t w7;                  // 2c
    uint32_t w8;                  // 30
} compiled_func1_t;

typedef struct {
    char  *function_name;      // 00
    char  *end_function_name;  // 04
    uint32_t w1;                  // 08
    uint32_t w2;                  // 0c
    uint8_t *after_end_fnname;   // 10
    uint32_t w4;                  // 14
    uint32_t nrparams;            // 18
    uint8_t *body;               // 1c
    uint32_t bodysize;            // 20
    uint32_t w5;                  // 24
} compiled_func2_t;

// ida530 and later
typedef struct {
    char *function_name;
    uint32_t namelen;
    uint32_t namelen2;
    uint32_t nrparams;
    uint8_t *body;
    uint32_t bodysize;
    uint32_t roundedbodysize;
} compiled_func3_t;

typedef struct {
    uint32_t unk0;
    char *filename;
    uint32_t namelen;
    uint32_t name_alloced;
} srcfile4_t;
#ifdef _WIN32
#define PACKED
#pragma pack(push,1)
#else
#define PACKED __attribute__((packed))
#endif
typedef struct PACKED {
    uint32_t unk0;
    char *filename;
    uint64_t namelen;
    uint64_t name_alloced;
} srcfile6_t;
#ifdef _WIN32
#pragma pack(pop)
#else
#define PACKED __attribute__((packed))
#endif

typedef struct {
    uint32_t ofs;
    uint32_t linenr;
} linenr4_t;
typedef struct {
    char *function_name;
    uint32_t namelen;
    uint32_t name_alloced;
    uint32_t nrparams;
    uint8_t *body;
    uint32_t bodysize;
    uint32_t body_alloced;
    uint32_t ofs_lastinsn;
    srcfile4_t *srcfile;
    uint32_t nsrc;
    uint32_t src_alloced;
    linenr4_t *lineinfo;
    uint32_t nlines;
    uint32_t line_alloced;
} compiled_func4_t;

typedef compiled_func4_t compiled_func5_t;

typedef struct {
    char *function_name;
    uint64_t namelen;
    uint64_t name_alloced;

    uint64_t nrparams;

    uint8_t *body;
    uint64_t bodysize;
    uint64_t body_alloced;

    uint64_t ofs_lastinsn;

    srcfile6_t *srcfile;
    uint64_t nsrc;
    uint64_t src_alloced;

    linenr4_t *lineinfo;
    uint64_t nlines;
    uint64_t line_alloced;

    void *unkinfo;
    uint64_t unkcount;
    uint64_t unkalloc;
} compiled_func6_t;

typedef struct {
    char *function_name;
    uint64_t namelen;
    uint64_t name_alloced;

    uint64_t nrparams;

    uint8_t *body;
    uint64_t bodysize;
    uint64_t body_alloced;

    uint64_t ofs_lastinsn;

    srcfile6_t *srcfile;
    uint64_t nsrc;
    uint64_t src_alloced;

    linenr4_t *lineinfo;
    uint64_t nlines;
    uint64_t line_alloced;

    void *unkinfo;
    uint64_t unkcount;
    uint64_t unkalloc;

    uint64_t unknown;
} compiled_func7_t;

// !!! GLOBAL ... initialized by dump_compiled_functions
//   used by disassemble, to resolve compiled functions indexes.

compiled_func1_t *g_flist1;
compiled_func1_t *g_end1;
compiled_func2_t *g_flist2;
compiled_func2_t *g_end2;
compiled_func3_t *g_flist3;
compiled_func3_t *g_end3;
compiled_func4_t *g_flist4;
compiled_func4_t *g_end4;
compiled_func5_t **g_flist5;
compiled_func6_t **g_flist6;
compiled_func7_t **g_flist7;

int g_type=0;
std::string getcompiledname(int id)
{
    if (g_flist1)
        return g_flist1[id].function_name;
    else if (g_flist2)
        return g_flist2[id].function_name;
    else if (g_flist3)
        return g_flist3[id].function_name;
    else if (g_flist4)
        return g_flist4[id].function_name;
    else if (g_flist5)
        return g_flist5[id]->function_name;
    else if (g_flist6)
        return g_flist6[id]->function_name;
    else if (g_flist7)
        return g_flist7[id]->function_name;
    else
        return "unknown!!!";
}

std::string hexdump(const uint8_t *p, int len)
{
    if (p==NULL)
        return "(null)";
    std::string str;
    for (int i=0 ; i<len ; i++) {
        if (!str.empty()) str += " ";
        char strbuf[16];
        qsnprintf(strbuf, 16, "%02x", p[i]);

        str += strbuf;
    }
    return str;
}

std::string ascdump(const unsigned char *buf, size_t len)
{
    const std::string& escaped="\n\r\t";
    bool bBreakOnEol= false;
    std::string result;
    bool bQuoted= false;
    bool bLastWasEolChar= false;

    if (len==size_t(-1))
        return "(null)";
    if (len==0)
        return "\"\"";

    if (len==4)
        result = str(boost::format("[%08lx]") % *(const long*)buf);

    for (size_t i=0 ; i<len ; i++)
    {
        bool bNeedsEscape= escaped.find((char)buf[i])!=escaped.npos
            || buf[i]=='\"'
            || buf[i]=='\\';

        if (isprint(buf[i]) || bNeedsEscape) {
            if (!bQuoted) {
                if (!result.empty())
                    result += ",";
                result += "\"";
                bQuoted= true;
            }
            if (bNeedsEscape) {
                std::string escapecode;
                switch(buf[i]) {
                    case '\n': escapecode= "\\n"; break;
                    case '\r': escapecode= "\\r"; break;
                    case '\t': escapecode= "\\t"; break;
                    case '\"': escapecode= "\\\""; break;
                    case '\\': escapecode= "\\\\"; break;
                    default:
                       escapecode = str(boost::format("\\x%02x") % (((unsigned int)buf[i])&0xff));
                }
                result += escapecode;
            }
            else {
                result += (char) buf[i];
            }
        }
        else {
            if (bQuoted) {
                result += "\"";
                bQuoted= false;
            }
            if (!result.empty())
                result += ",";
            result += str(boost::format("%02x") % (int)buf[i]);
        }
        bool bThisIsEolChar= (buf[i]==0x0a || buf[i]==0x0d);

        if (bLastWasEolChar && !bThisIsEolChar && bBreakOnEol)
            result += "\n";

        bLastWasEolChar= bThisIsEolChar;
    }

    if (bQuoted) {
        result += "\"";
        bQuoted= false;
    }

    return result;
}
std::string tagstr(char tag)
{
    if (tag>=' ' && tag<='~') {
        char strbuf[2];
        strbuf[0]= tag;
        strbuf[1]= 0;
        return std::string(strbuf);
    }
    else {
        char strbuf[16];
        qsnprintf(strbuf, 16, "%02x", (uint8_t)tag);
        return std::string(strbuf);
    }
}
std::ostream& operator<<(std::ostream& os, nodeidx_t idx)
{
    return os << boost::format("%08lx") % ((int)idx);
}
#if IDP_INTERFACE_VERSION<76
std::ostream& operator<<(std::ostream& os, netnode& node)
{
    os << boost::format("node %08lx ll=%d  %s\n")
            % ((nodeidx_t)node)
            % node.last_length()
            % (node.name()?node.name():"(null)");

    if (node.value_exists()) {
        os << boost::format("long_value: %08lx str=%s\n")
            % ascdump((unsigned char*)node.value(), MAXSPECSIZE);
    }
    else {
        os << "no value\n";
    }
    for (int tag= 0 ; tag < 0x100 ; tag++)
        for (nodeidx_t idx= node.supfirst(tag) ; idx!=BADNODE ; idx= node.supnext(idx, tag))
        {
            os << boost::format("[%s, %08lx] : alt=%08lx ch=%02x sup=%s\n")
                    % tagstr(tag) % idx
                    % node.altval(idx, tag)
                    % ((int)node.charval(idx, tag))
                    % ascdump((unsigned char*)node.supval(idx, tag), MAXSPECSIZE);
        }
/*
    for (int tag=0 ; tag<0x100 ; tag++)
        for (char* idx= node.hashfirst(tag) ; idx ; idx=node.hashnext(idx, tag))
            os << boost::format("hashval(%s, %s) : %s\n")
                    % tagstr(tag) % idx
                    % (node.hashval(idx, tag)?node.hashval(idx, tag):"(null)");
*/
/* ... netlink is missing from ida.lib
    netlink l;
    if (l.start())
        os << boost::format("listing links of type %s\n") % l.name();
        do {
            for (netnode n= l.firstlink(node); n!=BADNODE ; n= l.nextlink(node, n)) {
                os << boost::format("  link to %08lx %s\n") % (nodeidx_t)n % n.name();
            }
        } while (l.next());
*/
    return os;
}
#else   // idp >= 76
std::ostream& operator<<(std::ostream& os, netnode& node)
{
	qstring name;
    char buf[MAXSPECSIZE];

    node.get_name(&name);

	os << boost::format("node %08lx %s %s\n")
            % ((nodeidx_t)node)
            % ascdump((const uint8_t*)name.c_str(), name.size())
            % ascdump((unsigned char*)buf, node.valobj(buf, MAXSPECSIZE));

    for (int tag= 0 ; tag < 0x100 ; tag++)
        for (nodeidx_t idx= node.supfirst(tag) ; idx!=BADNODE ; idx= node.supnext(idx, tag))
        {
            os << boost::format("[%s, %08lx] : %s\n")
                    % tagstr(tag) % idx
                    % ascdump((unsigned char*)buf, node.supval(idx, buf, MAXSPECSIZE, tag));
        }

	for (int tag=0 ; tag<0x100 ; tag++) {

        // use two alternating buffers for comparing if we are still moving forward with 'H'
		char idx[2][1024];
        int hs[2];  hs[0]=0; hs[1]=0;
		int i=0;
        memset(idx, 0, sizeof(idx));
		for (hs[i]= node.hashfirst(idx[i], 1024, tag) ; hs[i]>0 ; hs[i]=node.hashnext(idx[i^1], idx[i], 1024, tag)) {
            if (hs[0]==hs[1] && memcmp(idx[0], idx[1], hs[0])==0)
                break;
            i ^= 1;

            if (node.supval(*(sval_t*)idx[i^1], NULL, 0, tag)<0)
                os << boost::format("hashval(%s, %s) : %s\n")
                    % tagstr(tag) % ascdump((unsigned char*)idx[i^1], hs[i^1])
                    % ascdump((unsigned char*)buf, node.hashval(idx[i^1], buf, MAXSPECSIZE, tag));
		}
	}

/* ... netlink is missing from ida.lib
    netlink l;
    if (l.start())
        os << boost::format("listing links of type %s\n") % l.name();
        do {
            for (netnode n= l.firstlink(node); n!=BADNODE ; n= l.nextlink(node, n)) {
                os << boost::format("  link to %08lx %s\n") % (nodeidx_t)n % n.name();
            }
        } while (l.next());
*/
    return os;
}
#endif
std::string functionargs_string(const char *args)
{
    std::string str;
    if (args==NULL)
        return "(null)";
    while (*args) {
        if (!str.empty()) str += ", ";
        switch(*args)
        {
            case VT_STR:   str += "string"; break;
            case VT_LONG:  str += "long"; break;
            case VT_FLOAT: str += "float"; break;
            case VT_WILD:  str += "..."; break;
#ifdef VT_OBJ
            case VT_OBJ:   str += "object"; break;
            case VT_FUNC:  str += "function"; break;
#ifdef VT_STR2
            case VT_STR2:  str += "string2"; break;
#endif
            case VT_PVOID: str += "pvoid"; break;
            case VT_INT64: str += "int64"; break;
            case VT_REF:   str += "vref"; break;
#endif
            default:
               char strbuf[16];
               qsnprintf(strbuf, 16, "VT_%08x", *args);
               str += strbuf;
        }

        args++;
    }
    return str;
}
std::string escapestring(const std::string& ascstr)
{
    std::string esc;
    for (std::string::const_iterator i= ascstr.begin() ; i!=ascstr.end() ; ++i) {
             if ((*i)=='\n') esc += "\\n";    // 0x0a newline
        else if ((*i)=='\r') esc += "\\r";    // 0x0d carriage return
        else if ((*i)=='\t') esc += "\\t";    // 0x09 tab
        else if ((*i)=='\\') esc += "\\\\";   // 0x5c backslash
        else if ((*i)=='\v') esc += "\\v";    // 0x0b vertical tab
        else if ((*i)=='\b') esc += "\\b";    // 0x08 backspace
        else if ((*i)=='\f') esc += "\\f";    // 0x0c form feed
        else if ((*i)=='\a') esc += "\\a";    // 0x07 bell
        else if ((*i)=='\"') esc += "\\\"";   // 0x22 double quote
        else if (isprint(*i))
            esc += (*i);
        else
            esc += str(boost::format("\\x%02x") % (((unsigned int)(*i))&0xff));
    }
    return esc;
}

uint16_t get16le(const uint8_t *p) { return p[0] | (p[1]<<8); }
uint32_t get32le(const uint8_t *p) { return get16le(p) | (get16le(p+2)<<16); }
uint64_t get64le(const uint8_t *p) { return get32le(p) | (uint64_t(get32le(p+4))<<32); }

// ida5.40 has the idc bytecode dispatcher table at ida.wll : 100D5703
void disassemble(std::ostream&os, const uint8_t *body, int len)
{
    for (int i=0 ; i<len ; i++)
    {
        os << boost::format("%p %04x  %02x")
            % (void*)(body+i)
            % i
            % ((int)body[i]);

        // nyble and byte must be 'int'  to make boostformat choose the right representation
        int nyble = body[i]&0xf;
        int byte  = (i+1<len)?body[i+1] : 0;
        uint16_t word  = (i+2<len)?get16le(&body[i+1]):0;
        uint32_t dword = (i+4<len)?get32le(&body[i+1]):0;
        uint64_t qword = (i+8<len)?get64le(&body[i+1]):0;

        switch(body[i]&0xf0) {
            case 0x00: // call internfunc 00-0f
                os << boost::format("          ; call %04x %s\n")
                    % nyble
                    % IDCFuncs.f[nyble].name;
                break;
            case 0x10: // call userdef func 00-0f
                os << boost::format("          ; call compiled func %02x %s\n")
                    % nyble
                    % getcompiledname(nyble);
                break;
            case 0x20: // pop var 00-0f
                os << boost::format("          ; pop var%02x\n")
                    % nyble;
                break;
            case 0x30: // pop param 00-0f
                os << boost::format("          ; pop param%02x\n")
                    % nyble;
                break;
            case 0x40: // var 00-0f = tos
                os << boost::format("          ; var%02x := tos\n")
                    % nyble;
                break;
            case 0x50: // param 00-0f = tos
                os << boost::format("          ; param%02x := tos\n")
                    % nyble;
                break;
            case 0x60: // push var 00-0f
                os << boost::format("          ; push var%02x\n")
                    % nyble;
                break;
            case 0x70: // push param 00-0f
                os << boost::format("          ; push param%02x\n")
                    % nyble;
                break;
            // case 0x80: these are handled in default:
            // case 0x90: unused
            // case 0xa0: these are handled in default:
            // case 0xb0: these are handled in default:
            // case 0xc0: these are handled in default:
            // case 0xd0: these are handled in default:
            case 0xe0:
                os << boost::format("          ; push #%02x\n")
                    % nyble;
                break;
            // case 0xf0: handled by default

            // handle non nyble oriented opcodes
            default: switch(body[i]) {
            case 0x80:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; call %04x %s\n")
                    % byte
                    % byte
                    % IDCFuncs.f[byte].name;
                i++;
                break;
            case 0x81:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                if (word>=IDCFuncs.qnty) { os << boost::format("\nERROR: too large internal funcid: %04x\n") % word; break; }
                os << boost::format(" %04x     ; call %04x %s\n")
                    % word
                    % word
                    % IDCFuncs.f[word].name;
                i += 2;
                break;
            case 0x82:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; call compiled func %02x %s\n")
                    % byte
                    % byte
                    % getcompiledname(byte);
                i++;
                break;
            case 0x83:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; call compiled func %04x %s\n")
                    % word
                    % word
                    % getcompiledname(word);
                i += 2;
                break;
            case 0x84:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; pop var%02x\n")
                    % byte
                    % byte;
                i++;
                break;
            case 0x85:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; pop var%04x\n")
                    % word
                    % word;
                i += 2;
                break;
            case 0x86:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; param%02x := tos\n")
                    % byte
                    % byte;
                i++;
                break;
            case 0x87:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; param%04x := tos\n")
                    % word
                    % word;
                i += 2;
                break;
            case 0x88:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; var%02x := tos\n")
                    % byte
                    % byte;
                i++;
                break;
            case 0x89:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; var%04x := tos\n")
                    % word
                    % word;
                i += 2;
                break;
            case 0x8a:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; pop param%02x\n")
                    % byte
                    % byte;
                i++;
                break;
            case 0x8b:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; pop param%04x\n")
                    % word
                    % word;
                i += 2;
                break;
            case 0x8c:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; push var%02x\n")
                    % byte
                    % byte;
                i++;
                break;
            case 0x8d:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; push var%04x\n")
                    % word
                    % word;
                i += 2;
                break;
            case 0x8e:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; push param%02x\n")
                    % byte
                    % byte;
                i++;
                break;
            case 0x8f:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x       ; push param%04x\n")
                    % word
                    % word;
                i += 2;
                break;
            // 0x90 is unused
            case 0xa0:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code (i=%d, l=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; push #%02x\n")
                    % byte
                    % byte;
                i++;
                break;
            case 0xa1:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; push #%04x\n")
                    % word
                    % word;
                i+=2;
                break;
            case 0xa2:  // todo: figure this one out
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; unknown %02x\n")
                    % byte
                    % byte;
                i++;
                break;

            case 0xa3: // todo: figure this one out
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; unknown %04x\n")
                    % word
                    % word;
                i+=2;
                break;

            case 0xa4:
                if (g_type<=3) {
                    if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                    os << boost::format(" %02x       ; allocate %d local variables\n")
                        % byte
                        % byte;
                    i++;
                }
                else {
                    os << boost::format("          ; invoke fucntion reference\n");
                }
                break;
            case 0xa5:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; allocate %d local variables\n")
                    % word
                    % word;
                i+=2;
                break;

            // a6 is probably NOP
            case 0xa6: os << boost::format("          ; unknown\n"); break;
            case 0xa7:
                if (i >= len-4) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %08x ; push #%08x\n")
                    % dword
                    % dword;
                i+=4;
                break;
            case 0xa8:
                if (i >= len-2-word) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x ... ; push \"%s\"\n")
                    % word
                    % escapestring(std::string((char*)body+i+3, word)).c_str();
                i+=word+2;
                break;
            case 0xa9:
                os << boost::format("          ; pop\n");
                break;
            case 0xaa:
                os << boost::format("          ; start function param list\n");
                break;
            case 0xab:
                if (i >= len-4) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %08x ; branch always %08x -> %04x\n")
                    % dword
                    % dword
                    % (i+dword+5);
                i+=4;
                break;
            case 0xac:
                if (i >= len-4) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %08x ; branch do_while true %08x -> %04x\n")
                    % dword
                    % dword
                    % (i+dword+5);
                i+=4;
                break;
            case 0xad:
                if (i >= len-4) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %08x ; branch if true %08x -> %04x\n")
                    % dword
                    % dword
                    % (i+dword+5);
                i+=4;
                break;
            case 0xae:
                if (g_type<=3) {
                    if (i >= len-2-word) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                    os << boost::format(" %04x ... ; call by name \"%s\"\n")
                        % word
                        % escapestring(std::string((char*)body+i+3, word)).c_str();
                    i+=word+2;
                }
                else {
                    if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                    if (byte==0xa4)
                        os << boost::format("%02x        ; call by name\n") % byte;
                    else if (byte==0x40)
                        os << boost::format("%02x        ; create function reference\n") % byte;
                    else
                        os << boost::format(" %02x       ; unknown\n") % byte;
                    i+=1;
                }
                break;
            case 0xaf:
                os << boost::format("          ; return\n");
                break;
            case 0xb0: os << boost::format("          ; add\n"); break;
            case 0xb1: os << boost::format("          ; substract\n"); break;
            case 0xb2: os << boost::format("          ; multiply\n"); break;
            case 0xb3: os << boost::format("          ; divide\n"); break;
            case 0xb4: os << boost::format("          ; modulus\n"); break;
            case 0xb5: os << boost::format("          ; logical or\n"); break;
            case 0xb6: os << boost::format("          ; logical and\n"); break;
            case 0xb7: os << boost::format("          ; logical not\n"); break;
            case 0xb8: os << boost::format("          ; bitwise or\n"); break;
            case 0xb9: os << boost::format("          ; bitwise and\n"); break;
            case 0xba: os << boost::format("          ; bitwise xor\n"); break;
            case 0xbb: os << boost::format("          ; unary bitwise negate\n"); break;
            case 0xbc: os << boost::format("          ; shiftright\n"); break;
            case 0xbd: os << boost::format("          ; shiftleft\n"); break;
            case 0xbe: os << boost::format("          ; unary minus\n"); break;
            case 0xbf: os << boost::format("          ; cv to string2\n"); break;
            case 0xc0:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; increment var%02x\n")
                    % byte
                    % byte;
                i++;
                break;
            case 0xc1:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; increment var%04x\n")
                    % word
                    % word;
                i += 2;
                break;
            case 0xc2:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; increment param%02x\n")
                    % byte
                    % byte;
                i++;
                break;
            case 0xc3:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; increment param%04x\n")
                    % word
                    % word;
                i+=2;
                break;
            case 0xc4:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; decrement var%02x\n")
                    % byte
                    % byte;
                i++;
                break;
            case 0xc5:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; decrement var%04x\n")
                    % word
                    % word;
                i+=2;
                break;
            case 0xc6:
                if (i >= len-1) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %02x       ; decrement param%02x\n")
                    % byte
                    % byte;
                i++;
                break;
            case 0xc7:
                if (i >= len-2) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
                os << boost::format(" %04x     ; decrement param%04x\n")
                    % word
                    % word;
                i+=2;
                break;
            case 0xc8: os << boost::format("          ; compare ==\n"); break;
            case 0xc9: os << boost::format("          ; compare !=\n"); break;
            case 0xca: os << boost::format("          ; compare <=\n"); break;
            case 0xcb: os << boost::format("          ; compare >=\n"); break;
            case 0xcc: os << boost::format("          ; compare <\n"); break;
            case 0xcd: os << boost::format("          ; compare >\n"); break;
            case 0xce: os << boost::format("          ; cv to integer\n"); break;
            case 0xcf: os << boost::format("          ; cv to string\n"); break;
            case 0xd0: os << boost::format("          ; cv to float\n"); break;
            case 0xd1: os << boost::format("          ; ?????\n"); break;
//              if (i >= len-12) { os << boost::format("\nERROR: unexpected end of code(i=%d, len=%d, opc=%02x)\n") %i %len %((int)body[i]); break; }
//              os << boost::format(" .......... ; push float %s\n")
//                  % hexdump(body+i+1, 12);
//              i+=12;

            // 0xd2 is unused
            case 0xd3: os << boost::format(" %09llx; push #%016llx\n") % qword % qword; i+=8; break;
            case 0xd4: os << boost::format(" %02x       ; push global %02x\n") % byte % byte; i+=1; break;
            case 0xd5: os << boost::format(" %04x     ; push global %04x\n") % word % word; i+=2; break;
            case 0xd6: os << boost::format(" %02x       ; pop global %02x\n") % byte % byte; i+=1; break;

            case 0xd7: os << boost::format(" %04x     ; pop global %04x\n") % word % word; i+=2; break;

                       // todo: d7 e101  -> set global eq to 01
                       //       d7 e000  -> set global eq to tos

                       // probably  global = tos
            case 0xd8: os << boost::format("          ; unknown\n"); break; // todo: figure this one out
            case 0xd9: os << boost::format("          ; unknown\n"); break; // todo: figure this one out
            case 0xda: os << boost::format(" %02x       ; inc global %02x\n") % byte % byte; i+=1; break;
            case 0xdb: os << boost::format(" %04x     ; inc global %04x\n") % word % word; i+=2; break;
            case 0xdc: os << boost::format(" %02x       ; dec global %02x\n") % byte % byte; i+=1; break;
            case 0xdd: os << boost::format(" %04x     ; dec global %04x\n") % word % word; i+=2; break;
            // case 0xde:  unused
            case 0xdf: os << boost::format("          ; throw\n"); break;
            case 0xf0:
                       os << boost::format(" %04x     ; create object %04x\n") % word % word;
                       // todo: decode object type
                       i+=2;
                       break;
            // case 0xf1: ...
            case 0xf2: os << boost::format("          ; get object property\n"); break;
            case 0xf4: os << boost::format("          ; set object property\n"); break;
            case 0xf5: os << boost::format("          ; increment object property\n"); break;
            case 0xf7: os << boost::format("          ; method call\n"); break;
            case 0xf8: os << boost::format("          ; ???object ref???\n"); break;
            case 0xf9: os << boost::format("          ; create reference\n"); break;
            // 0xfa
            case 0xfb: os << boost::format("          ; set slice\n"); break;
            case 0xfc: os << boost::format("          ; get slice\n"); break;
            // 0xfd
            case 0xfe: os << boost::format("          ; get item at\n"); break;
            case 0xff: os << boost::format("          ; set item at\n"); break;
            default:
                os << boost::format("            ; ERROR: unused opcode\n");
             }
        }
    }
}
void funcbody(std::ostream&os, const char *name)
{

#if (IDP_INTERFACE_VERSION>=70) && (IDA_SDK_VERSION<700)
    int nargs=0;
    size_t bodylen=0;
// get_idc_func_body is only available since version 4.70
    uint8_t *body= get_idc_func_body(name, &nargs, &bodylen);
    if (body)
    {
        os << boost::format("body: %08lx-%08lx: %s(%d)\n")
            % ((int)body)
            % ((int)body+bodylen)
            % name
            % nargs;
        disassemble(os, body, bodylen);
        os << "\n";
    }
#endif
}
std::ostream& operator<<(std::ostream& os, const extfun_t& f)
{
    funcbody(os, f.name);

#if IDP_INTERFACE_VERSION>70
    return os << boost::format("fu=%08llx fl=%08lx %s(%s)")
        % ((uint64_t)f.fptr)
        % f.flags
        % (f.name ? f.name : "(null)")
        % functionargs_string(f.args);
#else
    // no 'flags' in ida 4.70 and earlier
    return os << boost::format("fu=%08lx %s(%s)")
        % ((int)f.fp)
        % f.name
        % functionargs_string(f.args);

#endif
}
std::ostream& operator<<(std::ostream& os, funcset_t& fset)
{
    os << boost::format("%d functions in set %08lx\n") % fset.qnty % (long)&fset;
    for (int i=0 ; i<fset.qnty ; i++) {
        os << boost::format("function %d : %s\n") % i % fset.f[i];
    }
    return os;
}

/*idp = IDP_INTERFACE_VERSION
 *
 *  these are all offsets in ida.wll ( or ida64.wll )
 *
 *  for recent versions, the ptr is between the string '(null)' and 'funcbody_t:'
 *
 *idp              IDCFuncs   compiled    IDCFuncs64  exe version
 * 61 ida430a      100b76b8
 * 63 ida450       1009ad8c
 * 66 ida460       100b31e4                           4.06.0000.0785
 * 67 ida460sp1    100b5224                           4.06.0000.0809
 * 70 ida470       100baaf3   100db2bc                4.07.0000.0830
 *  ?                         100ec1b0
 * 75 ida480       100bf3c0   100F3CCC                4.08.0000.0847
 *  ? ida48991
 *  ? ida48992
 *  ? ida48993
 *  ? ida48994
 *  ? ida48995     100E13AC                           4.08.0001.0849
 * 76 ida490       100d3748   101019C0    100E6748    4.09.0000.0863
 * 76 ida490sp1    100e9778   1011c2c0    10104778    4.09.0000.0877
 * 76 ida500       100eb778   1011e880    10106778    5.00.0000.0879
 * 76 ida510b2     100f9a44               10116A44
 * 76 ida510       100f9f44   1012a860    10116F44    5.01.0000.0899
 * 76 ida520       1010837a   10136ef0                5.02.0000.0908
 * 76 ida520       10103116   101310C0                update
 * ??              1010a63e   10137224
 * ?? ida530       100ff4d3   1012bfa0?               5.3.0.916
 * ?? ida540b1     101164f3   10146e2c?               5.4.0.920
 *    ida570       10139fff   1016E550
 */
typedef struct {
    compiled_func1_t *start;
    compiled_func1_t *end;
} listinfo1_t;
typedef struct {
    compiled_func2_t *start;
    uint32_t count;
} listinfo2_t;
typedef struct {
    compiled_func3_t *start;
    uint32_t count;
} listinfo3_t;
typedef struct {
    compiled_func4_t *start;
    uint32_t count;
} listinfo4_t;
typedef struct {
    compiled_func5_t **start;
    uint32_t count;
} listinfo5_t;
typedef struct {
    compiled_func6_t **start;
    uint64_t count;
} listinfo6_t;
typedef struct {
    compiled_func7_t **start;
    uint64_t count;
} listinfo7_t;

void dump_idc_funcs1(std::ostream& os, listinfo1_t *flist)
{
    g_flist1= flist->start;
    g_end1= flist->end;
    for (compiled_func1_t *f= g_flist1 ; f<g_end1 ; f++) {
        os << boost::format("body: %08llx-%08llx: %s(%d)\n")
            % ((uint64_t)f->body)
            % ((uint64_t)f->end_body)
            % f->function_name
            % ((int)f->nrparams);
        disassemble(os, f->body, f->end_body-f->body);
    }
}

void dump_idc_funcs2(std::ostream& os, listinfo2_t *flist)
{
    g_flist2= flist->start;
    g_end2= flist->start+flist->count;
    for (compiled_func2_t *f= g_flist2 ; f<g_end2 ; f++) {
        os << boost::format("body: %08llx-%08llx: %s(%d)\n")
            % ((uint64_t)f->body)
            % (((uint64_t)f->body)+f->bodysize)
            % f->function_name
            % ((int)f->nrparams);
        disassemble(os, f->body, f->bodysize);
    }
}
void dump_idc_funcs3(std::ostream& os, listinfo3_t *flist)
{
    g_flist3= flist->start;
    g_end3= flist->start+flist->count;
    for (compiled_func3_t *f= g_flist3 ; f<g_end3 ; f++) {
        os << boost::format("body: %08llx-%08llx: %s(%d)\n")
            % ((uint64_t)f->body)
            % (((uint64_t)f->body)+f->bodysize)
            % f->function_name
            % ((int)f->nrparams);
        disassemble(os, f->body, f->bodysize);
    }
}
void dump_idc_funcs4(std::ostream& os, listinfo4_t *flist)
{
    g_flist4= flist->start;
    g_end4= flist->start+flist->count;
    for (compiled_func4_t *f= g_flist4 ; f<g_end4 ; f++) {
        os << boost::format("body: %08llx-%08llx: rec=%p  %s(%d)\n")
            % ((uint64_t)f->body)
            % (((uint64_t)f->body)+f->bodysize)
            % f
            % f->function_name
            % ((int)f->nrparams);
        disassemble(os, f->body, f->ofs_lastinsn);
        if (f->body) {
            os << "extra: ";
            os << hexdump(f->body+f->ofs_lastinsn, f->bodysize-f->ofs_lastinsn);
            os << "\n";
        }
    }
}
void dump_idc_funcs5(std::ostream& os, listinfo5_t *flist)
{
    g_flist5= flist->start;
    for (unsigned i=0 ; i<flist->count ; i++) {
        compiled_func5_t *f= flist->start[i];
        os << boost::format("body: %08llx-%08llx: rec=%p  %s(%d)\n")
            % ((uint64_t)f->body)
            % (((uint64_t)f->body)+f->bodysize)
            % f
            % f->function_name
            % ((int)f->nrparams);
        if (f->body) {
            disassemble(os, f->body, f->ofs_lastinsn);
            os << "extra: ";
            os << hexdump(f->body+f->ofs_lastinsn, f->bodysize-f->ofs_lastinsn);
            os << "\n";
        }
    }
}
void dump_idc_funcs6(std::ostream& os, listinfo6_t *flist)
{
    g_flist6= flist->start;
    for (unsigned i=0 ; i<flist->count ; i++) {
        compiled_func6_t *f= flist->start[i];
        os << boost::format("body: %08llx-%08llx: rec=%p  %s(%d)\n")
            % ((uint64_t)f->body)
            % (((uint64_t)f->body)+f->bodysize)
            % f
            % f->function_name
            % ((int)f->nrparams);
        if (f->body) {
            disassemble(os, f->body, f->ofs_lastinsn);
            os << "extra: ";
            os << hexdump(f->body+f->ofs_lastinsn, f->bodysize-f->ofs_lastinsn);
            os << "\n";
        }
    }
}
void dump_idc_funcs7(std::ostream& os, listinfo7_t *flist)
{
    g_flist7= flist->start;
    for (unsigned i=0 ; i<flist->count ; i++) {
        compiled_func7_t *f= flist->start[i];
        os << boost::format("body: %08llx-%08llx: rec=%p  %s(%d)\n")
            % ((uint64_t)f->body)
            % (((uint64_t)f->body)+f->bodysize)
            % f
            % f->function_name
            % ((int)f->nrparams);
        if (f->body) {
            disassemble(os, f->body, f->ofs_lastinsn);
            os << "extra: ";
            os << hexdump(f->body+f->ofs_lastinsn, f->bodysize-f->ofs_lastinsn);
            os << "\n";
        }
    }
}

std::string getkernelversion()
{
    char kversion[16];
    if (get_kernel_version(kversion, 16))
    {
        kversion[15] = 0;
        return kversion;
    }
    return "";
}

void dump_idc_funcs(std::ostream& os)
{
    std::string kernelversion = getkernelversion();

    uint64_t listptr= 0;
    g_type=0;
    switch((uint64_t)&IDCFuncs) {

//=========== windows versions of ida ====================
//case 0x100b76b8: flist=(listinfo_t*) 0; break;
//case 0x1009ad8c: flist=(listinfo_t*) 0; break;
//case 0x100b31e4: flist=(listinfo_t*) 0; break;
//case 0x100b5224: flist=(listinfo_t*) 0; break;
case 0x100baaf3: g_type=1; listptr= 0x100db2bc; break; //ida4.70 // ?? 0x100EC1B0;
case 0x100bf3c0: g_type=1; listptr= 0x100F3CCC; break; //ida4.80
case 0x100d3748: g_type=1; listptr= 0x101019C0; break; //ida4.90       - RootNode+0x0014   ida490/ida.wll

case 0x100e9778: g_type=1; listptr= 0x1011c2c0; break; //ida4.90sp1    - RootNode+0x0014   ida490_std/ida.wll, ida490sp1/ida.wll
case 0x100eb778: g_type=1; listptr= 0x1011e880; break; //ida5.00       - RootNode+0x0220   ida500/ida.wll
case 0x100f9f44: g_type=1; listptr= 0x1012a860; break; //ida5.10       - RootNode+0x00f4   ida510/ida.wll
//case 0x100f9a44: g_type=1; listptr= 0; break;
case 0x1010837a: g_type=2; listptr= 0x10136ef0; break; //ida5.20
case 0x10103116: g_type=2; listptr= 0x101310C0;        //ida5.20 update
                 if (*(uint64_t*)listptr==0) listptr= 0x101310AC; // ??
                 break;
case 0x1010a63e: g_type=2; listptr= 0x10137224; break; // ??
case 0x100ff4d3: g_type=3; listptr= 0x1012bfa0; break; // ida5.30      - RootNode+0x00f4   ida530/ida.wll
case 0x101164f3: g_type=3; listptr= 0x10146e2c; break; // ida5.40b1    - RootNode+0x0100   ida540b1/ida.wll
case 0x1011e1ef: g_type=3; listptr= 0x1014df14; break; // ida5.40      - RootNode+0x0100   ida540/ida.wll
case 0x1010f217: g_type=3; listptr= 0x101376b8; break; // ida5.50      - RootNode+0x00e0   ida550/ida.wll
case 0x1012db1b: g_type=4; listptr= 0x101608D4; break; // ida5.60      - RootNode+0x00f0   ida560_effe/ida.wll
case 0x10139fff: g_type=4; listptr= 0x1016E550; break; // ida5.70

                 // _RootNode + 0x20

//=========== macosx versions of ida ====================
case 0x00424880: g_type=5; listptr= 0x0043541c; break; // ida/mac 6.00.101001
case 0x00435880: g_type=5; listptr= 0x0044641c; break; // ida/mac 6.00.101104

case 0x004f3860: g_type=5; listptr= 0x00504fb0; break; // ida/mac 6.01.110408
// search for / 0[^0]0* 0*9 0*9 0*3 /  ( for _idcfunc entry )

// case 0x004f1b40: g_type=5; listptr= 0x00504fb0; break; // ida/mac 6.1.??
//
// .. preceeded by <d n="Output window" ...
//
case 0x005508c0: g_type=5; listptr= 0x00561c90; break; // ida/mac 6.2
case 0x005788c0: g_type=5; listptr= 0x00580c30; break; // ida/mac 6.3
case 0x005aa8c0: g_type=5; listptr= 0x005b2e0c; break; // ida/mac 6.4
case 0x005ac8c0: g_type=5; listptr= 0x005b4e0c; break; // ida/mac 6.4.1

case 0x007978c0: g_type=5; listptr= 0x0079f67c; break; // ida/mac 6.5
case 0x006688c0: g_type=5; listptr= 0x0067067c; break; // ida/mac 6.5.1
//case 0x0079d8c0: g_type=5; listptr= ; break; // ida/mac 6.5.1+
case 0x006233c0: g_type=5; listptr= 0x00629260; break; // ida 6.7
case 0x006453e0: g_type=5; listptr= 0x0064b2c0; break; // ida 6.8
case 0x006463e0: g_type=5; listptr= 0x0064c2c0; break; // ida 6.8.1
case 0x006824a0: g_type=5; listptr= 0x006883a0; break; // ida 6.9
case 0x0068b4a0: g_type=5; listptr= 0x006913c0; break; // ida 6.9.5
case 0x007b54a0: g_type=5; listptr= 0x007BB3C0; break; // ida 6.9.5
    }
    uint32_t lowbits_IDCFunc = ((uint64_t)&IDCFuncs)&0xFFF;
    if (kernelversion == "6.95" && lowbits_IDCFunc == 0x4A0) {
        g_type = 5;
        listptr = 0x5F20 + ((uint64_t)&IDCFuncs);
    }
    else if (kernelversion == "7.00" /*&& lowbits_IDCFunc == 0xdb8*/) {
        g_type = 6;
        listptr = 0x1E8 + ((uint64_t)&root_node);

        msg("idcfuncs=%llx -> list=%llx\n", ((uint64_t)&IDCFuncs), listptr);
    }
    else if (kernelversion == "7.1" /*&& IDCFunc == 0x100729f00, ea2str = 1004e1020 */) {
        g_type = 6;
        listptr = 0x1E8 + ((uint64_t)&root_node);

        msg("idcfuncs=%llx -> list=%llx\n", ((uint64_t)&IDCFuncs), listptr);
    }
    else if (kernelversion == "7.2" ) {
        g_type = 7;
        listptr = -0x88 + ((uint64_t)&root_node);

        msg("idcfuncs=%llx -> list=%llx\n", ((uint64_t)&IDCFuncs), listptr);
    }
    else if (kernelversion == "7.4" ) {
        g_type = 7;
        listptr = -0x88 + ((uint64_t)&root_node);
        msg("idcfuncs=%llx -> list=%llx\n", ((uint64_t)&IDCFuncs), -0x88 + ((uint64_t)&root_node));
    }

    if (listptr==0) {
        msg("IDCFuncs unknown: %p, kernelversion=%s\n", &IDCFuncs, kernelversion.c_str() );
        msg("  idcfuncs.qnty = %p, dummy = %p, rootnode = %p\n", &IDCFuncs.qnty, &dummyfuncs, &root_node);
        return;
    }
    if (g_type==1)
        dump_idc_funcs1(os, (listinfo1_t *)listptr);
    else if (g_type==2)
        dump_idc_funcs2(os, (listinfo2_t *)listptr);
    else if (g_type==3)
        dump_idc_funcs3(os, (listinfo3_t *)listptr);
    else if (g_type==4)
        dump_idc_funcs4(os, (listinfo4_t *)listptr);
    else if (g_type==5)
        dump_idc_funcs5(os, (listinfo5_t *)listptr);
    else if (g_type==6)
        dump_idc_funcs6(os, (listinfo6_t *)listptr);
    else if (g_type==7)
        dump_idc_funcs7(os, (listinfo7_t *)listptr);
}

void dump_db(int flags)
{
    std::filebuf fb; fb.open("dump_db.log", std::ios::out);
    std::ostream os(&fb);

    if (flags&1) {
        os << "------------rootnode-----------\n";
        os << root_node;

        os << "------------node.start.next-----------\n";
        netnode n;
        if (n.start())
            do {
                os << n;
            } while (n.next());
    }
    else {
#if IDA_SDK_VERSION >= 700
        funcset_t *pfuncs = find_idcfuncs();
        if (!pfuncs) {
            os << "--- could not find idcfuncs\n";
            return;
        }
        IDCFuncs = *pfuncs;
#endif
        os << "------------idcfuncs-----------\n";
        os << IDCFuncs;

        // note: there seems to be no official way of getting a list of
        // currently loaded idc functions.

        os << "------------compiled functions-----------\n";

        dump_idc_funcs(os);
    }
}

ext: cpp

max_stars_repo_name: fengjixuchui/idcinternals

max_issues_repo_name: fengjixuchui/idcinternals

max_forks_repo_name: fengjixuchui/idcinternals


text:
/*
@copyright Louis Dionne 2014
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#include <boost/hana/detail/assert.hpp>
#include <boost/hana/integral.hpp>
#include <boost/hana/list/instance.hpp>
using namespace boost::hana;
using namespace literals;

int main() {
    //! [main]
    BOOST_HANA_CONSTEXPR_ASSERT(
        concat(list(1, '2'), list(3.3, 4_c)) == list(1, '2', 3.3, 4_c)
    );
    //! [main]
}

max_stars_repo_name: rbock/hana

max_issues_repo_name: rbock/hana

max_forks_repo_name: rbock/hana