<commit_before>// Copyright 2010-2021, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "rewriter/small_letter_rewriter.h"

#include <iterator>
#include <memory>
#include <string>

#include "base/system_util.h"
#include "engine/mock_data_engine_factory.h"
#include "protocol/commands.pb.h"
#include "protocol/config.pb.h"
#include "testing/base/public/gunit.h"

namespace mozc {
namespace {

void AddSegment(const std::string &key, const std::string &value,
                Segments *segments) {
  Segment *seg = segments->add_segment();
  Segment::Candidate *candidate = seg->add_candidate();
  seg->set_key(key);
  candidate->content_key = key;
  candidate->value = value;
  candidate->content_value = value;
}

void InitSegments(const std::string &key, const std::string &value,
                  Segments *segments) {
  segments->Clear();
  AddSegment(key, value, segments);
}

bool ContainCandidate(const Segments &segments, const std::string &candidate) {
  const Segment &segment = segments.segment(0);
  for (size_t i = 0; i < segment.candidates_size(); ++i) {
    if (candidate == segment.candidate(i).value) {
      return true;
    }
  }
  return false;
}

}  // namespace

class SmallLetterRewriterTest : public ::testing::Test {
 protected:
  // Workaround for C2512 error (no default appropriate constructor) on MSVS.
  SmallLetterRewriterTest() {}
  ~SmallLetterRewriterTest() override {}

  void SetUp() override {
    SystemUtil::SetUserProfileDirectory(absl::GetFlag(FLAGS_test_tmpdir));
    engine_ = MockDataEngineFactory::Create().value();
  }

  std::unique_ptr<EngineInterface> engine_;
  const commands::Request &default_request() const { return default_request_; }
  const config::Config &default_config() const { return default_config_; }

 private:
  const commands::Request default_request_;
  const config::Config default_config_;
};

TEST_F(SmallLetterRewriterTest, ScriptConversionTest) {
  Segments segments;
  SmallLetterRewriter rewriter(engine_->GetConverter());
  const ConversionRequest request;

  struct InputOutputData {
    const char *input;
    const char *output;
  };

  const InputOutputData kInputOutputData[] = {
      // Superscript
      {"^123", "¹²³"},
      {"^4", "⁴"},
      {"^56789", "⁵⁶⁷⁸⁹"},

      // Subscript
      {"_123", "₁₂₃"},
      {"_4", "₄"},
      {"_56789", "₅₆₇₈₉"},
  };

  const char *kMozcUnsupportedInput[] = {
      // Roman alhapet superscript/subscript
      "^n",
      "^x",
      "^a",
      "^2x",

      "_m",
      "_y",
      "_b",
      "_2y",

      // Symbol superscript/subscript
      "^+",
      "_-",
  };

  // Allowed cases
  for (size_t i = 0; i < std::size(kInputOutputData); ++i) {
    InitSegments(kInputOutputData[i].input, kInputOutputData[i].input,
                 &segments);
    EXPECT_TRUE(rewriter.Rewrite(request, &segments));
    EXPECT_TRUE(ContainCandidate(segments, kInputOutputData[i].output));
  }

  // Mozc does not accept some superscript/subscript supported in Unicode
  for (size_t i = 0; i < std::size(kMozcUnsupportedInput); ++i) {
    InitSegments(kMozcUnsupportedInput[i], kMozcUnsupportedInput[i], &segments);
    EXPECT_FALSE(rewriter.Rewrite(request, &segments));
  }

  // Invalid style input
  InitSegments("^", "^", &segments);
  EXPECT_FALSE(rewriter.Rewrite(request, &segments));

  InitSegments("_", "_", &segments);
  EXPECT_FALSE(rewriter.Rewrite(request, &segments));

  InitSegments("12345", "12345", &segments);
  EXPECT_FALSE(rewriter.Rewrite(request, &segments));

  InitSegments("^^12345", "^^12345", &segments);
  EXPECT_FALSE(rewriter.Rewrite(request, &segments));
}

TEST_F(SmallLetterRewriterTest, MultipleSegment) {
  Segments segments;
  SmallLetterRewriter rewriter(engine_->GetConverter());
  const ConversionRequest request;

  // Multiple segments are combined.
  InitSegments("^123", "^123", &segments);
  AddSegment("45", "45", &segments);
  AddSegment("6", "6", &segments);
  EXPECT_TRUE(rewriter.Rewrite(request, &segments));
  EXPECT_EQ(1, segments.conversion_segments_size());
  EXPECT_EQ("¹²³⁴⁵⁶", segments.conversion_segment(0).candidate(0).value);

  // If the segments is already resized, returns false.
  InitSegments("^123", "^123", &segments);
  AddSegment("^123", "^123", &segments);
  segments.set_resized(true);
  EXPECT_FALSE(rewriter.Rewrite(request, &segments));

  // History segment has to be ignored.
  // In this case 1st segment is HISTORY
  // so this rewriting returns true.
  InitSegments("^123", "^123", &segments);
  AddSegment("^123", "^123", &segments);
  segments.set_resized(true);
  segments.mutable_segment(0)->set_segment_type(Segment::HISTORY);
  EXPECT_TRUE(rewriter.Rewrite(request, &segments));
  EXPECT_EQ("¹²³", segments.conversion_segment(0).candidate(0).value);
}

}  // namespace mozc
<commit_msg>Include googletest.h to fix the build error.<commit_after>// Copyright 2010-2021, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "rewriter/small_letter_rewriter.h"

#include <iterator>
#include <memory>
#include <string>

#include "base/system_util.h"
#include "engine/mock_data_engine_factory.h"
#include "protocol/commands.pb.h"
#include "protocol/config.pb.h"
#include "testing/base/public/googletest.h"
#include "testing/base/public/gunit.h"

namespace mozc {
namespace {

void AddSegment(const std::string &key, const std::string &value,
                Segments *segments) {
  Segment *seg = segments->add_segment();
  Segment::Candidate *candidate = seg->add_candidate();
  seg->set_key(key);
  candidate->content_key = key;
  candidate->value = value;
  candidate->content_value = value;
}

void InitSegments(const std::string &key, const std::string &value,
                  Segments *segments) {
  segments->Clear();
  AddSegment(key, value, segments);
}

bool ContainCandidate(const Segments &segments, const std::string &candidate) {
  const Segment &segment = segments.segment(0);
  for (size_t i = 0; i < segment.candidates_size(); ++i) {
    if (candidate == segment.candidate(i).value) {
      return true;
    }
  }
  return false;
}

}  // namespace

class SmallLetterRewriterTest : public ::testing::Test {
 protected:
  // Workaround for C2512 error (no default appropriate constructor) on MSVS.
  SmallLetterRewriterTest() {}
  ~SmallLetterRewriterTest() override {}

  void SetUp() override {
    SystemUtil::SetUserProfileDirectory(absl::GetFlag(FLAGS_test_tmpdir));
    engine_ = MockDataEngineFactory::Create().value();
  }

  std::unique_ptr<EngineInterface> engine_;
  const commands::Request &default_request() const { return default_request_; }
  const config::Config &default_config() const { return default_config_; }

 private:
  const commands::Request default_request_;
  const config::Config default_config_;
};

TEST_F(SmallLetterRewriterTest, ScriptConversionTest) {
  Segments segments;
  SmallLetterRewriter rewriter(engine_->GetConverter());
  const ConversionRequest request;

  struct InputOutputData {
    const char *input;
    const char *output;
  };

  const InputOutputData kInputOutputData[] = {
      // Superscript
      {"^123", "¹²³"},
      {"^4", "⁴"},
      {"^56789", "⁵⁶⁷⁸⁹"},

      // Subscript
      {"_123", "₁₂₃"},
      {"_4", "₄"},
      {"_56789", "₅₆₇₈₉"},
  };

  const char *kMozcUnsupportedInput[] = {
      // Roman alhapet superscript/subscript
      "^n",
      "^x",
      "^a",
      "^2x",

      "_m",
      "_y",
      "_b",
      "_2y",

      // Symbol superscript/subscript
      "^+",
      "_-",
  };

  // Allowed cases
  for (size_t i = 0; i < std::size(kInputOutputData); ++i) {
    InitSegments(kInputOutputData[i].input, kInputOutputData[i].input,
                 &segments);
    EXPECT_TRUE(rewriter.Rewrite(request, &segments));
    EXPECT_TRUE(ContainCandidate(segments, kInputOutputData[i].output));
  }

  // Mozc does not accept some superscript/subscript supported in Unicode
  for (size_t i = 0; i < std::size(kMozcUnsupportedInput); ++i) {
    InitSegments(kMozcUnsupportedInput[i], kMozcUnsupportedInput[i], &segments);
    EXPECT_FALSE(rewriter.Rewrite(request, &segments));
  }

  // Invalid style input
  InitSegments("^", "^", &segments);
  EXPECT_FALSE(rewriter.Rewrite(request, &segments));

  InitSegments("_", "_", &segments);
  EXPECT_FALSE(rewriter.Rewrite(request, &segments));

  InitSegments("12345", "12345", &segments);
  EXPECT_FALSE(rewriter.Rewrite(request, &segments));

  InitSegments("^^12345", "^^12345", &segments);
  EXPECT_FALSE(rewriter.Rewrite(request, &segments));
}

TEST_F(SmallLetterRewriterTest, MultipleSegment) {
  Segments segments;
  SmallLetterRewriter rewriter(engine_->GetConverter());
  const ConversionRequest request;

  // Multiple segments are combined.
  InitSegments("^123", "^123", &segments);
  AddSegment("45", "45", &segments);
  AddSegment("6", "6", &segments);
  EXPECT_TRUE(rewriter.Rewrite(request, &segments));
  EXPECT_EQ(1, segments.conversion_segments_size());
  EXPECT_EQ("¹²³⁴⁵⁶", segments.conversion_segment(0).candidate(0).value);

  // If the segments is already resized, returns false.
  InitSegments("^123", "^123", &segments);
  AddSegment("^123", "^123", &segments);
  segments.set_resized(true);
  EXPECT_FALSE(rewriter.Rewrite(request, &segments));

  // History segment has to be ignored.
  // In this case 1st segment is HISTORY
  // so this rewriting returns true.
  InitSegments("^123", "^123", &segments);
  AddSegment("^123", "^123", &segments);
  segments.set_resized(true);
  segments.mutable_segment(0)->set_segment_type(Segment::HISTORY);
  EXPECT_TRUE(rewriter.Rewrite(request, &segments));
  EXPECT_EQ("¹²³", segments.conversion_segment(0).candidate(0).value);
}

}  // namespace mozc
<|endoftext|>


<commit_before>//      Command.cpp
//

#include <vector>
#include <string>
#include "CommandFactory.h"
#include "Command.h"

CommandAbstract* CommandFactory::create(Player* &player, std::vector <std::string> commandFull)
{
    std::string cmd = commandFull[0];
    commandFull.erase(commandFull.begin());

    CommandAbstract* command;

    if (cmd.compare("talk") == 0) {
        if (!player->isConnected() || !player->connect()) {
            throw "A player must be connected to launch the command talk";
        }
        command = new CommandTalk();
    }
    else {
        return NULL;
    }

    command->setArgs(commandFull);
    command->setPlayer(player);
    return command;
}
<commit_msg>command plugged<commit_after>//      Command.cpp
//

#include <vector>
#include <string>
#include "CommandFactory.h"
#include "Command.h"

CommandAbstract* CommandFactory::create(Player* &player, std::vector <std::string> commandFull)
{
    std::string cmd = commandFull[0];
    commandFull.erase(commandFull.begin());

    CommandAbstract* command;

    if (cmd.compare("talk") == 0) {
        if (!player->isConnected() || !player->connect()) {
            throw "A player must be connected to launch the command talk";
        }
        command = new CommandTalk();
    }
    else if (cmd.compare("createPlayer") == 0) {
        if (player->isConnected()) {
            throw "There must not be a connected player to create a new player";
        }
    }
    else {
        return NULL;
    }

    command->setArgs(commandFull);
    command->setPlayer(player);
    return command;
}
<|endoftext|>


<commit_before>/*
 * KaRad.c
 *
 *  Created on: Dec 24, 2015
 *      Author: molnarkaroly
 */

/**
 * KaRad
 *
 * (C) Karoly Molnar 2015
 * MIT license see license.md in the repository
 */

#include <Arduino.h>

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

extern "C" {
#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#include "mem.h"
#include "user_interface.h"
#include "cont.h"
}

#include "apikey.h" //contains a single line of 'String apikey = "XXXXXXXXXXXXX";'

ADC_MODE(ADC_VCC);

const int led_pin = BUILTIN_LED;//or 13;
const int beep_pin = D1; // GPIO05
const char ap_hostname[] = "KaRad1";
#define CPM_BEEP_LIMIT 100
#define T_REPORT_MS (60 * 1000)
const char* server = "emoncms.org";

#define CFG_VALID	0x1abbcc

void configModeCallback () {
    digitalWrite(led_pin, LOW); //turn LED on if AP mode i.e. configuration is needed
}

enum sensorState_t {
    sensor_standalone,
    sensor_connected,
    sensor_update,
    sensor_unknown};

bool sendUpdate(uint16_t voltage, uint16_t cpm);

WiFiManager wifiManager;

WiFiClient client;

typedef struct {
    uint32_t s_cpm;
    uint32_t s_time;
    uint32_t s_beep;
    uint32_t s_report;
    sensorState_t sensorState;
    uint32_t s_valid;
}saved_t;

saved_t rtcStore;
uint32_t cpm;

#define DEBUG

void setup() {
    bool report = false;
    //the wakeup was caused by a new impulse form the GM tube
    uint32_t t_now = millis();//we store ms not us
    system_rtc_mem_read(65, &rtcStore, sizeof(rtcStore));
    pinMode(led_pin, OUTPUT);

    if(rtcStore.s_valid != CFG_VALID) {
        rtcStore.s_cpm = 0;
        rtcStore.s_time = system_get_time()/1000;
        rtcStore.s_beep = 0;
        rtcStore.s_report = 0;
        rtcStore.sensorState = sensor_unknown;
        rtcStore.s_valid = CFG_VALID;
        cpm = 0;
    }else {
        if((rtcStore.s_beep) || (rtcStore.s_cpm > CPM_BEEP_LIMIT)) {
            analogWriteFreq(2000);
            pinMode(beep_pin,OUTPUT);
            analogWrite(beep_pin,PWMRANGE>>1);
            delay(10);
            analogWrite(beep_pin,0);
        }

#ifdef DEBUG
        digitalWrite(led_pin, LOW);
        delay(50);
        digitalWrite(led_pin, HIGH);
#endif

        uint32_t t_diff;
        if(t_now > rtcStore.s_time) {
            t_diff = t_now - rtcStore.s_time;
        }else {
            t_diff = (0xffffffff - rtcStore.s_time) + t_now;
        }
        rtcStore.s_cpm++;
        if(t_diff >= T_REPORT_MS) { // time to report!
            if(rtcStore.s_report) {
                cpm = (rtcStore.s_cpm * t_diff) / T_REPORT_MS;
                rtcStore.s_cpm = 0;
                rtcStore.s_report = 0;
            }else {
                rtcStore.s_cpm--;
                rtcStore.s_report = 1;
                system_rtc_mem_write(65, &rtcStore, sizeof(rtcStore));
                system_deep_sleep_set_option(1);	// enable radio after wakeup
                system_deep_sleep(2); // wake up immediately
            }
        }else {
            rtcStore.s_time = t_now;
            system_rtc_mem_write(65, &rtcStore, sizeof(rtcStore));
            system_deep_sleep_set_option(4);	// no radio after wakeup
            system_deep_sleep(0); // wait for falling edge on reset pin
        }

    }

    Serial.begin(115200);

    //reset saved settings
    //	wifiManager.resetSettings();
    if(rtcStore.sensorState != sensor_standalone) {
        struct rst_info *thisreset;
        thisreset = system_get_rst_info();

        if(thisreset->reason != REASON_DEEP_SLEEP_AWAKE) {
            wifiManager.setTimeout(180);
        }else {
            wifiManager.setTimeout(20);
        }

        wifiManager.setAPCallback(configModeCallback);

        ArduinoOTA.onStart([]() {
            digitalWrite(led_pin, LOW);
            rtcStore.sensorState = sensor_update;
        });
        ArduinoOTA.onEnd([]() {
            //invalidate config
            rtcStore.s_valid = 0;
            system_rtc_mem_write(65, &rtcStore, sizeof(rtcStore));
            digitalWrite(led_pin, HIGH);
        });
        ArduinoOTA.onError([](ota_error_t error) {
            Serial.printf("Error[%u]: ", error);
            rtcStore.sensorState = sensor_connected;
        });

        if(wifiManager.autoConnect(ap_hostname)) {
            //if you get here you have connected to the WiFi
            Serial.println("connected... :)");
            rtcStore.sensorState = sensor_connected;
            ArduinoOTA.setHostname(ap_hostname);
            ArduinoOTA.begin();
        }else {
            //was unable to connect and timeout
            Serial.println("No connection was possible within 3 minutes... :(");
            rtcStore.sensorState = sensor_standalone;
            rtcStore.s_beep = 1;
        }
    }else {
        rtcStore.s_time = millis();
        system_rtc_mem_write(65, &rtcStore, sizeof(rtcStore));
        system_deep_sleep_set_option(4);	// no radio after wakeup
        system_deep_sleep(0); // wait for falling edge on reset pin
    }
}

void loop() {

#ifdef WDT_ENABLED
    ESP.wdtFeed();
#endif

    if(rtcStore.sensorState == sensor_connected) {
        uint16_t voltage = ESP.getVcc();
        if(!sendUpdate(voltage,cpm)) {
            rtcStore.s_beep = 1;
        }
        rtcStore.s_time = millis();
        system_rtc_mem_write(65, &rtcStore, sizeof(rtcStore));
        system_deep_sleep_set_option(4);	// no radio after wakeup
        system_deep_sleep(0); // wait for falling edge on reset pin

    }

    if(rtcStore.sensorState == sensor_update) {
        ArduinoOTA.handle();
    }
}

bool sendUpdate(uint16_t voltage, uint16_t cpm) {
    if (client.connect(server,80)) {
        client.print("GET /input/post.json?json={");
        client.print("vbat:");
        client.print(voltage);
        client.print(",cpm:");
        client.print(cpm);
        client.print("}&apikey=");
        client.print(apikey);
        client.println(" HTTP/1.1");
        client.println("Host:emoncms.org");
        client.println("User-Agent: ESP8266-KaRad");
        client.println("Connection: close");
        client.println();
        return true;
    }else {
        return false;
    }
}

<commit_msg>voltage reading moved up before Wifi is connected in order to improve accuracy<commit_after>/*
 * KaRad.c
 *
 *  Created on: Dec 24, 2015
 *      Author: molnarkaroly
 */

/**
 * KaRad
 *
 * (C) Karoly Molnar 2015
 * MIT license see license.md in the repository
 */

#include <Arduino.h>

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

extern "C" {
#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#include "mem.h"
#include "user_interface.h"
#include "cont.h"
}

#include "apikey.h" //contains a single line of 'String apikey = "XXXXXXXXXXXXX";'

ADC_MODE(ADC_VCC);

const int led_pin = BUILTIN_LED;//or 13;
const int beep_pin = D1; // GPIO05
const char ap_hostname[] = "KaRad1";
#define CPM_BEEP_LIMIT 100
#define T_REPORT_MS (60 * 1000)
const char* server = "emoncms.org";

#define CFG_VALID	0x1abbcc

void configModeCallback () {
    digitalWrite(led_pin, LOW); //turn LED on if AP mode i.e. configuration is needed
}

enum sensorState_t {
    sensor_standalone,
    sensor_connected,
    sensor_update,
    sensor_unknown};

bool sendUpdate(uint16_t voltage, uint16_t cpm);

WiFiManager wifiManager;

WiFiClient client;

typedef struct {
    uint32_t s_cpm;
    uint32_t s_time;
    uint32_t s_beep;
    uint32_t s_report;
    sensorState_t sensorState;
    uint32_t s_valid;
}saved_t;

saved_t rtcStore;
uint32_t cpm;
uint16_t voltage;

#define DEBUG

void setup() {
    bool report = false;
    //the wakeup was caused by a new impulse form the GM tube
    uint32_t t_now = millis();//we store ms not us
    system_rtc_mem_read(65, &rtcStore, sizeof(rtcStore));
    pinMode(led_pin, OUTPUT);

    if(rtcStore.s_valid != CFG_VALID) {
        rtcStore.s_cpm = 0;
        rtcStore.s_time = system_get_time()/1000;
        rtcStore.s_beep = 0;
        rtcStore.s_report = 0;
        rtcStore.sensorState = sensor_unknown;
        rtcStore.s_valid = CFG_VALID;
        cpm = 0;
    }else {
        if((rtcStore.s_beep) || (rtcStore.s_cpm > CPM_BEEP_LIMIT)) {
            analogWriteFreq(2000);
            pinMode(beep_pin,OUTPUT);
            analogWrite(beep_pin,PWMRANGE>>1);
            delay(10);
            analogWrite(beep_pin,0);
        }

#ifdef DEBUG
        digitalWrite(led_pin, LOW);
        delay(50);
        digitalWrite(led_pin, HIGH);
#endif

        uint32_t t_diff;
        if(t_now > rtcStore.s_time) {
            t_diff = t_now - rtcStore.s_time;
        }else {
            t_diff = (0xffffffff - rtcStore.s_time) + t_now;
        }
        rtcStore.s_cpm++;
        if(t_diff >= T_REPORT_MS) { // time to report!
            if(rtcStore.s_report) {
                cpm = (rtcStore.s_cpm * t_diff) / T_REPORT_MS;
                rtcStore.s_cpm = 0;
                rtcStore.s_report = 0;
            }else {
                rtcStore.s_cpm--;
                rtcStore.s_report = 1;
                system_rtc_mem_write(65, &rtcStore, sizeof(rtcStore));
                system_deep_sleep_set_option(1);	// enable radio after wakeup
                system_deep_sleep(2); // wake up immediately
            }
        }else {
            rtcStore.s_time = t_now;
            system_rtc_mem_write(65, &rtcStore, sizeof(rtcStore));
            system_deep_sleep_set_option(4);	// no radio after wakeup
            system_deep_sleep(0); // wait for falling edge on reset pin
        }

    }

    Serial.begin(115200);
    voltage = ESP.getVcc();

    //reset saved settings
    //	wifiManager.resetSettings();
    if(rtcStore.sensorState != sensor_standalone) {
        struct rst_info *thisreset;
        thisreset = system_get_rst_info();

        if(thisreset->reason != REASON_DEEP_SLEEP_AWAKE) {
            wifiManager.setTimeout(180);
        }else {
            wifiManager.setTimeout(20);
        }

        wifiManager.setAPCallback(configModeCallback);

        ArduinoOTA.onStart([]() {
            digitalWrite(led_pin, LOW);
            rtcStore.sensorState = sensor_update;
        });
        ArduinoOTA.onEnd([]() {
            //invalidate config
            rtcStore.s_valid = 0;
            system_rtc_mem_write(65, &rtcStore, sizeof(rtcStore));
            digitalWrite(led_pin, HIGH);
        });
        ArduinoOTA.onError([](ota_error_t error) {
            Serial.printf("Error[%u]: ", error);
            rtcStore.sensorState = sensor_connected;
        });

        if(wifiManager.autoConnect(ap_hostname)) {
            //if you get here you have connected to the WiFi
            Serial.println("connected... :)");
            rtcStore.sensorState = sensor_connected;
            ArduinoOTA.setHostname(ap_hostname);
            ArduinoOTA.begin();
        }else {
            //was unable to connect and timeout
            Serial.println("No connection was possible within 3 minutes... :(");
            rtcStore.sensorState = sensor_standalone;
            rtcStore.s_beep = 1;
        }
    }else {
        rtcStore.s_time = millis();
        system_rtc_mem_write(65, &rtcStore, sizeof(rtcStore));
        system_deep_sleep_set_option(4);	// no radio after wakeup
        system_deep_sleep(0); // wait for falling edge on reset pin
    }
}

void loop() {

#ifdef WDT_ENABLED
    ESP.wdtFeed();
#endif

    if(rtcStore.sensorState == sensor_connected) {
        if(!sendUpdate(voltage,cpm)) {
            rtcStore.s_beep = 1;
        }
        rtcStore.s_time = millis();
        system_rtc_mem_write(65, &rtcStore, sizeof(rtcStore));
        system_deep_sleep_set_option(4);	// no radio after wakeup
        system_deep_sleep(0); // wait for falling edge on reset pin

    }

    if(rtcStore.sensorState == sensor_update) {
        ArduinoOTA.handle();
    }
}

bool sendUpdate(uint16_t voltage, uint16_t cpm) {
    if (client.connect(server,80)) {
        client.print("GET /input/post.json?json={");
        client.print("vbat:");
        client.print(voltage);
        client.print(",cpm:");
        client.print(cpm);
        client.print("}&apikey=");
        client.print(apikey);
        client.println(" HTTP/1.1");
        client.println("Host:emoncms.org");
        client.println("User-Agent: ESP8266-KaRad");
        client.println("Connection: close");
        client.println();
        return true;
    }else {
        return false;
    }
}

<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexVB.cxx
 ** Lexer for Visual Basic and VBScript.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static bool IsVBComment(Accessor &styler, int pos, int len) {
	return len>0 && styler[pos]=='\'';
}

inline bool IsTypeCharacter(const int ch) {
	return ch == '%' || ch == '&' || ch == '@' || ch == '!' || ch == '#' || ch == '$';
}

inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static void ColouriseVBDoc(unsigned int startPos, int length, int initStyle,
                           WordList *keywordlists[], Accessor &styler, bool vbScriptSyntax) {

	WordList &keywords = *keywordlists[0];

	styler.StartAt(startPos);

	int visibleChars = 0;

	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward()) {

		if (sc.state == SCE_B_OPERATOR) {
			sc.SetState(SCE_B_DEFAULT);
		} else if (sc.state == SCE_B_KEYWORD) {
			if (!IsAWordChar(sc.ch)) {
				if (vbScriptSyntax || !IsTypeCharacter(sc.ch)) {
					if (sc.ch == ']')
						sc.Forward();
					char s[100];
					sc.GetCurrentLowered(s, sizeof(s));
					if (keywords.InList(s)) {
						if (strcmp(s, "rem") == 0) {
							sc.ChangeState(SCE_B_COMMENT);
							if (sc.atLineEnd) {
								sc.SetState(SCE_B_DEFAULT);
							}
						} else {
							sc.SetState(SCE_B_DEFAULT);
						}
					} else {
						sc.ChangeState(SCE_B_IDENTIFIER);
						sc.SetState(SCE_B_DEFAULT);
					}
				}
			}
		} else if (sc.state == SCE_B_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_B_DEFAULT);
			}
		} else if (sc.state == SCE_B_STRING) {
			// VB doubles quotes to preserve them, so just end this string
			// state now as a following quote will start again
			if (sc.ch == '\"') {
				if (tolower(sc.chNext) == 'c') {
					sc.Forward();
				}
				sc.ForwardSetState(SCE_B_DEFAULT);
			}
		} else if (sc.state == SCE_B_COMMENT) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_B_DEFAULT);
			}
		} else if (sc.state == SCE_B_PREPROCESSOR) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_B_DEFAULT);
			}
		} else if (sc.state == SCE_B_DATE) {
			if (sc.ch == '#') {
				sc.ForwardSetState(SCE_B_DEFAULT);
			}
		}

		if (sc.state == SCE_B_DEFAULT) {
			if (sc.ch == '\'') {
				sc.SetState(SCE_B_COMMENT);
			} else if (sc.ch == '\"') {
				sc.SetState(SCE_B_STRING);
			} else if (sc.ch == '#' && visibleChars == 0) {
				// Preprocessor commands are alone on their line
				sc.SetState(SCE_B_PREPROCESSOR);
			} else if (sc.ch == '#') {
				int n = 1;
				int chSeek = ' ';
				while (chSeek == ' ' || chSeek == '\t') {
					chSeek = sc.GetRelative(n);
					n++;
				}
				if (IsADigit(chSeek)) {
					sc.SetState(SCE_B_DATE);
				} else {
					sc.SetState(SCE_B_OPERATOR);
				}
			} else if (sc.ch == '&' && tolower(sc.chNext) == 'h') {
				sc.SetState(SCE_B_NUMBER);
			} else if (sc.ch == '&' && tolower(sc.chNext) == 'o') {
				sc.SetState(SCE_B_NUMBER);
			} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				sc.SetState(SCE_B_NUMBER);
			} else if (IsAWordStart(sc.ch) || (sc.ch == '[')) {
				sc.SetState(SCE_B_KEYWORD);
			} else if (isoperator(static_cast<char>(sc.ch)) || (sc.ch == '\\')) {
				sc.SetState(SCE_B_OPERATOR);
			}
		}

		if (sc.atLineEnd) {
			visibleChars = 0;
		}
		if (!IsASpace(sc.ch)) {
			visibleChars++;
		}
	}
	sc.Complete();
}

static void FoldVBDoc(unsigned int startPos, int length, int,
						   WordList *[], Accessor &styler) {
	int endPos = startPos + length;

	// Backtrack to previous line in case need to fix its fold status
	int lineCurrent = styler.GetLine(startPos);
	if (startPos > 0) {
		if (lineCurrent > 0) {
			lineCurrent--;
			startPos = styler.LineStart(lineCurrent);
		}
	}
	int spaceFlags = 0;
	int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsVBComment);
	char chNext = styler[startPos];
	for (int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) {
			int lev = indentCurrent;
			int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsVBComment);
			if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
				// Only non whitespace lines can be headers
				if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
					lev |= SC_FOLDLEVELHEADERFLAG;
				} else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
					// Line after is blank so check the next - maybe should continue further?
					int spaceFlags2 = 0;
					int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsVBComment);
					if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
						lev |= SC_FOLDLEVELHEADERFLAG;
					}
				}
			}
			indentCurrent = indentNext;
			styler.SetLevel(lineCurrent, lev);
			lineCurrent++;
		}
	}
}

static void ColouriseVBNetDoc(unsigned int startPos, int length, int initStyle,
                           WordList *keywordlists[], Accessor &styler) {
	ColouriseVBDoc(startPos, length, initStyle, keywordlists, styler, false);
}

static void ColouriseVBScriptDoc(unsigned int startPos, int length, int initStyle,
                           WordList *keywordlists[], Accessor &styler) {
	ColouriseVBDoc(startPos, length, initStyle, keywordlists, styler, true);
}

LexerModule lmVB(SCLEX_VB, ColouriseVBNetDoc, "vb", FoldVBDoc);
LexerModule lmVBScript(SCLEX_VBSCRIPT, ColouriseVBScriptDoc, "vbscript", FoldVBDoc);

<commit_msg>Made file handle constants in statements such as "close #1" work by styling them in the date literal style.<commit_after>// Scintilla source code edit control
/** @file LexVB.cxx
 ** Lexer for Visual Basic and VBScript.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static bool IsVBComment(Accessor &styler, int pos, int len) {
	return len>0 && styler[pos]=='\'';
}

inline bool IsTypeCharacter(const int ch) {
	return ch == '%' || ch == '&' || ch == '@' || ch == '!' || ch == '#' || ch == '$';
}

inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

inline bool IsADateCharacter(const int ch) {
	return (ch < 0x80) &&
		(isalnum(ch) || ch == '|' || ch == '-' || ch == '/' || ch == ':' || ch == ' ' || ch == '\t');
}

static void ColouriseVBDoc(unsigned int startPos, int length, int initStyle,
                           WordList *keywordlists[], Accessor &styler, bool vbScriptSyntax) {

	WordList &keywords = *keywordlists[0];

	styler.StartAt(startPos);

	int visibleChars = 0;

	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward()) {

		if (sc.state == SCE_B_OPERATOR) {
			sc.SetState(SCE_B_DEFAULT);
		} else if (sc.state == SCE_B_KEYWORD) {
			if (!IsAWordChar(sc.ch)) {
				if (vbScriptSyntax || !IsTypeCharacter(sc.ch)) {
					if (sc.ch == ']')
						sc.Forward();
					char s[100];
					sc.GetCurrentLowered(s, sizeof(s));
					if (keywords.InList(s)) {
						if (strcmp(s, "rem") == 0) {
							sc.ChangeState(SCE_B_COMMENT);
							if (sc.atLineEnd) {
								sc.SetState(SCE_B_DEFAULT);
							}
						} else {
							sc.SetState(SCE_B_DEFAULT);
						}
					} else {
						sc.ChangeState(SCE_B_IDENTIFIER);
						sc.SetState(SCE_B_DEFAULT);
					}
				}
			}
		} else if (sc.state == SCE_B_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_B_DEFAULT);
			}
		} else if (sc.state == SCE_B_STRING) {
			// VB doubles quotes to preserve them, so just end this string
			// state now as a following quote will start again
			if (sc.ch == '\"') {
				if (tolower(sc.chNext) == 'c') {
					sc.Forward();
				}
				sc.ForwardSetState(SCE_B_DEFAULT);
			}
		} else if (sc.state == SCE_B_COMMENT) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_B_DEFAULT);
			}
		} else if (sc.state == SCE_B_PREPROCESSOR) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_B_DEFAULT);
			}
		} else if (sc.state == SCE_B_DATE) {
			if (sc.ch == '#' || !IsADateCharacter(sc.chNext)) {
				sc.ForwardSetState(SCE_B_DEFAULT);
			}
		}

		if (sc.state == SCE_B_DEFAULT) {
			if (sc.ch == '\'') {
				sc.SetState(SCE_B_COMMENT);
			} else if (sc.ch == '\"') {
				sc.SetState(SCE_B_STRING);
			} else if (sc.ch == '#' && visibleChars == 0) {
				// Preprocessor commands are alone on their line
				sc.SetState(SCE_B_PREPROCESSOR);
			} else if (sc.ch == '#') {
				int n = 1;
				int chSeek = ' ';
				while (chSeek == ' ' || chSeek == '\t') {
					chSeek = sc.GetRelative(n);
					n++;
				}
				if (IsADigit(chSeek)) {
					sc.SetState(SCE_B_DATE);
				} else {
					sc.SetState(SCE_B_OPERATOR);
				}
			} else if (sc.ch == '&' && tolower(sc.chNext) == 'h') {
				sc.SetState(SCE_B_NUMBER);
			} else if (sc.ch == '&' && tolower(sc.chNext) == 'o') {
				sc.SetState(SCE_B_NUMBER);
			} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				sc.SetState(SCE_B_NUMBER);
			} else if (IsAWordStart(sc.ch) || (sc.ch == '[')) {
				sc.SetState(SCE_B_KEYWORD);
			} else if (isoperator(static_cast<char>(sc.ch)) || (sc.ch == '\\')) {
				sc.SetState(SCE_B_OPERATOR);
			}
		}

		if (sc.atLineEnd) {
			visibleChars = 0;
		}
		if (!IsASpace(sc.ch)) {
			visibleChars++;
		}
	}
	sc.Complete();
}

static void FoldVBDoc(unsigned int startPos, int length, int,
						   WordList *[], Accessor &styler) {
	int endPos = startPos + length;

	// Backtrack to previous line in case need to fix its fold status
	int lineCurrent = styler.GetLine(startPos);
	if (startPos > 0) {
		if (lineCurrent > 0) {
			lineCurrent--;
			startPos = styler.LineStart(lineCurrent);
		}
	}
	int spaceFlags = 0;
	int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsVBComment);
	char chNext = styler[startPos];
	for (int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) {
			int lev = indentCurrent;
			int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsVBComment);
			if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
				// Only non whitespace lines can be headers
				if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
					lev |= SC_FOLDLEVELHEADERFLAG;
				} else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
					// Line after is blank so check the next - maybe should continue further?
					int spaceFlags2 = 0;
					int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsVBComment);
					if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
						lev |= SC_FOLDLEVELHEADERFLAG;
					}
				}
			}
			indentCurrent = indentNext;
			styler.SetLevel(lineCurrent, lev);
			lineCurrent++;
		}
	}
}

static void ColouriseVBNetDoc(unsigned int startPos, int length, int initStyle,
                           WordList *keywordlists[], Accessor &styler) {
	ColouriseVBDoc(startPos, length, initStyle, keywordlists, styler, false);
}

static void ColouriseVBScriptDoc(unsigned int startPos, int length, int initStyle,
                           WordList *keywordlists[], Accessor &styler) {
	ColouriseVBDoc(startPos, length, initStyle, keywordlists, styler, true);
}

LexerModule lmVB(SCLEX_VB, ColouriseVBNetDoc, "vb", FoldVBDoc);
LexerModule lmVBScript(SCLEX_VBSCRIPT, ColouriseVBScriptDoc, "vbscript", FoldVBDoc);

<|endoftext|>


<commit_before>// sensorFile.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iomanip>

template <typename T> BaseImage<T> undistort(const BaseImage<T>& src, const mat4f& intrinsic, const float coeff[5])
{
	BaseImage<T> res(src.getWidth(), src.getHeight());
	res.setInvalidValue(src.getInvalidValue());
	res.setPixels(res.getInvalidValue());

	for (unsigned int y = 0; y < src.getHeight(); y++)	{
		for (unsigned int x = 0; x < src.getWidth(); x++)	{
			vec2f nic_loc;
			vec2f sample_loc;

			//Normalized image coords
			nic_loc.x = (x - intrinsic(0, 2)) / intrinsic(0, 0);
			nic_loc.y = (y - intrinsic(1, 2)) / intrinsic(1, 1);

			float r2 = nic_loc.x * nic_loc.x + nic_loc.y * nic_loc.y;

			// Radial distortion
			sample_loc.x = nic_loc.x * (1.0f + r2 * coeff[0] + r2*r2 * coeff[1] + r2*r2*r2 * coeff[4]);
			sample_loc.y = nic_loc.y * (1.0f + r2 * coeff[0] + r2*r2 * coeff[1] + r2*r2*r2 * coeff[4]);

			// Tangential distortion
			sample_loc.x += 2.0f * coeff[2] * nic_loc.x * nic_loc.y + coeff[3] * (r2 + 2.0f * nic_loc.x * nic_loc.x);
			sample_loc.y += coeff[2] * (r2 + 2.0f * nic_loc.y * nic_loc.y) + 2.0f * coeff[3] * nic_loc.x * nic_loc.y;

			// Move back to the image space
			sample_loc.x = sample_loc.x * intrinsic(0, 0) + intrinsic(0, 2);
			sample_loc.y = sample_loc.y * intrinsic(1, 1) + intrinsic(1, 2);

			vec2i sample_loc_i = math::round(sample_loc);
			if (src.isValidCoordinate(sample_loc_i)) {
				res(x, y) = src(sample_loc_i);
			}
		}
	}
	return res;
}

void convertToSens(const std::string& srcPath, const std::string& outFile)
{
	Directory dir(srcPath);
	std::vector<std::string> baseFiles = dir.getFilesWithSuffix("_d0_0.png");
	for (auto& f : baseFiles) f = util::replace(f, "_d0_0.png", "");

	const unsigned int numCams = 3;
	SensorData sd[numCams];
	for (size_t fidx = 0; fidx < baseFiles.size(); fidx++) {
		std::cout << "\rProcessed [ " << fidx << " | " << baseFiles.size() << " ] ";
		const std::string& f = baseFiles[fidx];
		for (unsigned int camIdx = 0; camIdx < numCams; camIdx++) {
			for (unsigned int poseIdx = 0; poseIdx < 6; poseIdx++) {
				const std::string depthFile = srcPath + "/" + f + "_d" + std::to_string(camIdx) + "_" + std::to_string(poseIdx) + ".png";
				const std::string colorFile = srcPath + "/" + f + "_i" + std::to_string(camIdx) + "_" + std::to_string(poseIdx) + ".jpg";
				const std::string poseFile = srcPath + "/" + f + "_pose_" + std::to_string(camIdx) + "_" + std::to_string(poseIdx) + ".txt";
				const std::string intrFile = srcPath + "/" + f + "_intrinsics_" + std::to_string(camIdx) + ".txt";

				DepthImage16 depthImage16;
				FreeImageWrapper::loadImage(depthFile, depthImage16);
				depthImage16.setInvalidValue(0);
				//for (auto& p : depthImage16) p.value /= 5;

				//DepthImage32 depthImage32(depthImage16.getWidth(), depthImage16.getHeight());
				//depthImage32.setInvalidValue(0.0f);
				//for (auto& p : depthImage32) p.value = 0.001f * depthImage16(p.x, p.y);
				//FreeImageWrapper::saveImage("test.png", ColorImageR32G32B32A32(depthImage32, true));
				//std::cout << "DONE" << std::endl;
				//getchar();
				//exit(1);

				ColorImageR8G8B8 colorImage;
				FreeImageWrapper::loadImage(colorFile, colorImage);

				mat4f pose;
				{
					std::ifstream inFile(poseFile);
					for (unsigned int i = 0; i < 16; i++) inFile >> pose[i];
				}
				unsigned int width, height;
				float fx, fy, mx, my;
				float k[5];
				float k1, k2, p1, p2, k3;
				{
					std::ifstream inFile(intrFile);
					inFile >> width >> height;
					inFile >> fx >> fy >> mx >> my;
					//for (unsigned i = 0; i < 5; i++) inFile >> k[i];
					inFile >> k1 >> k2 >> p1 >> p2 >> k3;
				}
				k[0] = k1;
				k[1] = k2;
				k[2] = p1;
				k[3] = p2;
				k[4] = k3;

				if (fidx == 0 && poseIdx == 0) {
					SensorData::CalibrationData calibrationDepth(
						mat4f(
						fx, 0.0f, mx, 0.0f,
						0.0f, fy, my, 0.0f,
						0.0f, 0.0f, 1.0f, 0.0f,
						0.0f, 0.0f, 0.0f, 1.0f
						));
					SensorData::CalibrationData calibrationColor = calibrationDepth;

					float depthShift = 1.0f / 0.00025f;	//depth values are 0.25mm
					sd[camIdx].initDefault(width, height, width, height, calibrationColor, calibrationDepth,
						SensorData::COMPRESSION_TYPE_COLOR::TYPE_JPEG, SensorData::COMPRESSION_TYPE_DEPTH::TYPE_ZLIB_USHORT, depthShift, "Matterport");
				}

				if (colorImage.getWidth() != width || depthImage16.getWidth() != width ||
					colorImage.getHeight() != height || depthImage16.getHeight() != height) {
					std::cout << "debug: " <<
						colorImage.getWidth() << " | " << width << " | " << depthImage16.getWidth() << " | " << width <<
						colorImage.getHeight() << " | " << height << " | " << depthImage16.getHeight() << " | " << height << std::endl;
					throw MLIB_EXCEPTION("image dimensions don't match");
				}

				colorImage = undistort(colorImage, sd[camIdx].m_calibrationColor.m_intrinsic, k);
				depthImage16 = DepthImage16(undistort(depthImage16, sd[camIdx].m_calibrationDepth.m_intrinsic, k));
				sd[camIdx].addFrame(colorImage.getData(), depthImage16.getData(), pose);

				//FreeImageWrapper::saveImage("test.png", colorImage);
				//std::cout << "bla" << std::endl;
				//getchar();
			}
		}
	}
	std::cout << std::endl;

	for (unsigned int i = 0; i < numCams; i++) {
		//std::cout << sd[i] << std::endl;

		//sd[i].saveToFile("test_" + std::to_string(i) + ".sens");
		auto s = util::splitOnLast(outFile, ".");
		std::string _outFile = s.first + "_" + std::to_string(i) + "." + s.second;
		sd[i].saveToFile(_outFile);
	}
}

int main(int argc, char* argv[])
{
#if defined(DEBUG) | defined(_DEBUG)
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
	//_CrtSetBreakAlloc(7545);
	try {

		//single debug
		if (true) {
			//const std::string s = "D7N2EKCX4Sj";
			//const std::string path = "W:/data/matterport/v1_converted/" + s;

			const std::string s = "1LXtFkjw3qL";
			const std::string path = "../testdata/";
			std::cout << "converting: " << path << std::endl;
			convertToSens(path + "/" + s + "/data/", path + "/" + s + ".sens");

			std::cout << "<< press key to exit >>" << std::endl;
			getchar();
			exit(1);
		}

		const std::string srcFolder = "W:/data/matterport/v1";
		const std::string dstFolder = "W:/data/matterport/v1_converted";

		util::makeDirectory(dstFolder);

		Directory srcDir(srcFolder);

		for (const std::string& s : srcDir.getDirectories()) {

			if (s == "archive") continue;

			std::cout << s << std::endl;
			const std::string outPath = dstFolder + "/" + s;

			if (util::directoryExists(outPath)) {
				Directory dir(outPath);
				if (dir.getFilesWithSuffix(".sens").size() == 3) {
					std::cout << "\t(output exists -- skipping)" << std::endl;
					continue;
				}
			}

			if (true) {
				util::deleteDirectory(outPath);
				util::makeDirectory(outPath);
				if (true) {
					//extract the mesh
					std::cout << "\textracting mesh... ";
					const std::string srcFileMesh = srcFolder + "/" + s + "/" + s + "_mesh.zip";
					const std::string cmd = "unzip -qq " + srcFileMesh + " -d " + outPath;
					system(cmd.c_str());
					const std::vector<std::string> dirs = Directory::enumerateDirectories(outPath);
					if (dirs.size() != 1) throw MLIB_EXCEPTION("excepting exactly one output directory");
					const std::string subDirSrc = outPath + "/" + dirs.front();
					const std::string newSubDirSrc = outPath + "/mesh/";
					util::renameFile(subDirSrc, newSubDirSrc);
					std::cout << "done!" << std::endl;
				}
				if (true) {
					std::cout << "\textracting raw data... ";
					//extract the raw data
					const std::string srcFileData = srcFolder + "/" + s + "/" + s + ".zip";
					const std::string cmd = "unzip -qq " + srcFileData + " -d " + outPath;
					system(cmd.c_str());
					const std::string subDirSrc = outPath + "/" + s;
					const std::string newSubDirSrc = outPath + "/data/";
					util::renameFile(subDirSrc, newSubDirSrc);
					std::cout << "done!" << std::endl;
				}
			}

			try {
				convertToSens(outPath + "/data/", outPath + "/" + s + ".sens");
			}
			catch (const std::exception& e) {
				std::cout << "exception caught during conversion: " << e.what() << std::endl;
			}
		}

	}
	catch (const std::exception& e)
	{
		MessageBoxA(NULL, e.what(), "Exception caught", MB_ICONERROR);
		exit(EXIT_FAILURE);
	}
	catch (...)
	{
		MessageBoxA(NULL, "UNKNOWN EXCEPTION", "Exception caught", MB_ICONERROR);
		exit(EXIT_FAILURE);
	}

	std::cout << "<press key to continue>" << std::endl;
	getchar();
	return 0;
}

<commit_msg>convert for new v1 format<commit_after>// sensorFile.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iomanip>

template <typename T> BaseImage<T> undistort(const BaseImage<T>& src, const mat4f& intrinsic, const float coeff[5])
{
	BaseImage<T> res(src.getWidth(), src.getHeight());
	res.setInvalidValue(src.getInvalidValue());
	res.setPixels(res.getInvalidValue());

	for (unsigned int y = 0; y < src.getHeight(); y++)	{
		for (unsigned int x = 0; x < src.getWidth(); x++)	{
			vec2f nic_loc;
			vec2f sample_loc;

			//Normalized image coords
			nic_loc.x = (x - intrinsic(0, 2)) / intrinsic(0, 0);
			nic_loc.y = (y - intrinsic(1, 2)) / intrinsic(1, 1);

			float r2 = nic_loc.x * nic_loc.x + nic_loc.y * nic_loc.y;

			// Radial distortion
			sample_loc.x = nic_loc.x * (1.0f + r2 * coeff[0] + r2*r2 * coeff[1] + r2*r2*r2 * coeff[4]);
			sample_loc.y = nic_loc.y * (1.0f + r2 * coeff[0] + r2*r2 * coeff[1] + r2*r2*r2 * coeff[4]);

			// Tangential distortion
			sample_loc.x += 2.0f * coeff[2] * nic_loc.x * nic_loc.y + coeff[3] * (r2 + 2.0f * nic_loc.x * nic_loc.x);
			sample_loc.y += coeff[2] * (r2 + 2.0f * nic_loc.y * nic_loc.y) + 2.0f * coeff[3] * nic_loc.x * nic_loc.y;

			// Move back to the image space
			sample_loc.x = sample_loc.x * intrinsic(0, 0) + intrinsic(0, 2);
			sample_loc.y = sample_loc.y * intrinsic(1, 1) + intrinsic(1, 2);

			vec2i sample_loc_i = math::round(sample_loc);
			if (src.isValidCoordinate(sample_loc_i)) {
				res(x, y) = src(sample_loc_i);
			}
		}
	}
	return res;
}

void convertToSens(const std::string& srcPath, const std::string& outFile)
{
	const std::string srcColorPath = srcPath + "/matterport_color_images";
	const std::string srcDepthPath = srcPath + "/matterport_depth_images";
	const std::string srcPosePath = srcPath + "/matterport_camera_poses";
	const std::string srcCalibPath = srcPath + "/matterport_camera_intrinsics";
	if (!util::directoryExists(srcColorPath) || !util::directoryExists(srcDepthPath) ||
		!util::directoryExists(srcPosePath) || !util::directoryExists(srcCalibPath))
		throw MLIB_EXCEPTION("raw color/depth/pose/calib dir(s) do not exist [" + srcPath + "]");

	Directory dir(srcDepthPath);
	std::vector<std::string> baseFiles = dir.getFilesWithSuffix("_d0_0.png");
	for (auto& f : baseFiles) f = util::replace(f, "_d0_0.png", "");

	const unsigned int numCams = 3;
	SensorData sd[numCams];
	for (size_t fidx = 0; fidx < baseFiles.size(); fidx++) {
		std::cout << "\rProcessed [ " << fidx << " | " << baseFiles.size() << " ] ";
		const std::string& f = baseFiles[fidx];
		for (unsigned int camIdx = 0; camIdx < numCams; camIdx++) {
			for (unsigned int poseIdx = 0; poseIdx < 6; poseIdx++) {
				const std::string depthFile = srcDepthPath + "/" + f + "_d" + std::to_string(camIdx) + "_" + std::to_string(poseIdx) + ".png";
				const std::string colorFile = srcColorPath + "/" + f + "_i" + std::to_string(camIdx) + "_" + std::to_string(poseIdx) + ".jpg";
				const std::string poseFile = srcPosePath + "/" + f + "_pose_" + std::to_string(camIdx) + "_" + std::to_string(poseIdx) + ".txt";
				const std::string intrFile = srcCalibPath + "/" + f + "_intrinsics_" + std::to_string(camIdx) + ".txt";

				DepthImage16 depthImage16;
				FreeImageWrapper::loadImage(depthFile, depthImage16);
				depthImage16.setInvalidValue(0);
				//for (auto& p : depthImage16) p.value /= 5;

				//DepthImage32 depthImage32(depthImage16.getWidth(), depthImage16.getHeight());
				//depthImage32.setInvalidValue(0.0f);
				//for (auto& p : depthImage32) p.value = 0.001f * depthImage16(p.x, p.y);
				//FreeImageWrapper::saveImage("test.png", ColorImageR32G32B32A32(depthImage32, true));
				//std::cout << "DONE" << std::endl;
				//getchar();
				//exit(1);

				ColorImageR8G8B8 colorImage;
				FreeImageWrapper::loadImage(colorFile, colorImage);

				mat4f pose;
				{
					std::ifstream inFile(poseFile);
					for (unsigned int i = 0; i < 16; i++) inFile >> pose[i];
				}
				unsigned int width, height;
				float fx, fy, mx, my;
				float k[5];
				float k1, k2, p1, p2, k3;
				{
					std::ifstream inFile(intrFile);
					inFile >> width >> height;
					inFile >> fx >> fy >> mx >> my;
					//for (unsigned i = 0; i < 5; i++) inFile >> k[i];
					inFile >> k1 >> k2 >> p1 >> p2 >> k3;
				}
				k[0] = k1;
				k[1] = k2;
				k[2] = p1;
				k[3] = p2;
				k[4] = k3;

				if (fidx == 0 && poseIdx == 0) {
					SensorData::CalibrationData calibrationDepth(
						mat4f(
						fx, 0.0f, mx, 0.0f,
						0.0f, fy, my, 0.0f,
						0.0f, 0.0f, 1.0f, 0.0f,
						0.0f, 0.0f, 0.0f, 1.0f
						));
					SensorData::CalibrationData calibrationColor = calibrationDepth;

					float depthShift = 1.0f / 0.00025f;	//depth values are 0.25mm
					sd[camIdx].initDefault(width, height, width, height, calibrationColor, calibrationDepth,
						SensorData::COMPRESSION_TYPE_COLOR::TYPE_JPEG, SensorData::COMPRESSION_TYPE_DEPTH::TYPE_ZLIB_USHORT, depthShift, "Matterport");
				}

				if (colorImage.getWidth() != width || depthImage16.getWidth() != width ||
					colorImage.getHeight() != height || depthImage16.getHeight() != height) {
					std::cout << "debug: " <<
						colorImage.getWidth() << " | " << width << " | " << depthImage16.getWidth() << " | " << width <<
						colorImage.getHeight() << " | " << height << " | " << depthImage16.getHeight() << " | " << height << std::endl;
					throw MLIB_EXCEPTION("image dimensions don't match");
				}

				colorImage = undistort(colorImage, sd[camIdx].m_calibrationColor.m_intrinsic, k);
				depthImage16 = DepthImage16(undistort(depthImage16, sd[camIdx].m_calibrationDepth.m_intrinsic, k));
				sd[camIdx].addFrame(colorImage.getData(), depthImage16.getData(), pose);

				//FreeImageWrapper::saveImage("test.png", colorImage);
				//std::cout << "bla" << std::endl;
				//getchar();
			}
		}
	}
	std::cout << std::endl;

	for (unsigned int i = 0; i < numCams; i++) {
		//std::cout << sd[i] << std::endl;

		//sd[i].saveToFile("test_" + std::to_string(i) + ".sens");
		auto s = util::splitOnLast(outFile, ".");
		std::string _outFile = s.first + "_" + std::to_string(i) + "." + s.second;
		sd[i].saveToFile(_outFile);
	}
}

int main(int argc, char* argv[])
{
#if defined(DEBUG) | defined(_DEBUG)
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
	//_CrtSetBreakAlloc(7545);
	try {

		//single debug
		if (false) {
			//const std::string s = "D7N2EKCX4Sj";
			//const std::string path = "W:/data/matterport/v1_converted/" + s;

			const std::string s = "1LXtFkjw3qL";
			const std::string path = "../testdata/";
			std::cout << "converting: " << path << std::endl;
			convertToSens(path + "/" + s + "/data/", path + "/" + s + ".sens");

			std::cout << "<< press key to exit >>" << std::endl;
			getchar();
			exit(1);
		}

		//const std::string srcFolder = "W:/data/matterport/v1";
		const std::string srcFolder = "//falas/Matterport/v1";
		const std::string dstFolder = "W:/data/matterport/v1_converted";

		if (!util::directoryExists(dstFolder)) util::makeDirectory(dstFolder);

		Directory srcDir(srcFolder);

		for (const std::string& s : srcDir.getDirectories()) {

			if (s == "archive") continue;

			std::cout << s << std::endl;
			const std::string outPath = dstFolder + "/" + s;

			if (util::directoryExists(outPath)) {
				Directory dir(outPath);
				if (dir.getFilesWithSuffix(".sens").size() == 3) {
					std::cout << "\t(output exists -- skipping)" << std::endl;
					continue;
				}
			}

			if (false) { //data in src is already unzipped
				util::deleteDirectory(outPath);
				util::makeDirectory(outPath);
				if (true) {
					//extract the mesh
					std::cout << "\textracting mesh... ";
					const std::string srcFileMesh = srcFolder + "/" + s + "/" + s + "_mesh.zip";
					const std::string cmd = "unzip -qq " + srcFileMesh + " -d " + outPath;
					system(cmd.c_str());
					const std::vector<std::string> dirs = Directory::enumerateDirectories(outPath);
					if (dirs.size() != 1) throw MLIB_EXCEPTION("excepting exactly one output directory");
					const std::string subDirSrc = outPath + "/" + dirs.front();
					const std::string newSubDirSrc = outPath + "/mesh/";
					util::renameFile(subDirSrc, newSubDirSrc);
					std::cout << "done!" << std::endl;
				}
				if (true) {
					std::cout << "\textracting raw data... ";
					//extract the raw data
					const std::string srcFileData = srcFolder + "/" + s + "/" + s + ".zip";
					const std::string cmd = "unzip -qq " + srcFileData + " -d " + outPath;
					system(cmd.c_str());
					const std::string subDirSrc = outPath + "/" + s;
					const std::string newSubDirSrc = outPath + "/data/";
					util::renameFile(subDirSrc, newSubDirSrc);
					std::cout << "done!" << std::endl;
				}
			}

			try {
				//convertToSens(outPath + "/data/", outPath + "/" + s + ".sens");
				convertToSens(srcFolder + "/" + s, outPath + "/" + s + ".sens");
			}
			catch (const std::exception& e) {
				std::cout << "exception caught during conversion: " << e.what() << std::endl;
			}
		}

	}
	catch (const std::exception& e)
	{
		MessageBoxA(NULL, e.what(), "Exception caught", MB_ICONERROR);
		exit(EXIT_FAILURE);
	}
	catch (...)
	{
		MessageBoxA(NULL, "UNKNOWN EXCEPTION", "Exception caught", MB_ICONERROR);
		exit(EXIT_FAILURE);
	}

	std::cout << "<press key to continue>" << std::endl;
	getchar();
	return 0;
}

<|endoftext|>


<commit_before>/*
Copyright 2015 Esri
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.
A local copy of the license and additional notices are located with the
source distribution at:
http://github.com/Esri/lerc/
Contributors:  Thomas Maurer
*/

#include "Huffman.h"
#include "BitStuffer2.h"
#include <queue>
#include <cstring>

NAMESPACE_MRF_START

using namespace std;

// -------------------------------------------------------------------------- ;

bool Huffman::ComputeCodes(const vector<int>& histo)
{
  if (histo.empty() || histo.size() >= m_maxHistoSize)
    return false;

  priority_queue<Node, vector<Node>, less<Node> > pq;

  int numNodes = 0;

  int size = (int)histo.size();
  for (int i = 0; i < size; i++)    // add all leaf nodes
    if (histo[i] > 0)
      pq.push(Node((short)i, histo[i]));

  if (pq.size() < 2)    // histo has only 0 or 1 bin that is not empty; quit Huffman and give it to Lerc
    return false;

  while (pq.size() > 1)    // build the Huffman tree
  {
    Node* child0 = new Node(pq.top());
    numNodes++;
    pq.pop();
    Node* child1 = new Node(pq.top());
    numNodes++;
    pq.pop();
    pq.push(Node(child0, child1));
  }

  m_codeTable.resize(size);
  memset(&m_codeTable[0], 0, size * sizeof(m_codeTable[0]));
  if (!pq.top().TreeToLUT(0, 0, m_codeTable))    // fill the LUT
    return false;

  pq.top().child0->FreeTree(numNodes);    // free all the nodes
  pq.top().child1->FreeTree(numNodes);

  if (numNodes != 0)    // check the ref count
    return false;

  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::ComputeCompressedSize(const std::vector<int>& histo, int& numBytes, double& avgBpp) const
{
  if (histo.empty() || histo.size() >= m_maxHistoSize)
    return false;

  numBytes = 0;
  if (!ComputeNumBytesCodeTable(numBytes))    // header and code table
    return false;

  int numBits = 0, numElem = 0;
  int size = (int)histo.size();
  for (int i = 0; i < size; i++)
    if (histo[i] > 0)
    {
      numBits += histo[i] * m_codeTable[i].first;
      numElem += histo[i];
    }

  int numUInts = ((((numBits + 7) >> 3) + 3) >> 2) + 1;    // add one more as the decode LUT can read ahead
  numBytes += 4 * numUInts;    // data huffman coded
  avgBpp = 8 * numBytes / (double)numElem;

  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::SetCodes(const vector<pair<short, unsigned int> >& codeTable)
{
  if (codeTable.empty() || codeTable.size() >= m_maxHistoSize)
    return false;

  m_codeTable = codeTable;
  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::WriteCodeTable(Byte** ppByte) const
{
  if (!ppByte)
    return false;

  int i0, i1, maxLen;
  if (!GetRange(i0, i1, maxLen))
    return false;

  int size = (int)m_codeTable.size();
  vector<unsigned int> dataVec(i1 - i0, 0);

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    dataVec[i - i0] = (unsigned int)m_codeTable[k].first;
  }

  // header
  vector<int> intVec;
  intVec.push_back(2);    // version
  intVec.push_back(size);
  intVec.push_back(i0);   // code range
  intVec.push_back(i1);

  Byte* ptr = *ppByte;

  for (size_t i = 0; i < intVec.size(); i++)
  {
    *((int*)ptr) = intVec[i];
    ptr += sizeof(int);
  }

  BitStuffer2 bitStuffer2;
  if (!bitStuffer2.EncodeSimple(&ptr, dataVec))    // code lengths, bit stuffed
    return false;

  if (!BitStuffCodes(&ptr, i0, i1))    // variable length codes, bit stuffed
    return false;

  *ppByte = ptr;
  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::ReadCodeTable(const Byte** ppByte)
{
  if (!ppByte || !(*ppByte))
    return false;

  const Byte* ptr = *ppByte;

  int version = *((int*)ptr);    // version
  ptr += sizeof(int);

  if (version != 2)
    return false;

  vector<int> intVec(4, 0);
  for (size_t i = 1; i < intVec.size(); i++)
  {
    intVec[i] = *((int*)ptr);
    ptr += sizeof(int);
  }

  int size = intVec[1];
  int i0 = intVec[2];
  int i1 = intVec[3];

  if (i0 >= i1 || size > (int)m_maxHistoSize)
    return false;

  vector<unsigned int> dataVec(i1 - i0, 0);
  BitStuffer2 bitStuffer2;
  if (!bitStuffer2.Decode(&ptr, dataVec))    // unstuff the code lengths
    return false;

  m_codeTable.resize(size);
  memset(&m_codeTable[0], 0, size * sizeof(m_codeTable[0]));

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    m_codeTable[k].first = (short)dataVec[i - i0];
  }

  if (!BitUnStuffCodes(&ptr, i0, i1))    // unstuff the codes
    return false;

  *ppByte = ptr;
  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::BuildTreeFromCodes(int& numBitsLUT)
{
  int i0, i1, maxLen;
  if (!GetRange(i0, i1, maxLen))
    return false;

  // build decode LUT using max of 12 bits
  int size = (int)m_codeTable.size();

  bool bNeedTree = maxLen > m_maxNumBitsLUT;
  numBitsLUT = min(maxLen, m_maxNumBitsLUT);

  m_decodeLUT.clear();
  m_decodeLUT.assign(1 << numBitsLUT, pair<short, short>((short)-1, (short)-1));

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    int len = m_codeTable[k].first;
    if (len > 0 && len <= numBitsLUT)
    {
      int code = m_codeTable[k].second << (numBitsLUT - len);
      pair<short, short> entry((short)len, (short)k);
      int numEntries = 1 << (numBitsLUT - len);
      for (int j = 0; j < numEntries; j++)
        m_decodeLUT[code | j] = entry;    // add the duplicates
    }
  }

  if (!bNeedTree)    // decode LUT covers it all, no tree needed
    return true;

  int numNodesCreated = 1;
  Node emptyNode((short)-1, 0);

  if (!m_root)
    m_root = new Node(emptyNode);

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    int len = m_codeTable[k].first;
    if (len > 0 && len > numBitsLUT)    // add only codes not in the decode LUT
    {
      unsigned int code = m_codeTable[k].second;
      Node* node = m_root;
      int j = len;
      while (--j >= 0)    // go over the bits
      {
        if (code & (1 << j))
        {
          if (!node->child1)
          {
            node->child1 = new Node(emptyNode);
            numNodesCreated++;
          }
          node = node->child1;
        }
        else
        {
          if (!node->child0)
          {
            node->child0 = new Node(emptyNode);
            numNodesCreated++;
          }
          node = node->child0;
        }

        if (j == 0)    // last bit, leaf node
        {
          node->value = (short)k;    // set the value
        }
      }
    }
  }

  return true;
}

// -------------------------------------------------------------------------- ;

void Huffman::Clear()
{
  m_codeTable.clear();
  m_decodeLUT.clear();
  if (m_root)
  {
    int n = 0;
    m_root->FreeTree(n);
  }
}

// -------------------------------------------------------------------------- ;
// -------------------------------------------------------------------------- ;

bool Huffman::ComputeNumBytesCodeTable(int& numBytes) const
{
  int i0, i1, maxLen;
  if (!GetRange(i0, i1, maxLen))
    return false;

  int size = (int)m_codeTable.size();
  int sum = 0;
  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    sum += m_codeTable[k].first;
  }

  numBytes = 4 * sizeof(int);    // version, size, first bin, (last + 1) bin

  BitStuffer2 bitStuffer2;
  numBytes += bitStuffer2.ComputeNumBytesNeededSimple((unsigned int)(i1 - i0), (unsigned int)maxLen);    // code lengths
  int numUInts = (((sum + 7) >> 3) + 3) >> 2;
  numBytes += 4 * numUInts;    // byte array with the codes bit stuffed

  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::GetRange(int& i0, int& i1, int& maxCodeLength) const
{
  if (m_codeTable.empty() || m_codeTable.size() >= m_maxHistoSize)
    return false;

  // first, check for peak somewhere in the middle with 0 stretches left and right
  int size = (int)m_codeTable.size();
  int i = 0;
  while (i < size && m_codeTable[i].first == 0) i++;
  i0 = i;
  i = size - 1;
  while (i >= 0 && m_codeTable[i].first == 0) i--;
  i1 = i + 1;    // exclusive

  if (i1 <= i0)
    return false;

  // second, cover the common case that the peak is close to 0
  pair<int, int> segm(0, 0);
  int j = 0;
  while (j < size)    // find the largest stretch of 0's, if any
  {
    while (j < size && m_codeTable[j].first > 0) j++;
    int k0 = j;
    while (j < size && m_codeTable[j].first == 0) j++;
    int k1 = j;

    if (k1 - k0 > segm.second)
      segm = pair<int, int>(k0, k1 - k0);
  }

  if (size - segm.second < i1 - i0)
  {
    i0 = segm.first + segm.second;
    i1 = segm.first + size;    // do wrap around
  }

  if (i1 <= i0)
    return false;

  int maxLen = 0;
  for (i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    int len = m_codeTable[k].first;
    maxLen = max(maxLen, len);
  }

  if (maxLen <= 0 || maxLen > 32)
    return false;

  maxCodeLength = maxLen;
  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::BitStuffCodes(Byte** ppByte, int i0, int i1) const
{
  if (!ppByte)
    return false;

  unsigned int* arr = (unsigned int*)(*ppByte);
  unsigned int* dstPtr = arr;
  int size = (int)m_codeTable.size();
  int bitPos = 0;

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    int len = m_codeTable[k].first;
    if (len > 0)
    {
      unsigned int val = m_codeTable[k].second;
      if (32 - bitPos >= len)
      {
        if (bitPos == 0)
          *dstPtr = 0;

        *dstPtr |= val << (32 - bitPos - len);
        bitPos += len;
        if (bitPos == 32)
        {
          bitPos = 0;
          dstPtr++;
        }
      }
      else
      {
        bitPos += len - 32;
        *dstPtr++ |= val >> bitPos;
        *dstPtr = val << (32 - bitPos);
      }
    }
  }

  size_t numUInts = dstPtr - arr + (bitPos > 0 ? 1 : 0);
  *ppByte += numUInts * sizeof(unsigned int);
  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::BitUnStuffCodes(const Byte** ppByte, int i0, int i1)
{
  if (!ppByte || !(*ppByte))
    return false;

  const unsigned int* arr = (const unsigned int*)(*ppByte);
  const unsigned int* srcPtr = arr;
  int size = (int)m_codeTable.size();
  int bitPos = 0;

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    int len = m_codeTable[k].first;
    if (len > 0)
    {
      m_codeTable[k].second = ((*srcPtr) << bitPos) >> (32 - len);

      if (32 - bitPos >= len)
      {
        bitPos += len;
        if (bitPos == 32)
        {
          bitPos = 0;
          srcPtr++;
        }
      }
      else
      {
        bitPos += len - 32;
        srcPtr++;
        m_codeTable[k].second |= (*srcPtr) >> (32 - bitPos);
      }
    }
  }

  size_t numUInts = srcPtr - arr + (bitPos > 0 ? 1 : 0);
  *ppByte += numUInts * sizeof(unsigned int);
  return true;
}

// -------------------------------------------------------------------------- ;

NAMESPACE_MRF_END
<commit_msg>GDAL integration #58<commit_after>/*
Copyright 2015 Esri
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.
A local copy of the license and additional notices are located with the
source distribution at:
http://github.com/Esri/lerc/
Contributors:  Thomas Maurer
*/

#include "Huffman.h"
#include "BitStuffer2.h"
#include <queue>
#include <cstring>

NAMESPACE_MRF_START

using namespace std;

// -------------------------------------------------------------------------- ;

bool Huffman::ComputeCodes(const vector<int>& histo)
{
  if (histo.empty() || histo.size() >= m_maxHistoSize)
    return false;

  priority_queue<Node, vector<Node>, less<Node> > pq;

  int numNodes = 0;

  int size = (int)histo.size();
  for (int i = 0; i < size; i++)    // add all leaf nodes
    if (histo[i] > 0)
      pq.push(Node((short)i, histo[i]));

  if (pq.size() < 2)    // histo has only 0 or 1 bin that is not empty; quit Huffman and give it to Lerc
    return false;

  while (pq.size() > 1)    // build the Huffman tree
  {
    Node* child0 = new Node(pq.top());
    numNodes++;
    pq.pop();
    Node* child1 = new Node(pq.top());
    numNodes++;
    pq.pop();
    pq.push(Node(child0, child1));
  }

  m_codeTable.resize(size);
  memset(&m_codeTable[0], 0, size * sizeof(m_codeTable[0]));
  if (!pq.top().TreeToLUT(0, 0, m_codeTable))    // fill the LUT
    return false;

  pq.top().child0->FreeTree(numNodes);    // free all the nodes
  pq.top().child1->FreeTree(numNodes);

  if (numNodes != 0)    // check the ref count
    return false;

  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::ComputeCompressedSize(const std::vector<int>& histo, int& numBytes, double& avgBpp) const
{
  if (histo.empty() || histo.size() >= m_maxHistoSize)
    return false;

  numBytes = 0;
  if (!ComputeNumBytesCodeTable(numBytes))    // header and code table
    return false;

  int numBits = 0, numElem = 0;
  int size = (int)histo.size();
  for (int i = 0; i < size; i++)
    if (histo[i] > 0)
    {
      numBits += histo[i] * m_codeTable[i].first;
      numElem += histo[i];
    }

  /* to please Coverity about potential divide by zero below */
  if( numElem == 0 )
    return false;

  int numUInts = ((((numBits + 7) >> 3) + 3) >> 2) + 1;    // add one more as the decode LUT can read ahead
  numBytes += 4 * numUInts;    // data huffman coded
  avgBpp = 8 * numBytes / (double)numElem;

  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::SetCodes(const vector<pair<short, unsigned int> >& codeTable)
{
  if (codeTable.empty() || codeTable.size() >= m_maxHistoSize)
    return false;

  m_codeTable = codeTable;
  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::WriteCodeTable(Byte** ppByte) const
{
  if (!ppByte)
    return false;

  int i0, i1, maxLen;
  if (!GetRange(i0, i1, maxLen))
    return false;

  int size = (int)m_codeTable.size();
  vector<unsigned int> dataVec(i1 - i0, 0);

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    dataVec[i - i0] = (unsigned int)m_codeTable[k].first;
  }

  // header
  vector<int> intVec;
  intVec.push_back(2);    // version
  intVec.push_back(size);
  intVec.push_back(i0);   // code range
  intVec.push_back(i1);

  Byte* ptr = *ppByte;

  for (size_t i = 0; i < intVec.size(); i++)
  {
    *((int*)ptr) = intVec[i];
    ptr += sizeof(int);
  }

  BitStuffer2 bitStuffer2;
  if (!bitStuffer2.EncodeSimple(&ptr, dataVec))    // code lengths, bit stuffed
    return false;

  if (!BitStuffCodes(&ptr, i0, i1))    // variable length codes, bit stuffed
    return false;

  *ppByte = ptr;
  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::ReadCodeTable(const Byte** ppByte)
{
  if (!ppByte || !(*ppByte))
    return false;

  const Byte* ptr = *ppByte;

  int version = *((int*)ptr);    // version
  ptr += sizeof(int);

  if (version != 2)
    return false;

  vector<int> intVec(4, 0);
  for (size_t i = 1; i < intVec.size(); i++)
  {
    intVec[i] = *((int*)ptr);
    ptr += sizeof(int);
  }

  int size = intVec[1];
  int i0 = intVec[2];
  int i1 = intVec[3];

  if (i0 >= i1 || size > (int)m_maxHistoSize)
    return false;

  vector<unsigned int> dataVec(i1 - i0, 0);
  BitStuffer2 bitStuffer2;
  if (!bitStuffer2.Decode(&ptr, dataVec))    // unstuff the code lengths
    return false;

  m_codeTable.resize(size);
  memset(&m_codeTable[0], 0, size * sizeof(m_codeTable[0]));

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    m_codeTable[k].first = (short)dataVec[i - i0];
  }

  if (!BitUnStuffCodes(&ptr, i0, i1))    // unstuff the codes
    return false;

  *ppByte = ptr;
  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::BuildTreeFromCodes(int& numBitsLUT)
{
  int i0, i1, maxLen;
  if (!GetRange(i0, i1, maxLen))
    return false;

  // build decode LUT using max of 12 bits
  int size = (int)m_codeTable.size();

  bool bNeedTree = maxLen > m_maxNumBitsLUT;
  numBitsLUT = min(maxLen, m_maxNumBitsLUT);

  m_decodeLUT.clear();
  m_decodeLUT.assign(1 << numBitsLUT, pair<short, short>((short)-1, (short)-1));

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    int len = m_codeTable[k].first;
    if (len > 0 && len <= numBitsLUT)
    {
      int code = m_codeTable[k].second << (numBitsLUT - len);
      pair<short, short> entry((short)len, (short)k);
      int numEntries = 1 << (numBitsLUT - len);
      for (int j = 0; j < numEntries; j++)
        m_decodeLUT[code | j] = entry;    // add the duplicates
    }
  }

  if (!bNeedTree)    // decode LUT covers it all, no tree needed
    return true;

  int numNodesCreated = 1;
  Node emptyNode((short)-1, 0);

  if (!m_root)
    m_root = new Node(emptyNode);

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    int len = m_codeTable[k].first;
    if (len > 0 && len > numBitsLUT)    // add only codes not in the decode LUT
    {
      unsigned int code = m_codeTable[k].second;
      Node* node = m_root;
      int j = len;
      while (--j >= 0)    // go over the bits
      {
        if (code & (1 << j))
        {
          if (!node->child1)
          {
            node->child1 = new Node(emptyNode);
            numNodesCreated++;
          }
          node = node->child1;
        }
        else
        {
          if (!node->child0)
          {
            node->child0 = new Node(emptyNode);
            numNodesCreated++;
          }
          node = node->child0;
        }

        if (j == 0)    // last bit, leaf node
        {
          node->value = (short)k;    // set the value
        }
      }
    }
  }

  return true;
}

// -------------------------------------------------------------------------- ;

void Huffman::Clear()
{
  m_codeTable.clear();
  m_decodeLUT.clear();
  if (m_root)
  {
    int n = 0;
    m_root->FreeTree(n);
  }
}

// -------------------------------------------------------------------------- ;
// -------------------------------------------------------------------------- ;

bool Huffman::ComputeNumBytesCodeTable(int& numBytes) const
{
  int i0, i1, maxLen;
  if (!GetRange(i0, i1, maxLen))
    return false;

  int size = (int)m_codeTable.size();
  int sum = 0;
  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    sum += m_codeTable[k].first;
  }

  numBytes = 4 * sizeof(int);    // version, size, first bin, (last + 1) bin

  BitStuffer2 bitStuffer2;
  numBytes += bitStuffer2.ComputeNumBytesNeededSimple((unsigned int)(i1 - i0), (unsigned int)maxLen);    // code lengths
  int numUInts = (((sum + 7) >> 3) + 3) >> 2;
  numBytes += 4 * numUInts;    // byte array with the codes bit stuffed

  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::GetRange(int& i0, int& i1, int& maxCodeLength) const
{
  if (m_codeTable.empty() || m_codeTable.size() >= m_maxHistoSize)
    return false;

  // first, check for peak somewhere in the middle with 0 stretches left and right
  int size = (int)m_codeTable.size();
  int i = 0;
  while (i < size && m_codeTable[i].first == 0) i++;
  i0 = i;
  i = size - 1;
  while (i >= 0 && m_codeTable[i].first == 0) i--;
  i1 = i + 1;    // exclusive

  if (i1 <= i0)
    return false;

  // second, cover the common case that the peak is close to 0
  pair<int, int> segm(0, 0);
  int j = 0;
  while (j < size)    // find the largest stretch of 0's, if any
  {
    while (j < size && m_codeTable[j].first > 0) j++;
    int k0 = j;
    while (j < size && m_codeTable[j].first == 0) j++;
    int k1 = j;

    if (k1 - k0 > segm.second)
      segm = pair<int, int>(k0, k1 - k0);
  }

  if (size - segm.second < i1 - i0)
  {
    i0 = segm.first + segm.second;
    i1 = segm.first + size;    // do wrap around
  }

  if (i1 <= i0)
    return false;

  int maxLen = 0;
  for (i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    int len = m_codeTable[k].first;
    maxLen = max(maxLen, len);
  }

  if (maxLen <= 0 || maxLen > 32)
    return false;

  maxCodeLength = maxLen;
  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::BitStuffCodes(Byte** ppByte, int i0, int i1) const
{
  if (!ppByte)
    return false;

  unsigned int* arr = (unsigned int*)(*ppByte);
  unsigned int* dstPtr = arr;
  int size = (int)m_codeTable.size();
  int bitPos = 0;

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    int len = m_codeTable[k].first;
    if (len > 0)
    {
      unsigned int val = m_codeTable[k].second;
      if (32 - bitPos >= len)
      {
        if (bitPos == 0)
          *dstPtr = 0;

        *dstPtr |= val << (32 - bitPos - len);
        bitPos += len;
        if (bitPos == 32)
        {
          bitPos = 0;
          dstPtr++;
        }
      }
      else
      {
        bitPos += len - 32;
        *dstPtr++ |= val >> bitPos;
        *dstPtr = val << (32 - bitPos);
      }
    }
  }

  size_t numUInts = dstPtr - arr + (bitPos > 0 ? 1 : 0);
  *ppByte += numUInts * sizeof(unsigned int);
  return true;
}

// -------------------------------------------------------------------------- ;

bool Huffman::BitUnStuffCodes(const Byte** ppByte, int i0, int i1)
{
  if (!ppByte || !(*ppByte))
    return false;

  const unsigned int* arr = (const unsigned int*)(*ppByte);
  const unsigned int* srcPtr = arr;
  int size = (int)m_codeTable.size();
  int bitPos = 0;

  for (int i = i0; i < i1; i++)
  {
    int k = GetIndexWrapAround(i, size);
    int len = m_codeTable[k].first;
    if (len > 0)
    {
      m_codeTable[k].second = ((*srcPtr) << bitPos) >> (32 - len);

      if (32 - bitPos >= len)
      {
        bitPos += len;
        if (bitPos == 32)
        {
          bitPos = 0;
          srcPtr++;
        }
      }
      else
      {
        bitPos += len - 32;
        srcPtr++;
        m_codeTable[k].second |= (*srcPtr) >> (32 - bitPos);
      }
    }
  }

  size_t numUInts = srcPtr - arr + (bitPos > 0 ? 1 : 0);
  *ppByte += numUInts * sizeof(unsigned int);
  return true;
}

// -------------------------------------------------------------------------- ;

NAMESPACE_MRF_END
<|endoftext|>


<commit_before>/**
 * @file
 * @author  Mamadou Babaei <info@babaei.net>
 * @version 0.1.0
 *
 * @section LICENSE
 *
 * (The MIT License)
 *
 * Copyright (c) 2016 - 2020 Mamadou Babaei
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * Cross-platform OS level utility function.
 */

#include <fstream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#if defined ( __unix__ )
#if defined ( __linux )
#include <dirent.h>
#endif  // defined ( __linux )
#if defined ( __FreeBSD__ )
#include <kvm.h>
#include <sys/dirent.h>
#endif  // defined ( __FreeBSD__ )
#include <sys/fcntl.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/unistd.h>
#include <sys/user.h>
#endif  // defined ( __unix__ )
#if defined ( _WIN32 )
#include <tlhelp32.h>
#include <windows.h>
#endif  // defined ( _WIN32 )
#include "Log.hpp"
#include "make_unique.hpp"
#include "System.hpp"

using namespace std;
using namespace CoreLib;

struct System::Impl
{
#if defined ( __unix__ )
    static constexpr mode_t LOCK_FILE_PERMISSION = 0666;
#endif  // defined ( __unix__ )
};

bool System::Exec(const string &cmd)
{
    int r = system(cmd.c_str());
    if (r == EXIT_SUCCESS)
        return true;
    else
        return false;
}

bool System::Exec(const string &cmd, string &out_output)
{
    out_output.clear();

    FILE *pipe = popen(cmd.c_str(), "r");
    if (!pipe)
        return false;

    char buffer[256];
    while (!feof(pipe)) {
        if (fgets(buffer, 256, pipe) != NULL) {
            out_output += buffer;
        }
    }

    pclose(pipe);
    return true;
}

#if defined ( __unix__ )

bool System::GetLock(const std::string &name, int &out_handle)
{
    struct flock fl;

    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 1;

    if ((out_handle = open(name.c_str(), O_WRONLY | O_CREAT, Impl::LOCK_FILE_PERMISSION)) == -1)
        return false;

    if (fcntl(out_handle, F_SETLK, &fl) == -1)
        return false;

    return true;
}

void System::ReleaseLock(int &handle)
{
    close(handle);
}

#elif defined ( _WIN32 )

bool System::GetLock(const std::string &name, HANDLE &out_handle)
{
    try {
        out_handle = OpenMutexA(MUTEX_ALL_ACCESS, TRUE, name.c_str());
        if (!out_handle) {
            out_handle = CreateMutexA(NULL, TRUE, name.c_str());
            return true;
        }
    } catch (...) {
    }

    return false;
}

void System::ReleaseLock(HANDLE &handle)
{
    ReleaseMutex(handle);
    CloseHandle(handle);
}

#endif  // defined ( __unix__ )

std::string System::GetProcessNameFromPath(const std::string &fullPath)
{
    return fullPath.substr(fullPath.rfind("/") + 1);
}

std::size_t System::GetPidsOfProcess(const std::string &process, std::vector<int> &out_pids)
{
    out_pids.clear();

#if defined ( __FreeBSD__ )
    static kvm_t *kd = nullptr;

    if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY, "kvm_open")) == nullptr) {
        LOG_ERROR(kvm_geterr(kd));
        return 0;
    }

    int count;
#if __FreeBSD__ >= 5
    struct kinfo_proc *p = kvm_getprocs(kd, KERN_PROC_PROC, 0, &count);
#else
    struct kinfo_proc *p = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count);
#endif  // __FreeBSD__ >= 5

    for (int i = 0; i < count; ++i) {
#if __FreeBSD__ >= 5
        if (process.compare(0, COMMLEN, p[i].ki_comm) == 0) {
            out_pids.push_back(static_cast<int>(p[i].ki_pid));
#else
        if (process.compare(0, MAXCOMLEN, p[i].kp_proc.p_comm) == 0) {
            out_pids.push_back(static_cast<int>(p[i].kp_proc.p_pid));
#endif  // __FreeBSD__ >= 5
        }
    }

    kvm_close(kd);
#elif defined ( __linux )
    DIR *dp = opendir("/proc");

    if (dp != nullptr) {
        struct dirent *dir = readdir(dp);

        while (dir != nullptr) {
            int pid = atoi(dir->d_name);

            if (pid > 0) {
                std::stringstream ss;
                ss << "/proc/";
                ss << dir->d_name;
                ss << "/cmdline";
                std::ifstream cmdFile(ss.str().c_str());
                std::string cmdLine;
                getline(cmdFile, cmdLine);

                if (!cmdLine.empty()) {
                    size_t pos = cmdLine.find('\0');

                    if (pos != std::string::npos) {
                        cmdLine = cmdLine.substr(0, pos);
                    }

                    pos = cmdLine.rfind('/');

                    if (pos != std::string::npos) {
                        cmdLine = cmdLine.substr(pos + 1);
                    }

                    if (process.compare(cmdLine) == 0) {
                        out_pids.push_back(pid);
                    }
                }
            }

            dir = readdir(dp);
        }
    }
#elif defined ( _WIN32 )
    PROCESSENTRY32 pe32;
    HANDLE hSnapshot = nullptr;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (Process32First(hSnapshot, &pe32)) {
        do {
            if (process.compare(pe32.szExeFile) == 0) {
                out_pids.push_back(pe32.th32ProcessID);
            }
        } while (Process32Next(hSnapshot, &pe32));
    }

    if(hSnapshot != INVALID_HANDLE_VALUE) {
        CloseHandle(hSnapshot);
    }
#endif  // defined( __FreeBSD__ )

    return out_pids.size();
}

long System::RandSeed()
{
    timespec ts;

#if defined ( __FreeBSD__ )
    clock_gettime(CLOCK_MONOTONIC, &ts);
#elif defined ( __linux )
    clock_gettime(CLOCK_REALTIME, &ts);
#endif  // defined ( __FreeBSD__ )

    return ts.tv_nsec;
}
<commit_msg>fix a linux build error<commit_after>/**
 * @file
 * @author  Mamadou Babaei <info@babaei.net>
 * @version 0.1.0
 *
 * @section LICENSE
 *
 * (The MIT License)
 *
 * Copyright (c) 2016 - 2020 Mamadou Babaei
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * Cross-platform OS level utility function.
 */

#include <fstream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#if defined ( __unix__ )
#if defined ( __linux )
#include <dirent.h>
#endif  // defined ( __linux )
#if defined ( __linux )
#include <linux/sysctl.h>
#endif  // defined ( __linux )
#if defined ( __FreeBSD__ )
#include <kvm.h>
#include <sys/dirent.h>
#endif  // defined ( __FreeBSD__ )
#include <sys/fcntl.h>
#include <sys/param.h>
#if !defined ( __linux )
#include <sys/sysctl.h>
#endif  // !defined ( __linux )
#include <sys/time.h>
#include <sys/unistd.h>
#include <sys/user.h>
#endif  // defined ( __unix__ )
#if defined ( _WIN32 )
#include <tlhelp32.h>
#include <windows.h>
#endif  // defined ( _WIN32 )
#include "Log.hpp"
#include "make_unique.hpp"
#include "System.hpp"

using namespace std;
using namespace CoreLib;

struct System::Impl
{
#if defined ( __unix__ )
    static constexpr mode_t LOCK_FILE_PERMISSION = 0666;
#endif  // defined ( __unix__ )
};

bool System::Exec(const string &cmd)
{
    int r = system(cmd.c_str());
    if (r == EXIT_SUCCESS)
        return true;
    else
        return false;
}

bool System::Exec(const string &cmd, string &out_output)
{
    out_output.clear();

    FILE *pipe = popen(cmd.c_str(), "r");
    if (!pipe)
        return false;

    char buffer[256];
    while (!feof(pipe)) {
        if (fgets(buffer, 256, pipe) != NULL) {
            out_output += buffer;
        }
    }

    pclose(pipe);
    return true;
}

#if defined ( __unix__ )

bool System::GetLock(const std::string &name, int &out_handle)
{
    struct flock fl;

    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 1;

    if ((out_handle = open(name.c_str(), O_WRONLY | O_CREAT, Impl::LOCK_FILE_PERMISSION)) == -1)
        return false;

    if (fcntl(out_handle, F_SETLK, &fl) == -1)
        return false;

    return true;
}

void System::ReleaseLock(int &handle)
{
    close(handle);
}

#elif defined ( _WIN32 )

bool System::GetLock(const std::string &name, HANDLE &out_handle)
{
    try {
        out_handle = OpenMutexA(MUTEX_ALL_ACCESS, TRUE, name.c_str());
        if (!out_handle) {
            out_handle = CreateMutexA(NULL, TRUE, name.c_str());
            return true;
        }
    } catch (...) {
    }

    return false;
}

void System::ReleaseLock(HANDLE &handle)
{
    ReleaseMutex(handle);
    CloseHandle(handle);
}

#endif  // defined ( __unix__ )

std::string System::GetProcessNameFromPath(const std::string &fullPath)
{
    return fullPath.substr(fullPath.rfind("/") + 1);
}

std::size_t System::GetPidsOfProcess(const std::string &process, std::vector<int> &out_pids)
{
    out_pids.clear();

#if defined ( __FreeBSD__ )
    static kvm_t *kd = nullptr;

    if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY, "kvm_open")) == nullptr) {
        LOG_ERROR(kvm_geterr(kd));
        return 0;
    }

    int count;
#if __FreeBSD__ >= 5
    struct kinfo_proc *p = kvm_getprocs(kd, KERN_PROC_PROC, 0, &count);
#else
    struct kinfo_proc *p = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count);
#endif  // __FreeBSD__ >= 5

    for (int i = 0; i < count; ++i) {
#if __FreeBSD__ >= 5
        if (process.compare(0, COMMLEN, p[i].ki_comm) == 0) {
            out_pids.push_back(static_cast<int>(p[i].ki_pid));
#else
        if (process.compare(0, MAXCOMLEN, p[i].kp_proc.p_comm) == 0) {
            out_pids.push_back(static_cast<int>(p[i].kp_proc.p_pid));
#endif  // __FreeBSD__ >= 5
        }
    }

    kvm_close(kd);
#elif defined ( __linux )
    DIR *dp = opendir("/proc");

    if (dp != nullptr) {
        struct dirent *dir = readdir(dp);

        while (dir != nullptr) {
            int pid = atoi(dir->d_name);

            if (pid > 0) {
                std::stringstream ss;
                ss << "/proc/";
                ss << dir->d_name;
                ss << "/cmdline";
                std::ifstream cmdFile(ss.str().c_str());
                std::string cmdLine;
                getline(cmdFile, cmdLine);

                if (!cmdLine.empty()) {
                    size_t pos = cmdLine.find('\0');

                    if (pos != std::string::npos) {
                        cmdLine = cmdLine.substr(0, pos);
                    }

                    pos = cmdLine.rfind('/');

                    if (pos != std::string::npos) {
                        cmdLine = cmdLine.substr(pos + 1);
                    }

                    if (process.compare(cmdLine) == 0) {
                        out_pids.push_back(pid);
                    }
                }
            }

            dir = readdir(dp);
        }
    }
#elif defined ( _WIN32 )
    PROCESSENTRY32 pe32;
    HANDLE hSnapshot = nullptr;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (Process32First(hSnapshot, &pe32)) {
        do {
            if (process.compare(pe32.szExeFile) == 0) {
                out_pids.push_back(pe32.th32ProcessID);
            }
        } while (Process32Next(hSnapshot, &pe32));
    }

    if(hSnapshot != INVALID_HANDLE_VALUE) {
        CloseHandle(hSnapshot);
    }
#endif  // defined( __FreeBSD__ )

    return out_pids.size();
}

long System::RandSeed()
{
    timespec ts;

#if defined ( __FreeBSD__ )
    clock_gettime(CLOCK_MONOTONIC, &ts);
#elif defined ( __linux )
    clock_gettime(CLOCK_REALTIME, &ts);
#endif  // defined ( __FreeBSD__ )

    return ts.tv_nsec;
}
<|endoftext|>