<commit_before>/**
 * @file   Uri.hpp
 * @brief  Uri class prototype.
 * @author zer0
 * @date   2017-05-19
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_NETWORK_URI_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_NETWORK_URI_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/Err.hpp>

#include <cstdint>
#include <algorithm>
#include <string>
#include <map>

/**
 * Successfully parse triple slashes.
 */
#define ENABLE_TRIPLE_SLASH_FAKER

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace network {

enum _uri_state
{
    _uri_state_schema,
    _uri_state_schema_colon,
    _uri_state_schema_slash,
    _uri_state_schema_slash_slash,
};

// @formatter:off
TBAG_CONSTEXPR int const _uri_state_result_error       = -1;
TBAG_CONSTEXPR int const _uri_state_result_no_slash    = 0;
TBAG_CONSTEXPR int const _uri_state_result_success_min = sizeof((char[]){":///"}) - (2/* remove null char & size to index */);
static_assert(_uri_state_result_success_min == 3, "Why not?");
// @formatter:on

/**
 * Make sure that the slashes appear three times in succession.
 *
 * @param[in] buffer
 *  string buffer.
 * @param[in] size
 *  string length.
 *
 * @return
 *  >=_uri_state_result_success_min is index searched.
 *
 * @retval _uri_state_result_error
 *  parsing error.
 * @retval _uri_state_result_no_slash
 *  Not found.
 */
TBAG_API int _is_triple_slash(char const * buffer, int size);
TBAG_API int _is_triple_slash2(char const * buffer);

/**
 * Uri class prototype.
 *
 * @author zer0
 * @date   2017-05-19
 */
class TBAG_API Uri
{
public:
    struct FieldInfo
    {
        uint16_t offset; ///< Offset into buffer in which field starts.
        uint16_t length; ///< Length of run in buffer.
        bool     enable; ///< Enable flag.

        FieldInfo(uint16_t off, uint16_t len, bool en = true) : offset(off), length(len), enable(en)
        { /* EMPTY. */ }
        FieldInfo() : FieldInfo(0, 0, false)
        { /* EMPTY. */ }

        inline void set(uint16_t off, uint16_t len, bool en = true) TBAG_NOEXCEPT
        { offset = off; length = len; enable = en; }
        inline void clear() TBAG_NOEXCEPT
        { offset = 0; length = 0; enable = false; }

        inline bool operator ==(FieldInfo const & obj) const TBAG_NOEXCEPT
        { return offset == obj.offset && length == obj.length && enable == obj.enable; }
        inline bool operator !=(FieldInfo const & obj) const TBAG_NOEXCEPT
        { return !((*this).operator==(obj)); }

        void swap(FieldInfo & obj) TBAG_NOEXCEPT
        {
            if (this != &obj) {
                std::swap(offset, obj.offset);
                std::swap(length, obj.length);
                std::swap(enable, obj.enable);
            }
        }
    };

private:
    std::string _uri;

private:
    FieldInfo _schema  ;
    FieldInfo _host    ;
    FieldInfo _port    ;
    FieldInfo _path    ;
    FieldInfo _query   ;
    FieldInfo _fragment;
    FieldInfo _userinfo;

public:
    Uri();
    explicit Uri(char const * uri, bool is_connect = false);
    explicit Uri(std::string const & uri, bool is_connect = false);
    Uri(Uri const & obj);
    Uri(Uri && obj);
    ~Uri();

public:
    Uri & operator =(char const * uri);
    Uri & operator =(std::string const & uri);

    Uri & operator =(Uri const & obj);
    Uri & operator =(Uri && obj);

// Casting
public:
    operator std::string() const;
    operator char const *() const;

public:
    void swap(Uri & obj) TBAG_NOEXCEPT;

public:
    inline FieldInfo getSchemaInfo  () const TBAG_NOEXCEPT { return _schema  ; }
    inline FieldInfo getHostInfo    () const TBAG_NOEXCEPT { return _host    ; }
    inline FieldInfo getPortInfo    () const TBAG_NOEXCEPT { return _port    ; }
    inline FieldInfo getPathInfo    () const TBAG_NOEXCEPT { return _path    ; }
    inline FieldInfo getQueryInfo   () const TBAG_NOEXCEPT { return _query   ; }
    inline FieldInfo getFragmentInfo() const TBAG_NOEXCEPT { return _fragment; }
    inline FieldInfo getUserinfoInfo() const TBAG_NOEXCEPT { return _userinfo; }

public:
    inline bool isSchema  () const TBAG_NOEXCEPT { return _schema  .enable; }
    inline bool isHost    () const TBAG_NOEXCEPT { return _host    .enable; }
    inline bool isPort    () const TBAG_NOEXCEPT { return _port    .enable; }
    inline bool isPath    () const TBAG_NOEXCEPT { return _path    .enable; }
    inline bool isQuery   () const TBAG_NOEXCEPT { return _query   .enable; }
    inline bool isFragment() const TBAG_NOEXCEPT { return _fragment.enable; }
    inline bool isUserinfo() const TBAG_NOEXCEPT { return _userinfo.enable; }

public:
    std::string getSchema  () const { return getFieldString(_uri, _schema  ); }
    std::string getHost    () const { return getFieldString(_uri, _host    ); }
    std::string getPort    () const { return getFieldString(_uri, _port    ); }
    std::string getPath    () const { return getFieldString(_uri, _path    ); }
    std::string getQuery   () const { return getFieldString(_uri, _query   ); }
    std::string getFragment() const { return getFieldString(_uri, _fragment); }
    std::string getUserinfo() const { return getFieldString(_uri, _userinfo); }

public:
    int getPortNumber() const;
    std::string getUrl() const;
    std::string getRequestPath() const;

public:
    void clear();
    bool parse(std::string const & uri, bool is_connect = false);

// Alias methods.
public:
    inline bool set(std::string const & uri, bool is_connect = false)
    { return parse(uri, is_connect); }

public:
    inline std::string getString() const { return _uri; }
    inline std::string  toString() const { return _uri; }

public:
    enum class AddrFlags
    {
        MOST_IPV4,
        MOST_IPV6,
    };

    Err requestAddrInfo(std::string & host, int & port, AddrFlags flags = AddrFlags::MOST_IPV4) const;

// Extension methods.
public:
    std::map<std::string, std::string> getQueryMap() const;

// Static methods.
public:
    static std::string getFieldString(std::string const & original, FieldInfo const & info);
};

/**
 * @warning
 *  This method checks for errors that are found.
 */
TBAG_API bool __check_error__http_parser_url_fields();

} // namespace network

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_NETWORK_URI_HPP__

<commit_msg>Update _uri_state_result_success_min variables.<commit_after>/**
 * @file   Uri.hpp
 * @brief  Uri class prototype.
 * @author zer0
 * @date   2017-05-19
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_NETWORK_URI_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_NETWORK_URI_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/Err.hpp>

#include <cstdint>
#include <algorithm>
#include <string>
#include <map>

/**
 * Successfully parse triple slashes.
 */
#define ENABLE_TRIPLE_SLASH_FAKER

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace network {

enum _uri_state
{
    _uri_state_schema,
    _uri_state_schema_colon,
    _uri_state_schema_slash,
    _uri_state_schema_slash_slash,
};

// @formatter:off
TBAG_CONSTEXPR int const _uri_state_result_error       = -1;
TBAG_CONSTEXPR int const _uri_state_result_no_slash    =  0;
TBAG_CONSTEXPR int const _uri_state_result_success_min =  3; // The last character index of ":///"
// @formatter:on

/**
 * Make sure that the slashes appear three times in succession.
 *
 * @param[in] buffer
 *  string buffer.
 * @param[in] size
 *  string length.
 *
 * @return
 *  >=_uri_state_result_success_min is index searched.
 *
 * @retval _uri_state_result_error
 *  parsing error.
 * @retval _uri_state_result_no_slash
 *  Not found.
 */
TBAG_API int _is_triple_slash(char const * buffer, int size);
TBAG_API int _is_triple_slash2(char const * buffer);

/**
 * Uri class prototype.
 *
 * @author zer0
 * @date   2017-05-19
 */
class TBAG_API Uri
{
public:
    struct FieldInfo
    {
        uint16_t offset; ///< Offset into buffer in which field starts.
        uint16_t length; ///< Length of run in buffer.
        bool     enable; ///< Enable flag.

        FieldInfo(uint16_t off, uint16_t len, bool en = true) : offset(off), length(len), enable(en)
        { /* EMPTY. */ }
        FieldInfo() : FieldInfo(0, 0, false)
        { /* EMPTY. */ }

        inline void set(uint16_t off, uint16_t len, bool en = true) TBAG_NOEXCEPT
        { offset = off; length = len; enable = en; }
        inline void clear() TBAG_NOEXCEPT
        { offset = 0; length = 0; enable = false; }

        inline bool operator ==(FieldInfo const & obj) const TBAG_NOEXCEPT
        { return offset == obj.offset && length == obj.length && enable == obj.enable; }
        inline bool operator !=(FieldInfo const & obj) const TBAG_NOEXCEPT
        { return !((*this).operator==(obj)); }

        void swap(FieldInfo & obj) TBAG_NOEXCEPT
        {
            if (this != &obj) {
                std::swap(offset, obj.offset);
                std::swap(length, obj.length);
                std::swap(enable, obj.enable);
            }
        }
    };

private:
    std::string _uri;

private:
    FieldInfo _schema  ;
    FieldInfo _host    ;
    FieldInfo _port    ;
    FieldInfo _path    ;
    FieldInfo _query   ;
    FieldInfo _fragment;
    FieldInfo _userinfo;

public:
    Uri();
    explicit Uri(char const * uri, bool is_connect = false);
    explicit Uri(std::string const & uri, bool is_connect = false);
    Uri(Uri const & obj);
    Uri(Uri && obj);
    ~Uri();

public:
    Uri & operator =(char const * uri);
    Uri & operator =(std::string const & uri);

    Uri & operator =(Uri const & obj);
    Uri & operator =(Uri && obj);

// Casting
public:
    operator std::string() const;
    operator char const *() const;

public:
    void swap(Uri & obj) TBAG_NOEXCEPT;

public:
    inline FieldInfo getSchemaInfo  () const TBAG_NOEXCEPT { return _schema  ; }
    inline FieldInfo getHostInfo    () const TBAG_NOEXCEPT { return _host    ; }
    inline FieldInfo getPortInfo    () const TBAG_NOEXCEPT { return _port    ; }
    inline FieldInfo getPathInfo    () const TBAG_NOEXCEPT { return _path    ; }
    inline FieldInfo getQueryInfo   () const TBAG_NOEXCEPT { return _query   ; }
    inline FieldInfo getFragmentInfo() const TBAG_NOEXCEPT { return _fragment; }
    inline FieldInfo getUserinfoInfo() const TBAG_NOEXCEPT { return _userinfo; }

public:
    inline bool isSchema  () const TBAG_NOEXCEPT { return _schema  .enable; }
    inline bool isHost    () const TBAG_NOEXCEPT { return _host    .enable; }
    inline bool isPort    () const TBAG_NOEXCEPT { return _port    .enable; }
    inline bool isPath    () const TBAG_NOEXCEPT { return _path    .enable; }
    inline bool isQuery   () const TBAG_NOEXCEPT { return _query   .enable; }
    inline bool isFragment() const TBAG_NOEXCEPT { return _fragment.enable; }
    inline bool isUserinfo() const TBAG_NOEXCEPT { return _userinfo.enable; }

public:
    std::string getSchema  () const { return getFieldString(_uri, _schema  ); }
    std::string getHost    () const { return getFieldString(_uri, _host    ); }
    std::string getPort    () const { return getFieldString(_uri, _port    ); }
    std::string getPath    () const { return getFieldString(_uri, _path    ); }
    std::string getQuery   () const { return getFieldString(_uri, _query   ); }
    std::string getFragment() const { return getFieldString(_uri, _fragment); }
    std::string getUserinfo() const { return getFieldString(_uri, _userinfo); }

public:
    int getPortNumber() const;
    std::string getUrl() const;
    std::string getRequestPath() const;

public:
    void clear();
    bool parse(std::string const & uri, bool is_connect = false);

// Alias methods.
public:
    inline bool set(std::string const & uri, bool is_connect = false)
    { return parse(uri, is_connect); }

public:
    inline std::string getString() const { return _uri; }
    inline std::string  toString() const { return _uri; }

public:
    enum class AddrFlags
    {
        MOST_IPV4,
        MOST_IPV6,
    };

    Err requestAddrInfo(std::string & host, int & port, AddrFlags flags = AddrFlags::MOST_IPV4) const;

// Extension methods.
public:
    std::map<std::string, std::string> getQueryMap() const;

// Static methods.
public:
    static std::string getFieldString(std::string const & original, FieldInfo const & info);
};

/**
 * @warning
 *  This method checks for errors that are found.
 */
TBAG_API bool __check_error__http_parser_url_fields();

} // namespace network

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_NETWORK_URI_HPP__

<|endoftext|>


<commit_before>#include "webcam.hpp"

using namespace cv;
using namespace std;

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

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 while (keepGoing) {

  image = cvQueryFrame(capture);
  imshow("webcam", image);

// thresholds on dark regions
  Mat black, blurred;
  Mat channel[3];
  split(image, channel);
  equalizeHist(channel[0], channel[0]);
  equalizeHist(channel[1], channel[1]);
  equalizeHist(channel[2], channel[2]);
  merge(channel, 3, black);
  blur(black, blurred, Size(width/4.5,height/9));
  split(blurred, channel);
  black = (channel[0] + channel[1] + channel[2])/3.0;
  equalizeHist(black, black);
  bitwise_not(black,black);
  threshold(black, black, 210, 1, THRESH_BINARY);
  imshow("black", black);

  split(image, channel);
  channel[0] = channel[0].mul(black);
  channel[1] = channel[1].mul(black);
  channel[2] = channel[2].mul(black);
  merge(channel, 3, image);
  //image = (image)/(255*255);
  imshow("yox", image);

//do some weird morphological closing thing
//  Mat channel[3];
  blur(image, image, Size(width/20, height/20));
  split(image, channel);
  image = (channel[0] + channel[1] + channel[2])/3.0;

  Mat smooth;
  Mat closed;
  Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(19,19));
  morphologyEx(image, closed, MORPH_CLOSE, kernel);
  divide(image, closed, closed, 1, CV_32F);
  normalize(closed, image, 0, 255, NORM_MINMAX, CV_8U);
  threshold(image, image, -1, 255, THRESH_BINARY_INV + THRESH_OTSU);
  imshow("yo", image);

/*
  Mat canny;
  Canny(image, canny, 0, 50);
  imshow("canny", canny);
*/

/*
  Mat fill = image.clone();
  Point seed(rand()%width, rand()%height);
  floodFill(fill, seed, Scalar(200,0,0), 0, Scalar(0,0,0), Scalar(25,25,25));
  imshow("fill", fill);
*/

  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"

using namespace cv;
using namespace std;

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

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 while (keepGoing) {

  image = cvQueryFrame(capture);
  imshow("webcam", image);

// thresholds on dark regions
  Mat black, blurred;
  Mat channel[3];
  split(image, channel);
  equalizeHist(channel[0], channel[0]);
  equalizeHist(channel[1], channel[1]);
  equalizeHist(channel[2], channel[2]);
  merge(channel, 3, black);
  blur(black, blurred, Size(width/4.5,height/9));
  split(blurred, channel);
  black = (channel[0] + channel[1] + channel[2])/3.0;
  equalizeHist(black, black);
  bitwise_not(black,black);
  threshold(black, black, 210, 1, THRESH_BINARY);
//  imshow("black", black);

  split(image, channel);
  channel[0] = channel[0].mul(black);
  channel[1] = channel[1].mul(black);
  channel[2] = channel[2].mul(black);
  merge(channel, 3, image);
  //image = (image)/(255*255);
  imshow("yox", image);

//do some weird morphological closing thing
//  Mat channel[3];
  blur(image, image, Size(width/20, height/20));
  split(image, channel);
  image = (channel[0] + channel[1] + channel[2])/3.0;

  Mat smooth;
  Mat closed;
  Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(100,100));
  morphologyEx(image, closed, MORPH_CLOSE, kernel);
  divide(image, closed, closed, 1, CV_32F);
  normalize(closed, image, 0, 255, NORM_MINMAX, CV_8U);
  threshold(image, image, -1, 255, THRESH_BINARY_INV + THRESH_OTSU);
  imshow("yo", image);

/*
  Mat canny;
  Canny(image, canny, 0, 50);
  imshow("canny", canny);
*/

/*
  Mat fill = image.clone();
  Point seed(rand()%width, rand()%height);
  floodFill(fill, seed, Scalar(200,0,0), 0, Scalar(0,0,0), Scalar(25,25,25));
  imshow("fill", fill);
*/

  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>#include "webcam.hpp"
#include <chrono>

using namespace cv;
using namespace std;

Mat ellipticKernel(int width, int height = -1) {
 if (height==-1) {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,width), Point(width/2, width/2));
 } else {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,height), Point(width/2, height/2));
 }
}

unsigned long long getMilliseconds() {
 return chrono::system_clock::now().time_since_epoch()/chrono::milliseconds(1);
}

void morphFast(Mat inout, int smallsize = 100, int factor = 25, int eq = 1, int diler = 0) {
 int width, height;
 width = inout.size().width;
 height = inout.size().height;
 Mat downsample;
 resize(inout, downsample, Size(smallsize,smallsize));
 Mat kernel = ellipticKernel(factor);
 if (diler) {
  erode(downsample, downsample, kernel);
 } else {
  dilate(downsample, downsample, kernel);
 }
 if (eq) {
  equalizeHist(downsample, downsample);
 }
 resize(downsample, inout, Size(width, height));
}

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

 int tracker1, tracker2, tracker3;
 namedWindow("s",1);
 createTrackbar("1","s",&tracker1,100);
 createTrackbar("2","s",&tracker2,100);
 createTrackbar("3","s",&tracker3,100);

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 unsigned long long times[100];
 int f = 0;
 for (int i=0; i<100; i++)
  times[i] = 0;

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

 Mat background = cvQueryFrame(capture);
 background = background.clone();
 blur(background, background, Size(50,50));

 Mat image;
 Mat channel[3];
 unsigned long long timenow = getMilliseconds();

 while (keepGoing) {
  image = cvQueryFrame(capture);
  times[0] += getMilliseconds() - timenow;
  timenow = getMilliseconds();
// preprocess by rotating according to OVR roll
//  imshow("webcam", image);

// let's make multiple masks where 0=not mouth, 1=uncertain

// then multiply them together and multiply that with image
// and run haar classifier on image

  Mat gray, blurred_img;
  cvtColor(image, gray, CV_RGB2GRAY);
  blur(image, blurred_img, Size(50,50));
  times[1] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask filters out areas with too many edges
// removed for now; it didn't generalize well
/*
  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 200, 1, THRESH_BINARY);
  blur(canny*255, canny, Size(width/10, height/10));
  threshold(canny, canny, 220, 1, THRESH_BINARY);
  imshow("canny mask", gray.mul(canny));
*/

// this mask filters out areas which have not changed much
// background needs to be updated when person is not in frame
// use OVR SDK to do this later
  Mat flow;
  absdiff(blurred_img, background, flow);
  cvtColor(flow, flow, CV_RGB2GRAY);
  morphFast(flow);
  threshold(flow, flow, 60, 1, THRESH_BINARY);
//  imshow("flow mask", gray.mul(flow));
  times[2] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask gets anything kind of dark (DK2) and dilates
  Mat kindofdark;
  equalizeHist(gray, kindofdark);
  threshold(kindofdark, kindofdark, 100, 1, THRESH_BINARY_INV);
  morphFast(kindofdark, 100, 17, 0);
//  imshow("dark mask", gray.mul(kindofdark));
  times[3] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask gets rid of anything far away from red stuff
// did not work well and was slow
/*
  Mat notlips;
  Mat channels[3];
  split(image, channels);
  channels[2].convertTo(notlips, CV_32FC1);
  divide(notlips, gray, notlips, 1, CV_32FC1);
  //equalistHist is horrible for a red background
  //equalizeHist(notlips, notlips);
  threshold(notlips, notlips, tracker3/30.0, 1, THRESH_BINARY);
  notlips.convertTo(notlips, CV_8UC1);
  imshow("lip mask", notlips*255);
  Mat otherMorph = notlips.clone();
  int tx = tracker1+1-(tracker1%2);
  if (tx<3) tx=1;
  if (tx>90) tx=91;
  morphFast(notlips, 100, tx, 0, 0);
  int ty = tracker2+1-(tracker2%2);
  if (ty<3) ty=1;
  if (ty>90) ty=91;
  morphFast(notlips, 100, ty, 0, 1);
  imshow("lips2", notlips.mul(gray));
  morphFast(otherMorph, 100, tx, 0, 1);
  morphFast(otherMorph, 100, tx, 0, 0);
  imshow("lips3", otherMorph.mul(gray));
  waitKey(1);
*/

  Mat mask = flow.mul(kindofdark);
// open the mask
  Mat smallMask0, smallMask1;
  resize(mask, smallMask0, Size(width/5,height/5));
  Mat smallKernel = ellipticKernel(69,79);
  erode(smallMask0, smallMask1, smallKernel);
  dilate(smallMask1, smallMask1, smallKernel);
  bitwise_and(smallMask0, smallMask1, smallMask1);
  resize(smallMask1, mask, Size(width, height));
//  imshow("morph mask", gray.mul(mask));
  times[4] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// update background with new morph mask
// average what we know is background with prior background
// dilate it first since we really want to be sure it's bg

/*
// actually dilation is slow and our current mask is already
// really nice :)
  Mat dilatedMask;
  dilate(smallMask1, dilatedMask, smallKernel);
  resize(dilatedMask, dilatedMask, Size(width, height));
  imshow("erosion", dilatedMask.mul(gray));
*/
  Mat mask_;
  subtract(1, mask ,mask_);
  Mat mask3, mask3_;
  channel[0] = mask;
  channel[1] = mask;
  channel[2] = mask;
  merge(channel, 3, mask3);
  channel[0] = mask_;
  channel[1] = mask_;
  channel[2] = mask_;
  merge(channel, 3, mask3_);

  background = background.mul(mask3) +
   (background.mul(mask3_)/2 + blurred_img.mul(mask3_)/2);
  times[5] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

//  imshow("background", background);

/*
  Moments lol = moments(gray, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/

  CascadeClassifier mouth_cascade;
  mouth_cascade.load("Mouth.xml");
  vector<Rect> mouths;
  int scale = 3;
  Mat classifyThis;
  equalizeHist(gray, gray);//ew; watch out not to use this later
  resize(gray.mul(mask), classifyThis, Size(width/scale,height/scale));
//  bilateralFilter(gray, classifyThis, 15, 10, 1);
  mouth_cascade.detectMultiScale(classifyThis, mouths, 1.1, 0, CV_HAAR_SCALE_IMAGE);
  Mat rectImage(height, width, CV_8UC1, Scalar(0));
  for (size_t i=0; i<mouths.size(); i++) {
   Rect scaled(mouths[i].x*scale, mouths[i].y*scale, mouths[i].width*scale,mouths[i].height*scale);
   rectangle(image, scaled, Scalar(255,0,0));
   rectangle(rectImage, scaled, Scalar(1), 5);
  }
//  blur(rectImage, rectImage, Size(tracker2+1,tracker2+1));
  threshold(rectImage, rectImage, tracker1, 1, THRESH_BINARY);
  times[6] += getMilliseconds() - timenow;
  timenow = getMilliseconds();
  imshow("MOUTH", rectImage*255);

  for (int i=0; i<7; i++) {
   printf("%llu , ", times[i]);
   times[i] = 0;
  }

  printf("\n");

  keepGoing = (waitKey(1)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"
#include <chrono>

using namespace cv;
using namespace std;

Mat ellipticKernel(int width, int height = -1) {
 if (height==-1) {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,width), Point(width/2, width/2));
 } else {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,height), Point(width/2, height/2));
 }
}

unsigned long long getMilliseconds() {
 return chrono::system_clock::now().time_since_epoch()/chrono::milliseconds(1);
}

void morphFast(Mat inout, int smallsize = 100, int factor = 25, int eq = 1, int diler = 0) {
 int width, height;
 width = inout.size().width;
 height = inout.size().height;
 Mat downsample;
 resize(inout, downsample, Size(smallsize,smallsize));
 Mat kernel = ellipticKernel(factor);
 if (diler) {
  erode(downsample, downsample, kernel);
 } else {
  dilate(downsample, downsample, kernel);
 }
 if (eq) {
  equalizeHist(downsample, downsample);
 }
 resize(downsample, inout, Size(width, height));
}

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

 int tracker1, tracker2, tracker3;
 namedWindow("s",1);
 createTrackbar("1","s",&tracker1,100);
 createTrackbar("2","s",&tracker2,100);
 createTrackbar("3","s",&tracker3,100);

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 unsigned long long times[100];
 int f = 0;
 for (int i=0; i<100; i++)
  times[i] = 0;

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

 Mat background = cvQueryFrame(capture);
 background = background.clone();
 blur(background, background, Size(50,50));

 Mat image;
 Mat channel[3];
 unsigned long long timenow = getMilliseconds();

 while (keepGoing) {
  image = cvQueryFrame(capture);
  times[0] += getMilliseconds() - timenow;
  timenow = getMilliseconds();
// preprocess by rotating according to OVR roll
//  imshow("webcam", image);

// let's make multiple masks where 0=not mouth, 1=uncertain

// then multiply them together and multiply that with image
// and run haar classifier on image

  Mat gray, blurred_img;
  cvtColor(image, gray, CV_RGB2GRAY);
  blur(image, blurred_img, Size(50,50));
  times[1] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask filters out areas with too many edges
// removed for now; it didn't generalize well
/*
  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 200, 1, THRESH_BINARY);
  blur(canny*255, canny, Size(width/10, height/10));
  threshold(canny, canny, 220, 1, THRESH_BINARY);
  imshow("canny mask", gray.mul(canny));
*/

// this mask filters out areas which have not changed much
// background needs to be updated when person is not in frame
// use OVR SDK to do this later
  Mat flow;
  absdiff(blurred_img, background, flow);
  cvtColor(flow, flow, CV_RGB2GRAY);
  morphFast(flow);
  threshold(flow, flow, 60, 1, THRESH_BINARY);
//  imshow("flow mask", gray.mul(flow));
  times[2] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask gets anything kind of dark (DK2) and dilates
  Mat kindofdark;
  equalizeHist(gray, kindofdark);
  threshold(kindofdark, kindofdark, 100, 1, THRESH_BINARY_INV);
  morphFast(kindofdark, 100, 17, 0);
//  imshow("dark mask", gray.mul(kindofdark));
  times[3] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask gets rid of anything far away from red stuff
// did not work well and was slow
/*
  Mat notlips;
  Mat channels[3];
  split(image, channels);
  channels[2].convertTo(notlips, CV_32FC1);
  divide(notlips, gray, notlips, 1, CV_32FC1);
  //equalistHist is horrible for a red background
  //equalizeHist(notlips, notlips);
  threshold(notlips, notlips, tracker3/30.0, 1, THRESH_BINARY);
  notlips.convertTo(notlips, CV_8UC1);
  imshow("lip mask", notlips*255);
  Mat otherMorph = notlips.clone();
  int tx = tracker1+1-(tracker1%2);
  if (tx<3) tx=1;
  if (tx>90) tx=91;
  morphFast(notlips, 100, tx, 0, 0);
  int ty = tracker2+1-(tracker2%2);
  if (ty<3) ty=1;
  if (ty>90) ty=91;
  morphFast(notlips, 100, ty, 0, 1);
  imshow("lips2", notlips.mul(gray));
  morphFast(otherMorph, 100, tx, 0, 1);
  morphFast(otherMorph, 100, tx, 0, 0);
  imshow("lips3", otherMorph.mul(gray));
  waitKey(1);
*/

  Mat mask = flow.mul(kindofdark);
// open the mask
  Mat smallMask0, smallMask1;
  resize(mask, smallMask0, Size(width/5,height/5));
  Mat smallKernel = ellipticKernel(69,79);
  erode(smallMask0, smallMask1, smallKernel);
  dilate(smallMask1, smallMask1, smallKernel);
  bitwise_and(smallMask0, smallMask1, smallMask1);
  resize(smallMask1, mask, Size(width, height));
//  imshow("morph mask", gray.mul(mask));
  times[4] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// update background with new morph mask
// average what we know is background with prior background
// dilate it first since we really want to be sure it's bg

/*
// actually dilation is slow and our current mask is already
// really nice :)
  Mat dilatedMask;
  dilate(smallMask1, dilatedMask, smallKernel);
  resize(dilatedMask, dilatedMask, Size(width, height));
  imshow("erosion", dilatedMask.mul(gray));
*/
  Mat mask_;
  subtract(1, mask ,mask_);
  Mat mask3, mask3_;
  channel[0] = mask;
  channel[1] = mask;
  channel[2] = mask;
  merge(channel, 3, mask3);
  channel[0] = mask_;
  channel[1] = mask_;
  channel[2] = mask_;
  merge(channel, 3, mask3_);

  background = background.mul(mask3) +
   (background.mul(mask3_)/2 + blurred_img.mul(mask3_)/2);
  times[5] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

//  imshow("background", background);

/*
  Moments lol = moments(gray, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/

  CascadeClassifier mouth_cascade;
  mouth_cascade.load("Mouth.xml");
  vector<Rect> mouths;
  int scale = 3;
  Mat classifyThis;
  equalizeHist(gray, gray);//ew; watch out not to use this later
  resize(gray.mul(mask), classifyThis, Size(width/scale,height/scale));
//  bilateralFilter(gray, classifyThis, 15, 10, 1);
  mouth_cascade.detectMultiScale(classifyThis, mouths, 1.1, 0, CV_HAAR_SCALE_IMAGE);
  Mat rectImage(height, width, CV_8UC1, Scalar(0));
  for (size_t i=0; i<mouths.size(); i++) {
   Rect scaled(mouths[i].x*scale, mouths[i].y*scale, mouths[i].width*scale,mouths[i].height*scale);
   rectangle(image, scaled, Scalar(255,0,0));
   rectangle(rectImage, scaled, Scalar(1), 5);
  }
  blur(rectImage, rectImage, Size(tracker2+3,tracker2+3));
  threshold(rectImage, rectImage, tracker1, 1, THRESH_BINARY);
  times[6] += getMilliseconds() - timenow;
  timenow = getMilliseconds();
  imshow("MOUTH", rectImage*255);

  for (int i=0; i<7; i++) {
   printf("%llu , ", times[i]);
   times[i] = 0;
  }

  printf("\n");

  keepGoing = (waitKey(1)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>
#include "logging/logging.h"
#include "uptane/exceptions.h"
#include "uptane/tuf.h"

using Uptane::Root;

Root::Root(const TimeStamp &now, const std::string &repository, const Json::Value &json, Root &root)
    : Root(repository, json) {
  root.UnpackSignedObject(now, repository, json);
  this->UnpackSignedObject(now, repository, json);
}

Root::Root(const std::string &repository, const Json::Value &json) : policy_(kCheck) {
  if (!json.isObject() || !json.isMember("signed")) {
    throw Uptane::InvalidMetadata("", "", "invalid metadata json");
  }

  version_ = json["signed"]["version"].asInt();
  expiry_ = Uptane::TimeStamp(json["signed"]["expires"].asString());
  original_object_ = json;

  if (!json.isObject() || !json["signed"].isMember("keys") || !json["signed"].isMember("roles")) {
    throw Uptane::InvalidMetadata(repository, "root", "missing keys/roles field");
  }

  Json::Value keys = json["signed"]["keys"];
  for (Json::ValueIterator it = keys.begin(); it != keys.end(); ++it) {
    std::string key_type = boost::algorithm::to_lower_copy((*it)["keytype"].asString());
    if (key_type != "rsa" && key_type != "ed25519") {
      throw SecurityException(repository, "Unsupported key type: " + (*it)["keytype"].asString());
    }
    KeyId keyid = it.key().asString();
    PublicKey key((*it)["keyval"]["public"].asString(), (*it)["keytype"].asString());
    keys_[keyid] = key;
  }

  Json::Value roles = json["signed"]["roles"];
  for (Json::ValueIterator it = roles.begin(); it != roles.end(); it++) {
    std::string role_name = it.key().asString();
    Role role = Role(role_name);
    if (role == Role::InvalidRole()) {
      LOG_WARNING << "Invalid role in root.json";
      LOG_TRACE << "Role name:" << role_name;
      LOG_TRACE << "root.json is:" << json;
      continue;
    }
    // Threshold
    int64_t requiredThreshold = (*it)["threshold"].asInt64();
    if (requiredThreshold < kMinSignatures) {
      // static_cast<int> is to stop << taking a reference to kMinSignatures
      // http://www.stroustrup.com/bs_faq2.html#in-class
      // this occurs in Boost 1.62 (and possibly other versions)
      LOG_DEBUG << "Failing with threshold for role " << role << " too small: " << requiredThreshold << " < "
                << static_cast<int>(kMinSignatures);
      throw IllegalThreshold(repository, "The role " + role.ToString() + " had an illegal signature threshold.");
    }
    if (kMaxSignatures < requiredThreshold) {
      // static_cast<int> is to stop << taking a reference to kMaxSignatures
      // http://www.stroustrup.com/bs_faq2.html#in-class
      // this occurs in Boost 1.62  (and possibly other versions)
      LOG_DEBUG << "Failing with threshold for role " << role << " too large: " << static_cast<int>(kMaxSignatures)
                << " < " << requiredThreshold;
      throw IllegalThreshold(repository, "root.json contains a role that requires too many signatures");
    }
    thresholds_for_role_[role] = requiredThreshold;

    // KeyIds
    Json::Value keyids = (*it)["keyids"];
    for (Json::ValueIterator itk = keyids.begin(); itk != keyids.end(); ++itk) {
      keys_for_role_.insert(std::make_pair(role, (*itk).asString()));
    }
  }
}

Json::Value Root::toJson() const {
  Json::Value res = BaseMeta::toJson();

  if (policy_ != kCheck) {
    throw Uptane::InvalidMetadata("", "root", "json representation will be invalid");
  }

  res["_type"] = "Root";
  res["consistent_snapshot"] = false;

  res["keys"] = Json::objectValue;
  std::map<KeyId, PublicKey>::const_iterator key_it;
  for (key_it = keys_.begin(); key_it != keys_.end(); key_it++) {
    res["keys"][key_it->first]["keytype"] = key_it->second.TypeString();
    res["keys"][key_it->first]["keyval"]["public"] = key_it->second.value;
  }
  // assuming that Root object has keys for all targets,
  //   should be a part of verification process
  res["roles"]["root"]["keyids"] = Json::arrayValue;
  res["roles"]["snapshot"]["keyids"] = Json::arrayValue;
  res["roles"]["targets"]["keyids"] = Json::arrayValue;
  res["roles"]["timestamp"]["keyids"] = Json::arrayValue;

  std::set<std::pair<Role, KeyId> >::const_iterator role_key_it;
  for (role_key_it = keys_for_role_.begin(); role_key_it != keys_for_role_.end(); role_key_it++) {
    res["roles"][role_key_it->first.ToString()]["keyids"].append(role_key_it->second);
  }

  auto th_it = thresholds_for_role_.find(Role::Root());
  if (th_it != thresholds_for_role_.end()) {
    res["roles"]["root"]["threshold"] = th_it->second;
  }

  th_it = thresholds_for_role_.find(Role::Snapshot());
  if (th_it != thresholds_for_role_.end()) {
    res["roles"]["snapshot"]["threshold"] = th_it->second;
  }

  th_it = thresholds_for_role_.find(Role::Targets());
  if (th_it != thresholds_for_role_.end()) {
    res["roles"]["targets"]["threshold"] = th_it->second;
  }

  th_it = thresholds_for_role_.find(Role::Timestamp());
  if (th_it != thresholds_for_role_.end()) {
    res["roles"]["timestamp"]["threshold"] = th_it->second;
  }

  return res;
}

void Uptane::Root::UnpackSignedObject(const TimeStamp &now, const std::string &repository,
                                      const Json::Value &signed_object) {
  Uptane::Role role(signed_object["signed"]["_type"].asString());
  if (policy_ == kAcceptAll) {
    return;
  }
  if (policy_ == kRejectAll) {
    throw SecurityException(repository, "Root policy is kRejectAll");
  }
  assert(policy_ == kCheck);

  std::string canonical = Json::FastWriter().write(signed_object["signed"]);
  Json::Value signatures = signed_object["signatures"];
  int valid_signatures = 0;

  std::vector<std::string> sig_values;
  for (Json::ValueIterator sig = signatures.begin(); sig != signatures.end(); ++sig) {
    std::string signature = (*sig)["sig"].asString();
    if (std::find(sig_values.begin(), sig_values.end(), signature) != sig_values.end()) {
      throw NonUniqueSignatures(repository, role.ToString());
    }
    sig_values.push_back(signature);

    std::string method((*sig)["method"].asString());
    std::transform(method.begin(), method.end(), method.begin(), ::tolower);

    if (method != "rsassa-pss" && method != "rsassa-pss-sha256" && method != "ed25519") {
      throw SecurityException(repository, std::string("Unsupported sign method: ") + (*sig)["method"].asString());
    }
    std::string keyid = (*sig)["keyid"].asString();
    if (keys_.count(keyid) == 0u) {
      LOG_INFO << "Signed by unknown keyid, skipping";
      LOG_TRACE << "Key ID: " << keyid;
      continue;
    }

    if (keys_for_role_.count(std::make_pair(role, keyid)) == 0u) {
      LOG_WARNING << "KeyId is not valid to sign for this role";
      LOG_TRACE << "KeyId: " << keyid;
      continue;
    }

    if (Crypto::VerifySignature(keys_[keyid], signature, canonical)) {
      valid_signatures++;
    } else {
      LOG_WARNING << "Signature was present but invalid";
      LOG_TRACE << "  keyid:" << keyid;
      LOG_TRACE << "  signature:" << signature;
      // throw SecurityException(repository, "Invalid signature, verification failed");
    }
  }
  int threshold = thresholds_for_role_[role];
  if (threshold < kMinSignatures || kMaxSignatures < threshold) {
    throw IllegalThreshold(repository, "Invalid signature threshold");
  }
  if (valid_signatures < threshold) {
    throw UnmetThreshold(repository, role.ToString());
  }

  // TODO: check _type matches role
  // TODO: check timestamp
  Uptane::TimeStamp expiry(Uptane::TimeStamp(signed_object["signed"]["expires"].asString()));
  if (expiry.IsExpiredAt(now)) {
    LOG_WARNING << "Metadata expired at:" << expiry;
    throw ExpiredMetadata(repository, role.ToString());
  }

  Uptane::Role actual_role(Uptane::Role(signed_object["signed"]["_type"].asString()));
  if (role != actual_role) {
    LOG_ERROR << "Object was signed for a different role";
    LOG_TRACE << "  role:" << role;
    LOG_TRACE << "  actual_role:" << actual_role;
    throw SecurityException(repository, "Object was signed for a different role");
  }
}
<commit_msg>uptane: Change logging for unknown keys<commit_after>
#include "logging/logging.h"
#include "uptane/exceptions.h"
#include "uptane/tuf.h"

using Uptane::Root;

Root::Root(const TimeStamp &now, const std::string &repository, const Json::Value &json, Root &root)
    : Root(repository, json) {
  root.UnpackSignedObject(now, repository, json);
  this->UnpackSignedObject(now, repository, json);
}

Root::Root(const std::string &repository, const Json::Value &json) : policy_(kCheck) {
  if (!json.isObject() || !json.isMember("signed")) {
    throw Uptane::InvalidMetadata("", "", "invalid metadata json");
  }

  version_ = json["signed"]["version"].asInt();
  expiry_ = Uptane::TimeStamp(json["signed"]["expires"].asString());
  original_object_ = json;

  if (!json.isObject() || !json["signed"].isMember("keys") || !json["signed"].isMember("roles")) {
    throw Uptane::InvalidMetadata(repository, "root", "missing keys/roles field");
  }

  Json::Value keys = json["signed"]["keys"];
  for (Json::ValueIterator it = keys.begin(); it != keys.end(); ++it) {
    std::string key_type = boost::algorithm::to_lower_copy((*it)["keytype"].asString());
    if (key_type != "rsa" && key_type != "ed25519") {
      throw SecurityException(repository, "Unsupported key type: " + (*it)["keytype"].asString());
    }
    KeyId keyid = it.key().asString();
    PublicKey key((*it)["keyval"]["public"].asString(), (*it)["keytype"].asString());
    keys_[keyid] = key;
  }

  Json::Value roles = json["signed"]["roles"];
  for (Json::ValueIterator it = roles.begin(); it != roles.end(); it++) {
    std::string role_name = it.key().asString();
    Role role = Role(role_name);
    if (role == Role::InvalidRole()) {
      LOG_WARNING << "Invalid role in root.json";
      LOG_TRACE << "Role name:" << role_name;
      LOG_TRACE << "root.json is:" << json;
      continue;
    }
    // Threshold
    int64_t requiredThreshold = (*it)["threshold"].asInt64();
    if (requiredThreshold < kMinSignatures) {
      // static_cast<int> is to stop << taking a reference to kMinSignatures
      // http://www.stroustrup.com/bs_faq2.html#in-class
      // this occurs in Boost 1.62 (and possibly other versions)
      LOG_DEBUG << "Failing with threshold for role " << role << " too small: " << requiredThreshold << " < "
                << static_cast<int>(kMinSignatures);
      throw IllegalThreshold(repository, "The role " + role.ToString() + " had an illegal signature threshold.");
    }
    if (kMaxSignatures < requiredThreshold) {
      // static_cast<int> is to stop << taking a reference to kMaxSignatures
      // http://www.stroustrup.com/bs_faq2.html#in-class
      // this occurs in Boost 1.62  (and possibly other versions)
      LOG_DEBUG << "Failing with threshold for role " << role << " too large: " << static_cast<int>(kMaxSignatures)
                << " < " << requiredThreshold;
      throw IllegalThreshold(repository, "root.json contains a role that requires too many signatures");
    }
    thresholds_for_role_[role] = requiredThreshold;

    // KeyIds
    Json::Value keyids = (*it)["keyids"];
    for (Json::ValueIterator itk = keyids.begin(); itk != keyids.end(); ++itk) {
      keys_for_role_.insert(std::make_pair(role, (*itk).asString()));
    }
  }
}

Json::Value Root::toJson() const {
  Json::Value res = BaseMeta::toJson();

  if (policy_ != kCheck) {
    throw Uptane::InvalidMetadata("", "root", "json representation will be invalid");
  }

  res["_type"] = "Root";
  res["consistent_snapshot"] = false;

  res["keys"] = Json::objectValue;
  std::map<KeyId, PublicKey>::const_iterator key_it;
  for (key_it = keys_.begin(); key_it != keys_.end(); key_it++) {
    res["keys"][key_it->first]["keytype"] = key_it->second.TypeString();
    res["keys"][key_it->first]["keyval"]["public"] = key_it->second.value;
  }
  // assuming that Root object has keys for all targets,
  //   should be a part of verification process
  res["roles"]["root"]["keyids"] = Json::arrayValue;
  res["roles"]["snapshot"]["keyids"] = Json::arrayValue;
  res["roles"]["targets"]["keyids"] = Json::arrayValue;
  res["roles"]["timestamp"]["keyids"] = Json::arrayValue;

  std::set<std::pair<Role, KeyId> >::const_iterator role_key_it;
  for (role_key_it = keys_for_role_.begin(); role_key_it != keys_for_role_.end(); role_key_it++) {
    res["roles"][role_key_it->first.ToString()]["keyids"].append(role_key_it->second);
  }

  auto th_it = thresholds_for_role_.find(Role::Root());
  if (th_it != thresholds_for_role_.end()) {
    res["roles"]["root"]["threshold"] = th_it->second;
  }

  th_it = thresholds_for_role_.find(Role::Snapshot());
  if (th_it != thresholds_for_role_.end()) {
    res["roles"]["snapshot"]["threshold"] = th_it->second;
  }

  th_it = thresholds_for_role_.find(Role::Targets());
  if (th_it != thresholds_for_role_.end()) {
    res["roles"]["targets"]["threshold"] = th_it->second;
  }

  th_it = thresholds_for_role_.find(Role::Timestamp());
  if (th_it != thresholds_for_role_.end()) {
    res["roles"]["timestamp"]["threshold"] = th_it->second;
  }

  return res;
}

void Uptane::Root::UnpackSignedObject(const TimeStamp &now, const std::string &repository,
                                      const Json::Value &signed_object) {
  Uptane::Role role(signed_object["signed"]["_type"].asString());
  if (policy_ == kAcceptAll) {
    return;
  }
  if (policy_ == kRejectAll) {
    throw SecurityException(repository, "Root policy is kRejectAll");
  }
  assert(policy_ == kCheck);

  std::string canonical = Json::FastWriter().write(signed_object["signed"]);
  Json::Value signatures = signed_object["signatures"];
  int valid_signatures = 0;

  std::vector<std::string> sig_values;
  for (Json::ValueIterator sig = signatures.begin(); sig != signatures.end(); ++sig) {
    std::string signature = (*sig)["sig"].asString();
    if (std::find(sig_values.begin(), sig_values.end(), signature) != sig_values.end()) {
      throw NonUniqueSignatures(repository, role.ToString());
    }
    sig_values.push_back(signature);

    std::string method((*sig)["method"].asString());
    std::transform(method.begin(), method.end(), method.begin(), ::tolower);

    if (method != "rsassa-pss" && method != "rsassa-pss-sha256" && method != "ed25519") {
      throw SecurityException(repository, std::string("Unsupported sign method: ") + (*sig)["method"].asString());
    }
    std::string keyid = (*sig)["keyid"].asString();
    if (keys_.count(keyid) == 0u) {
      LOG_DEBUG << "Signed by unknown keyid, " << keyid << ", skipping";
      continue;
    }

    if (keys_for_role_.count(std::make_pair(role, keyid)) == 0u) {
      LOG_WARNING << "KeyId is not valid to sign for this role";
      LOG_TRACE << "KeyId: " << keyid;
      continue;
    }

    if (Crypto::VerifySignature(keys_[keyid], signature, canonical)) {
      valid_signatures++;
    } else {
      LOG_WARNING << "Signature was present but invalid";
      LOG_TRACE << "  keyid:" << keyid;
      LOG_TRACE << "  signature:" << signature;
      // throw SecurityException(repository, "Invalid signature, verification failed");
    }
  }
  int threshold = thresholds_for_role_[role];
  if (threshold < kMinSignatures || kMaxSignatures < threshold) {
    throw IllegalThreshold(repository, "Invalid signature threshold");
  }
  if (valid_signatures < threshold) {
    throw UnmetThreshold(repository, role.ToString());
  }

  // TODO: check _type matches role
  // TODO: check timestamp
  Uptane::TimeStamp expiry(Uptane::TimeStamp(signed_object["signed"]["expires"].asString()));
  if (expiry.IsExpiredAt(now)) {
    LOG_WARNING << "Metadata expired at:" << expiry;
    throw ExpiredMetadata(repository, role.ToString());
  }

  Uptane::Role actual_role(Uptane::Role(signed_object["signed"]["_type"].asString()));
  if (role != actual_role) {
    LOG_ERROR << "Object was signed for a different role";
    LOG_TRACE << "  role:" << role;
    LOG_TRACE << "  actual_role:" << actual_role;
    throw SecurityException(repository, "Object was signed for a different role");
  }
}
<|endoftext|>


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

#include "manifest_parser.h"

#include <stdio.h>
#include <vector>

#include "graph.h"
#include "metrics.h"
#include "state.h"
#include "util.h"
#include "version.h"

ManifestParser::ManifestParser(State* state, FileReader* file_reader)
  : state_(state), file_reader_(file_reader) {
  env_ = &state->bindings_;
}
bool ManifestParser::Load(const string& filename, string* err) {
  string contents;
  string read_err;
  if (!file_reader_->ReadFile(filename, &contents, &read_err)) {
    *err = "loading '" + filename + "': " + read_err;
    return false;
  }
  contents.resize(contents.size() + 10);
  return Parse(filename, contents, err);
}

bool ManifestParser::Parse(const string& filename, const string& input,
                           string* err) {
  METRIC_RECORD(".ninja parse");
  lexer_.Start(filename, input);

  for (;;) {
    Lexer::Token token = lexer_.ReadToken();
    switch (token) {
    case Lexer::POOL:
      if (!ParsePool(err))
        return false;
      break;
    case Lexer::BUILD:
      if (!ParseEdge(err))
        return false;
      break;
    case Lexer::RULE:
      if (!ParseRule(err))
        return false;
      break;
    case Lexer::DEFAULT:
      if (!ParseDefault(err))
        return false;
      break;
    case Lexer::IDENT: {
      lexer_.UnreadToken();
      string name;
      EvalString let_value;
      if (!ParseLet(&name, &let_value, err))
        return false;
      string value = let_value.Evaluate(env_);
      // Check ninja_required_version immediately so we can exit
      // before encountering any syntactic surprises.
      if (name == "ninja_required_version")
        CheckNinjaVersion(value);
      env_->AddBinding(name, value);
      break;
    }
    case Lexer::INCLUDE:
      if (!ParseFileInclude(false, err))
        return false;
      break;
    case Lexer::SUBNINJA:
      if (!ParseFileInclude(true, err))
        return false;
      break;
    case Lexer::ERROR: {
      return lexer_.Error(lexer_.DescribeLastError(), err);
    }
    case Lexer::TEOF:
      return true;
    case Lexer::NEWLINE:
      break;
    default:
      return lexer_.Error(string("unexpected ") + Lexer::TokenName(token),
                          err);
    }
  }
  return false;  // not reached
}

bool ManifestParser::ParsePool(string* err) {
  string name;
  if (!lexer_.ReadIdent(&name))
    return lexer_.Error("expected pool name", err);

  if (!ExpectToken(Lexer::NEWLINE, err))
    return false;

  if (state_->LookupPool(name) != NULL)
    return lexer_.Error("duplicate pool '" + name + "'", err);

  int depth = -1;

  while (lexer_.PeekToken(Lexer::INDENT)) {
    string key;
    EvalString value;
    if (!ParseLet(&key, &value, err))
      return false;

    if (key == "depth") {
      string depth_string = value.Evaluate(env_);
      depth = atol(depth_string.c_str());
      if (depth < 0)
        return lexer_.Error("invalid pool depth", err);
    } else {
      return lexer_.Error("unexpected variable '" + key + "'", err);
    }
  }

  if (depth < 0)
    return lexer_.Error("expected 'depth =' line", err);

  state_->AddPool(new Pool(name, depth));
  return true;
}

bool ManifestParser::ParseRule(string* err) {
  string name;
  if (!lexer_.ReadIdent(&name))
    return lexer_.Error("expected rule name", err);

  if (!ExpectToken(Lexer::NEWLINE, err))
    return false;

  if (state_->LookupRule(name) != NULL) {
    *err = "duplicate rule '" + name + "'";
    return false;
  }

  Rule* rule = new Rule(name);  // XXX scoped_ptr

  while (lexer_.PeekToken(Lexer::INDENT)) {
    string key;
    EvalString value;
    if (!ParseLet(&key, &value, err))
      return false;

    if (Rule::IsReservedBinding(key)) {
      rule->AddBinding(key, value);
    } else {
      // Die on other keyvals for now; revisit if we want to add a
      // scope here.
      return lexer_.Error("unexpected variable '" + key + "'", err);
    }
  }

  if (rule->bindings_["rspfile"].empty() !=
      rule->bindings_["rspfile_content"].empty()) {
    return lexer_.Error("rspfile and rspfile_content need to be "
                        "both specified", err);
  }

  if (rule->bindings_["command"].empty())
    return lexer_.Error("expected 'command =' line", err);

  state_->AddRule(rule);
  return true;
}

bool ManifestParser::ParseLet(string* key, EvalString* value, string* err) {
  if (!lexer_.ReadIdent(key))
    return false;
  if (!ExpectToken(Lexer::EQUALS, err))
    return false;
  if (!lexer_.ReadVarValue(value, err))
    return false;
  return true;
}

bool ManifestParser::ParseDefault(string* err) {
  EvalString eval;
  if (!lexer_.ReadPath(&eval, err))
    return false;
  if (eval.empty())
    return lexer_.Error("expected target name", err);

  do {
    string path = eval.Evaluate(env_);
    string path_err;
    if (!CanonicalizePath(&path, &path_err))
      return lexer_.Error(path_err, err);
    if (!state_->AddDefault(path, &path_err))
      return lexer_.Error(path_err, err);

    eval.Clear();
    if (!lexer_.ReadPath(&eval, err))
      return false;
  } while (!eval.empty());

  if (!ExpectToken(Lexer::NEWLINE, err))
    return false;

  return true;
}

bool ManifestParser::ParseEdge(string* err) {
  vector<EvalString> ins, outs;

  {
    EvalString out;
    if (!lexer_.ReadPath(&out, err))
      return false;
    if (out.empty())
      return lexer_.Error("expected path", err);

    do {
      outs.push_back(out);

      out.Clear();
      if (!lexer_.ReadPath(&out, err))
        return false;
    } while (!out.empty());
  }

  if (!ExpectToken(Lexer::COLON, err))
    return false;

  string rule_name;
  if (!lexer_.ReadIdent(&rule_name))
    return lexer_.Error("expected build command name", err);

  const Rule* rule = state_->LookupRule(rule_name);
  if (!rule)
    return lexer_.Error("unknown build rule '" + rule_name + "'", err);

  for (;;) {
    // XXX should we require one path here?
    EvalString in;
    if (!lexer_.ReadPath(&in, err))
      return false;
    if (in.empty())
      break;
    ins.push_back(in);
  }

  // Add all implicit deps, counting how many as we go.
  int implicit = 0;
  if (lexer_.PeekToken(Lexer::PIPE)) {
    for (;;) {
      EvalString in;
      if (!lexer_.ReadPath(&in, err))
        return err;
      if (in.empty())
        break;
      ins.push_back(in);
      ++implicit;
    }
  }

  // Add all order-only deps, counting how many as we go.
  int order_only = 0;
  if (lexer_.PeekToken(Lexer::PIPE2)) {
    for (;;) {
      EvalString in;
      if (!lexer_.ReadPath(&in, err))
        return false;
      if (in.empty())
        break;
      ins.push_back(in);
      ++order_only;
    }
  }

  if (!ExpectToken(Lexer::NEWLINE, err))
    return false;

  // XXX scoped_ptr to handle error case.
  BindingEnv* env = new BindingEnv(env_);

  while (lexer_.PeekToken(Lexer::INDENT)) {
    string key;
    EvalString val;
    if (!ParseLet(&key, &val, err))
      return false;

    env->AddBinding(key, val.Evaluate(env_));
  }

  Edge* edge = state_->AddEdge(rule);
  edge->env_ = env;

  string pool_name = edge->GetBinding("pool");
  if (!pool_name.empty()) {
    Pool* pool = state_->LookupPool(pool_name);
    if (pool == NULL)
      return lexer_.Error("unknown pool name", err);
    edge->pool_ = pool;
  }

  for (vector<EvalString>::iterator i = ins.begin(); i != ins.end(); ++i) {
    string path = i->Evaluate(env);
    string path_err;
    if (!CanonicalizePath(&path, &path_err))
      return lexer_.Error(path_err, err);
    state_->AddIn(edge, path);
  }
  for (vector<EvalString>::iterator i = outs.begin(); i != outs.end(); ++i) {
    string path = i->Evaluate(env);
    string path_err;
    if (!CanonicalizePath(&path, &path_err))
      return lexer_.Error(path_err, err);
    state_->AddOut(edge, path);
  }
  edge->implicit_deps_ = implicit;
  edge->order_only_deps_ = order_only;

  // Multiple outputs aren't (yet?) supported with depslog.
  string deps_type = edge->GetBinding("deps");
  if (!deps_type.empty() && edge->outputs_.size() > 1) {
    return lexer_.Error("multiple outputs aren't (yet?) supported by depslog; "
                        "bring this up on the mailing list if it affects you",
                        err);
  }

  return true;
}

bool ManifestParser::ParseFileInclude(bool new_scope, string* err) {
  // XXX this should use ReadPath!
  EvalString eval;
  if (!lexer_.ReadPath(&eval, err))
    return false;
  string path = eval.Evaluate(env_);

  string contents;
  string read_err;
  if (!file_reader_->ReadFile(path, &contents, &read_err))
    return lexer_.Error("loading '" + path + "': " + read_err, err);

  ManifestParser subparser(state_, file_reader_);
  if (new_scope) {
    subparser.env_ = new BindingEnv(env_);
  } else {
    subparser.env_ = env_;
  }

  if (!subparser.Parse(path, contents, err))
    return false;

  if (!ExpectToken(Lexer::NEWLINE, err))
    return false;

  return true;
}

bool ManifestParser::ExpectToken(Lexer::Token expected, string* err) {
  Lexer::Token token = lexer_.ReadToken();
  if (token != expected) {
    string message = string("expected ") + Lexer::TokenName(expected);
    message += string(", got ") + Lexer::TokenName(token);
    message += Lexer::TokenErrorHint(expected);
    return lexer_.Error(message, err);
  }
  return true;
}
<commit_msg>Add stdlib.h include for atol().<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "manifest_parser.h"

#include <stdio.h>
#include <stdlib.h>
#include <vector>

#include "graph.h"
#include "metrics.h"
#include "state.h"
#include "util.h"
#include "version.h"

ManifestParser::ManifestParser(State* state, FileReader* file_reader)
  : state_(state), file_reader_(file_reader) {
  env_ = &state->bindings_;
}
bool ManifestParser::Load(const string& filename, string* err) {
  string contents;
  string read_err;
  if (!file_reader_->ReadFile(filename, &contents, &read_err)) {
    *err = "loading '" + filename + "': " + read_err;
    return false;
  }
  contents.resize(contents.size() + 10);
  return Parse(filename, contents, err);
}

bool ManifestParser::Parse(const string& filename, const string& input,
                           string* err) {
  METRIC_RECORD(".ninja parse");
  lexer_.Start(filename, input);

  for (;;) {
    Lexer::Token token = lexer_.ReadToken();
    switch (token) {
    case Lexer::POOL:
      if (!ParsePool(err))
        return false;
      break;
    case Lexer::BUILD:
      if (!ParseEdge(err))
        return false;
      break;
    case Lexer::RULE:
      if (!ParseRule(err))
        return false;
      break;
    case Lexer::DEFAULT:
      if (!ParseDefault(err))
        return false;
      break;
    case Lexer::IDENT: {
      lexer_.UnreadToken();
      string name;
      EvalString let_value;
      if (!ParseLet(&name, &let_value, err))
        return false;
      string value = let_value.Evaluate(env_);
      // Check ninja_required_version immediately so we can exit
      // before encountering any syntactic surprises.
      if (name == "ninja_required_version")
        CheckNinjaVersion(value);
      env_->AddBinding(name, value);
      break;
    }
    case Lexer::INCLUDE:
      if (!ParseFileInclude(false, err))
        return false;
      break;
    case Lexer::SUBNINJA:
      if (!ParseFileInclude(true, err))
        return false;
      break;
    case Lexer::ERROR: {
      return lexer_.Error(lexer_.DescribeLastError(), err);
    }
    case Lexer::TEOF:
      return true;
    case Lexer::NEWLINE:
      break;
    default:
      return lexer_.Error(string("unexpected ") + Lexer::TokenName(token),
                          err);
    }
  }
  return false;  // not reached
}

bool ManifestParser::ParsePool(string* err) {
  string name;
  if (!lexer_.ReadIdent(&name))
    return lexer_.Error("expected pool name", err);

  if (!ExpectToken(Lexer::NEWLINE, err))
    return false;

  if (state_->LookupPool(name) != NULL)
    return lexer_.Error("duplicate pool '" + name + "'", err);

  int depth = -1;

  while (lexer_.PeekToken(Lexer::INDENT)) {
    string key;
    EvalString value;
    if (!ParseLet(&key, &value, err))
      return false;

    if (key == "depth") {
      string depth_string = value.Evaluate(env_);
      depth = atol(depth_string.c_str());
      if (depth < 0)
        return lexer_.Error("invalid pool depth", err);
    } else {
      return lexer_.Error("unexpected variable '" + key + "'", err);
    }
  }

  if (depth < 0)
    return lexer_.Error("expected 'depth =' line", err);

  state_->AddPool(new Pool(name, depth));
  return true;
}

bool ManifestParser::ParseRule(string* err) {
  string name;
  if (!lexer_.ReadIdent(&name))
    return lexer_.Error("expected rule name", err);

  if (!ExpectToken(Lexer::NEWLINE, err))
    return false;

  if (state_->LookupRule(name) != NULL) {
    *err = "duplicate rule '" + name + "'";
    return false;
  }

  Rule* rule = new Rule(name);  // XXX scoped_ptr

  while (lexer_.PeekToken(Lexer::INDENT)) {
    string key;
    EvalString value;
    if (!ParseLet(&key, &value, err))
      return false;

    if (Rule::IsReservedBinding(key)) {
      rule->AddBinding(key, value);
    } else {
      // Die on other keyvals for now; revisit if we want to add a
      // scope here.
      return lexer_.Error("unexpected variable '" + key + "'", err);
    }
  }

  if (rule->bindings_["rspfile"].empty() !=
      rule->bindings_["rspfile_content"].empty()) {
    return lexer_.Error("rspfile and rspfile_content need to be "
                        "both specified", err);
  }

  if (rule->bindings_["command"].empty())
    return lexer_.Error("expected 'command =' line", err);

  state_->AddRule(rule);
  return true;
}

bool ManifestParser::ParseLet(string* key, EvalString* value, string* err) {
  if (!lexer_.ReadIdent(key))
    return false;
  if (!ExpectToken(Lexer::EQUALS, err))
    return false;
  if (!lexer_.ReadVarValue(value, err))
    return false;
  return true;
}

bool ManifestParser::ParseDefault(string* err) {
  EvalString eval;
  if (!lexer_.ReadPath(&eval, err))
    return false;
  if (eval.empty())
    return lexer_.Error("expected target name", err);

  do {
    string path = eval.Evaluate(env_);
    string path_err;
    if (!CanonicalizePath(&path, &path_err))
      return lexer_.Error(path_err, err);
    if (!state_->AddDefault(path, &path_err))
      return lexer_.Error(path_err, err);

    eval.Clear();
    if (!lexer_.ReadPath(&eval, err))
      return false;
  } while (!eval.empty());

  if (!ExpectToken(Lexer::NEWLINE, err))
    return false;

  return true;
}

bool ManifestParser::ParseEdge(string* err) {
  vector<EvalString> ins, outs;

  {
    EvalString out;
    if (!lexer_.ReadPath(&out, err))
      return false;
    if (out.empty())
      return lexer_.Error("expected path", err);

    do {
      outs.push_back(out);

      out.Clear();
      if (!lexer_.ReadPath(&out, err))
        return false;
    } while (!out.empty());
  }

  if (!ExpectToken(Lexer::COLON, err))
    return false;

  string rule_name;
  if (!lexer_.ReadIdent(&rule_name))
    return lexer_.Error("expected build command name", err);

  const Rule* rule = state_->LookupRule(rule_name);
  if (!rule)
    return lexer_.Error("unknown build rule '" + rule_name + "'", err);

  for (;;) {
    // XXX should we require one path here?
    EvalString in;
    if (!lexer_.ReadPath(&in, err))
      return false;
    if (in.empty())
      break;
    ins.push_back(in);
  }

  // Add all implicit deps, counting how many as we go.
  int implicit = 0;
  if (lexer_.PeekToken(Lexer::PIPE)) {
    for (;;) {
      EvalString in;
      if (!lexer_.ReadPath(&in, err))
        return err;
      if (in.empty())
        break;
      ins.push_back(in);
      ++implicit;
    }
  }

  // Add all order-only deps, counting how many as we go.
  int order_only = 0;
  if (lexer_.PeekToken(Lexer::PIPE2)) {
    for (;;) {
      EvalString in;
      if (!lexer_.ReadPath(&in, err))
        return false;
      if (in.empty())
        break;
      ins.push_back(in);
      ++order_only;
    }
  }

  if (!ExpectToken(Lexer::NEWLINE, err))
    return false;

  // XXX scoped_ptr to handle error case.
  BindingEnv* env = new BindingEnv(env_);

  while (lexer_.PeekToken(Lexer::INDENT)) {
    string key;
    EvalString val;
    if (!ParseLet(&key, &val, err))
      return false;

    env->AddBinding(key, val.Evaluate(env_));
  }

  Edge* edge = state_->AddEdge(rule);
  edge->env_ = env;

  string pool_name = edge->GetBinding("pool");
  if (!pool_name.empty()) {
    Pool* pool = state_->LookupPool(pool_name);
    if (pool == NULL)
      return lexer_.Error("unknown pool name", err);
    edge->pool_ = pool;
  }

  for (vector<EvalString>::iterator i = ins.begin(); i != ins.end(); ++i) {
    string path = i->Evaluate(env);
    string path_err;
    if (!CanonicalizePath(&path, &path_err))
      return lexer_.Error(path_err, err);
    state_->AddIn(edge, path);
  }
  for (vector<EvalString>::iterator i = outs.begin(); i != outs.end(); ++i) {
    string path = i->Evaluate(env);
    string path_err;
    if (!CanonicalizePath(&path, &path_err))
      return lexer_.Error(path_err, err);
    state_->AddOut(edge, path);
  }
  edge->implicit_deps_ = implicit;
  edge->order_only_deps_ = order_only;

  // Multiple outputs aren't (yet?) supported with depslog.
  string deps_type = edge->GetBinding("deps");
  if (!deps_type.empty() && edge->outputs_.size() > 1) {
    return lexer_.Error("multiple outputs aren't (yet?) supported by depslog; "
                        "bring this up on the mailing list if it affects you",
                        err);
  }

  return true;
}

bool ManifestParser::ParseFileInclude(bool new_scope, string* err) {
  // XXX this should use ReadPath!
  EvalString eval;
  if (!lexer_.ReadPath(&eval, err))
    return false;
  string path = eval.Evaluate(env_);

  string contents;
  string read_err;
  if (!file_reader_->ReadFile(path, &contents, &read_err))
    return lexer_.Error("loading '" + path + "': " + read_err, err);

  ManifestParser subparser(state_, file_reader_);
  if (new_scope) {
    subparser.env_ = new BindingEnv(env_);
  } else {
    subparser.env_ = env_;
  }

  if (!subparser.Parse(path, contents, err))
    return false;

  if (!ExpectToken(Lexer::NEWLINE, err))
    return false;

  return true;
}

bool ManifestParser::ExpectToken(Lexer::Token expected, string* err) {
  Lexer::Token token = lexer_.ReadToken();
  if (token != expected) {
    string message = string("expected ") + Lexer::TokenName(expected);
    message += string(", got ") + Lexer::TokenName(token);
    message += Lexer::TokenErrorHint(expected);
    return lexer_.Error(message, err);
  }
  return true;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "./webmdec.h"

#include <cstring>
#include <cstdio>

#include "third_party/libwebm/mkvparser.hpp"
#include "third_party/libwebm/mkvreader.hpp"

namespace {

void reset(struct WebmInputContext *const webm_ctx) {
  if (webm_ctx->reader != NULL) {
    mkvparser::MkvReader *const reader =
        reinterpret_cast<mkvparser::MkvReader*>(webm_ctx->reader);
    delete reader;
  }
  if (webm_ctx->segment != NULL) {
    mkvparser::Segment *const segment =
        reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment);
    delete segment;
  }
  if (webm_ctx->buffer != NULL) {
    delete[] webm_ctx->buffer;
  }
  webm_ctx->reader = NULL;
  webm_ctx->segment = NULL;
  webm_ctx->buffer = NULL;
  webm_ctx->cluster = NULL;
  webm_ctx->block_entry = NULL;
  webm_ctx->block = NULL;
  webm_ctx->block_frame_index = 0;
  webm_ctx->video_track_index = 0;
  webm_ctx->timestamp_ns = 0;
  webm_ctx->is_key_frame = false;
}

void get_first_cluster(struct WebmInputContext *const webm_ctx) {
  mkvparser::Segment *const segment =
      reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment);
  const mkvparser::Cluster *const cluster = segment->GetFirst();
  webm_ctx->cluster = cluster;
}

void rewind_and_reset(struct WebmInputContext *const webm_ctx,
                      struct VpxInputContext *const vpx_ctx) {
  rewind(vpx_ctx->file);
  reset(webm_ctx);
}

}  // namespace

int file_is_webm(struct WebmInputContext *webm_ctx,
                 struct VpxInputContext *vpx_ctx) {
  mkvparser::MkvReader *const reader = new mkvparser::MkvReader(vpx_ctx->file);
  webm_ctx->reader = reader;
  webm_ctx->reached_eos = 0;

  mkvparser::EBMLHeader header;
  long long pos = 0;
  if (header.Parse(reader, pos) < 0) {
    rewind_and_reset(webm_ctx, vpx_ctx);
    return 0;
  }

  mkvparser::Segment* segment;
  if (mkvparser::Segment::CreateInstance(reader, pos, segment)) {
    rewind_and_reset(webm_ctx, vpx_ctx);
    return 0;
  }
  webm_ctx->segment = segment;
  if (segment->Load() < 0) {
    rewind_and_reset(webm_ctx, vpx_ctx);
    return 0;
  }

  const mkvparser::Tracks *const tracks = segment->GetTracks();
  const mkvparser::VideoTrack* video_track = NULL;
  for (unsigned long i = 0; i < tracks->GetTracksCount(); ++i) {
    const mkvparser::Track* const track = tracks->GetTrackByIndex(i);
    if (track->GetType() == mkvparser::Track::kVideo) {
      video_track = static_cast<const mkvparser::VideoTrack*>(track);
      webm_ctx->video_track_index = track->GetNumber();
      break;
    }
  }

  if (video_track == NULL || video_track->GetCodecId() == NULL) {
    rewind_and_reset(webm_ctx, vpx_ctx);
    return 0;
  }

  if (!strncmp(video_track->GetCodecId(), "V_VP8", 5)) {
    vpx_ctx->fourcc = VP8_FOURCC;
  } else if (!strncmp(video_track->GetCodecId(), "V_VP9", 5)) {
    vpx_ctx->fourcc = VP9_FOURCC;
  } else if (!strncmp(video_track->GetCodecId(), "V_VP10", 6)) {
    vpx_ctx->fourcc = VP10_FOURCC;
  } else {
    rewind_and_reset(webm_ctx, vpx_ctx);
    return 0;
  }

  vpx_ctx->framerate.denominator = 0;
  vpx_ctx->framerate.numerator = 0;
  vpx_ctx->width = static_cast<uint32_t>(video_track->GetWidth());
  vpx_ctx->height = static_cast<uint32_t>(video_track->GetHeight());

  get_first_cluster(webm_ctx);

  return 1;
}

int webm_read_frame(struct WebmInputContext *webm_ctx,
                    uint8_t **buffer,
                    size_t *bytes_in_buffer,
                    size_t *buffer_size) {
  // This check is needed for frame parallel decoding, in which case this
  // function could be called even after it has reached end of input stream.
  if (webm_ctx->reached_eos) {
    return 1;
  }
  mkvparser::Segment *const segment =
      reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment);
  const mkvparser::Cluster* cluster =
      reinterpret_cast<const mkvparser::Cluster*>(webm_ctx->cluster);
  const mkvparser::Block *block =
      reinterpret_cast<const mkvparser::Block*>(webm_ctx->block);
  const mkvparser::BlockEntry *block_entry =
      reinterpret_cast<const mkvparser::BlockEntry*>(webm_ctx->block_entry);
  bool block_entry_eos = false;
  do {
    long status = 0;
    bool get_new_block = false;
    if (block_entry == NULL && !block_entry_eos) {
      status = cluster->GetFirst(block_entry);
      get_new_block = true;
    } else if (block_entry_eos || block_entry->EOS()) {
      cluster = segment->GetNext(cluster);
      if (cluster == NULL || cluster->EOS()) {
        *bytes_in_buffer = 0;
        webm_ctx->reached_eos = 1;
        return 1;
      }
      status = cluster->GetFirst(block_entry);
      block_entry_eos = false;
      get_new_block = true;
    } else if (block == NULL ||
               webm_ctx->block_frame_index == block->GetFrameCount() ||
               block->GetTrackNumber() != webm_ctx->video_track_index) {
      status = cluster->GetNext(block_entry, block_entry);
      if (block_entry == NULL || block_entry->EOS()) {
        block_entry_eos = true;
        continue;
      }
      get_new_block = true;
    }
    if (status) {
      return -1;
    }
    if (get_new_block) {
      block = block_entry->GetBlock();
      webm_ctx->block_frame_index = 0;
    }
  } while (block->GetTrackNumber() != webm_ctx->video_track_index ||
           block_entry_eos);

  webm_ctx->cluster = cluster;
  webm_ctx->block_entry = block_entry;
  webm_ctx->block = block;

  const mkvparser::Block::Frame& frame =
      block->GetFrame(webm_ctx->block_frame_index);
  ++webm_ctx->block_frame_index;
  if (frame.len > static_cast<long>(*buffer_size)) {
    delete[] *buffer;
    *buffer = new uint8_t[frame.len];
    if (*buffer == NULL) {
      return -1;
    }
    *buffer_size = frame.len;
    webm_ctx->buffer = *buffer;
  }
  *bytes_in_buffer = frame.len;
  webm_ctx->timestamp_ns = block->GetTime(cluster);
  webm_ctx->is_key_frame = block->IsKey();

  mkvparser::MkvReader *const reader =
      reinterpret_cast<mkvparser::MkvReader*>(webm_ctx->reader);
  return frame.Read(reader, *buffer) ? -1 : 0;
}

int webm_guess_framerate(struct WebmInputContext *webm_ctx,
                         struct VpxInputContext *vpx_ctx) {
  uint32_t i = 0;
  uint8_t *buffer = NULL;
  size_t bytes_in_buffer = 0;
  size_t buffer_size = 0;
  while (webm_ctx->timestamp_ns < 1000000000 && i < 50) {
    if (webm_read_frame(webm_ctx, &buffer, &bytes_in_buffer, &buffer_size)) {
      break;
    }
    ++i;
  }
  vpx_ctx->framerate.numerator = (i - 1) * 1000000;
  vpx_ctx->framerate.denominator =
      static_cast<int>(webm_ctx->timestamp_ns / 1000);
  delete[] buffer;

  get_first_cluster(webm_ctx);
  webm_ctx->block = NULL;
  webm_ctx->block_entry = NULL;
  webm_ctx->block_frame_index = 0;
  webm_ctx->timestamp_ns = 0;
  webm_ctx->reached_eos = 0;

  return 0;
}

void webm_free(struct WebmInputContext *webm_ctx) {
  reset(webm_ctx);
}
<commit_msg>Fix crash when mkvparser returns a NULL BlockEntry.<commit_after>/*
 *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "./webmdec.h"

#include <cstring>
#include <cstdio>

#include "third_party/libwebm/mkvparser.hpp"
#include "third_party/libwebm/mkvreader.hpp"

namespace {

void reset(struct WebmInputContext *const webm_ctx) {
  if (webm_ctx->reader != NULL) {
    mkvparser::MkvReader *const reader =
        reinterpret_cast<mkvparser::MkvReader*>(webm_ctx->reader);
    delete reader;
  }
  if (webm_ctx->segment != NULL) {
    mkvparser::Segment *const segment =
        reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment);
    delete segment;
  }
  if (webm_ctx->buffer != NULL) {
    delete[] webm_ctx->buffer;
  }
  webm_ctx->reader = NULL;
  webm_ctx->segment = NULL;
  webm_ctx->buffer = NULL;
  webm_ctx->cluster = NULL;
  webm_ctx->block_entry = NULL;
  webm_ctx->block = NULL;
  webm_ctx->block_frame_index = 0;
  webm_ctx->video_track_index = 0;
  webm_ctx->timestamp_ns = 0;
  webm_ctx->is_key_frame = false;
}

void get_first_cluster(struct WebmInputContext *const webm_ctx) {
  mkvparser::Segment *const segment =
      reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment);
  const mkvparser::Cluster *const cluster = segment->GetFirst();
  webm_ctx->cluster = cluster;
}

void rewind_and_reset(struct WebmInputContext *const webm_ctx,
                      struct VpxInputContext *const vpx_ctx) {
  rewind(vpx_ctx->file);
  reset(webm_ctx);
}

}  // namespace

int file_is_webm(struct WebmInputContext *webm_ctx,
                 struct VpxInputContext *vpx_ctx) {
  mkvparser::MkvReader *const reader = new mkvparser::MkvReader(vpx_ctx->file);
  webm_ctx->reader = reader;
  webm_ctx->reached_eos = 0;

  mkvparser::EBMLHeader header;
  long long pos = 0;
  if (header.Parse(reader, pos) < 0) {
    rewind_and_reset(webm_ctx, vpx_ctx);
    return 0;
  }

  mkvparser::Segment* segment;
  if (mkvparser::Segment::CreateInstance(reader, pos, segment)) {
    rewind_and_reset(webm_ctx, vpx_ctx);
    return 0;
  }
  webm_ctx->segment = segment;
  if (segment->Load() < 0) {
    rewind_and_reset(webm_ctx, vpx_ctx);
    return 0;
  }

  const mkvparser::Tracks *const tracks = segment->GetTracks();
  const mkvparser::VideoTrack* video_track = NULL;
  for (unsigned long i = 0; i < tracks->GetTracksCount(); ++i) {
    const mkvparser::Track* const track = tracks->GetTrackByIndex(i);
    if (track->GetType() == mkvparser::Track::kVideo) {
      video_track = static_cast<const mkvparser::VideoTrack*>(track);
      webm_ctx->video_track_index = track->GetNumber();
      break;
    }
  }

  if (video_track == NULL || video_track->GetCodecId() == NULL) {
    rewind_and_reset(webm_ctx, vpx_ctx);
    return 0;
  }

  if (!strncmp(video_track->GetCodecId(), "V_VP8", 5)) {
    vpx_ctx->fourcc = VP8_FOURCC;
  } else if (!strncmp(video_track->GetCodecId(), "V_VP9", 5)) {
    vpx_ctx->fourcc = VP9_FOURCC;
  } else if (!strncmp(video_track->GetCodecId(), "V_VP10", 6)) {
    vpx_ctx->fourcc = VP10_FOURCC;
  } else {
    rewind_and_reset(webm_ctx, vpx_ctx);
    return 0;
  }

  vpx_ctx->framerate.denominator = 0;
  vpx_ctx->framerate.numerator = 0;
  vpx_ctx->width = static_cast<uint32_t>(video_track->GetWidth());
  vpx_ctx->height = static_cast<uint32_t>(video_track->GetHeight());

  get_first_cluster(webm_ctx);

  return 1;
}

int webm_read_frame(struct WebmInputContext *webm_ctx,
                    uint8_t **buffer,
                    size_t *bytes_in_buffer,
                    size_t *buffer_size) {
  // This check is needed for frame parallel decoding, in which case this
  // function could be called even after it has reached end of input stream.
  if (webm_ctx->reached_eos) {
    return 1;
  }
  mkvparser::Segment *const segment =
      reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment);
  const mkvparser::Cluster* cluster =
      reinterpret_cast<const mkvparser::Cluster*>(webm_ctx->cluster);
  const mkvparser::Block *block =
      reinterpret_cast<const mkvparser::Block*>(webm_ctx->block);
  const mkvparser::BlockEntry *block_entry =
      reinterpret_cast<const mkvparser::BlockEntry*>(webm_ctx->block_entry);
  bool block_entry_eos = false;
  do {
    long status = 0;
    bool get_new_block = false;
    if (block_entry == NULL && !block_entry_eos) {
      status = cluster->GetFirst(block_entry);
      get_new_block = true;
    } else if (block_entry_eos || block_entry->EOS()) {
      cluster = segment->GetNext(cluster);
      if (cluster == NULL || cluster->EOS()) {
        *bytes_in_buffer = 0;
        webm_ctx->reached_eos = 1;
        return 1;
      }
      status = cluster->GetFirst(block_entry);
      block_entry_eos = false;
      get_new_block = true;
    } else if (block == NULL ||
               webm_ctx->block_frame_index == block->GetFrameCount() ||
               block->GetTrackNumber() != webm_ctx->video_track_index) {
      status = cluster->GetNext(block_entry, block_entry);
      if (block_entry == NULL || block_entry->EOS()) {
        block_entry_eos = true;
        continue;
      }
      get_new_block = true;
    }
    if (status || block_entry == NULL) {
      return -1;
    }
    if (get_new_block) {
      block = block_entry->GetBlock();
      webm_ctx->block_frame_index = 0;
    }
  } while (block->GetTrackNumber() != webm_ctx->video_track_index ||
           block_entry_eos);

  webm_ctx->cluster = cluster;
  webm_ctx->block_entry = block_entry;
  webm_ctx->block = block;

  const mkvparser::Block::Frame& frame =
      block->GetFrame(webm_ctx->block_frame_index);
  ++webm_ctx->block_frame_index;
  if (frame.len > static_cast<long>(*buffer_size)) {
    delete[] *buffer;
    *buffer = new uint8_t[frame.len];
    if (*buffer == NULL) {
      return -1;
    }
    *buffer_size = frame.len;
    webm_ctx->buffer = *buffer;
  }
  *bytes_in_buffer = frame.len;
  webm_ctx->timestamp_ns = block->GetTime(cluster);
  webm_ctx->is_key_frame = block->IsKey();

  mkvparser::MkvReader *const reader =
      reinterpret_cast<mkvparser::MkvReader*>(webm_ctx->reader);
  return frame.Read(reader, *buffer) ? -1 : 0;
}

int webm_guess_framerate(struct WebmInputContext *webm_ctx,
                         struct VpxInputContext *vpx_ctx) {
  uint32_t i = 0;
  uint8_t *buffer = NULL;
  size_t bytes_in_buffer = 0;
  size_t buffer_size = 0;
  while (webm_ctx->timestamp_ns < 1000000000 && i < 50) {
    if (webm_read_frame(webm_ctx, &buffer, &bytes_in_buffer, &buffer_size)) {
      break;
    }
    ++i;
  }
  vpx_ctx->framerate.numerator = (i - 1) * 1000000;
  vpx_ctx->framerate.denominator =
      static_cast<int>(webm_ctx->timestamp_ns / 1000);
  delete[] buffer;

  get_first_cluster(webm_ctx);
  webm_ctx->block = NULL;
  webm_ctx->block_entry = NULL;
  webm_ctx->block_frame_index = 0;
  webm_ctx->timestamp_ns = 0;
  webm_ctx->reached_eos = 0;

  return 0;
}

void webm_free(struct WebmInputContext *webm_ctx) {
  reset(webm_ctx);
}
<|endoftext|>