<commit_before>/*
* SHA-{224,256}
* (C) 1999-2008 Jack Lloyd
*     2007 FlexSecure GmbH
*
* Distributed under the terms of the Botan license
*/

#include <botan/sha2_32.h>
#include <botan/loadstor.h>
#include <botan/rotate.h>

namespace Botan {

namespace {

/*
* SHA-256 Rho Function
*/
inline u32bit rho(u32bit X, u32bit rot1, u32bit rot2, u32bit rot3)
   {
   return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^
           rotate_right(X, rot3));
   }

/*
* SHA-256 Sigma Function
*/
inline u32bit sigma(u32bit X, u32bit rot1, u32bit rot2, u32bit shift)
   {
   return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ (X >> shift));
   }

/*
* SHA-256 F1 Function
*/
inline void F1(u32bit A, u32bit B, u32bit C, u32bit& D,
               u32bit E, u32bit F, u32bit G, u32bit& H,
               u32bit msg, u32bit magic)
   {
   magic += rho(E, 6, 11, 25) + ((E & F) ^ (~E & G)) + msg;
   D += magic + H;
   H += magic + rho(A, 2, 13, 22) + ((A & B) ^ (A & C) ^ (B & C));
   }

}

/*
* SHA-256 Compression Function
*/
void SHA_224_256_BASE::compress_n(const byte input[], u32bit blocks)
   {
   u32bit A = digest[0], B = digest[1], C = digest[2],
          D = digest[3], E = digest[4], F = digest[5],
          G = digest[6], H = digest[7];

   for(u32bit i = 0; i != blocks; ++i)
      {
      load_be(W.begin(), input, 16);

      for(u32bit j = 16; j != 64; j += 8)
         {
         W[j  ] = sigma(W[j- 2], 17, 19, 10) + W[j-7] +
                  sigma(W[j-15],  7, 18,  3) + W[j-16];
         W[j+1] = sigma(W[j- 1], 17, 19, 10) + W[j-6] +
                  sigma(W[j-14],  7, 18,  3) + W[j-15];
         W[j+2] = sigma(W[j   ], 17, 19, 10) + W[j-5] +
                  sigma(W[j-13],  7, 18,  3) + W[j-14];
         W[j+3] = sigma(W[j+ 1], 17, 19, 10) + W[j-4] +
                  sigma(W[j-12],  7, 18,  3) + W[j-13];
         W[j+4] = sigma(W[j+ 2], 17, 19, 10) + W[j-3] +
                  sigma(W[j-11],  7, 18,  3) + W[j-12];
         W[j+5] = sigma(W[j+ 3], 17, 19, 10) + W[j-2] +
                  sigma(W[j-10],  7, 18,  3) + W[j-11];
         W[j+6] = sigma(W[j+ 4], 17, 19, 10) + W[j-1] +
                  sigma(W[j- 9],  7, 18,  3) + W[j-10];
         W[j+7] = sigma(W[j+ 5], 17, 19, 10) + W[j  ] +
                  sigma(W[j- 8],  7, 18,  3) + W[j- 9];
         }

      F1(A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98);
      F1(H, A, B, C, D, E, F, G, W[ 1], 0x71374491);
      F1(G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF);
      F1(F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5);
      F1(E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B);
      F1(D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1);
      F1(C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4);
      F1(B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5);
      F1(A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98);
      F1(H, A, B, C, D, E, F, G, W[ 9], 0x12835B01);
      F1(G, H, A, B, C, D, E, F, W[10], 0x243185BE);
      F1(F, G, H, A, B, C, D, E, W[11], 0x550C7DC3);
      F1(E, F, G, H, A, B, C, D, W[12], 0x72BE5D74);
      F1(D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE);
      F1(C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7);
      F1(B, C, D, E, F, G, H, A, W[15], 0xC19BF174);
      F1(A, B, C, D, E, F, G, H, W[16], 0xE49B69C1);
      F1(H, A, B, C, D, E, F, G, W[17], 0xEFBE4786);
      F1(G, H, A, B, C, D, E, F, W[18], 0x0FC19DC6);
      F1(F, G, H, A, B, C, D, E, W[19], 0x240CA1CC);
      F1(E, F, G, H, A, B, C, D, W[20], 0x2DE92C6F);
      F1(D, E, F, G, H, A, B, C, W[21], 0x4A7484AA);
      F1(C, D, E, F, G, H, A, B, W[22], 0x5CB0A9DC);
      F1(B, C, D, E, F, G, H, A, W[23], 0x76F988DA);
      F1(A, B, C, D, E, F, G, H, W[24], 0x983E5152);
      F1(H, A, B, C, D, E, F, G, W[25], 0xA831C66D);
      F1(G, H, A, B, C, D, E, F, W[26], 0xB00327C8);
      F1(F, G, H, A, B, C, D, E, W[27], 0xBF597FC7);
      F1(E, F, G, H, A, B, C, D, W[28], 0xC6E00BF3);
      F1(D, E, F, G, H, A, B, C, W[29], 0xD5A79147);
      F1(C, D, E, F, G, H, A, B, W[30], 0x06CA6351);
      F1(B, C, D, E, F, G, H, A, W[31], 0x14292967);
      F1(A, B, C, D, E, F, G, H, W[32], 0x27B70A85);
      F1(H, A, B, C, D, E, F, G, W[33], 0x2E1B2138);
      F1(G, H, A, B, C, D, E, F, W[34], 0x4D2C6DFC);
      F1(F, G, H, A, B, C, D, E, W[35], 0x53380D13);
      F1(E, F, G, H, A, B, C, D, W[36], 0x650A7354);
      F1(D, E, F, G, H, A, B, C, W[37], 0x766A0ABB);
      F1(C, D, E, F, G, H, A, B, W[38], 0x81C2C92E);
      F1(B, C, D, E, F, G, H, A, W[39], 0x92722C85);
      F1(A, B, C, D, E, F, G, H, W[40], 0xA2BFE8A1);
      F1(H, A, B, C, D, E, F, G, W[41], 0xA81A664B);
      F1(G, H, A, B, C, D, E, F, W[42], 0xC24B8B70);
      F1(F, G, H, A, B, C, D, E, W[43], 0xC76C51A3);
      F1(E, F, G, H, A, B, C, D, W[44], 0xD192E819);
      F1(D, E, F, G, H, A, B, C, W[45], 0xD6990624);
      F1(C, D, E, F, G, H, A, B, W[46], 0xF40E3585);
      F1(B, C, D, E, F, G, H, A, W[47], 0x106AA070);
      F1(A, B, C, D, E, F, G, H, W[48], 0x19A4C116);
      F1(H, A, B, C, D, E, F, G, W[49], 0x1E376C08);
      F1(G, H, A, B, C, D, E, F, W[50], 0x2748774C);
      F1(F, G, H, A, B, C, D, E, W[51], 0x34B0BCB5);
      F1(E, F, G, H, A, B, C, D, W[52], 0x391C0CB3);
      F1(D, E, F, G, H, A, B, C, W[53], 0x4ED8AA4A);
      F1(C, D, E, F, G, H, A, B, W[54], 0x5B9CCA4F);
      F1(B, C, D, E, F, G, H, A, W[55], 0x682E6FF3);
      F1(A, B, C, D, E, F, G, H, W[56], 0x748F82EE);
      F1(H, A, B, C, D, E, F, G, W[57], 0x78A5636F);
      F1(G, H, A, B, C, D, E, F, W[58], 0x84C87814);
      F1(F, G, H, A, B, C, D, E, W[59], 0x8CC70208);
      F1(E, F, G, H, A, B, C, D, W[60], 0x90BEFFFA);
      F1(D, E, F, G, H, A, B, C, W[61], 0xA4506CEB);
      F1(C, D, E, F, G, H, A, B, W[62], 0xBEF9A3F7);
      F1(B, C, D, E, F, G, H, A, W[63], 0xC67178F2);

      A = (digest[0] += A);
      B = (digest[1] += B);
      C = (digest[2] += C);
      D = (digest[3] += D);
      E = (digest[4] += E);
      F = (digest[5] += F);
      G = (digest[6] += G);
      H = (digest[7] += H);

      input += HASH_BLOCK_SIZE;
      }
   }

/*
* Copy out the digest
*/
void SHA_224_256_BASE::copy_out(byte output[])
   {
   for(u32bit j = 0; j != OUTPUT_LENGTH; j += 4)
      store_be(digest[j/4], output + j);
   }

/*
* Clear memory of sensitive data
*/
void SHA_224_256_BASE::clear()
   {
   MDx_HashFunction::clear();
   W.clear();
   }

/*
* Clear memory of sensitive data
*/
void SHA_224::clear()
   {
   SHA_224_256_BASE::clear();
   digest[0] = 0xC1059ED8;
   digest[1] = 0x367CD507;
   digest[2] = 0x3070DD17;
   digest[3] = 0xF70E5939;
   digest[4] = 0xFFC00B31;
   digest[5] = 0x68581511;
   digest[6] = 0x64F98FA7;
   digest[7] = 0xBEFA4FA4;
   }

/*
* Clear memory of sensitive data
*/
void SHA_256::clear()
   {
   SHA_224_256_BASE::clear();
   digest[0] = 0x6A09E667;
   digest[1] = 0xBB67AE85;
   digest[2] = 0x3C6EF372;
   digest[3] = 0xA54FF53A;
   digest[4] = 0x510E527F;
   digest[5] = 0x9B05688C;
   digest[6] = 0x1F83D9AB;
   digest[7] = 0x5BE0CD19;
   }

}
<commit_msg>Slightly cleaner SHA-256 F1 func; ~1% faster<commit_after>/*
* SHA-{224,256}
* (C) 1999-2008 Jack Lloyd
*     2007 FlexSecure GmbH
*
* Distributed under the terms of the Botan license
*/

#include <botan/sha2_32.h>
#include <botan/loadstor.h>
#include <botan/rotate.h>

namespace Botan {

namespace {

/*
* SHA-256 Rho Function
*/
inline u32bit rho(u32bit X, u32bit rot1, u32bit rot2, u32bit rot3)
   {
   return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^
           rotate_right(X, rot3));
   }

/*
* SHA-256 Sigma Function
*/
inline u32bit sigma(u32bit X, u32bit rot1, u32bit rot2, u32bit shift)
   {
   return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ (X >> shift));
   }

/*
* SHA-256 F1 Function
*/
inline void F1(u32bit A, u32bit B, u32bit C, u32bit& D,
               u32bit E, u32bit F, u32bit G, u32bit& H,
               u32bit msg, u32bit magic)
   {
   H += magic + rho(E, 6, 11, 25) + ((E & F) ^ (~E & G)) + msg;
   D += H;
   H += rho(A, 2, 13, 22) + ((A & B) | ((A | B) & C));
   }

}

/*
* SHA-256 Compression Function
*/
void SHA_224_256_BASE::compress_n(const byte input[], u32bit blocks)
   {
   u32bit A = digest[0], B = digest[1], C = digest[2],
          D = digest[3], E = digest[4], F = digest[5],
          G = digest[6], H = digest[7];

   for(u32bit i = 0; i != blocks; ++i)
      {
      load_be(W.begin(), input, 16);

      for(u32bit j = 16; j != 64; j += 8)
         {
         W[j  ] = sigma(W[j- 2], 17, 19, 10) + W[j-7] +
                  sigma(W[j-15],  7, 18,  3) + W[j-16];
         W[j+1] = sigma(W[j- 1], 17, 19, 10) + W[j-6] +
                  sigma(W[j-14],  7, 18,  3) + W[j-15];
         W[j+2] = sigma(W[j   ], 17, 19, 10) + W[j-5] +
                  sigma(W[j-13],  7, 18,  3) + W[j-14];
         W[j+3] = sigma(W[j+ 1], 17, 19, 10) + W[j-4] +
                  sigma(W[j-12],  7, 18,  3) + W[j-13];
         W[j+4] = sigma(W[j+ 2], 17, 19, 10) + W[j-3] +
                  sigma(W[j-11],  7, 18,  3) + W[j-12];
         W[j+5] = sigma(W[j+ 3], 17, 19, 10) + W[j-2] +
                  sigma(W[j-10],  7, 18,  3) + W[j-11];
         W[j+6] = sigma(W[j+ 4], 17, 19, 10) + W[j-1] +
                  sigma(W[j- 9],  7, 18,  3) + W[j-10];
         W[j+7] = sigma(W[j+ 5], 17, 19, 10) + W[j  ] +
                  sigma(W[j- 8],  7, 18,  3) + W[j- 9];
         }

      F1(A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98);
      F1(H, A, B, C, D, E, F, G, W[ 1], 0x71374491);
      F1(G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF);
      F1(F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5);
      F1(E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B);
      F1(D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1);
      F1(C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4);
      F1(B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5);
      F1(A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98);
      F1(H, A, B, C, D, E, F, G, W[ 9], 0x12835B01);
      F1(G, H, A, B, C, D, E, F, W[10], 0x243185BE);
      F1(F, G, H, A, B, C, D, E, W[11], 0x550C7DC3);
      F1(E, F, G, H, A, B, C, D, W[12], 0x72BE5D74);
      F1(D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE);
      F1(C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7);
      F1(B, C, D, E, F, G, H, A, W[15], 0xC19BF174);
      F1(A, B, C, D, E, F, G, H, W[16], 0xE49B69C1);
      F1(H, A, B, C, D, E, F, G, W[17], 0xEFBE4786);
      F1(G, H, A, B, C, D, E, F, W[18], 0x0FC19DC6);
      F1(F, G, H, A, B, C, D, E, W[19], 0x240CA1CC);
      F1(E, F, G, H, A, B, C, D, W[20], 0x2DE92C6F);
      F1(D, E, F, G, H, A, B, C, W[21], 0x4A7484AA);
      F1(C, D, E, F, G, H, A, B, W[22], 0x5CB0A9DC);
      F1(B, C, D, E, F, G, H, A, W[23], 0x76F988DA);
      F1(A, B, C, D, E, F, G, H, W[24], 0x983E5152);
      F1(H, A, B, C, D, E, F, G, W[25], 0xA831C66D);
      F1(G, H, A, B, C, D, E, F, W[26], 0xB00327C8);
      F1(F, G, H, A, B, C, D, E, W[27], 0xBF597FC7);
      F1(E, F, G, H, A, B, C, D, W[28], 0xC6E00BF3);
      F1(D, E, F, G, H, A, B, C, W[29], 0xD5A79147);
      F1(C, D, E, F, G, H, A, B, W[30], 0x06CA6351);
      F1(B, C, D, E, F, G, H, A, W[31], 0x14292967);
      F1(A, B, C, D, E, F, G, H, W[32], 0x27B70A85);
      F1(H, A, B, C, D, E, F, G, W[33], 0x2E1B2138);
      F1(G, H, A, B, C, D, E, F, W[34], 0x4D2C6DFC);
      F1(F, G, H, A, B, C, D, E, W[35], 0x53380D13);
      F1(E, F, G, H, A, B, C, D, W[36], 0x650A7354);
      F1(D, E, F, G, H, A, B, C, W[37], 0x766A0ABB);
      F1(C, D, E, F, G, H, A, B, W[38], 0x81C2C92E);
      F1(B, C, D, E, F, G, H, A, W[39], 0x92722C85);
      F1(A, B, C, D, E, F, G, H, W[40], 0xA2BFE8A1);
      F1(H, A, B, C, D, E, F, G, W[41], 0xA81A664B);
      F1(G, H, A, B, C, D, E, F, W[42], 0xC24B8B70);
      F1(F, G, H, A, B, C, D, E, W[43], 0xC76C51A3);
      F1(E, F, G, H, A, B, C, D, W[44], 0xD192E819);
      F1(D, E, F, G, H, A, B, C, W[45], 0xD6990624);
      F1(C, D, E, F, G, H, A, B, W[46], 0xF40E3585);
      F1(B, C, D, E, F, G, H, A, W[47], 0x106AA070);
      F1(A, B, C, D, E, F, G, H, W[48], 0x19A4C116);
      F1(H, A, B, C, D, E, F, G, W[49], 0x1E376C08);
      F1(G, H, A, B, C, D, E, F, W[50], 0x2748774C);
      F1(F, G, H, A, B, C, D, E, W[51], 0x34B0BCB5);
      F1(E, F, G, H, A, B, C, D, W[52], 0x391C0CB3);
      F1(D, E, F, G, H, A, B, C, W[53], 0x4ED8AA4A);
      F1(C, D, E, F, G, H, A, B, W[54], 0x5B9CCA4F);
      F1(B, C, D, E, F, G, H, A, W[55], 0x682E6FF3);
      F1(A, B, C, D, E, F, G, H, W[56], 0x748F82EE);
      F1(H, A, B, C, D, E, F, G, W[57], 0x78A5636F);
      F1(G, H, A, B, C, D, E, F, W[58], 0x84C87814);
      F1(F, G, H, A, B, C, D, E, W[59], 0x8CC70208);
      F1(E, F, G, H, A, B, C, D, W[60], 0x90BEFFFA);
      F1(D, E, F, G, H, A, B, C, W[61], 0xA4506CEB);
      F1(C, D, E, F, G, H, A, B, W[62], 0xBEF9A3F7);
      F1(B, C, D, E, F, G, H, A, W[63], 0xC67178F2);

      A = (digest[0] += A);
      B = (digest[1] += B);
      C = (digest[2] += C);
      D = (digest[3] += D);
      E = (digest[4] += E);
      F = (digest[5] += F);
      G = (digest[6] += G);
      H = (digest[7] += H);

      input += HASH_BLOCK_SIZE;
      }
   }

/*
* Copy out the digest
*/
void SHA_224_256_BASE::copy_out(byte output[])
   {
   for(u32bit j = 0; j != OUTPUT_LENGTH; j += 4)
      store_be(digest[j/4], output + j);
   }

/*
* Clear memory of sensitive data
*/
void SHA_224_256_BASE::clear()
   {
   MDx_HashFunction::clear();
   W.clear();
   }

/*
* Clear memory of sensitive data
*/
void SHA_224::clear()
   {
   SHA_224_256_BASE::clear();
   digest[0] = 0xC1059ED8;
   digest[1] = 0x367CD507;
   digest[2] = 0x3070DD17;
   digest[3] = 0xF70E5939;
   digest[4] = 0xFFC00B31;
   digest[5] = 0x68581511;
   digest[6] = 0x64F98FA7;
   digest[7] = 0xBEFA4FA4;
   }

/*
* Clear memory of sensitive data
*/
void SHA_256::clear()
   {
   SHA_224_256_BASE::clear();
   digest[0] = 0x6A09E667;
   digest[1] = 0xBB67AE85;
   digest[2] = 0x3C6EF372;
   digest[3] = 0xA54FF53A;
   digest[4] = 0x510E527F;
   digest[5] = 0x9B05688C;
   digest[6] = 0x1F83D9AB;
   digest[7] = 0x5BE0CD19;
   }

}
<|endoftext|>


<commit_before>/*
 *   Copyright (C) 2011 Ivan Cukic <ivan.cukic(at)kde.org>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License version 2,
 *   or (at your option) any later version, as published by the Free
 *   Software Foundation
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details
 *
 *   You should have received a copy of the GNU General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "connman-manager.h"
#include "connman-service.h"

#include "ConnmanNetworkNotifier.h"
#include "connmannetworknotifieradaptor.h"
#include <config-features.h>

#include <KDebug>

// #define CONNMAN_DBUS_SERVICE "org.moblin.connman"
#define CONNMAN_DBUS_SERVICE "net.connman"

REGISTER_NETWORK_NOTIFIER(ConnmanNetworkNotifier)

class ConnmanNetworkNotifier::Private {
public:
    Private()
        : iface(0), watcher(0)
    {}

    NetConnmanManagerInterface * iface;
    QDBusServiceWatcher * watcher;
};

ConnmanNetworkNotifier::ConnmanNetworkNotifier(QObject * parent)
    : NetworkNotifier(parent), d(new Private())
{
}

ConnmanNetworkNotifier::~ConnmanNetworkNotifier()
{
    delete d;
}

void ConnmanNetworkNotifier::init()
{
    // Hmh, connman doesn't show up when registered. Lets hope it will be online
    // before the location manager is started

    if (!QDBusConnection::systemBus().interface()->isServiceRegistered(CONNMAN_DBUS_SERVICE)) {
        kDebug() << "Watching for" << CONNMAN_DBUS_SERVICE << "to arrive";

        d->watcher = new QDBusServiceWatcher(
                CONNMAN_DBUS_SERVICE,
                QDBusConnection::systemBus(),
                QDBusServiceWatcher::WatchForRegistration |
                    QDBusServiceWatcher::WatchForUnregistration |
                    QDBusServiceWatcher::WatchForOwnerChange,
                this
            );

        kDebug() << "Connecting" <<
        connect(d->watcher, SIGNAL(serviceRegistered(QString)),
                this, SLOT(enable()));
    } else {
        enable();
    }
}

void ConnmanNetworkNotifier::enable()
{
    kDebug() << "Starting connman listener";

    (void) new ConnmanNetworkNotifierAdaptor(this);
    QDBusConnection::sessionBus().registerObject(
            QLatin1String("/ConnmanInterface"), this);

    delete d->iface;
    d->iface = new NetConnmanManagerInterface(CONNMAN_DBUS_SERVICE, QLatin1String("/"), QDBusConnection::systemBus(), this);
    connect(d->iface, SIGNAL(PropertyChanged(QString,QDBusVariant)), SLOT(propertyChanged(QString,QDBusVariant)));

    QDBusReply<QVariantMap> reply = d->iface->GetProperties();
    if (!reply.isValid()) {
        return;
    }
    QVariantMap properties = reply.value();
    //kDebug() << "Initial state: " << properties["State"].toString();
    propertyChanged("State", QDBusVariant(properties["State"]));
}

// monitor when connman connects to a network, or disconnects from it.
// On those events, this method passes the info to the locationmanager daemon
// via the dummy network notifier.
void ConnmanNetworkNotifier::propertyChanged(const QString &name, const QDBusVariant &value)
{
    //kDebug() << name << ": " << value.variant().toString();
    if (name != QLatin1String("State")) {
        return;
    }

    // we are offline
    if (value.variant().toString() != QLatin1String("online")) {
        kDebug() << "OFFLINE";
        setWifiName("");
        return;
    }

    QDBusReply<QVariantMap> reply = d->iface->GetProperties();
    if (!reply.isValid()) {
        kDebug() << reply.error().message();
        return;
    }

    QVariantMap properties = reply.value();
    //kDebug() << "got properties:" << properties.count();
    //kDebug() << "Services ==" << properties["Services"];
    QList<QDBusObjectPath> services = qdbus_cast<QList<QDBusObjectPath> >(properties["Services"]);
    //kDebug() << services.count() << "services";

    // searching for active wifi info
    foreach (const QDBusObjectPath &s, services) {
        //kDebug() << "testing service" << s.path();
        NetConnmanServiceInterface service(CONNMAN_DBUS_SERVICE, s.path(), QDBusConnection::systemBus());

        if (!service.isValid()) {
            continue;
        }
        //kDebug() << "testing service" << s.path() << "getting properties";

        QDBusReply<QVariantMap> reply = service.GetProperties();
        if (!reply.isValid()) {
            continue;
        }
        //kDebug() << "testing service" << s.path() << "testing state";

        QVariantMap serviceProperties = reply.value();
        if (serviceProperties["State"].toString() == QLatin1String("ready")) {
            kDebug() << "CONNECTED TO:" << serviceProperties["Name"];
            setWifiName(serviceProperties["Name"].toString());
            return;
        }
    }
}

void ConnmanNetworkNotifier::setWifiName(const QString & accessPoint)
{
    setActiveAccessPoint(accessPoint);
}

<commit_msg>Added some debugging output<commit_after>/*
 *   Copyright (C) 2011, 2012 Ivan Cukic <ivan.cukic(at)kde.org>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License version 2,
 *   or (at your option) any later version, as published by the Free
 *   Software Foundation
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details
 *
 *   You should have received a copy of the GNU General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "connman-manager.h"
#include "connman-service.h"

#include "ConnmanNetworkNotifier.h"
#include "connmannetworknotifieradaptor.h"
#include <config-features.h>

#include <KDebug>

// #define CONNMAN_DBUS_SERVICE "org.moblin.connman"
#define CONNMAN_DBUS_SERVICE "net.connman"

REGISTER_NETWORK_NOTIFIER(ConnmanNetworkNotifier)

class ConnmanNetworkNotifier::Private {
public:
    Private()
        : iface(0), watcher(0)
    {}

    NetConnmanManagerInterface * iface;
    QDBusServiceWatcher * watcher;
};

ConnmanNetworkNotifier::ConnmanNetworkNotifier(QObject * parent)
    : NetworkNotifier(parent), d(new Private())
{
}

ConnmanNetworkNotifier::~ConnmanNetworkNotifier()
{
    delete d;
}

void ConnmanNetworkNotifier::init()
{
    // Hmh, connman doesn't show up when registered. Lets hope it will be online
    // before the location manager is started

    if (!QDBusConnection::systemBus().interface()->isServiceRegistered(CONNMAN_DBUS_SERVICE)) {
        kDebug() << "Watching for" << CONNMAN_DBUS_SERVICE << "to arrive";

        d->watcher = new QDBusServiceWatcher(
                CONNMAN_DBUS_SERVICE,
                QDBusConnection::systemBus(),
                QDBusServiceWatcher::WatchForRegistration |
                    QDBusServiceWatcher::WatchForUnregistration |
                    QDBusServiceWatcher::WatchForOwnerChange,
                this
            );

        kDebug() << "Connecting" <<
        connect(d->watcher, SIGNAL(serviceRegistered(QString)),
                this, SLOT(enable()));
    } else {
        enable();
    }
}

void ConnmanNetworkNotifier::enable()
{
    kDebug() << "Starting connman listener";

    (void) new ConnmanNetworkNotifierAdaptor(this);
    QDBusConnection::sessionBus().registerObject(
            QLatin1String("/ConnmanInterface"), this);

    delete d->iface;
    d->iface = new NetConnmanManagerInterface(CONNMAN_DBUS_SERVICE, QLatin1String("/"), QDBusConnection::systemBus(), this);
    connect(d->iface, SIGNAL(PropertyChanged(QString,QDBusVariant)), SLOT(propertyChanged(QString,QDBusVariant)));

    QDBusReply<QVariantMap> reply = d->iface->GetProperties();
    if (!reply.isValid()) {
        kDebug() << "GetProperties reply was invalid";
        return;
    }
    QVariantMap properties = reply.value();
    //kDebug() << "Initial state: " << properties["State"].toString();
    propertyChanged("State", QDBusVariant(properties["State"]));
}

// monitor when connman connects to a network, or disconnects from it.
// On those events, this method passes the info to the locationmanager daemon
// via the dummy network notifier.
void ConnmanNetworkNotifier::propertyChanged(const QString &name, const QDBusVariant &value)
{
    //kDebug() << name << ": " << value.variant().toString();
    if (name != QLatin1String("State")) {
        kDebug() << "Property" << name << "ignored";
        return;
    }

    // we are offline
    if (value.variant().toString() != QLatin1String("online")) {
        kDebug() << "OFFLINE";
        setWifiName("");
        return;
    }

    QDBusReply<QVariantMap> reply = d->iface->GetProperties();
    if (!reply.isValid()) {
        kDebug() << "GetProperties failed" << reply.error().message();
        return;
    }

    QVariantMap properties = reply.value();
    //kDebug() << "got properties:" << properties.count();
    //kDebug() << "Services ==" << properties["Services"];
    QList<QDBusObjectPath> services = qdbus_cast<QList<QDBusObjectPath> >(properties["Services"]);
    //kDebug() << services.count() << "services";

    // searching for active wifi info
    foreach (const QDBusObjectPath &s, services) {
        kDebug() << "testing service" << s.path();

        NetConnmanServiceInterface service(CONNMAN_DBUS_SERVICE, s.path(), QDBusConnection::systemBus());

        if (!service.isValid()) {
            kDebug() << "Service" << s.path() << "is not valid";
            continue;
        }

        QDBusReply<QVariantMap> reply = service.GetProperties();
        if (!reply.isValid()) {
            kDebug() << "GetProperties failed for";
            continue;
        }

        QVariantMap serviceProperties = reply.value();
        if (serviceProperties["State"].toString() == QLatin1String("ready")) {
            kDebug() << "CONNECTED TO:" << serviceProperties["Name"];
            setWifiName(serviceProperties["Name"].toString());
            return;
        }
    }
}

void ConnmanNetworkNotifier::setWifiName(const QString & accessPoint)
{
    setActiveAccessPoint(accessPoint);
}

<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <cassert>
#include <sstream>
#include <algorithm>
#include <fstream>

#include <boost/program_options.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>

#include <boost/algorithm/string.hpp>

using std::string;
using std::ostream;
using std::ofstream;

namespace po=boost::program_options;

const string HELP_K = "help";
const string CONFIG_K = "config";
const string INPUT_K = "input";
const string OUTPUT_K = "output";

const string OPERATION_K = "operation";
const string SELECT_K = "select";
const string SPLIT_K = "split";
const string TRANSPOSE_K = "transpose";
const string COMBINE_K = "combine";

const string FORMAT_K = "format";
const string PREFIX_K = "prefix";
const string VALUE_K = "value";
const string KEYS_K = "keys";

const string JSON_K = "json";
const string GNUPLOT_K = "gnuplot";

const string OUTPUT_FORMAT_K = OUTPUT_K + "." + FORMAT_K;
const string OUTPUT_PREFIX_K = OUTPUT_K + "." + PREFIX_K;

const string INPUT_VALUE_K = INPUT_K + "." + VALUE_K;

int parse_configuration( int argc, char ** argv, boost::property_tree::ptree & cfg );
int command_line( int argc, char ** argv, po::variables_map & vm );
int transform( po::variables_map & vm, boost::property_tree::ptree & p );

void parse_data( boost::property_tree::ptree & cfg );

typedef void (*parser_op)( boost::property_tree::ptree & parameters );

// select keys from each input file into a
void select_op( boost::property_tree::ptree & parameters );
void select_op_gnuplot( boost::property_tree::ptree & params );

// combine all keys from each input file into a single output file
void combine_op( boost::property_tree::ptree & parameters );
void combine_op_json( boost::property_tree::ptree & parameters );
void transpose_op( boost::property_tree::ptree & params );

void write_json( const std::string & path, boost::property_tree::ptree & results );
void write_gnuplot( const std::string & path, const std::string & header, boost::property_tree::ptree & results );

int main( int argc, char ** argv ) {

    boost::property_tree::ptree cfg;
    int res = 0;
    if( (res = parse_configuration( argc, argv, cfg )) ) {
        return res;
    }

    BOOST_FOREACH( auto& c, cfg ) {
        std::cerr << c.first << std::endl;
        parse_data( c.second );
    }
}

void parse_data( boost::property_tree::ptree & cfg ) {
    string op = cfg.get< string >( OPERATION_K, "");

    if( op.empty() ) return;

    if( op == SELECT_K ) {
        select_op( cfg );
    } else if ( op == COMBINE_K ) {
//        combine_op( cfg );
    } else if( op == TRANSPOSE_K ) {
//        transpose_op( cfg );
    }
}

int parse_configuration( int argc, char ** argv, boost::property_tree::ptree & cfg ) {
    po::variables_map vm;
    int res = command_line( argc, argv, vm );

    if( res ) {
        return res;
    }

    string config_file = vm[ CONFIG_K ].as< string >();
    if( config_file.empty() ) {
        res = transform( vm, cfg );
    } else {
        boost::property_tree::read_json( config_file, cfg );
    }

    return res;
}

int command_line( int argc, char ** argv, po::variables_map & vm ) {
    po::options_description gen( "General" );
    gen.add_options()
    ((HELP_K + ",h").c_str(), "Print this" )
    ;

    po::options_description io_params("I/O Parameters");
    io_params.add_options()
    ( (CONFIG_K + ",c" ).c_str(), po::value< string >()->default_value(""), "Configuration file containing files to be parsed" )
    ;

    po::options_description cmdline;
    cmdline.add( gen ).add( io_params );
    po::store( po::command_line_parser( argc, argv ).options(cmdline).run(), vm );

    if( vm.count( HELP_K ) ) {
        std::cout << cmdline << std::endl;
        return 1;
    }

    return 0;
}

int transform( po::variables_map & vm, boost::property_tree::ptree & p ) {
    return 0;
}

void select_op( boost::property_tree::ptree & params ) {

    string frmt = params.get< string >( OUTPUT_FORMAT_K, "" );
    string output = params.get< string >( OUTPUT_PREFIX_K, "" );

    std::vector< string > keys;
    BOOST_FOREACH( auto& v, params.get_child( KEYS_K ) ) {
        std::ostringstream oss;
        oss << v.second.data();
        keys.push_back( oss.str() );
    }

    BOOST_FOREACH( auto& v, params.get_child( INPUT_K ) ) {
        std::ostringstream oss;
        oss << v.second.data();

        string path = oss.str();

        if( boost::algorithm::iends_with(path, "." + JSON_K) ) {
            std::cerr << "Parsing input JSON file: " << path << std::endl;

            string tmp_path = path.substr(0, path.size() - (JSON_K.size() + 1));
            boost::property_tree::ptree infile;
            boost::property_tree::read_json( path, infile );

            BOOST_FOREACH( auto& k, keys ) {
                if( infile.get_child_optional( k ) != boost::none ) {
//                    string tmp = tmp_path + "." + k;
//                    results.add_child( k, infile.get_child( k ) );
//

                    if( boost::iequals( frmt, JSON_K ) ) {
                        write_json( output, infile.get_child(k) );
                    } else if( boost::iequals( frmt, GNUPLOT_K ) ) {
                        write_gnuplot( output, k, infile.get_child(k) );
                    }
                }
            }
        }
    }
}
/*
void combine_op_json( boost::property_tree::ptree & params ) {
    boost::property_tree::ptree results;
    assert( params.get_child_optional( INPUT_K ) != boost::none );
    assert( params.get_child_optional( KEYS_K ) != boost::none );

    std::vector< string > keys;

    BOOST_FOREACH( auto& v, params.get_child( KEYS_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();
            keys.push_back( oss.str() );
    }

    BOOST_FOREACH( auto& v, params.get_child( INPUT_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();

            string path = oss.str();

            if( boost::algorithm::iends_with(path, "." + JSON_K) ) {
                std::cerr << "Parsing input JSON file: " << path << std::endl;

                string tmp_path = path.substr(0, path.size() - (JSON_K.size() + 1));
                boost::property_tree::ptree infile;
                boost::property_tree::read_json( path, infile );

                BOOST_FOREACH( auto& k, keys ) {
                    if( infile.get_child_optional( k ) != boost::none ) {
                        string tmp = tmp_path + "." + k;
                        results.add_child( tmp, infile.get_child( k ) );
                    }
                }
            }
        }

        if( output.empty() ) {
            boost::property_tree::write_json(std::cout, results );
        } else {
            boost::property_tree::write_json( output + "." + JSON_K, results );
        }

}

void select_op_gnuplot( boost::property_tree::ptree & params ) {

}

void transpose_op( boost::property_tree::ptree & params ) {
    assert( params.get_child_optional( OUTPUT_FORMAT_K ) != boost::none );

    string frmt = params.get< string >( OUTPUT_FORMAT_K, "" );
    string output = params.get< string >( OUTPUT_PREFIX_K, "" );

    if( boost::iequals( frmt, GNUPLOT_K ) ) {
        assert( params.get_child_optional( INPUT_K ) != boost::none );
        assert( params.get_child_optional( KEYS_K ) != boost::none );

        std::vector< string > keys;

        BOOST_FOREACH( auto& v, params.get_child( KEYS_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();
            keys.push_back( oss.str() );
        }

        BOOST_FOREACH( auto& v, params.get_child( INPUT_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();

            string path = oss.str();

            typedef std::vector< string > row_type;
            typedef std::map< string, std::vector< row_type > > value_map_type;
            value_map_type data;

            if( boost::algorithm::iends_with(path, "." + JSON_K) ) {
                std::cerr << "Parsing input JSON file: " << path << std::endl;

                string tmp_path = path.substr(0, path.size() - (JSON_K.size() + 1));
                boost::property_tree::ptree infile;
                boost::property_tree::read_json( path, infile );

                BOOST_FOREACH( auto& k, keys ) {
                    if( infile.get_child_optional( k ) != boost::none ) {
//                        string tmp = tmp_path + "." + k;
                        value_map_type::iterator it = data.find( k );
                        if( it == data.end() ) {
                            std::pair< value_map_type::iterator, bool > res = data.insert( std::make_pair(k, std::vector<row_type>() ));
                            assert( res.second );
                            it = res.first;
                        }

                        unsigned int max_columns = 0;
                        unsigned int j = 0;
                        BOOST_FOREACH( auto& dval, infile.get_child(k) ) {
                            unsigned int i = 0;
                            row_type r;
                            BOOST_FOREACH( auto& pval, dval.second ) {
                                std::ostringstream oss;
                                oss << pval.second.data();
                                r.push_back( oss.str() );
                                ++i;
                            }
                            if( i > max_columns ) { max_columns = i; }

                            it->second.push_back(r);
                            ++j;
                        }
                    }
                }
            }

            if( output.empty() ) {
                BOOST_FOREACH( auto& dval, data) {
                    std::cout << "# " << dval.first << std::endl;
                    unsigned int i = 0;
                    BOOST_FOREACH( auto& r, dval.second ) {
                        std::cout << i++;
                        BOOST_FOREACH( auto& c, r ) {
                            std::cout << "," << c;
                        }
                        std::cout << std::endl;
                    }
                    std::cout << std::endl;
                }
            }
        }
    }
}

void combine_op( boost::property_tree::ptree & params ) {
    assert( params.get_child_optional( OUTPUT_FORMAT_K ) != boost::none );

    string frmt = params.get< string >( OUTPUT_FORMAT_K, "" );
    string output = params.get< string >( OUTPUT_PREFIX_K, "" );

    if( boost::iequals( frmt, JSON_K ) ) {
        boost::property_tree::ptree  results;

        assert( params.get_child_optional( INPUT_K ) != boost::none );
        assert( params.get_child_optional( KEYS_K ) != boost::none );

        std::vector< string > keys;

        BOOST_FOREACH( auto& v, params.get_child( KEYS_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();
            keys.push_back( oss.str() );
        }
        BOOST_FOREACH( auto& v, params.get_child( INPUT_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();

            string path = oss.str();

            if( boost::algorithm::iends_with(path, "." + JSON_K) ) {
                std::cerr << "Parsing input JSON file: " << path << std::endl;

                string tmp_path = path.substr(0, path.size() - (JSON_K.size() + 1));
                boost::property_tree::ptree infile;
                boost::property_tree::read_json( path, infile );

                BOOST_FOREACH( auto& k, keys ) {
                    if( infile.get_child_optional( k ) != boost::none ) {
                        string tmp = tmp_path + "." + k;
                        results.add_child( tmp, infile.get_child( k ) );
                    }
                }
            }
        }
    }
}*/

void write_json( const string & path, boost::property_tree::ptree & results ) {
    if( path.empty() ) {
        boost::property_tree::write_json( std::cout, results );
    } else {
        boost::property_tree::write_json( path + "." + JSON_K, results );
    }
}
/*
void write( ostream * out, boost::property_tree::ptree::value_type  & node ) {
    if( node.first.empty() ) {
        (*out) << "\n";
        BOOST_FOREACH( auto & pval, node.second ) {
            std::ostringstream oss;
            oss << pval.second.data();

            (*out) << oss.str() << ",";
        }
    } else {
        (*out) << "." << node.first;
        BOOST_FOREACH( auto& c, node.second ) {
            write( out, c );
            (*out) << "\n";
        }
    }
}*/

void write_data( ostream * out, boost::property_tree::ptree & data ) {
    unsigned int i = 0;

    if( data.empty() ) {
        //(*out) << i << "," << data.data() << "\n";
        (*out) << "," << data.data();
    } else {
        BOOST_FOREACH( auto& c, data ) {
            if( c.second.empty() ) {
                (*out) << "," << c.second.data();
            } else {
                (*out) << ++i;
                 write_data( out, c.second);
                (*out) << "\n";
            }
        }
    }
}

void write( ostream * out, string path, boost::property_tree::ptree & tr ) {
    unsigned int i = 0;

    if( tr.empty() ) {
        (*out) << ++i << "," << tr.data() << "\n";
    } else {
        BOOST_FOREACH( auto& c, tr ) {
            if( c.first.empty() ) {
                (*out) << ++i;
                write_data(out, c.second);
                (*out) << "\n";
            } else {
                write( out, path + "." + c.first, c.second );
            }
        }
    }
}

void write_gnuplot( const string & path, const string & header, boost::property_tree::ptree & results ) {
    ostream * out;
    if( path.empty() ) {
        out = &std::cout;
    } else {
        out = new ofstream(path + ".dat");
    }

    (*out) << "# " << header << "\n";
    write(out, "", results );

    if( out != &std::cout ) {
        ((ofstream *)out)->close();
    }
}
<commit_msg>Formatting<commit_after>#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <cassert>
#include <sstream>
#include <algorithm>
#include <fstream>

#include <boost/program_options.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>

#include <boost/algorithm/string.hpp>

using std::string;
using std::ostream;
using std::ofstream;

namespace po=boost::program_options;

const string HELP_K = "help";
const string CONFIG_K = "config";
const string INPUT_K = "input";
const string OUTPUT_K = "output";

const string OPERATION_K = "operation";
const string SELECT_K = "select";
const string SPLIT_K = "split";
const string TRANSPOSE_K = "transpose";
const string COMBINE_K = "combine";

const string FORMAT_K = "format";
const string PREFIX_K = "prefix";
const string VALUE_K = "value";
const string KEYS_K = "keys";

const string JSON_K = "json";
const string GNUPLOT_K = "gnuplot";

const string OUTPUT_FORMAT_K = OUTPUT_K + "." + FORMAT_K;
const string OUTPUT_PREFIX_K = OUTPUT_K + "." + PREFIX_K;

const string INPUT_VALUE_K = INPUT_K + "." + VALUE_K;

int parse_configuration( int argc, char ** argv, boost::property_tree::ptree & cfg );
int command_line( int argc, char ** argv, po::variables_map & vm );
int transform( po::variables_map & vm, boost::property_tree::ptree & p );

void parse_data( boost::property_tree::ptree & cfg );

typedef void (*parser_op)( boost::property_tree::ptree & parameters );

// select keys from each input file into a
void select_op( boost::property_tree::ptree & parameters );
void select_op_gnuplot( boost::property_tree::ptree & params );

// combine all keys from each input file into a single output file
void combine_op( boost::property_tree::ptree & parameters );
void combine_op_json( boost::property_tree::ptree & parameters );
void transpose_op( boost::property_tree::ptree & params );

void write_json( const std::string & path, boost::property_tree::ptree & results );
void write_gnuplot( const std::string & path, const std::string & header, boost::property_tree::ptree & results );

int main( int argc, char ** argv ) {

    boost::property_tree::ptree cfg;
    int res = 0;
    if( (res = parse_configuration( argc, argv, cfg )) ) {
        return res;
    }

    BOOST_FOREACH( auto& c, cfg ) {
        std::cerr << c.first << std::endl;
        parse_data( c.second );
    }
}

void parse_data( boost::property_tree::ptree & cfg ) {
    string op = cfg.get< string >( OPERATION_K, "");

    if( op.empty() ) return;

    if( op == SELECT_K ) {
        select_op( cfg );
    } else if ( op == COMBINE_K ) {
//        combine_op( cfg );
    } else if( op == TRANSPOSE_K ) {
//        transpose_op( cfg );
    }
}

int parse_configuration( int argc, char ** argv, boost::property_tree::ptree & cfg ) {
    po::variables_map vm;
    int res = command_line( argc, argv, vm );

    if( res ) {
        return res;
    }

    string config_file = vm[ CONFIG_K ].as< string >();
    if( config_file.empty() ) {
        res = transform( vm, cfg );
    } else {
        boost::property_tree::read_json( config_file, cfg );
    }

    return res;
}

int command_line( int argc, char ** argv, po::variables_map & vm ) {
    po::options_description gen( "General" );
    gen.add_options()
    ((HELP_K + ",h").c_str(), "Print this" )
    ;

    po::options_description io_params("I/O Parameters");
    io_params.add_options()
    ( (CONFIG_K + ",c" ).c_str(), po::value< string >()->default_value(""), "Configuration file containing files to be parsed" )
    ;

    po::options_description cmdline;
    cmdline.add( gen ).add( io_params );
    po::store( po::command_line_parser( argc, argv ).options(cmdline).run(), vm );

    if( vm.count( HELP_K ) ) {
        std::cout << cmdline << std::endl;
        return 1;
    }

    return 0;
}

int transform( po::variables_map & vm, boost::property_tree::ptree & p ) {
    return 0;
}

void select_op( boost::property_tree::ptree & params ) {

    string frmt = params.get< string >( OUTPUT_FORMAT_K, "" );
    string output = params.get< string >( OUTPUT_PREFIX_K, "" );

    std::vector< string > keys;
    BOOST_FOREACH( auto& v, params.get_child( KEYS_K ) ) {
        std::ostringstream oss;
        oss << v.second.data();
        keys.push_back( oss.str() );
    }

    BOOST_FOREACH( auto& v, params.get_child( INPUT_K ) ) {
        std::ostringstream oss;
        oss << v.second.data();

        string path = oss.str();

        if( boost::algorithm::iends_with(path, "." + JSON_K) ) {
            std::cerr << "Parsing input JSON file: " << path << std::endl;

            string tmp_path = path.substr(0, path.size() - (JSON_K.size() + 1));
            boost::property_tree::ptree infile;
            boost::property_tree::read_json( path, infile );

            BOOST_FOREACH( auto& k, keys ) {
                if( infile.get_child_optional( k ) != boost::none ) {
//                    string tmp = tmp_path + "." + k;
//                    results.add_child( k, infile.get_child( k ) );
//

                    if( boost::iequals( frmt, JSON_K ) ) {
                        write_json( output, infile.get_child(k) );
                    } else if( boost::iequals( frmt, GNUPLOT_K ) ) {
                        write_gnuplot( output, k, infile.get_child(k) );
                    }
                }
            }
        }
    }
}
/*
void combine_op_json( boost::property_tree::ptree & params ) {
    boost::property_tree::ptree results;
    assert( params.get_child_optional( INPUT_K ) != boost::none );
    assert( params.get_child_optional( KEYS_K ) != boost::none );

    std::vector< string > keys;

    BOOST_FOREACH( auto& v, params.get_child( KEYS_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();
            keys.push_back( oss.str() );
    }

    BOOST_FOREACH( auto& v, params.get_child( INPUT_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();

            string path = oss.str();

            if( boost::algorithm::iends_with(path, "." + JSON_K) ) {
                std::cerr << "Parsing input JSON file: " << path << std::endl;

                string tmp_path = path.substr(0, path.size() - (JSON_K.size() + 1));
                boost::property_tree::ptree infile;
                boost::property_tree::read_json( path, infile );

                BOOST_FOREACH( auto& k, keys ) {
                    if( infile.get_child_optional( k ) != boost::none ) {
                        string tmp = tmp_path + "." + k;
                        results.add_child( tmp, infile.get_child( k ) );
                    }
                }
            }
        }

        if( output.empty() ) {
            boost::property_tree::write_json(std::cout, results );
        } else {
            boost::property_tree::write_json( output + "." + JSON_K, results );
        }

}

void select_op_gnuplot( boost::property_tree::ptree & params ) {

}

void transpose_op( boost::property_tree::ptree & params ) {
    assert( params.get_child_optional( OUTPUT_FORMAT_K ) != boost::none );

    string frmt = params.get< string >( OUTPUT_FORMAT_K, "" );
    string output = params.get< string >( OUTPUT_PREFIX_K, "" );

    if( boost::iequals( frmt, GNUPLOT_K ) ) {
        assert( params.get_child_optional( INPUT_K ) != boost::none );
        assert( params.get_child_optional( KEYS_K ) != boost::none );

        std::vector< string > keys;

        BOOST_FOREACH( auto& v, params.get_child( KEYS_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();
            keys.push_back( oss.str() );
        }

        BOOST_FOREACH( auto& v, params.get_child( INPUT_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();

            string path = oss.str();

            typedef std::vector< string > row_type;
            typedef std::map< string, std::vector< row_type > > value_map_type;
            value_map_type data;

            if( boost::algorithm::iends_with(path, "." + JSON_K) ) {
                std::cerr << "Parsing input JSON file: " << path << std::endl;

                string tmp_path = path.substr(0, path.size() - (JSON_K.size() + 1));
                boost::property_tree::ptree infile;
                boost::property_tree::read_json( path, infile );

                BOOST_FOREACH( auto& k, keys ) {
                    if( infile.get_child_optional( k ) != boost::none ) {
//                        string tmp = tmp_path + "." + k;
                        value_map_type::iterator it = data.find( k );
                        if( it == data.end() ) {
                            std::pair< value_map_type::iterator, bool > res = data.insert( std::make_pair(k, std::vector<row_type>() ));
                            assert( res.second );
                            it = res.first;
                        }

                        unsigned int max_columns = 0;
                        unsigned int j = 0;
                        BOOST_FOREACH( auto& dval, infile.get_child(k) ) {
                            unsigned int i = 0;
                            row_type r;
                            BOOST_FOREACH( auto& pval, dval.second ) {
                                std::ostringstream oss;
                                oss << pval.second.data();
                                r.push_back( oss.str() );
                                ++i;
                            }
                            if( i > max_columns ) { max_columns = i; }

                            it->second.push_back(r);
                            ++j;
                        }
                    }
                }
            }

            if( output.empty() ) {
                BOOST_FOREACH( auto& dval, data) {
                    std::cout << "# " << dval.first << std::endl;
                    unsigned int i = 0;
                    BOOST_FOREACH( auto& r, dval.second ) {
                        std::cout << i++;
                        BOOST_FOREACH( auto& c, r ) {
                            std::cout << "," << c;
                        }
                        std::cout << std::endl;
                    }
                    std::cout << std::endl;
                }
            }
        }
    }
}

void combine_op( boost::property_tree::ptree & params ) {
    assert( params.get_child_optional( OUTPUT_FORMAT_K ) != boost::none );

    string frmt = params.get< string >( OUTPUT_FORMAT_K, "" );
    string output = params.get< string >( OUTPUT_PREFIX_K, "" );

    if( boost::iequals( frmt, JSON_K ) ) {
        boost::property_tree::ptree  results;

        assert( params.get_child_optional( INPUT_K ) != boost::none );
        assert( params.get_child_optional( KEYS_K ) != boost::none );

        std::vector< string > keys;

        BOOST_FOREACH( auto& v, params.get_child( KEYS_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();
            keys.push_back( oss.str() );
        }
        BOOST_FOREACH( auto& v, params.get_child( INPUT_K ) ) {
            std::ostringstream oss;
            oss << v.second.data();

            string path = oss.str();

            if( boost::algorithm::iends_with(path, "." + JSON_K) ) {
                std::cerr << "Parsing input JSON file: " << path << std::endl;

                string tmp_path = path.substr(0, path.size() - (JSON_K.size() + 1));
                boost::property_tree::ptree infile;
                boost::property_tree::read_json( path, infile );

                BOOST_FOREACH( auto& k, keys ) {
                    if( infile.get_child_optional( k ) != boost::none ) {
                        string tmp = tmp_path + "." + k;
                        results.add_child( tmp, infile.get_child( k ) );
                    }
                }
            }
        }
    }
}*/

void write_json( const string & path, boost::property_tree::ptree & results ) {
    if( path.empty() ) {
        boost::property_tree::write_json( std::cout, results );
    } else {
        boost::property_tree::write_json( path + "." + JSON_K, results );
    }
}
/*
void write( ostream * out, boost::property_tree::ptree::value_type  & node ) {
    if( node.first.empty() ) {
        (*out) << "\n";
        BOOST_FOREACH( auto & pval, node.second ) {
            std::ostringstream oss;
            oss << pval.second.data();

            (*out) << oss.str() << ",";
        }
    } else {
        (*out) << "." << node.first;
        BOOST_FOREACH( auto& c, node.second ) {
            write( out, c );
            (*out) << "\n";
        }
    }
}*/

void write_data( ostream * out, boost::property_tree::ptree & data ) {
    unsigned int i = 0;

    if( data.empty() ) {
        //(*out) << i << "," << data.data() << "\n";
        (*out) << "," << data.data();
    } else {
        BOOST_FOREACH( auto& c, data ) {
            if( c.second.empty() ) {
                (*out) << "," << c.second.data();
            } else {
                (*out) << ++i;
                write_data( out, c.second);
                (*out) << "\n";
            }
        }
    }
}

void write( ostream * out, string path, boost::property_tree::ptree & tr ) {
    unsigned int i = 0;

    if( tr.empty() ) {
        (*out) << ++i << "," << tr.data() << "\n";
    } else {
        BOOST_FOREACH( auto& c, tr ) {
            if( c.first.empty() ) {
                (*out) << ++i;
                write_data(out, c.second);
                (*out) << "\n";
            } else {
                write( out, path + "." + c.first, c.second );
            }
        }
    }
}

void write_gnuplot( const string & path, const string & header, boost::property_tree::ptree & results ) {
    ostream * out;
    if( path.empty() ) {
        out = &std::cout;
    } else {
        out = new ofstream(path + ".dat");
    }

    (*out) << "# " << header << "\n";
    write(out, "", results );

    if( out != &std::cout ) {
        ((ofstream *)out)->close();
    }
}
<|endoftext|>


<commit_before>// ========================================================================== //
// This file is part of Sara, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2018 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

//! @example

#include <set>

#include <DO/Sara/Graphics.hpp>
#include <DO/Sara/ImageIO.hpp>
#include <DO/Sara/ImageProcessing.hpp>
#include <DO/Sara/VideoIO.hpp>

#include <DO/Sara/Geometry/Algorithms/RobustEstimation/LineSolver.hpp>
#include <DO/Sara/Geometry/Algorithms/RobustEstimation/RANSAC.hpp>
#include <DO/Sara/Geometry/Objects/LineSegment.hpp>

using namespace std;
using namespace DO::Sara;

auto to_map(const std::map<int, std::vector<Eigen::Vector2i>>& contours,
            const Eigen::Vector2i& image_sizes)
{
  auto labeled_edges = Image<int>{image_sizes};
  labeled_edges.flat_array().fill(-1);
  for (const auto& [label, points] : contours)
  {
    for (const auto& p : points)
      labeled_edges(p) = label;
  }
  return labeled_edges;
}

auto random_colors(const std::map<int, std::vector<Eigen::Vector2i>>& contours)
{
  auto colors = std::map<int, Rgb8>{};
  for (const auto& c : contours)
    colors[c.first] = Rgb8(rand() % 255, rand() % 255, rand() % 255);
  return colors;
}

auto fit_line(const std::vector<Eigen::Vector2i>& curve_points,
              float error_threshold = 1.5f) -> std::tuple<bool, LineSegment>
{
  enum class Axis : std::uint8_t
  {
    X = 0,
    Y = 1
  };

  if (curve_points.size() < 2)
    return {false, {}};

  auto line_solver = LineSolver2D<float>{};
  auto inlier_predicate = InlierPredicate<LinePointDistance2D<float>>{
      .distance = {},                     //
      .error_threshold = error_threshold  //
  };

  auto points = Tensor_<float, 2>(curve_points.size(), 3);
  auto point_matrix = points.matrix();
  for (auto r = 0u; r < curve_points.size(); ++r)
    point_matrix.row(r) = curve_points[r]      //
                              .transpose()     //
                              .homogeneous()   //
                              .cast<float>();  //

  const auto num_iterations = std::clamp(                //
      static_cast<int>(curve_points.size() * 0.20) + 1,  //
      5, 20);
  const auto [line, inliers, subset_best] = ransac(points,            //
                                                   line_solver,       //
                                                   inlier_predicate,  //
                                                   num_iterations);

  const Eigen::Vector2f t = Projective::tangent(line).cwiseAbs();
  const auto fast_axis = t.x() > t.y() ? Axis::X : Axis::Y;

  const auto first_inlier = std::find(inliers.begin(), inliers.end(), 1);
  if (first_inlier == inliers.end())
    return {false, LineSegment{}};

  auto i = std::size_t(first_inlier - inliers.begin());

  auto tl = Eigen::Vector2f{};
  auto br = Eigen::Vector2f{};
  tl = br = point_matrix.row(i).transpose();

  for (++i; i < inliers.size(); ++i)
  {
    if (!inliers(i))
      continue;

    if (fast_axis == Axis::X)
    {
      if (tl.x() > point_matrix(i, 0))
        tl = point_matrix.row(i).hnormalized().transpose();
      if (br.x() < point_matrix(i, 0))
        br = point_matrix.row(i).hnormalized().transpose();
    }
    else
    {
      if (tl.y() > point_matrix(i, 1))
        tl = point_matrix.row(i).hnormalized().transpose();
      if (br.y() < point_matrix(i, 1))
        br = point_matrix.row(i).hnormalized().transpose();
    }
  }

  return {true, {tl.cast<double>(), br.cast<double>()}};
}

auto test_on_image()
{
  // Read an image.
  const auto image =
      imread<float>(src_path("../../../../data/sunflowerField.jpg"));

  auto sigma = sqrt(pow(1.6f, 2) - pow(0.5f, 2));
  auto image_curr = deriche_blur(image, sigma);

  constexpr auto high_threshold_ratio = 5e-2f;
  constexpr auto low_threshold_ratio = 2e-2f;
  constexpr auto angular_threshold = 20. / 180.f * M_PI;

  create_window(image.sizes());
  display(image_curr);

  for (auto s = 0; s < 500; ++s)
  {
    // Blur.
    const auto grad = gradient(image_curr);
    const auto grad_mag = grad.cwise_transform(  //
        [](const auto& v) { return v.norm(); });
    const auto grad_ori = grad.cwise_transform(
        [](const auto& v) { return std::atan2(v.y(), v.x()); });

    // Canny.
    const auto& grad_mag_max = grad_mag.flat_array().maxCoeff();
    const auto& high_thres = grad_mag_max * high_threshold_ratio;
    const auto& low_thres = grad_mag_max * low_threshold_ratio;

    auto edges = suppress_non_maximum_edgels(grad_mag, grad_ori,  //
                                             high_thres, low_thres);

    hysteresis(edges);

    // Extract quasi-straight curve.
    const auto curves = connected_components(edges, grad_ori, angular_threshold);
    const auto labeled_curves = to_map(curves, edges.sizes());
    const auto curve_colors = random_colors(curves);

    // Fit a line to each curve.
    auto line_segments = std::map<int, LineSegment>{};
    for (const auto& [curve_id, curve_points] : curves)
    {
      if (curve_points.size() < 5)
        continue;
      const auto [success, line_segment] = fit_line(curve_points);
      if (success)
        line_segments[curve_id] = line_segment;
    }

    // Display the fitted lines.
    fill_rect(0, 0, image_curr.width(), image_curr.height(), Black8);
    for (const auto& [curve_id, line]: line_segments)
      draw_line(line.p1(), line.p2(), curve_colors.at(curve_id), 2);

    millisleep(1);

    const auto delta = std::pow(2., 1. / 100.);
    const auto sigma = 1.6 * sqrt(pow(delta, 2 * s + 2) - pow(delta, 2 * s));
    image_curr = deriche_blur(image_curr, sigma);
  }

  get_key();
}

auto test_on_video()
{
  using namespace std::string_literals;

#ifdef _WIN32
  const auto video_filepath =
      "C:/Users/David/Desktop/david-archives/gopro-backup-2/GOPR0542.MP4"s;
#elif __APPLE__
  // const auto video_filepath = "/Users/david/Desktop/Datasets/sfm/Family.mp4"s;
  const auto video_filepath =
      //"/Users/david/Desktop/Datasets/videos/sample1.mp4"s;
      "/Users/david/Desktop/Datasets/videos/sample4.mp4"s;
  //     //"/Users/david/Desktop/Datasets/videos/sample10.mp4"s;
#else
  const auto video_filepath = "/home/david/Desktop/Datasets/sfm/Family.mp4"s;
#endif

  // Input and output from Sara.
  VideoStream video_stream(video_filepath);
  auto frame = video_stream.frame();
  auto frame_gray32f = Image<float>{frame.sizes()};

  // Show the local extrema.
  create_window(frame.sizes());
  set_antialiasing();

  constexpr auto high_threshold_ratio = 5e-2f;
  constexpr auto low_threshold_ratio = 2e-2f;
  constexpr auto angular_threshold = 20. / 180.f * M_PI;

  auto frames_read = 0;
  const auto skip = 2;
  while (true)
  {
    if (!video_stream.read())
    {
      std::cout << "Reached the end of the video!" << std::endl;
      break;
    }
    ++frames_read;
    if (frames_read % (skip + 1) != 0)
       continue;

    frame_gray32f = frame.convert<float>();

    // Blur.
    inplace_deriche_blur(frame_gray32f, std::sqrt(std::pow(1.6f, 2) - 1));

    // Canny.
    const auto& grad = gradient(frame_gray32f);
    const auto& grad_mag = grad.cwise_transform(  //
        [](const auto& v) { return v.norm(); });
    const auto& grad_ori = grad.cwise_transform(
        [](const auto& v) { return std::atan2(v.y(), v.x()); });

    const auto& grad_mag_max = grad_mag.flat_array().maxCoeff();
    const auto& high_thres = grad_mag_max * high_threshold_ratio;
    const auto& low_thres = grad_mag_max * low_threshold_ratio;

    auto edges = suppress_non_maximum_edgels(grad_mag, grad_ori,  //
                                             high_thres, low_thres);
    hysteresis(edges);

    // Extract quasi-straight curve.
    const auto curves = connected_components(edges, grad_ori, angular_threshold);
    const auto labeled_curves = to_map(curves, edges.sizes());
    const auto curve_colors = random_colors(curves);

    // Fit a line to each curve.
    auto line_segments = std::map<int, LineSegment>{};
    for (const auto& [curve_id, curve_points] : curves)
    {
      if (curve_points.size() < 5)
        continue;
      const auto [success, line_segment] = fit_line(curve_points);
      if (success)
        line_segments[curve_id] = line_segment;
    }

    // Display the fitted lines.
    fill_rect(0, 0, frame.width(), frame.height(), Black8);
    for (const auto& [curve_id, line]: line_segments)
      draw_line(line.p1(), line.p2(), curve_colors.at(curve_id), 2);
  }
}

GRAPHICS_MAIN()
{
  // test_on_image();
  test_on_video();
  return 0;
}
<commit_msg>MAINT: clean up results.<commit_after>// ========================================================================== //
// This file is part of Sara, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2018 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

//! @example

#include <set>

#include <DO/Sara/Graphics.hpp>
#include <DO/Sara/ImageIO.hpp>
#include <DO/Sara/ImageProcessing.hpp>
#include <DO/Sara/VideoIO.hpp>

#include <DO/Sara/Geometry/Algorithms/RobustEstimation/LineSolver.hpp>
#include <DO/Sara/Geometry/Algorithms/RobustEstimation/RANSAC.hpp>
#include <DO/Sara/Geometry/Objects/LineSegment.hpp>

using namespace std;
using namespace DO::Sara;

auto to_map(const std::map<int, std::vector<Eigen::Vector2i>>& contours,
            const Eigen::Vector2i& image_sizes)
{
  auto labeled_edges = Image<int>{image_sizes};
  labeled_edges.flat_array().fill(-1);
  for (const auto& [label, points] : contours)
  {
    for (const auto& p : points)
      labeled_edges(p) = label;
  }
  return labeled_edges;
}

auto random_colors(const std::map<int, std::vector<Eigen::Vector2i>>& contours)
{
  auto colors = std::map<int, Rgb8>{};
  for (const auto& c : contours)
    colors[c.first] = Rgb8(rand() % 255, rand() % 255, rand() % 255);
  return colors;
}

auto fit_line(const std::vector<Eigen::Vector2i>& curve_points,
              float error_threshold = 1.5f) -> std::tuple<bool, LineSegment>
{
  enum class Axis : std::uint8_t
  {
    X = 0,
    Y = 1
  };

  if (curve_points.size() < 2)
    return {false, {}};

  auto line_solver = LineSolver2D<float>{};
  auto inlier_predicate = InlierPredicate<LinePointDistance2D<float>>{
      .distance = {},                     //
      .error_threshold = error_threshold  //
  };

  auto points = Tensor_<float, 2>(curve_points.size(), 3);
  auto point_matrix = points.matrix();
  for (auto r = 0u; r < curve_points.size(); ++r)
    point_matrix.row(r) = curve_points[r]      //
                              .transpose()     //
                              .homogeneous()   //
                              .cast<float>();  //

  const auto num_iterations = std::clamp(                //
      static_cast<int>(curve_points.size() * 0.20) + 1,  //
      5, 20);
  const auto [line, inliers, subset_best] = ransac(points,            //
                                                   line_solver,       //
                                                   inlier_predicate,  //
                                                   num_iterations);

  if (inliers.flat_array().count() < 0.50 * curve_points.size())
    return {false, {}};

  const Eigen::Vector2f t = Projective::tangent(line).cwiseAbs();
  const auto fast_axis = t.x() > t.y() ? Axis::X : Axis::Y;

  const auto first_inlier = std::find(inliers.begin(), inliers.end(), 1);
  if (first_inlier == inliers.end())
    return {false, LineSegment{}};

  auto i = std::size_t(first_inlier - inliers.begin());

  auto tl = Eigen::Vector2f{};
  auto br = Eigen::Vector2f{};
  tl = br = point_matrix.row(i).transpose();

  for (++i; i < inliers.size(); ++i)
  {
    if (!inliers(i))
      continue;

    if (fast_axis == Axis::X)
    {
      if (tl.x() > point_matrix(i, 0))
        tl = point_matrix.row(i).hnormalized().transpose();
      if (br.x() < point_matrix(i, 0))
        br = point_matrix.row(i).hnormalized().transpose();
    }
    else
    {
      if (tl.y() > point_matrix(i, 1))
        tl = point_matrix.row(i).hnormalized().transpose();
      if (br.y() < point_matrix(i, 1))
        br = point_matrix.row(i).hnormalized().transpose();
    }
  }

  return {true, {tl.cast<double>(), br.cast<double>()}};
}

auto test_on_image()
{
  // Read an image.
  const auto image =
      imread<float>(src_path("../../../../data/sunflowerField.jpg"));

  auto sigma = sqrt(pow(1.6f, 2) - pow(0.5f, 2));
  auto image_curr = deriche_blur(image, sigma);

  constexpr auto high_threshold_ratio = 5e-2f;
  constexpr auto low_threshold_ratio = 2e-2f;
  constexpr auto angular_threshold = 20. / 180.f * M_PI;

  create_window(image.sizes());
  display(image_curr);

  for (auto s = 0; s < 500; ++s)
  {
    // Blur.
    const auto grad = gradient(image_curr);
    const auto grad_mag = grad.cwise_transform(  //
        [](const auto& v) { return v.norm(); });
    const auto grad_ori = grad.cwise_transform(
        [](const auto& v) { return std::atan2(v.y(), v.x()); });

    // Canny.
    const auto& grad_mag_max = grad_mag.flat_array().maxCoeff();
    const auto& high_thres = grad_mag_max * high_threshold_ratio;
    const auto& low_thres = grad_mag_max * low_threshold_ratio;

    auto edges = suppress_non_maximum_edgels(grad_mag, grad_ori,  //
                                             high_thres, low_thres);

    hysteresis(edges);

    // Extract quasi-straight curve.
    const auto curves = connected_components(edges, grad_ori, angular_threshold);
    const auto labeled_curves = to_map(curves, edges.sizes());
    const auto curve_colors = random_colors(curves);

    // Fit a line to each curve.
    auto line_segments = std::map<int, LineSegment>{};
    for (const auto& [curve_id, curve_points] : curves)
    {
      if (curve_points.size() < 5)
        continue;
      const auto [success, line_segment] = fit_line(curve_points);
      if (success)
        line_segments[curve_id] = line_segment;
    }

    // Display the fitted lines.
    fill_rect(0, 0, image_curr.width(), image_curr.height(), Black8);
    for (const auto& [curve_id, line]: line_segments)
      draw_line(line.p1(), line.p2(), curve_colors.at(curve_id), 2);

    millisleep(1);

    const auto delta = std::pow(2., 1. / 100.);
    const auto sigma = 1.6 * sqrt(pow(delta, 2 * s + 2) - pow(delta, 2 * s));
    image_curr = deriche_blur(image_curr, sigma);
  }

  get_key();
}

auto test_on_video()
{
  using namespace std::string_literals;

#ifdef _WIN32
  const auto video_filepath =
      "C:/Users/David/Desktop/david-archives/gopro-backup-2/GOPR0542.MP4"s;
#elif __APPLE__
  // const auto video_filepath = "/Users/david/Desktop/Datasets/sfm/Family.mp4"s;
  const auto video_filepath =
      //"/Users/david/Desktop/Datasets/videos/sample1.mp4"s;
      "/Users/david/Desktop/Datasets/videos/sample4.mp4"s;
  //     //"/Users/david/Desktop/Datasets/videos/sample10.mp4"s;
#else
  const auto video_filepath = "/home/david/Desktop/Datasets/sfm/Family.mp4"s;
#endif

  // Input and output from Sara.
  VideoStream video_stream(video_filepath);
  auto frame = video_stream.frame();
  auto frame_gray32f = Image<float>{frame.sizes()};

  // Show the local extrema.
  create_window(frame.sizes());
  set_antialiasing();

  constexpr auto high_threshold_ratio = 5e-2f;
  constexpr auto low_threshold_ratio = 2e-2f;
  constexpr auto angular_threshold = 20. / 180.f * M_PI;

  auto frames_read = 0;
  const auto skip = 2;
  while (true)
  {
    if (!video_stream.read())
    {
      std::cout << "Reached the end of the video!" << std::endl;
      break;
    }
    ++frames_read;
    if (frames_read % (skip + 1) != 0)
       continue;

    frame_gray32f = frame.convert<float>();

    // Blur.
    inplace_deriche_blur(frame_gray32f, std::sqrt(std::pow(1.6f, 2) - 1));

    // Canny.
    const auto& grad = gradient(frame_gray32f);
    const auto& grad_mag = grad.cwise_transform(  //
        [](const auto& v) { return v.norm(); });
    const auto& grad_ori = grad.cwise_transform(
        [](const auto& v) { return std::atan2(v.y(), v.x()); });

    const auto& grad_mag_max = grad_mag.flat_array().maxCoeff();
    const auto& high_thres = grad_mag_max * high_threshold_ratio;
    const auto& low_thres = grad_mag_max * low_threshold_ratio;

    auto edges = suppress_non_maximum_edgels(grad_mag, grad_ori,  //
                                             high_thres, low_thres);
    hysteresis(edges);

    // Extract quasi-straight curve.
    const auto curves = connected_components(edges, grad_ori, angular_threshold);
    const auto labeled_curves = to_map(curves, edges.sizes());
    const auto curve_colors = random_colors(curves);

    // Fit a line to each curve.
    auto line_segments = std::map<int, LineSegment>{};
    for (const auto& [curve_id, curve_points] : curves)
    {
      if (curve_points.size() < 5)
        continue;
      const auto [success, line_segment] = fit_line(curve_points);
      if (success)
        line_segments[curve_id] = line_segment;
    }

    // Display the fitted lines.
    fill_rect(0, 0, frame.width(), frame.height(), Black8);
    for (const auto& [curve_id, line]: line_segments)
      draw_line(line.p1(), line.p2(), curve_colors.at(curve_id), 2);
  }
}

GRAPHICS_MAIN()
{
  // test_on_image();
  test_on_video();
  return 0;
}
<|endoftext|>


<commit_before>// 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

#ifndef __PROCESS_NETWORK_HPP__
#define __PROCESS_NETWORK_HPP__

#include <process/address.hpp>

#include <stout/net.hpp>
#include <stout/try.hpp>

#include <stout/os/socket.hpp>

namespace process {
namespace network {

using net::socket;

using SocketError =
#ifndef __WINDOWS__
  ErrnoError;
#else
  WindowsSocketError;
#endif

// TODO(benh): Remove and defer to Socket::accept.
inline Try<int> accept(int s)
{
  struct sockaddr_storage storage;
  socklen_t storagelen = sizeof(storage);

  int accepted = ::accept(s, (struct sockaddr*) &storage, &storagelen);
  if (accepted < 0) {
    return ErrnoError("Failed to accept");
  }

  return accepted;
}

// TODO(benh): Remove and defer to Socket::bind.
inline Try<int> bind(int s, const Address& address)
{
  struct sockaddr_storage storage =
    net::createSockaddrStorage(address.ip, address.port);

  int error = ::bind(s, (struct sockaddr*) &storage, address.size());
  if (error < 0) {
    return ErrnoError("Failed to bind on " + stringify(address));
  }

  return error;
}

// TODO(benh): Remove and defer to Socket::connect.
inline Try<int, SocketError> connect(int s, const Address& address)
{
  struct sockaddr_storage storage =
    net::createSockaddrStorage(address.ip, address.port);

  int error = ::connect(s, (struct sockaddr*) &storage, address.size());
  if (error < 0) {
    return SocketError("Failed to connect to " + stringify(address));
  }

  return error;
}

/**
 * Returns the `Address` with the assigned ip and assigned port.
 *
 * @return An `Address` or an error if the `getsockname` system call
 *     fails or the family type is not supported.
 */
inline Try<Address> address(int s)
{
  struct sockaddr_storage storage;
  socklen_t storagelen = sizeof(storage);

  if (::getsockname(s, (struct sockaddr*) &storage, &storagelen) < 0) {
    return ErrnoError("Failed to getsockname");
  }

  return Address::create(storage);
}

/**
 * Returns the peer's `Address` for the accepted or connected socket.
 *
 * @return An `Address` or an error if the `getpeername` system call
 *     fails or the family type is not supported.
 */
inline Try<Address> peer(int s)
{
  struct sockaddr_storage storage;
  socklen_t storagelen = sizeof(storage);

  if (::getpeername(s, (struct sockaddr*) &storage, &storagelen) < 0) {
    return ErrnoError("Failed to getpeername");
  }

  return Address::create(storage);
}

} // namespace network {
} // namespace process {

#endif // __PROCESS_NETWORK_HPP__
<commit_msg>Windows: Moved `SocketError` definition to `stout/error.hpp`.<commit_after>// 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

#ifndef __PROCESS_NETWORK_HPP__
#define __PROCESS_NETWORK_HPP__

#include <process/address.hpp>

#include <stout/net.hpp>
#include <stout/try.hpp>

#include <stout/os/socket.hpp>

namespace process {
namespace network {

using net::socket;

// TODO(benh): Remove and defer to Socket::accept.
inline Try<int> accept(int s)
{
  struct sockaddr_storage storage;
  socklen_t storagelen = sizeof(storage);

  int accepted = ::accept(s, (struct sockaddr*) &storage, &storagelen);
  if (accepted < 0) {
    return ErrnoError("Failed to accept");
  }

  return accepted;
}

// TODO(benh): Remove and defer to Socket::bind.
inline Try<int> bind(int s, const Address& address)
{
  struct sockaddr_storage storage =
    net::createSockaddrStorage(address.ip, address.port);

  int error = ::bind(s, (struct sockaddr*) &storage, address.size());
  if (error < 0) {
    return ErrnoError("Failed to bind on " + stringify(address));
  }

  return error;
}

// TODO(benh): Remove and defer to Socket::connect.
inline Try<int, SocketError> connect(int s, const Address& address)
{
  struct sockaddr_storage storage =
    net::createSockaddrStorage(address.ip, address.port);

  int error = ::connect(s, (struct sockaddr*) &storage, address.size());
  if (error < 0) {
    return SocketError("Failed to connect to " + stringify(address));
  }

  return error;
}

/**
 * Returns the `Address` with the assigned ip and assigned port.
 *
 * @return An `Address` or an error if the `getsockname` system call
 *     fails or the family type is not supported.
 */
inline Try<Address> address(int s)
{
  struct sockaddr_storage storage;
  socklen_t storagelen = sizeof(storage);

  if (::getsockname(s, (struct sockaddr*) &storage, &storagelen) < 0) {
    return ErrnoError("Failed to getsockname");
  }

  return Address::create(storage);
}

/**
 * Returns the peer's `Address` for the accepted or connected socket.
 *
 * @return An `Address` or an error if the `getpeername` system call
 *     fails or the family type is not supported.
 */
inline Try<Address> peer(int s)
{
  struct sockaddr_storage storage;
  socklen_t storagelen = sizeof(storage);

  if (::getpeername(s, (struct sockaddr*) &storage, &storagelen) < 0) {
    return ErrnoError("Failed to getpeername");
  }

  return Address::create(storage);
}

} // namespace network {
} // namespace process {

#endif // __PROCESS_NETWORK_HPP__
<|endoftext|>


<commit_before>/**
 * \file
 * \brief SignalsWaitTestCase class implementation
 *
 * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-02-18
 */

#include "SignalsWaitTestCase.hpp"

#include "priorityTestPhases.hpp"
#include "SequenceAsserter.hpp"

#include "distortos/StaticThread.hpp"
#include "distortos/statistics.hpp"
#include "distortos/ThisThread-Signals.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {384};

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// type of test thread function
using TestThreadFunction = void(SequenceAsserter&, unsigned int);

/// type of test thread
using TestThread = decltype(makeStaticThread<testThreadStackSize>({}, std::declval<TestThreadFunction>(),
		std::ref(std::declval<SequenceAsserter&>()), std::declval<unsigned int>()));

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Test thread.
 *
 * Marks the first sequence point in SequenceAsserter, waits for any possible signal and uses the accepted signal as the
 * last sequence point - marking it in SequenceAsserter.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] firstSequencePoint is the first sequence point of this instance
 */

void thread(SequenceAsserter& sequenceAsserter, const unsigned int firstSequencePoint)
{
	sequenceAsserter.sequencePoint(firstSequencePoint);
	SignalSet signalSet {SignalSet::full};
	const auto waitResult = ThisThread::Signals::wait(signalSet);
	if (waitResult.first != 0)
		return;
	sequenceAsserter.sequencePoint(waitResult.second);
}

/**
 * \brief Builder of TestThread objects.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] firstSequencePoint is the first sequence point for this instance - equal to the order in which this
 * thread will be started
 *
 * \return constructed TestThread object
 */

TestThread makeTestThread(SequenceAsserter& sequenceAsserter, const unsigned int firstSequencePoint)
{
	return makeStaticThread<testThreadStackSize>(UINT8_MAX, thread, std::ref(sequenceAsserter),
			static_cast<unsigned int>(firstSequencePoint));
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool SignalsWaitTestCase::Implementation::run_() const
{
	const auto contextSwitchCount = statistics::getContextSwitchCount();
	std::remove_const<decltype(contextSwitchCount)>::type expectedContextSwitchCount {};

	for (const auto& phase : priorityTestPhases)
	{
		SequenceAsserter sequenceAsserter;

		std::array<TestThread, totalThreads> threads
		{{
				makeTestThread(sequenceAsserter, 0),
				makeTestThread(sequenceAsserter, 1),
				makeTestThread(sequenceAsserter, 2),
				makeTestThread(sequenceAsserter, 3),
				makeTestThread(sequenceAsserter, 4),
				makeTestThread(sequenceAsserter, 5),
				makeTestThread(sequenceAsserter, 6),
				makeTestThread(sequenceAsserter, 7),
				makeTestThread(sequenceAsserter, 8),
				makeTestThread(sequenceAsserter, 9),
		}};

		bool result {true};

		for (auto& thread : threads)
		{
			thread.start();
			// 2 context switches: "into" the thread and "back" to main thread when test thread blocks on queue
			expectedContextSwitchCount += 2;
			if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
				result = false;
		}

		if (sequenceAsserter.assertSequence(totalThreads) == false)
			result = false;

		for (size_t i = 0; i < phase.second.size(); ++i)
		{
			const auto threadIndex = phase.second[i];
			const auto ret = threads[threadIndex].generateSignal(totalThreads + i);
			if (ret != 0)
				result = false;
			// 2 context switches: into" the unblocked thread and "back" to main thread when test thread terminates
			expectedContextSwitchCount += 2;
			if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
				result = false;
		}

		for (auto& thread : threads)
			thread.join();

		if (result == false || sequenceAsserter.assertSequence(totalThreads * 2) == false)
			return false;
	}

	if (statistics::getContextSwitchCount() - contextSwitchCount != 4 * totalThreads * priorityTestPhases.size())
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<commit_msg>SignalsWaitTestCase: enable reception of signals for all test threads<commit_after>/**
 * \file
 * \brief SignalsWaitTestCase class implementation
 *
 * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-03-14
 */

#include "SignalsWaitTestCase.hpp"

#include "priorityTestPhases.hpp"
#include "SequenceAsserter.hpp"

#include "distortos/StaticThread.hpp"
#include "distortos/statistics.hpp"
#include "distortos/ThisThread-Signals.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {384};

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// type of test thread function
using TestThreadFunction = void(SequenceAsserter&, unsigned int);

/// type of test thread
using TestThread = decltype(makeStaticThread<testThreadStackSize, true>({}, std::declval<TestThreadFunction>(),
		std::ref(std::declval<SequenceAsserter&>()), std::declval<unsigned int>()));

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Test thread.
 *
 * Marks the first sequence point in SequenceAsserter, waits for any possible signal and uses the accepted signal as the
 * last sequence point - marking it in SequenceAsserter.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] firstSequencePoint is the first sequence point of this instance
 */

void thread(SequenceAsserter& sequenceAsserter, const unsigned int firstSequencePoint)
{
	sequenceAsserter.sequencePoint(firstSequencePoint);
	SignalSet signalSet {SignalSet::full};
	const auto waitResult = ThisThread::Signals::wait(signalSet);
	if (waitResult.first != 0)
		return;
	sequenceAsserter.sequencePoint(waitResult.second);
}

/**
 * \brief Builder of TestThread objects.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] firstSequencePoint is the first sequence point for this instance - equal to the order in which this
 * thread will be started
 *
 * \return constructed TestThread object
 */

TestThread makeTestThread(SequenceAsserter& sequenceAsserter, const unsigned int firstSequencePoint)
{
	return makeStaticThread<testThreadStackSize, true>(UINT8_MAX, thread, std::ref(sequenceAsserter),
			static_cast<unsigned int>(firstSequencePoint));
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool SignalsWaitTestCase::Implementation::run_() const
{
	const auto contextSwitchCount = statistics::getContextSwitchCount();
	std::remove_const<decltype(contextSwitchCount)>::type expectedContextSwitchCount {};

	for (const auto& phase : priorityTestPhases)
	{
		SequenceAsserter sequenceAsserter;

		std::array<TestThread, totalThreads> threads
		{{
				makeTestThread(sequenceAsserter, 0),
				makeTestThread(sequenceAsserter, 1),
				makeTestThread(sequenceAsserter, 2),
				makeTestThread(sequenceAsserter, 3),
				makeTestThread(sequenceAsserter, 4),
				makeTestThread(sequenceAsserter, 5),
				makeTestThread(sequenceAsserter, 6),
				makeTestThread(sequenceAsserter, 7),
				makeTestThread(sequenceAsserter, 8),
				makeTestThread(sequenceAsserter, 9),
		}};

		bool result {true};

		for (auto& thread : threads)
		{
			thread.start();
			// 2 context switches: "into" the thread and "back" to main thread when test thread blocks on queue
			expectedContextSwitchCount += 2;
			if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
				result = false;
		}

		if (sequenceAsserter.assertSequence(totalThreads) == false)
			result = false;

		for (size_t i = 0; i < phase.second.size(); ++i)
		{
			const auto threadIndex = phase.second[i];
			const auto ret = threads[threadIndex].generateSignal(totalThreads + i);
			if (ret != 0)
				result = false;
			// 2 context switches: into" the unblocked thread and "back" to main thread when test thread terminates
			expectedContextSwitchCount += 2;
			if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
				result = false;
		}

		for (auto& thread : threads)
			thread.join();

		if (result == false || sequenceAsserter.assertSequence(totalThreads * 2) == false)
			return false;
	}

	if (statistics::getContextSwitchCount() - contextSwitchCount != 4 * totalThreads * priorityTestPhases.size())
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<|endoftext|>