<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "device/bluetooth/bluetooth_device.h"

#include <string>

#include "base/strings/utf_string_conversions.h"
#include "device/bluetooth/bluetooth_gatt_service.h"
#include "grit/device_bluetooth_strings.h"
#include "ui/base/l10n/l10n_util.h"

namespace device {

BluetoothDevice::BluetoothDevice() {
}

BluetoothDevice::~BluetoothDevice() {
  STLDeleteValues(&gatt_services_);
}

base::string16 BluetoothDevice::GetName() const {
  std::string name = GetDeviceName();
  if (!name.empty()) {
    return base::UTF8ToUTF16(name);
  } else {
    return GetAddressWithLocalizedDeviceTypeName();
  }
}

base::string16 BluetoothDevice::GetAddressWithLocalizedDeviceTypeName() const {
  base::string16 address_utf16 = base::UTF8ToUTF16(GetAddress());
  BluetoothDevice::DeviceType device_type = GetDeviceType();
  switch (device_type) {
    case DEVICE_COMPUTER:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_COMPUTER,
                                        address_utf16);
    case DEVICE_PHONE:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_PHONE,
                                        address_utf16);
    case DEVICE_MODEM:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MODEM,
                                        address_utf16);
    case DEVICE_AUDIO:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_AUDIO,
                                        address_utf16);
    case DEVICE_CAR_AUDIO:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_CAR_AUDIO,
                                        address_utf16);
    case DEVICE_VIDEO:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_VIDEO,
                                        address_utf16);
    case DEVICE_JOYSTICK:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_JOYSTICK,
                                        address_utf16);
    case DEVICE_GAMEPAD:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_GAMEPAD,
                                        address_utf16);
    case DEVICE_KEYBOARD:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_KEYBOARD,
                                        address_utf16);
    case DEVICE_MOUSE:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MOUSE,
                                        address_utf16);
    case DEVICE_TABLET:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_TABLET,
                                        address_utf16);
    case DEVICE_KEYBOARD_MOUSE_COMBO:
      return l10n_util::GetStringFUTF16(
          IDS_BLUETOOTH_DEVICE_KEYBOARD_MOUSE_COMBO, address_utf16);
    default:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_UNKNOWN,
                                        address_utf16);
  }
}

BluetoothDevice::DeviceType BluetoothDevice::GetDeviceType() const {
  // https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
  uint32 bluetooth_class = GetBluetoothClass();
  switch ((bluetooth_class & 0x1f00) >> 8) {
    case 0x01:
      // Computer major device class.
      return DEVICE_COMPUTER;
    case 0x02:
      // Phone major device class.
      switch ((bluetooth_class & 0xfc) >> 2) {
        case 0x01:
        case 0x02:
        case 0x03:
          // Cellular, cordless and smart phones.
          return DEVICE_PHONE;
        case 0x04:
        case 0x05:
          // Modems: wired or voice gateway and common ISDN access.
          return DEVICE_MODEM;
      }
      break;
    case 0x04:
      // Audio major device class.
      switch ((bluetooth_class & 0xfc) >> 2) {
        case 0x08:
          // Car audio.
          return DEVICE_CAR_AUDIO;
        case 0x0b:
        case 0x0c:
        case 0x0d:
        case 0x0e:
        case 0x0f:
        case 0x010:
          // Video devices.
          return DEVICE_VIDEO;
        default:
          return DEVICE_AUDIO;
      }
      break;
    case 0x05:
      // Peripheral major device class.
      switch ((bluetooth_class & 0xc0) >> 6) {
        case 0x00:
          // "Not a keyboard or pointing device."
          switch ((bluetooth_class & 0x01e) >> 2) {
            case 0x01:
              // Joystick.
              return DEVICE_JOYSTICK;
            case 0x02:
              // Gamepad.
              return DEVICE_GAMEPAD;
            default:
              return DEVICE_PERIPHERAL;
          }
          break;
        case 0x01:
          // Keyboard.
          return DEVICE_KEYBOARD;
        case 0x02:
          // Pointing device.
          switch ((bluetooth_class & 0x01e) >> 2) {
            case 0x05:
              // Digitizer tablet.
              return DEVICE_TABLET;
            default:
              // Mouse.
              return DEVICE_MOUSE;
          }
          break;
        case 0x03:
          // Combo device.
          return DEVICE_KEYBOARD_MOUSE_COMBO;
      }
      break;
  }

  return DEVICE_UNKNOWN;
}

bool BluetoothDevice::IsPairable() const {
  DeviceType type = GetDeviceType();

  // Get the vendor part of the address: "00:11:22" for "00:11:22:33:44:55"
  std::string vendor = GetAddress().substr(0, 8);

  // Verbatim "Bluetooth Mouse", model 96674
  if ((type == DEVICE_MOUSE && vendor == "00:12:A1") ||
  // Microsoft "Microsoft Bluetooth Notebook Mouse 5000", model X807028-001
      (type == DEVICE_MOUSE && vendor == "7C:ED:8D"))
      return false;
  // TODO: Move this database into a config file.

  return true;
}

std::vector<BluetoothGattService*>
    BluetoothDevice::GetGattServices() const {
  std::vector<BluetoothGattService*> services;
  for (GattServiceMap::const_iterator iter = gatt_services_.begin();
       iter != gatt_services_.end(); ++iter)
    services.push_back(iter->second);
  return services;
}

BluetoothGattService* BluetoothDevice::GetGattService(
    const std::string& identifier) const {
  GattServiceMap::const_iterator iter = gatt_services_.find(identifier);
  if (iter != gatt_services_.end())
    return iter->second;
  return NULL;
}

}  // namespace device
<commit_msg>Minor cleanup in bluetooth_device.cc<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "device/bluetooth/bluetooth_device.h"

#include <string>

#include "base/strings/utf_string_conversions.h"
#include "device/bluetooth/bluetooth_gatt_service.h"
#include "grit/device_bluetooth_strings.h"
#include "ui/base/l10n/l10n_util.h"

namespace device {

BluetoothDevice::BluetoothDevice() {
}

BluetoothDevice::~BluetoothDevice() {
  STLDeleteValues(&gatt_services_);
}

base::string16 BluetoothDevice::GetName() const {
  std::string name = GetDeviceName();
  if (!name.empty()) {
    return base::UTF8ToUTF16(name);
  } else {
    return GetAddressWithLocalizedDeviceTypeName();
  }
}

base::string16 BluetoothDevice::GetAddressWithLocalizedDeviceTypeName() const {
  base::string16 address_utf16 = base::UTF8ToUTF16(GetAddress());
  BluetoothDevice::DeviceType device_type = GetDeviceType();
  switch (device_type) {
    case DEVICE_COMPUTER:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_COMPUTER,
                                        address_utf16);
    case DEVICE_PHONE:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_PHONE,
                                        address_utf16);
    case DEVICE_MODEM:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MODEM,
                                        address_utf16);
    case DEVICE_AUDIO:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_AUDIO,
                                        address_utf16);
    case DEVICE_CAR_AUDIO:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_CAR_AUDIO,
                                        address_utf16);
    case DEVICE_VIDEO:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_VIDEO,
                                        address_utf16);
    case DEVICE_JOYSTICK:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_JOYSTICK,
                                        address_utf16);
    case DEVICE_GAMEPAD:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_GAMEPAD,
                                        address_utf16);
    case DEVICE_KEYBOARD:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_KEYBOARD,
                                        address_utf16);
    case DEVICE_MOUSE:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_MOUSE,
                                        address_utf16);
    case DEVICE_TABLET:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_TABLET,
                                        address_utf16);
    case DEVICE_KEYBOARD_MOUSE_COMBO:
      return l10n_util::GetStringFUTF16(
          IDS_BLUETOOTH_DEVICE_KEYBOARD_MOUSE_COMBO, address_utf16);
    default:
      return l10n_util::GetStringFUTF16(IDS_BLUETOOTH_DEVICE_UNKNOWN,
                                        address_utf16);
  }
}

BluetoothDevice::DeviceType BluetoothDevice::GetDeviceType() const {
  // https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
  uint32 bluetooth_class = GetBluetoothClass();
  switch ((bluetooth_class & 0x1f00) >> 8) {
    case 0x01:
      // Computer major device class.
      return DEVICE_COMPUTER;
    case 0x02:
      // Phone major device class.
      switch ((bluetooth_class & 0xfc) >> 2) {
        case 0x01:
        case 0x02:
        case 0x03:
          // Cellular, cordless and smart phones.
          return DEVICE_PHONE;
        case 0x04:
        case 0x05:
          // Modems: wired or voice gateway and common ISDN access.
          return DEVICE_MODEM;
      }
      break;
    case 0x04:
      // Audio major device class.
      switch ((bluetooth_class & 0xfc) >> 2) {
        case 0x08:
          // Car audio.
          return DEVICE_CAR_AUDIO;
        case 0x0b:
        case 0x0c:
        case 0x0d:
        case 0x0e:
        case 0x0f:
        case 0x010:
          // Video devices.
          return DEVICE_VIDEO;
        default:
          return DEVICE_AUDIO;
      }
      break;
    case 0x05:
      // Peripheral major device class.
      switch ((bluetooth_class & 0xc0) >> 6) {
        case 0x00:
          // "Not a keyboard or pointing device."
          switch ((bluetooth_class & 0x01e) >> 2) {
            case 0x01:
              // Joystick.
              return DEVICE_JOYSTICK;
            case 0x02:
              // Gamepad.
              return DEVICE_GAMEPAD;
            default:
              return DEVICE_PERIPHERAL;
          }
          break;
        case 0x01:
          // Keyboard.
          return DEVICE_KEYBOARD;
        case 0x02:
          // Pointing device.
          switch ((bluetooth_class & 0x01e) >> 2) {
            case 0x05:
              // Digitizer tablet.
              return DEVICE_TABLET;
            default:
              // Mouse.
              return DEVICE_MOUSE;
          }
          break;
        case 0x03:
          // Combo device.
          return DEVICE_KEYBOARD_MOUSE_COMBO;
      }
      break;
  }

  return DEVICE_UNKNOWN;
}

bool BluetoothDevice::IsPairable() const {
  DeviceType type = GetDeviceType();

  // Get the vendor part of the address: "00:11:22" for "00:11:22:33:44:55"
  std::string vendor = GetAddress().substr(0, 8);

  // Verbatim "Bluetooth Mouse", model 96674
  if (type == DEVICE_MOUSE && vendor == "00:12:A1")
    return false;
  // Microsoft "Microsoft Bluetooth Notebook Mouse 5000", model X807028-001
  if (type == DEVICE_MOUSE && vendor == "7C:ED:8D")
    return false;
  // TODO: Move this database into a config file.

  return true;
}

std::vector<BluetoothGattService*>
    BluetoothDevice::GetGattServices() const {
  std::vector<BluetoothGattService*> services;
  for (GattServiceMap::const_iterator iter = gatt_services_.begin();
       iter != gatt_services_.end(); ++iter)
    services.push_back(iter->second);
  return services;
}

BluetoothGattService* BluetoothDevice::GetGattService(
    const std::string& identifier) const {
  GattServiceMap::const_iterator iter = gatt_services_.find(identifier);
  if (iter != gatt_services_.end())
    return iter->second;
  return NULL;
}

}  // namespace device
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <stack>
#include <map>
#include <assert.h>
#include <fstream>

// From git file
#include "include/yaml.h"
#include "yaml-cpp/yaml.h"

// ---------------------------------------------------------------------------------
// ------------------------------- libyaml test code -------------------------------
// ---------------------------------------------------------------------------------

std::string positionAnalysis(char reference_character, bool map_mode)
{
    if (reference_character == 'M')
    {
        if (map_mode)
        {
            return "K:";
        }
        else
        {
            return "V:";
        }
        map_mode = !map_mode;
    }
    else if (reference_character == 'S')
    {
        return "L:";
    }
    else
    {
        return "U:";
    }

}

void addToMap(std::map<std::string, std::string> & anchor_map,
    std::string& anchor, std::string& anchor_data)
{
    if (&anchor != nullptr)
    {
        if (anchor_map.count(anchor))
        {
            anchor_map[anchor] = anchor_data;
        }
        else
        {
            anchor_map.insert({anchor, anchor_data});
        }
    }
}

void addInfoToDataStack(std::stack<std::string>& anchor_data,
    std::string info)
{
    if (!anchor_data.empty())
    {
        std::string& temp = anchor_data.top();
        temp += info;
    }
    else
    {
        anchor_data.push(info);
    }
}

std::string parseLibyaml(std::string name_of_file)
{
    FILE *input;
    yaml_parser_t parser;
    yaml_event_t event;

    int flow = -1;
    int i = 0;
    int foundfile = 0;

    std::string libyaml_final_output = "";

    std::map<std::string, std::string> anchor_map;

    std::stack<std::string> anchor_save_stack;

    std::stack<std::string> anchor_data_save_stack;

    std::stack<char> mode_stack;

    bool map_mode = true;

    input = fopen(name_of_file.c_str(), "rb");
    foundfile = 1;

    if (!foundfile)
    {
        input = stdin;
    }
    assert(input);

    if (!yaml_parser_initialize(&parser))
    {
        return "ERROR: Could not initialize the parser object\n";
    }
    yaml_parser_set_input_file(&parser, input);

    while (1)
    {
        std::string local_event_output = "";

        yaml_event_type_t type;

        if (!yaml_parser_parse(&parser, &event))
        {
            if ( parser.problem_mark.line || parser.problem_mark.column )
            {
                fprintf(stderr, "Parse error: %s\nLine: %lu Column: %lu\n",
                    parser.problem,
                    (unsigned long)parser.problem_mark.line + 1,
                    (unsigned long)parser.problem_mark.column + 1);
            }
            else {
                fprintf(stderr, "Parse error: %s\n", parser.problem);
            }
            return "ERROR: Bad parsing";
        }
        type = event.type;

        switch (type)
        {
            case YAML_NO_EVENT:
                local_event_output += ("???\n");

                break;
            case YAML_STREAM_START_EVENT:
                break;
            case YAML_STREAM_END_EVENT:
                if (!anchor_save_stack.empty())
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                }

                break;
            case YAML_DOCUMENT_START_EVENT:
                if (!event.data.document_start.implicit)
                    local_event_output += (" ---");

                break;
            case YAML_DOCUMENT_END_EVENT:
                if (!event.data.document_end.implicit)
                    local_event_output += (" ...");

                if (!anchor_save_stack.empty())
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                }

                break;
            case YAML_MAPPING_START_EVENT:
                if(!mode_stack.empty())
                {
                    local_event_output += positionAnalysis(mode_stack.top(), map_mode) + "\n";
                }

                mode_stack.push('M');

                map_mode = true;

                if (flow == 0 && event.data.mapping_start.style == YAML_FLOW_MAPPING_STYLE)
                    local_event_output += (" {}");

                else if (flow == 1)
                    local_event_output += (" {}");

                if (event.data.mapping_start.anchor)
                {
                    anchor_save_stack.push(((char*)event.data.mapping_start.anchor));
                }
                if (event.data.mapping_start.tag)
                {
                    std::string temp_translator = ((char*)event.data.mapping_start.tag);

                    local_event_output += " " + temp_translator + " - ";
                }

                break;
            case YAML_MAPPING_END_EVENT:
                mode_stack.pop();

                if (!anchor_save_stack.empty())
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                }

                break;
            case YAML_SEQUENCE_START_EVENT:
                if(!mode_stack.empty())
                {
                    local_event_output += positionAnalysis(mode_stack.top(), map_mode) + "\n";
                }

                map_mode != map_mode;

                mode_stack.push('S');

                if (flow == 0 && event.data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE)
                    local_event_output += (" []");

                else if (flow == 1)
                    local_event_output += (" []");

                if (event.data.sequence_start.anchor)
                if (event.data.scalar.anchor)
                {
                    anchor_save_stack.push((char*)event.data.sequence_start.anchor);
                }
                if (event.data.sequence_start.tag)
                {
                    std::string temp_translator = ((char*)event.data.sequence_start.tag);

                    local_event_output += (" " + temp_translator + " - ");
                }

                break;
            case YAML_SEQUENCE_END_EVENT:
                mode_stack.pop();

                if (!anchor_save_stack.empty())
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                }

                break;
            case YAML_SCALAR_EVENT:
                local_event_output += positionAnalysis(mode_stack.top(), map_mode);

                map_mode != map_mode;

                if (event.data.scalar.tag)
                {
                    std::string temp_translator = ((char*)event.data.scalar.tag);

                    local_event_output += " " + temp_translator + " - ";
                }
                else
                {
                    local_event_output += " - ";
                }

                if (event.data.scalar.anchor)
                {
                    anchor_save_stack.push((char*)event.data.scalar.anchor);
                }

                local_event_output += std::string((char*)event.data.scalar.value, event.data.scalar.length);

                local_event_output += ("\n");

                break;
            case YAML_ALIAS_EVENT:
            {
                std::string temp_translator = ((char*) event.data.alias.anchor);

                local_event_output += positionAnalysis(mode_stack.top(), map_mode) + " - " + temp_translator + "\n";

                map_mode != map_mode;

                std::string& temp_holder = anchor_map[temp_translator];

                if (!temp_holder.empty())
                {
                    local_event_output += temp_holder;
                }
                else
                {
                    local_event_output += "ERROR";
                }
                break;
            }
            default:
                abort();
        }

        yaml_event_delete(&event);

        if (type == YAML_STREAM_END_EVENT)
            break;

        addInfoToDataStack(anchor_data_save_stack, local_event_output);

        libyaml_final_output += local_event_output;
    }

    assert(!fclose(input));

    yaml_parser_delete(&parser);

    fflush(stdout);

    return libyaml_final_output;
}

// ---------------------------------------------------------------------------------
// ------------------------------ yaml-cpp test code -------------------------------
// ---------------------------------------------------------------------------------

std::string parseYamlCppNode(YAML::Node& head)
{
    std::stack <YAML::Node> iteration_list_stack;

    std::stack <std::string> additional_info_stack;

    iteration_list_stack.push(head);
    additional_info_stack.push("s");

    std::string yamlcpp_final_output = "";

    int key_counter = 1;

    while (!iteration_list_stack.empty())
    {
        YAML::Node base_iterator = iteration_list_stack.top();
        iteration_list_stack.pop();

        yamlcpp_final_output += additional_info_stack.top() + ": ";
        additional_info_stack.pop();

        // Processes tags:
        const std::string& tag_holder = base_iterator.Tag();

        if(tag_holder != "?" && tag_holder != "!")
        {
            yamlcpp_final_output += tag_holder + " ";
        }

        switch (base_iterator.Type())
        {
            case YAML::NodeType::Null:
            {
                yamlcpp_final_output += "- Null case";
                break;
            }
            case YAML::NodeType::Scalar:
            {
                // if(map_mode)
                // {
                //     if(key_counter%2)
                //     {
                //         yamlcpp_final_output += "K";
                //     }
                //     else
                //     {
                //         yamlcpp_final_output += "V";

                //     }
                // }
                // else
                // {
                //     yamlcpp_final_output += "V";
                // }

                // key_counter--;

                yamlcpp_final_output +=  "- " + base_iterator.as<std::string>() + "\n";
                break;
            }
            case YAML::NodeType::Sequence:
            {
                yamlcpp_final_output += "\n";
                for (int i = base_iterator.size() - 1; i >= 0; i--)
                {
                    iteration_list_stack.push(base_iterator[i]);
                    additional_info_stack.push("L");
                }

                break;
            }
            case YAML::NodeType::Map:
            {
                yamlcpp_final_output += "\n";
                std::stack <YAML::const_iterator> loca_iterators_temp_stack;

                for (YAML::const_iterator it = base_iterator.begin(); it != base_iterator.end(); ++it)
                {
                    loca_iterators_temp_stack.push(it);
                }

                while (!loca_iterators_temp_stack.empty())
                {
                    YAML::const_iterator it = loca_iterators_temp_stack.top();
                    loca_iterators_temp_stack.pop();

                    iteration_list_stack.push(it->second);
                    additional_info_stack.push("V");
                    iteration_list_stack.push(it->first);
                    additional_info_stack.push("K");
                }
                break;
            }
            case YAML::NodeType::Undefined:
            {
                yamlcpp_final_output += "- Undef \n";

                break;
            }
            default:
            {
                yamlcpp_final_output += "- ERROR: Unknown Input Type \n";
            }
        }
    }
    return yamlcpp_final_output;
}

// ---------------------------------------------------------------------------------
// -------------------------------------- main -------------------------------------
// ---------------------------------------------------------------------------------
int main(int argc, char* args[])
{
    std::cout << "----------- libyaml tests -----------" << std::endl;

    // parseLibyaml(args[1]);

    std::string libyaml_final_output = parseLibyaml(args[1]);
    std::cout << libyaml_final_output << std::endl;

    std::cout << "----------- yaml-cpp tests -----------" << std::endl;

    std::string yamlcpp_final_output;
    try
    {
        YAML::Node node = YAML::LoadFile(args[1]);
        // YAML::Node node = YAML::Load("[1, 2, 3]");
        std::cout << "Node type: " << node.Type() << std::endl;

        yamlcpp_final_output = parseYamlCppNode(node);
    }
    catch (const std::exception& err)
    {
        std::cout << err.what() << std::endl;
    }

    std::cout << "--------yaml-cpp Output:" << std::endl;
    std::cout << yamlcpp_final_output << std::endl;
    std::cout << "--------" << std::endl;

    return 0;
}

// \0 in the middle<commit_msg>Better Normalization For Libyaml(work in progress)<commit_after>#include <iostream>
#include <string>
#include <stack>
#include <map>
#include <assert.h>
#include <fstream>

// From git file
#include "include/yaml.h"
#include "yaml-cpp/yaml.h"

// ---------------------------------------------------------------------------------
// ------------------------------- libyaml test code -------------------------------
// ---------------------------------------------------------------------------------

bool positionAnalysis(std::string& add_to_me, char reference_character, bool map_mode)
{
    if (reference_character == 'M')
    {
        if (map_mode)
        {
            add_to_me += "K: ";
        }
        else
        {
            add_to_me += "V: ";
        }
        return !map_mode;
    }
    else if (reference_character == 'S')
    {
        add_to_me += "L: ";
    }
    else
    {
        add_to_me += "U: ";
    }

    return map_mode;
}

void addToMap(std::map<std::string, std::string> & anchor_map,
    std::string& anchor, std::string& anchor_data)
{
    if (&anchor != nullptr)
    {
        if (anchor_map.count(anchor))
        {
            anchor_map[anchor] = anchor_data;
        }
        else
        {
            anchor_map.insert({anchor, anchor_data});
        }
    }
}

void addInfoToDataStack(std::stack<std::string>& anchor_data,
    std::string info)
{
    if (!anchor_data.empty())
    {
        std::string& temp = anchor_data.top();
        temp += info;
    }
    else
    {
        anchor_data.push(info);
    }
}

std::string parseLibyaml(std::string name_of_file)
{
    FILE *input;
    yaml_parser_t parser;
    yaml_event_t event;

    int flow = -1;
    int i = 0;
    int foundfile = 0;

    std::string libyaml_final_output = "";

    std::map<std::string, std::string> anchor_map;

    std::stack<std::string> anchor_save_stack;

    std::stack<std::string> anchor_data_save_stack;

    std::stack<char> mode_stack;

    mode_stack.push(' ');

    std::stack<bool> map_mode_stack;

    bool map_mode = true;

    input = fopen(name_of_file.c_str(), "rb");
    foundfile = 1;

    if (!foundfile)
    {
        input = stdin;
    }
    assert(input);

    if (!yaml_parser_initialize(&parser))
    {
        return "ERROR: Could not initialize the parser object\n";
    }
    yaml_parser_set_input_file(&parser, input);

    while (1)
    {
        std::string local_event_output = "";

        yaml_event_type_t type;

        if (!yaml_parser_parse(&parser, &event))
        {
            if ( parser.problem_mark.line || parser.problem_mark.column )
            {
                fprintf(stderr, "Parse error: %s\nLine: %lu Column: %lu\n",
                    parser.problem,
                    (unsigned long)parser.problem_mark.line + 1,
                    (unsigned long)parser.problem_mark.column + 1);
            }
            else {
                fprintf(stderr, "Parse error: %s\n", parser.problem);
            }
            return "ERROR: Bad parsing";
        }
        type = event.type;

        switch (type)
        {
            case YAML_NO_EVENT:
                local_event_output += ("???\n");

                break;
            case YAML_STREAM_START_EVENT:
                break;
            case YAML_STREAM_END_EVENT:
                if (!anchor_save_stack.empty())
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                }

                break;
            case YAML_DOCUMENT_START_EVENT:
                if (!event.data.document_start.implicit)
                {
                    // local_event_output += (" ---");
                }

                break;
            case YAML_DOCUMENT_END_EVENT:
                if (!event.data.document_end.implicit)
                {
                    // local_event_output += (" ...");
                }

                if (!anchor_save_stack.empty())
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                }

                break;
            case YAML_MAPPING_START_EVENT:
                if (!mode_stack.empty())
                {
                    // local_event_output += "->";
                    positionAnalysis(local_event_output, mode_stack.top(), map_mode);
                }

                if(mode_stack.top()=='M')
                {
                    map_mode_stack.push(map_mode);
                }

                mode_stack.push('M');

                map_mode = true;

                if (flow == 0 && event.data.mapping_start.style == YAML_FLOW_MAPPING_STYLE)
                    local_event_output += (" {}");

                else if (flow == 1)
                    local_event_output += (" {}");

                if (event.data.mapping_start.anchor)
                {
                    anchor_save_stack.push(((char*)event.data.mapping_start.anchor));
                }
                if (event.data.mapping_start.tag)
                {
                    std::string temp_translator = ((char*)event.data.mapping_start.tag);

                    local_event_output += temp_translator + "\n";
                }
                else
                {
                    local_event_output += "\n";
                }

                break;
            case YAML_MAPPING_END_EVENT:
                mode_stack.pop();

                if(mode_stack.top()=='M')
                {
                    map_mode = map_mode_stack.top();
                    map_mode_stack.pop();
                }

                if (!anchor_save_stack.empty())
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                }

                break;
            case YAML_SEQUENCE_START_EVENT:
                if (!mode_stack.empty())
                {
                    map_mode = positionAnalysis(local_event_output, mode_stack.top(), map_mode);
                }

                mode_stack.push('S');

                if (flow == 0 && event.data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE)
                    local_event_output += ("[]");

                else if (flow == 1)
                    local_event_output += ("[]");

                if (event.data.sequence_start.anchor)
                if (event.data.scalar.anchor)
                {
                    anchor_save_stack.push((char*)event.data.sequence_start.anchor);
                }
                if (event.data.sequence_start.tag)
                {
                    std::string temp_translator = ((char*)event.data.sequence_start.tag);

                    local_event_output += (temp_translator + "\n");
                }
                else
                {
                    local_event_output += "\n";
                }

                break;
            case YAML_SEQUENCE_END_EVENT:
                mode_stack.pop();

                if (!anchor_save_stack.empty())
                {
                    addToMap(anchor_map, anchor_save_stack.top(), anchor_data_save_stack.top());
                    anchor_save_stack.pop();
                    anchor_data_save_stack.pop();
                }

                break;
            case YAML_SCALAR_EVENT:
                map_mode = positionAnalysis(local_event_output, mode_stack.top(), map_mode);

                if (event.data.scalar.tag)
                {
                    std::string temp_translator = ((char*)event.data.scalar.tag);

                    local_event_output += temp_translator + " - ";
                }
                else
                {
                    local_event_output += "- ";
                }

                if (event.data.scalar.anchor)
                {
                    anchor_save_stack.push((char*)event.data.scalar.anchor);
                }

                local_event_output += std::string((char*)event.data.scalar.value, event.data.scalar.length);

                local_event_output += ("\n");

                break;
            case YAML_ALIAS_EVENT:
            {
                std::string temp_translator = ((char*) event.data.alias.anchor);

                map_mode = positionAnalysis(local_event_output, mode_stack.top(), map_mode);

                local_event_output += "- " + temp_translator + "\n";

                std::string& temp_holder = anchor_map[temp_translator];

                if (!temp_holder.empty())
                {
                    local_event_output += temp_holder;
                }
                else
                {
                    local_event_output += "ERROR";
                }
                break;
            }
            default:
                abort();
        }

        yaml_event_delete(&event);

        if (type == YAML_STREAM_END_EVENT)
            break;

        addInfoToDataStack(anchor_data_save_stack, local_event_output);

        libyaml_final_output += local_event_output;
    }

    assert(!fclose(input));

    yaml_parser_delete(&parser);

    fflush(stdout);

    return libyaml_final_output;
}

// ---------------------------------------------------------------------------------
// ------------------------------ yaml-cpp test code -------------------------------
// ---------------------------------------------------------------------------------

std::string parseYamlCppNode(YAML::Node& head)
{
    std::stack <YAML::Node> iteration_list_stack;

    std::stack <std::string> additional_info_stack;

    iteration_list_stack.push(head);
    additional_info_stack.push("U");

    std::string yamlcpp_final_output = "";

    int key_counter = 1;

    while (!iteration_list_stack.empty())
    {
        YAML::Node base_iterator = iteration_list_stack.top();
        iteration_list_stack.pop();

        yamlcpp_final_output += additional_info_stack.top() + ": ";
        additional_info_stack.pop();

        // Processes tags:
        const std::string& tag_holder = base_iterator.Tag();

        if(tag_holder != "?" && tag_holder != "!")
        {
            yamlcpp_final_output += tag_holder + " ";
        }

        switch (base_iterator.Type())
        {
            case YAML::NodeType::Null:
            {
                yamlcpp_final_output += "- Null case";
                break;
            }
            case YAML::NodeType::Scalar:
            {
                yamlcpp_final_output +=  "- " + base_iterator.as<std::string>() + "\n";
                break;
            }
            case YAML::NodeType::Sequence:
            {
                yamlcpp_final_output += "\n";
                for (int i = base_iterator.size() - 1; i >= 0; i--)
                {
                    iteration_list_stack.push(base_iterator[i]);
                    additional_info_stack.push("L");
                }

                break;
            }
            case YAML::NodeType::Map:
            {
                yamlcpp_final_output += "\n";
                std::stack <YAML::const_iterator> loca_iterators_temp_stack;

                for (YAML::const_iterator it = base_iterator.begin(); it != base_iterator.end(); ++it)
                {
                    loca_iterators_temp_stack.push(it);
                }

                while (!loca_iterators_temp_stack.empty())
                {
                    YAML::const_iterator it = loca_iterators_temp_stack.top();
                    loca_iterators_temp_stack.pop();

                    iteration_list_stack.push(it->second);
                    additional_info_stack.push("V");
                    iteration_list_stack.push(it->first);
                    additional_info_stack.push("K");
                }
                break;
            }
            case YAML::NodeType::Undefined:
            {
                yamlcpp_final_output += "- Undef \n";

                break;
            }
            default:
            {
                yamlcpp_final_output += "- ERROR: Unknown Input Type \n";
            }
        }
    }
    return yamlcpp_final_output;
}

bool compareStringsCustom(std::string compareMeOne, std::string compareMeTwo)
{
    std::string::iterator ptrOne = compareMeOne.begin();
    std::string::iterator ptrTwo = compareMeTwo.begin();

    while (*ptrOne == *ptrTwo && ((ptrOne != compareMeOne.end()) || (ptrTwo != compareMeTwo.end())))
    {
        if(*ptrOne == *ptrTwo)
        {
            std::cout << *ptrTwo;
        }
        ptrOne++;
        ptrTwo++;
    }

    if(!((ptrOne == compareMeOne.end())  && (ptrTwo == compareMeTwo.end())))
    {
        std::cout << "(X)";
        return false;
    }
    else
    {
        return true;
    }
}

// ---------------------------------------------------------------------------------
// -------------------------------------- main -------------------------------------
// ---------------------------------------------------------------------------------
int main(int argc, char* args[])
{
    std::cout << "----------- libyaml tests -----------" << std::endl;

    // parseLibyaml(args[1]);

    std::string libyaml_final_output = parseLibyaml(args[1]);
    std::cout << libyaml_final_output << std::endl;

    std::cout << "----------- yaml-cpp tests -----------" << std::endl;

    std::string yamlcpp_final_output;
    try
    {
        YAML::Node node = YAML::LoadFile(args[1]);
        // YAML::Node node = YAML::Load("[1, 2, 3]");
        std::cout << "Node type: " << node.Type() << std::endl;

        yamlcpp_final_output = parseYamlCppNode(node);
    }
    catch (const std::exception& err)
    {
        std::cout << err.what() << std::endl;
    }

    std::cout << "--------yaml-cpp Output:" << std::endl;
    std::cout << yamlcpp_final_output << std::endl;
    std::cout << "--------" << std::endl;
    std::cout << "- Conclusion: " << std::endl;

    if(compareStringsCustom(libyaml_final_output, yamlcpp_final_output))
    {
        std::cout << "(END)" << std::endl;
        std::cout << "Cases equal!" << std::endl;
    }
    else
    {
        std::cout << "(END)" << std::endl;
        std::cout << "Cases different!" << std::endl;
    }

    return 0;
}

// \0 in the middle<|endoftext|>


<commit_before>/**
 * @file heartbeats.cpp
 * @brief Classes for heartbeating Sync configuration and status
 *
 * (c) 2013 by Mega Limited, Auckland, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "mega/heartbeats.h"
#include "mega/command.h"
#include "assert.h"
#include "mega.h"

namespace mega {

#ifdef ENABLE_SYNC

HeartBeatBackupInfo::HeartBeatBackupInfo()
{
}

double HeartBeatBackupInfo::progress(m_off_t inflightProgress) const
{
    return mProgress + static_cast<double>(inflightProgress);
}

void HeartBeatBackupInfo::invalidateProgress()
{
    mProgressInvalid = true;
}

m_time_t HeartBeatBackupInfo::lastAction() const
{
    return mLastAction;
}

handle HeartBeatBackupInfo::lastItemUpdated() const
{
    return mLastItemUpdated;
}

void HeartBeatBackupInfo::setLastSyncedItem(const handle &lastSyncedItem)
{
    if (mLastItemUpdated != lastSyncedItem)
    {
        mLastItemUpdated = lastSyncedItem;
        updateLastActionTime();
    }
}

void HeartBeatBackupInfo::setSPState(SPState state)
{
    if (mSPState != state)
    {
        mSPState = state;
        updateLastActionTime();
    }
}

void HeartBeatBackupInfo::setProgress(const double &progress)
{
    mProgressInvalid = false;
    mProgress = progress;
    updateLastActionTime();
}

void HeartBeatBackupInfo::setLastAction(const m_time_t &lastAction)
{
    mLastAction = lastAction;
}

void HeartBeatBackupInfo::updateLastActionTime()
{
    setLastAction(m_time(nullptr));
    mModified = true;
}

void HeartBeatBackupInfo::setLastBeat(const m_time_t &lastBeat)
{
    mLastBeat = lastBeat;
    mModified = false;
}

m_time_t HeartBeatBackupInfo::lastBeat() const
{
    return mLastBeat;
}

////////// HeartBeatTransferProgressedInfo ////////
double HeartBeatTransferProgressedInfo::progress(m_off_t inflightProgress) const
{
    return mProgressInvalid ? -1.0 : std::max(0., std::min(1., static_cast<double>((mTransferredBytes + inflightProgress)) / static_cast<double>(mTotalBytes)));
}

void HeartBeatTransferProgressedInfo::adjustTransferCounts(int32_t upcount, int32_t downcount, long long totalBytes, long long transferBytes)
{
    if (mProgressInvalid &&
        !mPendingUps && !mPendingDowns &&
        mTotalBytes == mTransferredBytes)
    {
        mProgressInvalid = false;
        mPendingUps = 0;
        mPendingDowns = 0;
        mTotalBytes = 0;
        mTransferredBytes = 0;
    }

    mPendingUps += upcount;
    mPendingDowns += downcount;
    mTotalBytes += totalBytes;
    mTransferredBytes += transferBytes;
    updateLastActionTime();
}

void HeartBeatSyncInfo::updateSPHBStatus(UnifiedSync& us)
{
    SPHBStatus status = CommandBackupPutHeartBeat::INACTIVE;

    if (us.mSync)
    {
        switch(us.mSync->localroot->ts)
        {
        case TREESTATE_SYNCED:
            status = CommandBackupPutHeartBeat::UPTODATE;
            break;
        case TREESTATE_PENDING:
            status = CommandBackupPutHeartBeat::PENDING;
            break;
        case TREESTATE_SYNCING:
            status = CommandBackupPutHeartBeat::SYNCING;
            break;
        default:
            status = CommandBackupPutHeartBeat::UNKNOWN;
            break;
        }
    }

    if (mSPHBStatus != status)
    {
        mSPHBStatus = status;
        updateLastActionTime();
    }
}

BackupInfoSync::BackupInfoSync(const SyncConfig& config, const string& device, handle drive, CommandBackupPut::SPState calculatedState)
{
    backupId = config.mBackupId;
    type = getSyncType(config);
    backupName = config.mName,
    nodeHandle = config.getRemoteNode();
    localFolder = config.getLocalPath();
    state = calculatedState;
    subState = config.getError();
    deviceId = device;
    driveId = drive;
}

BackupInfoSync::BackupInfoSync(const UnifiedSync &us, bool pauseDown, bool pauseUp)
{
    backupId = us.mConfig.mBackupId;
    type = getSyncType(us.mConfig);
    backupName = us.mConfig.mName,
    nodeHandle = us.mConfig.getRemoteNode();
    localFolder = us.mConfig.getLocalPath();
    state = BackupInfoSync::getSyncState(us, pauseDown, pauseUp);
    subState = us.mConfig.getError();
    deviceId = us.syncs.mClient.getDeviceidHash();
    driveId = BackupInfoSync::getDriveId(us);
    assert(!(us.mConfig.isBackup() && us.mConfig.isExternal())  // not an external backup...
           || !ISUNDEF(driveId));  // ... or it must have a valid drive-id
}

HeartBeatBackupInfo::SPState BackupInfoSync::calculatePauseActiveState(bool pauseDown, bool pauseUp)
{
    if (pauseDown && pauseUp)
    {
        return CommandBackupPut::PAUSE_FULL;
    }
    else if (pauseDown)
    {
        return CommandBackupPut::PAUSE_DOWN;
    }
    else if (pauseUp)
    {
        return CommandBackupPut::PAUSE_UP;
    }

    return CommandBackupPut::ACTIVE;
}

HeartBeatBackupInfo::SPState BackupInfoSync::getSyncState(const UnifiedSync& us, bool pauseDown, bool pauseUp)
{
    SyncError error = us.mConfig.getError();
    syncstate_t state = us.mSync ? us.mSync->state() : SYNC_FAILED;

    return getSyncState(error, state, pauseDown, pauseUp);
}

HeartBeatBackupInfo::SPState BackupInfoSync::getSyncState(SyncError error, syncstate_t state, bool pauseDown, bool pauseUp)
{
    if (state == SYNC_DISABLED && error != NO_SYNC_ERROR)
    {
        return CommandBackupPut::TEMPORARY_DISABLED;
    }
    else if (state != SYNC_FAILED && state != SYNC_CANCELED && state != SYNC_DISABLED)
    {
        return calculatePauseActiveState(pauseDown, pauseUp);
    }
    else if (!(state != SYNC_CANCELED && (state != SYNC_DISABLED || error != NO_SYNC_ERROR)))
    {
        return CommandBackupPut::DISABLED;
    }
    else
    {
        return CommandBackupPut::FAILED;
    }
}

HeartBeatBackupInfo::SPState BackupInfoSync::getSyncState(const SyncConfig& config, bool pauseDown, bool pauseUp)
{
    auto error = config.getError();
    if (!error)
    {
        if (config.getEnabled())
        {
            return calculatePauseActiveState(pauseDown, pauseUp);
        }
        else
        {
            return CommandBackupPut::DISABLED;
        }
    }
    else //error
    {
        if (config.getEnabled())
        {
            return CommandBackupPut::TEMPORARY_DISABLED;
        }
        else
        {
            return CommandBackupPut::DISABLED;
        }
    }
}

handle BackupInfoSync::getDriveId(const UnifiedSync &us)
{
    const LocalPath& drivePath = us.mConfig.mExternalDrivePath;
    const auto& fsAccess = *us.mClient.fsaccess;
    const string& drivePathUtf8 = drivePath.toPath(fsAccess);
    handle driveId;
    us.mClient.readDriveId(drivePathUtf8.c_str(), driveId); // It shouldn't happen very often

    return driveId;
}

BackupType BackupInfoSync::getSyncType(const SyncConfig& config)
{
    switch (config.getType())
    {
    case SyncConfig::TYPE_UP:
            return BackupType::UP_SYNC;
    case SyncConfig::TYPE_DOWN:
            return BackupType::DOWN_SYNC;
    case SyncConfig::TYPE_TWOWAY:
            return BackupType::TWO_WAY;
    case SyncConfig::TYPE_BACKUP:
            return BackupType::BACKUP_UPLOAD;
    default:
            return BackupType::INVALID;
    }
}

BackupMonitor::BackupMonitor(Syncs& s)
    : syncs(s), mClient(&syncs.mClient)
{
}

void BackupMonitor::updateOrRegisterSync(UnifiedSync& us)
{
#ifdef DEBUG
    handle backupId = us.mConfig.getBackupId();
    assert(!ISUNDEF(backupId)); // syncs are registered before adding them
#endif

    auto currentInfo = BackupInfoSync(us, syncs.mDownloadsPaused, syncs.mUploadsPaused);
    if (us.mBackupInfo && currentInfo != *us.mBackupInfo)
    {
        syncs.mClient.reqs.add(new CommandBackupPut(&syncs.mClient, currentInfo, nullptr));
    }
    us.mBackupInfo = ::mega::make_unique<BackupInfoSync>(currentInfo);
}

bool BackupInfoSync::operator==(const BackupInfoSync& o) const
{
    return  backupId == o.backupId &&
            driveId == o.driveId &&
            type == o.type &&
            backupName == o.backupName &&
            nodeHandle == o.nodeHandle &&
            localFolder == o.localFolder &&
            deviceId == o.deviceId &&
            state == o.state &&
            subState == o.subState;
}

bool BackupInfoSync::operator!=(const BackupInfoSync &o) const
{
    return !(*this == o);
}

void BackupMonitor::beatBackupInfo(UnifiedSync& us)
{
    // send registration or update in case we missed it
    updateOrRegisterSync(us);

    if (ISUNDEF(us.mConfig.getBackupId()))
    {
        LOG_warn << "Backup not registered yet. Skipping heartbeat...";
        return;
    }

    std::shared_ptr<HeartBeatSyncInfo> hbs = us.mNextHeartbeat;

    if ( !hbs->mSending && (hbs->mModified
         || m_time(nullptr) - hbs->lastBeat() > MAX_HEARBEAT_SECS_DELAY))
    {
        hbs->updateSPHBStatus(us);
        hbs->setLastBeat(m_time(nullptr));

        m_off_t inflightProgress = 0;
        if (us.mSync)
        {
            inflightProgress = us.mSync->getInflightProgress();
        }

        int8_t progress = (hbs->progress(inflightProgress) < 0) ? -1 : static_cast<int8_t>(std::lround(hbs->progress(inflightProgress)*100.0));

        hbs->mSending = true;
        auto newCommand = new CommandBackupPutHeartBeat(mClient, us.mConfig.getBackupId(),  hbs->sphbStatus(),
                          progress, hbs->mPendingUps, hbs->mPendingDowns,
                          hbs->lastAction(), hbs->lastItemUpdated(),
                          [hbs](Error){
                               hbs->mSending = false;
                          });

#ifdef ENABLE_SYNC
        if (hbs->sphbStatus() == CommandBackupPutHeartBeat::UPTODATE && progress >= 100)
        {
            hbs->invalidateProgress(); // we invalidate progress, so as not to keep on reporting 100% progress after reached up to date
            // note: new transfer updates will modify the progress and make it valid again
        }
#endif

        mClient->reqs.add(newCommand);
    }
}

void BackupMonitor::beat()
{
    // Only send heartbeats for enabled active syncs.
    for (auto& us : syncs.mSyncVec)
    {
        if (us->mSync && us->mConfig.getEnabled())
        {
            beatBackupInfo(*us);
        }
    };
}

#endif

}
<commit_msg>Send `sp` for each sync initially, since Backup Centre continues to display the sync as Disabled (for active syncs) otherwise.<commit_after>/**
 * @file heartbeats.cpp
 * @brief Classes for heartbeating Sync configuration and status
 *
 * (c) 2013 by Mega Limited, Auckland, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "mega/heartbeats.h"
#include "mega/command.h"
#include "assert.h"
#include "mega.h"

namespace mega {

#ifdef ENABLE_SYNC

HeartBeatBackupInfo::HeartBeatBackupInfo()
{
}

double HeartBeatBackupInfo::progress(m_off_t inflightProgress) const
{
    return mProgress + static_cast<double>(inflightProgress);
}

void HeartBeatBackupInfo::invalidateProgress()
{
    mProgressInvalid = true;
}

m_time_t HeartBeatBackupInfo::lastAction() const
{
    return mLastAction;
}

handle HeartBeatBackupInfo::lastItemUpdated() const
{
    return mLastItemUpdated;
}

void HeartBeatBackupInfo::setLastSyncedItem(const handle &lastSyncedItem)
{
    if (mLastItemUpdated != lastSyncedItem)
    {
        mLastItemUpdated = lastSyncedItem;
        updateLastActionTime();
    }
}

void HeartBeatBackupInfo::setSPState(SPState state)
{
    if (mSPState != state)
    {
        mSPState = state;
        updateLastActionTime();
    }
}

void HeartBeatBackupInfo::setProgress(const double &progress)
{
    mProgressInvalid = false;
    mProgress = progress;
    updateLastActionTime();
}

void HeartBeatBackupInfo::setLastAction(const m_time_t &lastAction)
{
    mLastAction = lastAction;
}

void HeartBeatBackupInfo::updateLastActionTime()
{
    setLastAction(m_time(nullptr));
    mModified = true;
}

void HeartBeatBackupInfo::setLastBeat(const m_time_t &lastBeat)
{
    mLastBeat = lastBeat;
    mModified = false;
}

m_time_t HeartBeatBackupInfo::lastBeat() const
{
    return mLastBeat;
}

////////// HeartBeatTransferProgressedInfo ////////
double HeartBeatTransferProgressedInfo::progress(m_off_t inflightProgress) const
{
    return mProgressInvalid ? -1.0 : std::max(0., std::min(1., static_cast<double>((mTransferredBytes + inflightProgress)) / static_cast<double>(mTotalBytes)));
}

void HeartBeatTransferProgressedInfo::adjustTransferCounts(int32_t upcount, int32_t downcount, long long totalBytes, long long transferBytes)
{
    if (mProgressInvalid &&
        !mPendingUps && !mPendingDowns &&
        mTotalBytes == mTransferredBytes)
    {
        mProgressInvalid = false;
        mPendingUps = 0;
        mPendingDowns = 0;
        mTotalBytes = 0;
        mTransferredBytes = 0;
    }

    mPendingUps += upcount;
    mPendingDowns += downcount;
    mTotalBytes += totalBytes;
    mTransferredBytes += transferBytes;
    updateLastActionTime();
}

void HeartBeatSyncInfo::updateSPHBStatus(UnifiedSync& us)
{
    SPHBStatus status = CommandBackupPutHeartBeat::INACTIVE;

    if (us.mSync)
    {
        switch(us.mSync->localroot->ts)
        {
        case TREESTATE_SYNCED:
            status = CommandBackupPutHeartBeat::UPTODATE;
            break;
        case TREESTATE_PENDING:
            status = CommandBackupPutHeartBeat::PENDING;
            break;
        case TREESTATE_SYNCING:
            status = CommandBackupPutHeartBeat::SYNCING;
            break;
        default:
            status = CommandBackupPutHeartBeat::UNKNOWN;
            break;
        }
    }

    if (mSPHBStatus != status)
    {
        mSPHBStatus = status;
        updateLastActionTime();
    }
}

BackupInfoSync::BackupInfoSync(const SyncConfig& config, const string& device, handle drive, CommandBackupPut::SPState calculatedState)
{
    backupId = config.mBackupId;
    type = getSyncType(config);
    backupName = config.mName,
    nodeHandle = config.getRemoteNode();
    localFolder = config.getLocalPath();
    state = calculatedState;
    subState = config.getError();
    deviceId = device;
    driveId = drive;
}

BackupInfoSync::BackupInfoSync(const UnifiedSync &us, bool pauseDown, bool pauseUp)
{
    backupId = us.mConfig.mBackupId;
    type = getSyncType(us.mConfig);
    backupName = us.mConfig.mName,
    nodeHandle = us.mConfig.getRemoteNode();
    localFolder = us.mConfig.getLocalPath();
    state = BackupInfoSync::getSyncState(us, pauseDown, pauseUp);
    subState = us.mConfig.getError();
    deviceId = us.syncs.mClient.getDeviceidHash();
    driveId = BackupInfoSync::getDriveId(us);
    assert(!(us.mConfig.isBackup() && us.mConfig.isExternal())  // not an external backup...
           || !ISUNDEF(driveId));  // ... or it must have a valid drive-id
}

HeartBeatBackupInfo::SPState BackupInfoSync::calculatePauseActiveState(bool pauseDown, bool pauseUp)
{
    if (pauseDown && pauseUp)
    {
        return CommandBackupPut::PAUSE_FULL;
    }
    else if (pauseDown)
    {
        return CommandBackupPut::PAUSE_DOWN;
    }
    else if (pauseUp)
    {
        return CommandBackupPut::PAUSE_UP;
    }

    return CommandBackupPut::ACTIVE;
}

HeartBeatBackupInfo::SPState BackupInfoSync::getSyncState(const UnifiedSync& us, bool pauseDown, bool pauseUp)
{
    SyncError error = us.mConfig.getError();
    syncstate_t state = us.mSync ? us.mSync->state() : SYNC_FAILED;

    return getSyncState(error, state, pauseDown, pauseUp);
}

HeartBeatBackupInfo::SPState BackupInfoSync::getSyncState(SyncError error, syncstate_t state, bool pauseDown, bool pauseUp)
{
    if (state == SYNC_DISABLED && error != NO_SYNC_ERROR)
    {
        return CommandBackupPut::TEMPORARY_DISABLED;
    }
    else if (state != SYNC_FAILED && state != SYNC_CANCELED && state != SYNC_DISABLED)
    {
        return calculatePauseActiveState(pauseDown, pauseUp);
    }
    else if (!(state != SYNC_CANCELED && (state != SYNC_DISABLED || error != NO_SYNC_ERROR)))
    {
        return CommandBackupPut::DISABLED;
    }
    else
    {
        return CommandBackupPut::FAILED;
    }
}

HeartBeatBackupInfo::SPState BackupInfoSync::getSyncState(const SyncConfig& config, bool pauseDown, bool pauseUp)
{
    auto error = config.getError();
    if (!error)
    {
        if (config.getEnabled())
        {
            return calculatePauseActiveState(pauseDown, pauseUp);
        }
        else
        {
            return CommandBackupPut::DISABLED;
        }
    }
    else //error
    {
        if (config.getEnabled())
        {
            return CommandBackupPut::TEMPORARY_DISABLED;
        }
        else
        {
            return CommandBackupPut::DISABLED;
        }
    }
}

handle BackupInfoSync::getDriveId(const UnifiedSync &us)
{
    const LocalPath& drivePath = us.mConfig.mExternalDrivePath;
    const auto& fsAccess = *us.mClient.fsaccess;
    const string& drivePathUtf8 = drivePath.toPath(fsAccess);
    handle driveId;
    us.mClient.readDriveId(drivePathUtf8.c_str(), driveId); // It shouldn't happen very often

    return driveId;
}

BackupType BackupInfoSync::getSyncType(const SyncConfig& config)
{
    switch (config.getType())
    {
    case SyncConfig::TYPE_UP:
            return BackupType::UP_SYNC;
    case SyncConfig::TYPE_DOWN:
            return BackupType::DOWN_SYNC;
    case SyncConfig::TYPE_TWOWAY:
            return BackupType::TWO_WAY;
    case SyncConfig::TYPE_BACKUP:
            return BackupType::BACKUP_UPLOAD;
    default:
            return BackupType::INVALID;
    }
}

BackupMonitor::BackupMonitor(Syncs& s)
    : syncs(s), mClient(&syncs.mClient)
{
}

void BackupMonitor::updateOrRegisterSync(UnifiedSync& us)
{
#ifdef DEBUG
    handle backupId = us.mConfig.getBackupId();
    assert(!ISUNDEF(backupId)); // syncs are registered before adding them
#endif

    auto currentInfo = BackupInfoSync(us, syncs.mDownloadsPaused, syncs.mUploadsPaused);
    if (!us.mBackupInfo || currentInfo != *us.mBackupInfo)
    {
        // Send if anything changed, or it's the first time we're considering for this sync (gets around Backup Centre continuing to show Disabled even though we sent sphb)
        syncs.mClient.reqs.add(new CommandBackupPut(&syncs.mClient, currentInfo, nullptr));
    }
    us.mBackupInfo = ::mega::make_unique<BackupInfoSync>(currentInfo);
}

bool BackupInfoSync::operator==(const BackupInfoSync& o) const
{
    return  backupId == o.backupId &&
            driveId == o.driveId &&
            type == o.type &&
            backupName == o.backupName &&
            nodeHandle == o.nodeHandle &&
            localFolder == o.localFolder &&
            deviceId == o.deviceId &&
            state == o.state &&
            subState == o.subState;
}

bool BackupInfoSync::operator!=(const BackupInfoSync &o) const
{
    return !(*this == o);
}

void BackupMonitor::beatBackupInfo(UnifiedSync& us)
{
    // send registration or update in case we missed it
    updateOrRegisterSync(us);

    if (ISUNDEF(us.mConfig.getBackupId()))
    {
        LOG_warn << "Backup not registered yet. Skipping heartbeat...";
        return;
    }

    std::shared_ptr<HeartBeatSyncInfo> hbs = us.mNextHeartbeat;

    if ( !hbs->mSending && (hbs->mModified
         || m_time(nullptr) - hbs->lastBeat() > MAX_HEARBEAT_SECS_DELAY))
    {
        hbs->updateSPHBStatus(us);
        hbs->setLastBeat(m_time(nullptr));

        m_off_t inflightProgress = 0;
        if (us.mSync)
        {
            inflightProgress = us.mSync->getInflightProgress();
        }

        int8_t progress = (hbs->progress(inflightProgress) < 0) ? -1 : static_cast<int8_t>(std::lround(hbs->progress(inflightProgress)*100.0));

        hbs->mSending = true;
        auto newCommand = new CommandBackupPutHeartBeat(mClient, us.mConfig.getBackupId(),  hbs->sphbStatus(),
                          progress, hbs->mPendingUps, hbs->mPendingDowns,
                          hbs->lastAction(), hbs->lastItemUpdated(),
                          [hbs](Error){
                               hbs->mSending = false;
                          });

#ifdef ENABLE_SYNC
        if (hbs->sphbStatus() == CommandBackupPutHeartBeat::UPTODATE && progress >= 100)
        {
            hbs->invalidateProgress(); // we invalidate progress, so as not to keep on reporting 100% progress after reached up to date
            // note: new transfer updates will modify the progress and make it valid again
        }
#endif

        mClient->reqs.add(newCommand);
    }
}

void BackupMonitor::beat()
{
    // Only send heartbeats for enabled active syncs.
    for (auto& us : syncs.mSyncVec)
    {
        if (us->mSync && us->mConfig.getEnabled())
        {
            beatBackupInfo(*us);
        }
    };
}

#endif

}
<|endoftext|>


<commit_before>#include <mantella_bits/helper/mpi.hpp>

// C++ standard library
#include <algorithm>

#if defined(SUPPORT_MPI)
namespace mant {
  void mpiGetBestSample(
      void* firstInput,
      void* secondInput,
      int* size,
      MPI_Datatype* type) {
    double* firstParameters = static_cast<double*>(firstInput);
    double* secondParameters = static_cast<double*>(secondInput);

    if(firstParameters[1] < secondParameters[1]) {
      std::copy(&firstParameters[1], &firstParameters[1 + static_cast<unsigned int>(secondParameters[0])], &secondParameters[1]);
    }
  }
}
#endif
<commit_msg>Added support for the size parameter of mpiGetBestSample<commit_after>#include <mantella_bits/helper/mpi.hpp>

// C++ standard library
#include <iostream>
#include <algorithm>

// Armadillo
#include <armadillo>

#if defined(SUPPORT_MPI)
namespace mant {
  void mpiGetBestSample(
      void* firstInput,
      void* secondInput,
      int* size,
      MPI_Datatype* type) {
    double* firstParameters = static_cast<double*>(firstInput);
    double* secondParameters = static_cast<double*>(secondInput);

    for (int n = 0; n < *size; ++n) {
      const arma::uword numberOfDimensions = static_cast<unsigned int>(firstParameters[0]);

      if(firstParameters[1] < secondParameters[1]) {
        std::copy(&firstParameters[1], &firstParameters[1 + numberOfDimensions], &secondParameters[1]);
      }

      firstParameters += 2 + numberOfDimensions;
      secondParameters += 2 + numberOfDimensions;
    }
  }
}
#endif
<|endoftext|>


<commit_before>#pragma once

#define BOOST_RESULT_OF_USE_DECLTYPE

#include<complex>
#include<iostream>
#include<utility>
#include<typeinfo>

#include<boost/version.hpp>
#if BOOST_VERSION >= 105600
#define BOOST_HAS_DEMANGLE
#endif

#ifdef BOOST_HAS_DEMANGLE
#include<boost/core/demangle.hpp>
#endif

namespace gftools {

// DEBUG messages with custom verbosity.
// Adapted from http://efesx.com/2010/08/31/overloading-macros/
#ifndef NDEBUG
#define MSG_PREFIX            __FILE__ << ":" << __LINE__ << ": "
#define DEBUG3(MSG,VERBOSITY,VERB_LEVEL)            if (VERBOSITY >= VERB_LEVEL) std::cerr << MSG_PREFIX << MSG << std::endl;
#else
#define DEBUG3(MSG,VERBOSITY,VERB_LEVEL)            ;
#endif

#define DEBUG1(MSG) DEBUG3(MSG,3,3)
#define DEBUG2(MSG,VERBOSITY) DEBUG3(MSG,VERBOSITY,3)

#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
#define macro_dispatcher(func, ...) \
            macro_dispatcher_(func, VA_NUM_ARGS(__VA_ARGS__))
#define macro_dispatcher_(func, nargs) \
            macro_dispatcher__(func, nargs)
#define macro_dispatcher__(func, nargs) \
            func ## nargs

#define DEBUG(...) macro_dispatcher(DEBUG, __VA_ARGS__)(__VA_ARGS__)

// some more output presets
#ifndef INFO
#define INFO(MSG)             std::cout << MSG << std::endl;
#define INFO_NONEWLINE(MSG)   std::cout << MSG << std::flush;
#define INFO2(MSG)            std::cout << "\t"     << MSG << std::endl;
#define INFO3(MSG)            std::cout << "\t\t"   << MSG << std::endl;
#define INFO4(MSG)            std::cout << "\t\t\t" << MSG << std::endl;
#endif

#ifndef ERROR
#define MSG_PREFIX            __FILE__ << ":" << __LINE__ << ": "
#define ERROR(MSG)            std::cerr << MSG_PREFIX << MSG << std::endl;
#endif

/** Extract demangled name from a type_info object */
std::string demangled_name(std::type_info const& info) {
#ifdef BOOST_HAS_DEMANGLE
    return boost::core::demangle(info.name());
#else
    return info.name();
#endif
}

typedef double real_type;
typedef std::complex<real_type> complex_type;

/** A short name for imaginary unit. TODO: remove this in dependent codes.*/
static const complex_type I = complex_type(0.0,1.0);    // 'static' to prevent linking problems
/** A short name for pi. TODO: remove this in dependent codes.*/
const real_type PI = M_PI;

} // end namespace gftools

<commit_msg>mark demangled_name inline to avoid multiple definition errors<commit_after>#pragma once

#define BOOST_RESULT_OF_USE_DECLTYPE

#include<complex>
#include<iostream>
#include<utility>
#include<typeinfo>

#include<boost/version.hpp>
#if BOOST_VERSION >= 105600
#define BOOST_HAS_DEMANGLE
#endif

#ifdef BOOST_HAS_DEMANGLE
#include<boost/core/demangle.hpp>
#endif

namespace gftools {

// DEBUG messages with custom verbosity.
// Adapted from http://efesx.com/2010/08/31/overloading-macros/
#ifndef NDEBUG
#define MSG_PREFIX            __FILE__ << ":" << __LINE__ << ": "
#define DEBUG3(MSG,VERBOSITY,VERB_LEVEL)            if (VERBOSITY >= VERB_LEVEL) std::cerr << MSG_PREFIX << MSG << std::endl;
#else
#define DEBUG3(MSG,VERBOSITY,VERB_LEVEL)            ;
#endif

#define DEBUG1(MSG) DEBUG3(MSG,3,3)
#define DEBUG2(MSG,VERBOSITY) DEBUG3(MSG,VERBOSITY,3)

#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
#define macro_dispatcher(func, ...) \
            macro_dispatcher_(func, VA_NUM_ARGS(__VA_ARGS__))
#define macro_dispatcher_(func, nargs) \
            macro_dispatcher__(func, nargs)
#define macro_dispatcher__(func, nargs) \
            func ## nargs

#define DEBUG(...) macro_dispatcher(DEBUG, __VA_ARGS__)(__VA_ARGS__)

// some more output presets
#ifndef INFO
#define INFO(MSG)             std::cout << MSG << std::endl;
#define INFO_NONEWLINE(MSG)   std::cout << MSG << std::flush;
#define INFO2(MSG)            std::cout << "\t"     << MSG << std::endl;
#define INFO3(MSG)            std::cout << "\t\t"   << MSG << std::endl;
#define INFO4(MSG)            std::cout << "\t\t\t" << MSG << std::endl;
#endif

#ifndef ERROR
#define MSG_PREFIX            __FILE__ << ":" << __LINE__ << ": "
#define ERROR(MSG)            std::cerr << MSG_PREFIX << MSG << std::endl;
#endif

/** Extract demangled name from a type_info object */
inline std::string demangled_name(std::type_info const& info) {
#ifdef BOOST_HAS_DEMANGLE
    return boost::core::demangle(info.name());
#else
    return info.name();
#endif
}

typedef double real_type;
typedef std::complex<real_type> complex_type;

/** A short name for imaginary unit. TODO: remove this in dependent codes.*/
static const complex_type I = complex_type(0.0,1.0);    // 'static' to prevent linking problems
/** A short name for pi. TODO: remove this in dependent codes.*/
const real_type PI = M_PI;

} // end namespace gftools

<|endoftext|>


<commit_before>/**
 * @file   llsdmessage_test.cpp
 * @author Nat Goodspeed
 * @date   2008-12-22
 * @brief  Test of llsdmessage.h
 *
 * $LicenseInfo:firstyear=2008&license=viewergpl$
 * Copyright (c) 2008, Linden Research, Inc.
 * $/LicenseInfo$
 */

#if LL_WINDOWS
#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
#endif

// Precompiled header
#include "linden_common.h"
// associated header
#include "llsdmessage.h"
// STL headers
#include <iostream>
// std headers
#include <stdexcept>
// external library headers
// other Linden headers
#include "../test/lltut.h"
#include "llsdserialize.h"
#include "llevents.h"
#include "stringize.h"
#include "llhost.h"
#include "tests/networkio.h"
#include "tests/commtest.h"

/*****************************************************************************
*   TUT
*****************************************************************************/
namespace tut
{
    struct llsdmessage_data: public commtest_data
    {
        LLEventPump& httpPump;

        llsdmessage_data():
            httpPump(pumps.obtain("LLHTTPClient"))
        {
            LLSDMessage::link();
        }
    };
    typedef test_group<llsdmessage_data> llsdmessage_group;
    typedef llsdmessage_group::object llsdmessage_object;
    llsdmessage_group llsdmgr("llsdmessage");

    template<> template<>
    void llsdmessage_object::test<1>()
    {
        bool threw = false;
        // This should fail...
        try
        {
            LLSDMessage localListener;
        }
        catch (const LLEventPump::DupPumpName&)
        {
            threw = true;
        }
        ensure("second LLSDMessage should throw", threw);
    }

    template<> template<>
    void llsdmessage_object::test<2>()
    {
        LLSD request, body;
        body["data"] = "yes";
        request["payload"] = body;
        request["reply"] = replyPump.getName();
        request["error"] = errorPump.getName();
        bool threw = false;
        try
        {
            httpPump.post(request);
        }
        catch (const LLSDMessage::ArgError&)
        {
            threw = true;
        }
        ensure("missing URL", threw);
    }

    template<> template<>
    void llsdmessage_object::test<3>()
    {
        LLSD request, body;
        body["data"] = "yes";
        request["url"] = server + "got-message";
        request["payload"] = body;
        request["reply"] = replyPump.getName();
        request["error"] = errorPump.getName();
        httpPump.post(request);
        ensure("got response", netio.pump());
        ensure("success response", success);
        ensure_equals(result.asString(), "success");

        body["status"] = 499;
        body["reason"] = "custom error message";
        request["url"] = server + "fail";
        request["payload"] = body;
        httpPump.post(request);
        ensure("got response", netio.pump());
        ensure("failure response", ! success);
        ensure_equals(result["status"].asInteger(), body["status"].asInteger());
        ensure_equals(result["reason"].asString(),  body["reason"].asString());
    }
} // namespace tut
<commit_msg>Work around Linux viewer test program catch failure<commit_after>/**
 * @file   llsdmessage_test.cpp
 * @author Nat Goodspeed
 * @date   2008-12-22
 * @brief  Test of llsdmessage.h
 *
 * $LicenseInfo:firstyear=2008&license=viewergpl$
 * Copyright (c) 2008, Linden Research, Inc.
 * $/LicenseInfo$
 */

#if LL_WINDOWS
#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
#endif

// Precompiled header
#include "linden_common.h"
// associated header
#include "llsdmessage.h"
// STL headers
#include <iostream>
// std headers
#include <stdexcept>
#include <typeinfo>
// external library headers
// other Linden headers
#include "../test/lltut.h"
#include "llsdserialize.h"
#include "llevents.h"
#include "stringize.h"
#include "llhost.h"
#include "tests/networkio.h"
#include "tests/commtest.h"

/*****************************************************************************
*   TUT
*****************************************************************************/
namespace tut
{
    struct llsdmessage_data: public commtest_data
    {
        LLEventPump& httpPump;

        llsdmessage_data():
            httpPump(pumps.obtain("LLHTTPClient"))
        {
            LLSDMessage::link();
        }
    };
    typedef test_group<llsdmessage_data> llsdmessage_group;
    typedef llsdmessage_group::object llsdmessage_object;
    llsdmessage_group llsdmgr("llsdmessage");

    template<> template<>
    void llsdmessage_object::test<1>()
    {
        bool threw = false;
        // This should fail...
        try
        {
            LLSDMessage localListener;
        }
        catch (const LLEventPump::DupPumpName&)
        {
            threw = true;
        }
        catch (const std::runtime_error& ex)
        {
            // This clause is because on Linux, on the viewer side, for this
            // one test program (though not others!), the
            // LLEventPump::DupPumpName exception isn't caught by the clause
            // above. Warn the user...
            std::cerr << "Failed to catch " << typeid(ex).name() << std::endl;
            // But if the expected exception was thrown, allow the test to
            // succeed anyway. Not sure how else to handle this odd case.
            if (std::string(typeid(ex).name()) == typeid(LLEventPump::DupPumpName).name())
            {
                threw = true;
            }
            else
            {
                // We don't even recognize this exception. Let it propagate
                // out to TUT to fail the test.
                throw;
            }
        }
        catch (...)
        {
            std::cerr << "Utterly failed to catch expected exception!" << std::endl;
            // This case is full of fail. We HAVE to address it.
            throw;
        }
        ensure("second LLSDMessage should throw", threw);
    }

    template<> template<>
    void llsdmessage_object::test<2>()
    {
        LLSD request, body;
        body["data"] = "yes";
        request["payload"] = body;
        request["reply"] = replyPump.getName();
        request["error"] = errorPump.getName();
        bool threw = false;
        try
        {
            httpPump.post(request);
        }
        catch (const LLSDMessage::ArgError&)
        {
            threw = true;
        }
        ensure("missing URL", threw);
    }

    template<> template<>
    void llsdmessage_object::test<3>()
    {
        LLSD request, body;
        body["data"] = "yes";
        request["url"] = server + "got-message";
        request["payload"] = body;
        request["reply"] = replyPump.getName();
        request["error"] = errorPump.getName();
        httpPump.post(request);
        ensure("got response", netio.pump());
        ensure("success response", success);
        ensure_equals(result.asString(), "success");

        body["status"] = 499;
        body["reason"] = "custom error message";
        request["url"] = server + "fail";
        request["payload"] = body;
        httpPump.post(request);
        ensure("got response", netio.pump());
        ensure("failure response", ! success);
        ensure_equals(result["status"].asInteger(), body["status"].asInteger());
        ensure_equals(result["reason"].asString(),  body["reason"].asString());
    }
} // namespace tut
<|endoftext|>


<commit_before>// Copyright (c) 2011 Zeex
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cstring>

#include "hooknative.h"

AMX_NATIVE HookNative(AMX *amx, const char *nativeName, AMX_NATIVE native) {
    AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
    AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);

    int numberOfNatives;
    amx_NumNatives(amx, &numberOfNatives);

    for (int i = 0; i < numberOfNatives; i++) {
        char *currentName = reinterpret_cast<char*>(amx->base + natives[i].nameofs);
        if (std::strcmp(currentName, nativeName) == 0) {
            cell address = natives[i].address;
            natives[i].address = reinterpret_cast<cell>(native);
            return reinterpret_cast<AMX_NATIVE>(address);
        }
    }

    return 0;
}

<commit_msg>Fix weird undefined reference to HookNative (GCC 4.5.2)<commit_after>// Copyright (c) 2011 Zeex
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cstring>

AMX_NATIVE HookNative(AMX *amx, const char *nativeName, AMX_NATIVE native) {
    AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
    AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);

    int numberOfNatives;
    amx_NumNatives(amx, &numberOfNatives);

    for (int i = 0; i < numberOfNatives; i++) {
        char *currentName = reinterpret_cast<char*>(amx->base + natives[i].nameofs);
        if (std::strcmp(currentName, nativeName) == 0) {
            cell address = natives[i].address;
            natives[i].address = reinterpret_cast<cell>(native);
            return reinterpret_cast<AMX_NATIVE>(address);
        }
    }

    return 0;
}

<|endoftext|>


<commit_before>#include <string.h>
#include <stdio.h>

#include "httpServer.h"
#include "logging.h"

HttpServer::HttpServer(int portNr)
{
    listenSocket.listen(portNr);
    selector.add(listenSocket);
}

HttpServer::~HttpServer()
{
    listenSocket.close();
    for(unsigned int n=0; n<connections.size(); n++)
        delete connections[n];
    for(unsigned int n=0; n<handlers.size(); n++)
        delete handlers[n];
}

void HttpServer::update(float delta)
{
    if (selector.wait(sf::microseconds(1)))
    {
        if (selector.isReady(listenSocket))
        {
            HttpServerConnection* connection = new HttpServerConnection(this);
            if (listenSocket.accept(connection->socket) == sf::Socket::Done)
            {
                connections.push_back(connection);
                selector.add(connection->socket);
            }else{
                delete connection;
            }
        }
        for(unsigned int n=0; n<connections.size(); n++)
        {
            if (selector.isReady(connections[n]->socket))
            {
                if (!connections[n]->read())
                {
                    selector.remove(connections[n]->socket);
                    delete connections[n];
                    connections.erase(connections.begin() + n);
                }
            }
        }
    }
}

HttpServerConnection::HttpServerConnection(HttpServer* server)
: server(server)
{
    recvBufferCount = 0;
    status = METHOD;
}

bool HttpServerConnection::read()
{
    char buffer[1024];
    size_t size;
    if (socket.receive(buffer, sizeof(buffer), size) != sf::Socket::Done)
        return false;
    if (recvBufferCount + size > recvBufferSize)
        size = recvBufferSize - recvBufferCount;
    if (size < 1)
        return false;
    memcpy(recvBuffer + recvBufferCount, buffer, size);
    recvBufferCount += size;

    while(true)
    {
        char* ptr = (char*)memchr(recvBuffer, '\n', recvBufferCount);
        if (!ptr)
            break;
        *ptr = '\0';
        string line(recvBuffer);
        ptr++;
        size_t len = ptr - recvBuffer;
        recvBufferCount -= len;
        memmove(recvBuffer, ptr, recvBufferCount);
        if (line.endswith("\r"))
            line = line.substr(0, -1);
        if (!handleLine(line))
            return false;
    }
    return true;
}

/** \brief Decode a percent-encoded URI
 * Uri decoding according to RFC1630, RFC1738, RFC2396
 * Credits: Jin Qing
 * \param sSrc const string&   Percent-encoded URI
 * \return string              Decoded URI-string
 *
 */
string HttpServerConnection::UriDecode(const string & sSrc)
{
   // Note from RFC1630: "Sequences which start with a percent
   // sign but are not followed by two hexadecimal characters
   // (0-9, A-F) are reserved for future extension"

   const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
   const int SRC_LEN = sSrc.length();
   const unsigned char * const SRC_END = pSrc + SRC_LEN;
   // last decodable '%'
   const unsigned char * const SRC_LAST_DEC = SRC_END - 2;

   char * const pStart = new char[SRC_LEN];
   char * pEnd = pStart;

   while (pSrc < SRC_LAST_DEC)
   {
      if (*pSrc == '%')
      {
         char dec1, dec2;
         if (-1 != (dec1 = HEX2DEC[*(pSrc + 1)])
            && -1 != (dec2 = HEX2DEC[*(pSrc + 2)]))
         {
            *pEnd++ = (dec1 << 4) + dec2;
            pSrc += 3;
            continue;
         }
      }

      *pEnd++ = *pSrc++;
   }

   // the last 2- chars
   while (pSrc < SRC_END)
      *pEnd++ = *pSrc++;

   std::string sResult(pStart, pEnd);
   delete [] pStart;
   return (string) sResult;
}

/**< Map to convert between character encodings */
const signed char HttpServerConnection::HEX2DEC[256] =
{
    /*       0  1  2  3   4  5  6  7   8  9  A  B   C  D  E  F */
    /* 0 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 1 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 2 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 3 */  0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,

    /* 4 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 5 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 6 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 7 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,

    /* 8 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 9 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* A */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* B */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,

    /* C */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* D */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* E */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* F */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
};

/** \brief Parse a URL, splitting it in its part and optional parameters
 *
 * \param sSrc const string&  URL
 * \return void
 *
 */
void HttpServerConnection::parseUri(const string & sSrc)
{
    string uri = UriDecode(sSrc);
    std::size_t found = uri.find('?');
    if (found==std::string::npos)
    {
        request.path = uri;
        return;
    }
    else
    {
        std::vector<string> parts = uri.split("?", 1);
        request.path = parts[0];

        std::vector<string> parameters = parts[1].split("&");
        for (unsigned int n=0; n<parameters.size(); n++)
        {
            string param = parameters[n];
            std::size_t found = param.find('=');
            if (found==std::string::npos)
            {
                request.parameters[param] = "";
                LOG(DEBUG) << "HTTP Parameter: " << param;
            }
            else
            {
                if (param.endswith('='))
                {
                    request.parameters[param.substr(0, param.length()-1)] = "";
                    LOG(DEBUG) << "HTTP Parameter: " << param.substr(0, param.length()-1);
                }
                else
                {
                    std::vector<string> items = param.split("=", 1);
                    request.parameters[items[0]] = items[1];
                    LOG(DEBUG) << "HTTP Parameter: " << items[0] << " = " << items[1];
                }
            }
        }
    }
    LOG(DEBUG) << "HTTP Path: " << request.path;
}

bool HttpServerConnection::handleLine(string line)
{
    switch(status)
    {
    case METHOD:{
        std::vector<string> parts = line.split();
        if (parts.size() != 3)
            return false;
        request.method = parts[0];
        parseUri(parts[1]);
        status = HEADERS;
        }break;
    case HEADERS:
        if (line.length() == 0)
        {
            request.post_data = "";
            if (request.method == "POST")
            {
                if (request.headers.find("content-length") != request.headers.end())
                {
                    unsigned int body_length = request.headers["content-length"].toInt();
                    if (body_length > recvBufferSize)
                        return false;
                    while (body_length > recvBufferCount)
                    {
                        size_t received;
                        if (socket.receive(recvBuffer + recvBufferCount, body_length - recvBufferCount, received) != sf::Socket::Done)
                            return false;
                        recvBufferCount += received;
                    }
                    request.post_data = string(recvBuffer, body_length);
                    recvBufferCount -= body_length;
                    memmove(recvBuffer, recvBuffer + body_length, recvBufferCount);
                }
            }
            status = METHOD;
#ifdef DEBUG
            for (std::unordered_map<string, string>::iterator iter = request.headers.begin(); iter != request.headers.end(); iter++)
            {
                string key=iter->first;
                string value=iter->second;
                LOG(DEBUG) << "HTTP header: (" << key << ", " << value << ")";
            }
#endif // DEBUG
            handleRequest();
        }else{
            std::vector<string> parts = line.split(":", 1);
            if (parts.size() != 2)
                LOG(WARNING) << "Invalid HTTP header: " << line;
            else
                request.headers[parts[0].strip().lower()] = parts[1];
        }
        break;
    }
    return true;
}

void HttpServerConnection::handleRequest()
{
    reply_code = 200;
    headers_send = false;

    for(unsigned int n=0; n<server->handlers.size(); n++)
    {
        if (server->handlers[n]->handleRequest(request, this))
            break;
        if (headers_send)
            break;
    }

    if (!headers_send)
    {
        reply_code = 404;
        string replyData = "File not found";
        sendData(replyData.c_str(), replyData.size());
    }
    string end_chunk = "0\r\n\r\n";
    socket.send(end_chunk.c_str(), end_chunk.size());
    request.parameters.clear();
}

void HttpServerConnection::sendHeaders()
{
    string reply = string("HTTP/1.1 ") + string(reply_code) + " OK\r\n";
    reply += "Content-type: text/html\r\n";
    reply += "Connection: Keep-Alive\r\n";
    reply += "Transfer-Encoding: chunked\r\n";
    reply += "\r\n";
    socket.send(reply.c_str(), reply.size());
    headers_send = true;
}

void HttpServerConnection::sendData(const char* data, size_t data_length)
{
    if (!headers_send)
        sendHeaders();
    if (data_length < 1)
        return;
    string chunk_len_string = string::hex(data_length) + "\r\n";
    socket.send(chunk_len_string.c_str(), chunk_len_string.size());
    socket.send(data, data_length);
    socket.send("\r\n", 2);
}

bool HttpRequestFileHandler::handleRequest(HttpRequest& request, HttpServerConnection* connection)
{
    string replyData = "";
    FILE* f = NULL;
    if (request.path == "/")
        request.path = "/index.html";
    if (request.path.find("..") != -1)
        return false;

    string fullPath = base_path + request.path;
    f = fopen(fullPath.c_str(), "rb");
    if (!f)
        return false;

    while(true)
    {
        char buffer[1024];
        size_t n = fread(buffer, 1, sizeof(buffer), f);
        if (n < 1)
            break;
        connection->sendData(buffer, n);
    }
    fclose(f);
    return true;
}
<commit_msg>Update httpServer.cpp (#89)<commit_after>#include <string.h>
#include <stdio.h>

#include "httpServer.h"
#include "logging.h"

HttpServer::HttpServer(int portNr)
{
    listenSocket.listen(static_cast<uint16_t>(portNr));
    selector.add(listenSocket);
}

HttpServer::~HttpServer()
{
    listenSocket.close();
    for(unsigned int n=0; n<connections.size(); n++)
        delete connections[n];
    for(unsigned int n=0; n<handlers.size(); n++)
        delete handlers[n];
}

void HttpServer::update(float /*delta*/)
{
    if (selector.wait(sf::microseconds(1)))
    {
        if (selector.isReady(listenSocket))
        {
            HttpServerConnection* connection = new HttpServerConnection(this);
            if (listenSocket.accept(connection->socket) == sf::Socket::Done)
            {
                connections.push_back(connection);
                selector.add(connection->socket);
            }else{
                delete connection;
            }
        }
        for(unsigned int n=0; n<connections.size(); n++)
        {
            if (selector.isReady(connections[n]->socket))
            {
                if (!connections[n]->read())
                {
                    selector.remove(connections[n]->socket);
                    delete connections[n];
                    connections.erase(connections.begin() + n);
                }
            }
        }
    }
}

HttpServerConnection::HttpServerConnection(HttpServer* server)
: server(server)
{
    recvBufferCount = 0;
    status = METHOD;
}

bool HttpServerConnection::read()
{
    char buffer[1024];
    size_t size;
    if (socket.receive(buffer, sizeof(buffer), size) != sf::Socket::Done)
        return false;
    if (recvBufferCount + size > recvBufferSize)
        size = recvBufferSize - recvBufferCount;
    if (size < 1)
        return false;
    memcpy(recvBuffer + recvBufferCount, buffer, size);
    recvBufferCount += size;

    while(true)
    {
        char* ptr = (char*)memchr(recvBuffer, '\n', recvBufferCount);
        if (!ptr)
            break;
        *ptr = '\0';
        string line(recvBuffer);
        ptr++;
        size_t len = ptr - recvBuffer;
        recvBufferCount -= len;
        memmove(recvBuffer, ptr, recvBufferCount);
        if (line.endswith("\r"))
            line = line.substr(0, -1);
        if (!handleLine(line))
            return false;
    }
    return true;
}

/** \brief Decode a percent-encoded URI
 * Uri decoding according to RFC1630, RFC1738, RFC2396
 * Credits: Jin Qing
 * \param sSrc const string&   Percent-encoded URI
 * \return string              Decoded URI-string
 *
 */
string HttpServerConnection::UriDecode(const string & sSrc)
{
   // Note from RFC1630: "Sequences which start with a percent
   // sign but are not followed by two hexadecimal characters
   // (0-9, A-F) are reserved for future extension"

   const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
   const size_t SRC_LEN = sSrc.length();
   const unsigned char * const SRC_END = pSrc + SRC_LEN;
   // last decodable '%'
   const unsigned char * const SRC_LAST_DEC = SRC_END - 2;

   char * const pStart = new char[SRC_LEN];
   char * pEnd = pStart;

   while (pSrc < SRC_LAST_DEC)
   {
      if (*pSrc == '%')
      {
         char dec1, dec2;
         if (-1 != (dec1 = HEX2DEC[*(pSrc + 1)])
            && -1 != (dec2 = HEX2DEC[*(pSrc + 2)]))
         {
            *pEnd++ = (dec1 << 4) + dec2;
            pSrc += 3;
            continue;
         }
      }

      *pEnd++ = *pSrc++;
   }

   // the last 2- chars
   while (pSrc < SRC_END)
      *pEnd++ = *pSrc++;

   std::string sResult(pStart, pEnd);
   delete [] pStart;
   return (string) sResult;
}

/**< Map to convert between character encodings */
const signed char HttpServerConnection::HEX2DEC[256] =
{
    /*       0  1  2  3   4  5  6  7   8  9  A  B   C  D  E  F */
    /* 0 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 1 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 2 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 3 */  0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,

    /* 4 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 5 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 6 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 7 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,

    /* 8 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* 9 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* A */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* B */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,

    /* C */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* D */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* E */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
    /* F */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
};

/** \brief Parse a URL, splitting it in its part and optional parameters
 *
 * \param sSrc const string&  URL
 * \return void
 *
 */
void HttpServerConnection::parseUri(const string & sSrc)
{
    string uri = UriDecode(sSrc);
    std::size_t found = uri.find('?');
    if (found==std::string::npos)
    {
        request.path = uri;
        return;
    }
    else
    {
        std::vector<string> parts = uri.split("?", 1);
        request.path = parts[0];

        std::vector<string> parameters = parts[1].split("&");
        for (unsigned int n=0; n<parameters.size(); n++)
        {
            string param = parameters[n];
            found = param.find('=');
            if (found==std::string::npos)
            {
                request.parameters[param] = "";
                LOG(DEBUG) << "HTTP Parameter: " << param;
            }
            else
            {
                if (param.endswith('='))
                {
                    auto param_end = static_cast<int>(param.length()) - 1;
                    auto param_key = param.substr(0, param_end);
                    request.parameters[param_key] = "";
                    LOG(DEBUG) << "HTTP Parameter: " << param_key;
                }
                else
                {
                    std::vector<string> items = param.split("=", 1);
                    request.parameters[items[0]] = items[1];
                    LOG(DEBUG) << "HTTP Parameter: " << items[0] << " = " << items[1];
                }
            }
        }
    }
    LOG(DEBUG) << "HTTP Path: " << request.path;
}

bool HttpServerConnection::handleLine(string line)
{
    switch(status)
    {
    case METHOD:{
        std::vector<string> parts = line.split();
        if (parts.size() != 3)
            return false;
        request.method = parts[0];
        parseUri(parts[1]);
        status = HEADERS;
        }break;
    case HEADERS:
        if (line.length() == 0)
        {
            request.post_data = "";
            if (request.method == "POST")
            {
                if (request.headers.find("content-length") != request.headers.end())
                {
                    unsigned int body_length = request.headers["content-length"].toInt();
                    if (body_length > recvBufferSize)
                        return false;
                    while (body_length > recvBufferCount)
                    {
                        size_t received;
                        if (socket.receive(recvBuffer + recvBufferCount, body_length - recvBufferCount, received) != sf::Socket::Done)
                            return false;
                        recvBufferCount += received;
                    }
                    request.post_data = string(recvBuffer, body_length);
                    recvBufferCount -= body_length;
                    memmove(recvBuffer, recvBuffer + body_length, recvBufferCount);
                }
            }
            status = METHOD;
#ifdef DEBUG
            for (std::unordered_map<string, string>::iterator iter = request.headers.begin(); iter != request.headers.end(); iter++)
            {
                string key=iter->first;
                string value=iter->second;
                LOG(DEBUG) << "HTTP header: (" << key << ", " << value << ")";
            }
#endif // DEBUG
            handleRequest();
        }else{
            std::vector<string> parts = line.split(":", 1);
            if (parts.size() != 2)
                LOG(WARNING) << "Invalid HTTP header: " << line;
            else
                request.headers[parts[0].strip().lower()] = parts[1];
        }
        break;
    }
    return true;
}

void HttpServerConnection::handleRequest()
{
    reply_code = 200;
    headers_send = false;

    for(unsigned int n=0; n<server->handlers.size(); n++)
    {
        if (server->handlers[n]->handleRequest(request, this))
            break;
        if (headers_send)
            break;
    }

    if (!headers_send)
    {
        reply_code = 404;
        string replyData = "File not found";
        sendData(replyData.c_str(), replyData.size());
    }
    string end_chunk = "0\r\n\r\n";
    socket.send(end_chunk.c_str(), end_chunk.size());
    request.parameters.clear();
}

void HttpServerConnection::sendHeaders()
{
    string reply = string("HTTP/1.1 ") + string(reply_code) + " OK\r\n";
    reply += "Content-type: text/html\r\n";
    reply += "Connection: Keep-Alive\r\n";
    reply += "Transfer-Encoding: chunked\r\n";
    reply += "\r\n";
    socket.send(reply.c_str(), reply.size());
    headers_send = true;
}

void HttpServerConnection::sendData(const char* data, size_t data_length)
{
    if (!headers_send)
        sendHeaders();
    if (data_length < 1)
        return;
    string chunk_len_string = string::hex(static_cast<int>(data_length)) + "\r\n";
    socket.send(chunk_len_string.c_str(), chunk_len_string.size());
    socket.send(data, data_length);
    socket.send("\r\n", 2);
}

bool HttpRequestFileHandler::handleRequest(HttpRequest& request, HttpServerConnection* connection)
{
    string replyData = "";
    FILE* f = NULL;
    if (request.path == "/")
        request.path = "/index.html";
    if (request.path.find("..") != -1)
        return false;

    string fullPath = base_path + request.path;
    f = fopen(fullPath.c_str(), "rb");
    if (!f)
        return false;

    while(true)
    {
        char buffer[1024];
        size_t n = fread(buffer, 1, sizeof(buffer), f);
        if (n < 1)
            break;
        connection->sendData(buffer, n);
    }
    fclose(f);
    return true;
}
<|endoftext|>