code:
// ©2008-2017 despair <despair@netrunner.cc>
#include "HTTPSRequest.h"
#include <errno.h>
#include <iostream>
#include <string.h>

// PolarSSL internal state
mbedtls_net_context server_fd;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt cacert;

HTTPSRequest::HTTPSRequest(const std::shared_ptr<URL> u) {
    if (!initTLS()){
        printf("failed to start TLS!");
        return;
    }
    uri = u;
    version = Version::HTTP10;
    method = Method::GET;
    userAgent = "NetRunner/0.1 PolarSSL/2.5.1";
}

bool HTTPSRequest::sendRequest(std::function<void(const HTTPResponse&)> responseCallback, std::unique_ptr<std::string> ptrPostBody) const {
    std::string response;
    std::string document = uri->path;
    if (uri->query != "") {
        document += "?" + uri->query;
    }
    std::string host = uri->host;
    std::string port = std::to_string(uri->port);

    char buffer[512];
    int ret;
    unsigned flags;

    if(mbedtls_net_connect(&server_fd, host.c_str(),port.c_str(), MBEDTLS_NET_PROTO_TCP) != 0 ){
        return false;
    }

    if (mbedtls_ssl_config_defaults(&conf,MBEDTLS_SSL_IS_CLIENT,MBEDTLS_SSL_TRANSPORT_STREAM,MBEDTLS_SSL_PRESET_DEFAULT) != 0){
        return false;
    }

    mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
    mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
    mbedtls_ssl_conf_ca_chain( &conf, &cacert, nullptr );

    if( mbedtls_ssl_setup( &ssl, &conf ) != 0 ){
        return false;
    }
    if(mbedtls_ssl_set_hostname( &ssl, uri->host.c_str() ) != 0 ){
        return false;
    }

    mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, nullptr );

    int state = mbedtls_ssl_handshake( &ssl );

    while(state != 0){
        if( state != MBEDTLS_ERR_SSL_WANT_READ && state != MBEDTLS_ERR_SSL_WANT_WRITE ){
            printf( " failed\n  ! mbedtls_ssl_handshake returned -0x%x\n\n", -state );
            return false;
        }
    }

    if( ( flags = mbedtls_ssl_get_verify_result( &ssl ) ) != 0 ){
        printf("Invalid server cert!");
        return false;
    }
    std::string postBody = "";
    if (ptrPostBody) {
        // The moral of the story is, if you have binary (non-alphanumeric) data (or a significantly sized payload) to transmit, use multipart/form-data
        std::string fixedPostBody(*ptrPostBody);
        auto search = fixedPostBody.find(" ");
        if (search != std::string::npos) {
            fixedPostBody.replace(search, 1, "+");
        }
        // close userAgent
        postBody = "\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " + std::to_string(fixedPostBody.size())+ "\r\n\r\n" + fixedPostBody;
    }

    const std::string request = methodToString(method) + std::string(" ") + document + std::string(" ") + versionToString(version) + std::string("\r\nHost: ") + host + std::string("\r\nUser-Agent: ") + userAgent + postBody + std::string("\r\n\r\n");
    std::cout << "HTTPS Request: " << request << std::endl;

    while( ( state = mbedtls_ssl_write( &ssl, reinterpret_cast<const unsigned char*>(request.c_str()), request.length() ) ) <= 0 ){
        if( state != MBEDTLS_ERR_SSL_WANT_READ && state != MBEDTLS_ERR_SSL_WANT_WRITE ){
            printf( " failed\n  ! mbedtls_ssl_write returned %d\n\n", state );
            return false;
        }
    }

    do{
        ret = mbedtls_ssl_read( &ssl, reinterpret_cast<unsigned char *>(buffer), 512 );
        if (ret <= 0){
            break;
        }
        else{
            response += std::string(buffer, static_cast<unsigned int>(ret));
        }
    }
    while( ret != 0 );

    // clean up after the request
    mbedtls_ssl_close_notify( &ssl );
    responseCallback(HTTPResponse(response));
    mbedtls_net_free( &server_fd );
    mbedtls_x509_crt_free( &cacert );
    mbedtls_ssl_free( &ssl );
    mbedtls_ssl_config_free( &conf );
    mbedtls_ctr_drbg_free( &ctr_drbg );
    mbedtls_entropy_free( &entropy );
    return true;
}

const std::string HTTPSRequest::versionToString(const Version ver) const {
    switch (ver) {
        case Version::HTTP10:
            return "HTTP/1.0";
        case Version::HTTP11:
            return "HTTP/1.1";
        default:
            return "ERROR";
    }
}

const std::string HTTPSRequest::methodToString(const Method meth) const {
    switch (meth) {
        case Method::GET:
            return "GET";
        case Method::POST:
            return "POST";
        default:
            return "ERROR";
    }
}

bool HTTPSRequest::initTLS()
{
    mbedtls_net_init( &server_fd );
    mbedtls_ssl_init( &ssl );
    mbedtls_ssl_config_init( &conf );
    mbedtls_x509_crt_init( &cacert );
    mbedtls_ctr_drbg_init( &ctr_drbg );

    const char *seed = "!@netrunner_ssl_seed$%?rvx86_despair##^^%$#@";
    mbedtls_entropy_init( &entropy );
    if(mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, reinterpret_cast<const unsigned char*>(seed), strlen(seed) ) != 0 ){
        return false;
    }

    int ret = mbedtls_x509_crt_parse_file( &cacert, "ca-bundle.crt");
    if( ret < 0 ){
        printf( " failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", -ret );
        return false;
    }
    return true;
}


code:
#ifndef HTTPSREQUEST_H
#define HTTPSREQUEST_H

#include "HTTPCommon.h"
#include "HTTPResponse.h"
#include "../URL.h"
#include <functional>
#include <string>
#ifdef NULL
#undef NULL
#define NULL nullptr
#endif

// PolarSSL
#include <mbedtls/ssl.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/error.h>
#include <mbedtls/certs.h>

// FIXME: needs to extend HTTPRequest
class HTTPSRequest {
public:
    HTTPSRequest(const std::shared_ptr<URL> u);
    bool sendRequest(std::function<void(const HTTPResponse&)> responseCallback, std::unique_ptr<std::string> ptrPostBody) const;
    const std::string versionToString(const Version version) const;
    const std::string methodToString(const Method method) const;
    bool initTLS();
    // has to be public, otherwise how are we going to change it
    Method method;
    Version version;
private:
    std::string userAgent;
    std::shared_ptr<URL> uri;
};

#endif

repo_name: vaartis/netrunner

license: mit


code:
#include "pnm.h"
#include <string>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <map>
#ifdef _WIN32
#include <io.h>
#include <windows.h>
#include <fcntl.h>
#endif

#include "../../../environment/Environment.h"

// pnm
// The PNM format is just an abstraction of the PBM, PGM, and PPM formats. I.e. the name "PNM" refers collectively to PBM, PGM, and PPM.
// pam has the advanced header

RGBAPNMObject * readPPM(const char* fileName) {
    RGBAPNMObject *data=new RGBAPNMObject;
    // open the file to read just the header reading
    FILE* fr = fopen((Environment::getResourceDir() + "/" + fileName).c_str(), "rb");
    if (!fr) {
        std::cout << "Can't open " << fileName << std::endl;
        return nullptr;
    }

    // formatted read of header
    char fileType[11];
    int res=0;
    res = fscanf(fr, "%9s", fileType);
    data->magicNum=fileType;

    //std::cout << "fileType:" << fileType << std::endl;

    unsigned char bits = 0;
    bool pamType = false;
    std::map<std::string, std::string> pamHeader;

    // check to see if it's a PPM image file
    if (strncmp(fileType, "P4" , 2) == 0) {
        bits = 1; // PBM
    } else if (strncmp(fileType, "P5" , 2) == 0) {
        bits = 8; // PGM
    } else if (strncmp(fileType, "P6" , 2) == 0) {
        bits = 24; // PPM
    } else if (strncmp(fileType, "P7" , 2) == 0) {
        pamType = true;
        bool headerDone = false;
        char cLine[80];
        char *read;
        while(!headerDone) {
            //read = getline(&cLine, &len, fr);
            read = fgets(cLine, 80, fr);
            //res = fscanf(fr, "%s\n", cLine);
            std::string line(cLine);
            line.erase(line.find_last_not_of(" \t\n\r\f\v") + 1);
            //std::cout << "read " << line << std::endl;
            size_t spacePos = line.find(" ");
            std::string key(line.substr(0, spacePos));
            std::string val(line.substr(spacePos + 1));
            //std::cout << "read [" << key << "]=[" << val << "]" << std::endl;
            pamHeader[key]=val;
            if (read == nullptr) headerDone = true;
            if (line == "ENDHDR") headerDone = true;
        }
        bits = std::stoi(pamHeader["DEPTH"]) * 8; // 4 * 8 = 32
        if (pamHeader["TUPLTYPE"] != "RGB_ALPHA") {
            std::cout << "Unsupported TUPLTYPE: " << pamHeader["TUPLTYPE"] << std::endl;
            return nullptr;
        }
        //
    } else if (strncmp(fileType, "P8" , 2) == 0) {
        bits = 32; // PPM
    }
    //std::cout << "bits:" << bits << std::endl;

    // read the rest of header
    unsigned int width, height;
    if (pamType) {
        width = static_cast<unsigned int>(std::stoi(pamHeader["WIDTH"]));
        height = static_cast<unsigned int>(std::stoi(pamHeader["HEIGHT"]));
    } else {
        res = fscanf(fr, "%u\n %u\n", &width, &height);
    }
    data->width = width;
    data->height = height;

    // read maximum
    data->maxColVal = 255; // just set a default
    if (bits != 1) {
        unsigned int maximum;
        if (pamType) {
            maximum = static_cast<unsigned int>(std::stoi(pamHeader["MAXVAL"]));
        } else {
            res = fscanf(fr, "%u\n", &maximum);
        }
        data->maxColVal = maximum;
    }
    unsigned int size = width * height;
    if (bits != 1) {
        size *= bits/8;
    }
    std::cout << "read " << fileName << " pnm/pam " << width << "," << height << "@" << static_cast<int>(bits) << "(" << bits/8 << ")" << "/" << data->maxColVal << std::endl;

    // allocate array for pixels
    unsigned char* pixels = static_cast<unsigned char*>(tlsf_malloc(size)); // used to be: new char[size];
    //unsigned char* pixels = reinterpret_cast<unsigned char*>(tlsf_calloc(size, sizeof(unsigned char))); // used to be: new char[size];

    // unformatted read of binary pixel data
    res = fread(pixels, 1, size,fr);
    data->m_Ptr = pixels;

    // close file
    fclose(fr);

    // return the array
    return data;
} // end of readPPM

void writePBM4(const char *filename, const RGBAPNMObject &data) {
  FILE *fp = fopen(filename, "wb"); /* b - binary mode */
  fprintf(fp, "P6\n%d %d\n255\n", data.width, data.height);
  for (unsigned int j = 0; j < data.height; ++j) {
    for (unsigned int i = 0; i < data.width; ++i) {
      static unsigned char color[1];
      unsigned int pos = ((i * 4) + (j * 4 * 1024));
      //color[0] = data.m_Ptr[pos + 0];  /* red */
      //color[1] = data.m_Ptr[pos + 1];  /* green */
      //color[2] = data.m_Ptr[pos + 2];  /* blue */
      color[0] = data.m_Ptr[pos + 3];  /* alpha */
      fwrite(color, 1, 1, fp);
    }
  }
  fclose(fp);
}

void writePGM5(const char *filename, const RGBAPNMObject &data) {
  FILE *fp = fopen(filename, "wb"); /* b - binary mode */
  fprintf(fp, "P5\n%d %d\n255\n", data.width, data.height);
  for (unsigned int j = 0; j < data.height; ++j) {
    for (unsigned int i = 0; i < data.width; ++i) {
      static unsigned char color[1];
      unsigned int pos = ((i * 4) + (j * 4 * 1024));
      color[0] = data.m_Ptr[pos + 0];  /* red */
      //color[1] = data.m_Ptr[pos + 1];  /* green */
      //color[2] = data.m_Ptr[pos + 2];  /* blue */
      //color[3] = data.m_Ptr[pos + 3];  /* alpha */
      fwrite(color, 1, 1, fp);
    }
  }
  fclose(fp);
}

void writePPM6(const char *filename, const RGBAPNMObject &data) {
  FILE *fp = fopen(filename, "wb"); /* b - binary mode */
  fprintf(fp, "P6\n%d %d\n255\n", data.width, data.height);
  for (unsigned int j = 0; j < data.height; ++j) {
    for (unsigned int i = 0; i < data.width; ++i) {
      static unsigned char color[3];
      unsigned int pos = ((i * 4) + (j * 4 * 1024));
      color[0] = data.m_Ptr[pos + 0];  /* red */
      color[1] = data.m_Ptr[pos + 1];  /* green */
      color[2] = data.m_Ptr[pos + 2];  /* blue */
      //color[3] = data.m_Ptr[pos + 3];  /* alpha */
      fwrite(color, 1, 3, fp);
    }
  }
  fclose(fp);
}

void writePPM8(const char *filename, const RGBAPNMObject &data) {
  FILE *fp = fopen(filename, "wb"); /* b - binary mode */
  fprintf(fp, "P8\n%d %d\n255\n", data.width, data.height);
  for (unsigned int j = 0; j < data.height; ++j) {
    for (unsigned int i = 0; i < data.width; ++i) {
      static unsigned char color[4];
      unsigned int pos = ((i * 4) + (j * 4 * 1024));
      color[0] = data.m_Ptr[pos + 0];  /* red */
      color[1] = data.m_Ptr[pos + 1];  /* green */
      color[2] = data.m_Ptr[pos + 2];  /* blue */
      color[3] = data.m_Ptr[pos + 3];  /* alpha */
      fwrite(color, 1, 4, fp);
    }
  }
  fclose(fp);
}


code:
#ifndef PNMPARSER_H
#define PNMPARSER_H

#include <string>
#include "../../../tlsf.h"

// this structure expects RGBA
struct RGBAPNMObject {
  std::string magicNum;
  unsigned int width, height, maxColVal;
  unsigned char * m_Ptr;

  // fast allocation!
  static void* operator new(size_t n){
    void *mem = tlsf_malloc(n);
    if (mem){
        return mem;
    }
    throw std::bad_alloc {};
  }
  static void operator delete(void *p){
    tlsf_free(p);
  }
};

RGBAPNMObject * readPPM(const char* fileName);
void writePBM4(const char *filename, const RGBAPNMObject &data);
void writePGM5(const char *filename, const RGBAPNMObject &data);
void writePPM6(const char *filename, const RGBAPNMObject &data);
void writePPM8(const char *filename, const RGBAPNMObject &data);

#endif


code:
#include "tga.h"
#include <string>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <map>

#include "../../../environment/Environment.h"

// tga

BitMapObject *LoadTGAFile(const char *filename) {
    BitMapObject *tgaFile = new BitMapObject;
    FILE *filePtr;
    unsigned char ucharBad;
    short int sintBad;
    long imageSize;
    int colorMode;
    unsigned char colorSwap;
    size_t res;

    // Open the TGA file.
    filePtr = fopen(filename, "rb");
    if (filePtr == nullptr) {
        return nullptr;
    }

    // Read the two first bytes we don't need.
    res = fread(&ucharBad, sizeof(unsigned char), 1, filePtr);
    res = fread(&ucharBad, sizeof(unsigned char), 1, filePtr);

    // Which type of image gets stored in imageTypeCode.
    unsigned char imageTypeCode;
    res = fread(&imageTypeCode, sizeof(unsigned char), 1, filePtr);

    // For our purposes, the type code should be 2 (uncompressed RGBA image)
    // or 3 (uncompressed black-and-white images).
    if (imageTypeCode != 2 && imageTypeCode != 3) {
        fclose(filePtr);
        return nullptr;
    }

    // Read 13 bytes of data we don't need.
    res = fread(&sintBad, sizeof(short int), 1, filePtr);
    res = fread(&sintBad, sizeof(short int), 1, filePtr);
    res = fread(&ucharBad, sizeof(unsigned char), 1, filePtr);
    res = fread(&sintBad, sizeof(short int), 1, filePtr);
    res = fread(&sintBad, sizeof(short int), 1, filePtr);

    // Read the image's width and height.
    short int imageWidth;
    short int imageHeight;
    res = fread(&imageWidth, sizeof(short int), 1, filePtr);
    res = fread(&imageHeight, sizeof(short int), 1, filePtr);
    tgaFile->width = static_cast<size_t>(imageWidth);
    tgaFile->height = static_cast<size_t>(imageHeight);

    // Read the bit depth.
    unsigned char bitCount;
    res = fread(&bitCount, sizeof(unsigned char), 1, filePtr);

    // Read one byte of data we don't need.
    res = fread(&ucharBad, sizeof(unsigned char), 1, filePtr);

    // Color mode -> 3 = BGR, 4 = BGRA.
    colorMode = bitCount / 8;
    imageSize = static_cast<long int>(tgaFile->width * tgaFile->height * static_cast<long unsigned int>(colorMode & 32));

    // Allocate memory for the image data.
    tgaFile->imageData = static_cast<unsigned char*>(malloc(sizeof(unsigned char) * static_cast<long unsigned int>(imageSize)));

    // Read the image data.
    res = fread(tgaFile->imageData, sizeof(unsigned char), static_cast<long unsigned int>(imageSize), filePtr);

    // Change from BGR to RGB so OpenGL can read the image data.
    for (int imageIdx = 0; imageIdx < imageSize; imageIdx += colorMode) {
        colorSwap = tgaFile->imageData[imageIdx];
        tgaFile->imageData[imageIdx] = tgaFile->imageData[imageIdx + 2];
        tgaFile->imageData[imageIdx + 2] = colorSwap;
    }

    fclose(filePtr);
    return tgaFile;
}


code:
#ifndef TGAPARSER_H
#define TGAPARSER_H

#include <string>
#include "../../../tlsf.h"

struct TGAObject {
    unsigned char imageTypeCode;
    short int imageWidth;
    short int imageHeight;
    unsigned char bitCount;
    unsigned char *imageData;
};

// we'll force RGBA for now
struct BitMapObject {
    std::string filename;
    size_t width, height;
    unsigned char *imageData;

    // fast allocation!
    static void* operator new(size_t n){
        void *mem = tlsf_malloc(n);
        if (mem){
            return mem;
        }
        throw std::bad_alloc {};
    }
    static void operator delete(void *p){
        tlsf_free(p);
    }
};

BitMapObject *LoadTGAFile(const char *filename);

#endif


code:
#include "Node.h"
#include "TagNode.h"

Node::Node(NodeType type) {
    nodeType = type;
}

Node::~Node() {
}

std::vector<std::string> Node::getSourceList() {
    std::vector<std::string> returnVec;

    for (std::shared_ptr<Node>& child : children) {
        auto childSrcs = child->getSourceList();
        returnVec.insert(returnVec.end(),
                         childSrcs.begin(),
                         childSrcs.end());
    }

    return returnVec;
}

std::shared_ptr<Node> Node::findTagNodeParent(std::string tag, std::shared_ptr<Node> node) {
    if (!node.get()) {
        // found root?
        return nullptr;
    }
    TagNode *tagNode = dynamic_cast<TagNode*>(node.get());
    if (tagNode) {
        if (tagNode->tag == tag) {
            return node;
        }
    }
    return Node::findTagNodeParent(tag, node->parent);
}


code:
#ifndef NODE_H
#define NODE_H

#include "../../interfaces/components/Component.h"
#include <memory>
#include <vector>
#include <functional>
#include <string>
#include <sstream>
#include <iostream>

enum class NodeType {
    ROOT,
    TAG,
    TEXT
};

class Node {
public:
    Node(NodeType type);
    virtual ~Node();
    NodeType nodeType;
    std::shared_ptr<Node> parent;
    std::vector<std::shared_ptr<Node>> children;
    std::shared_ptr<Component> component;

    static std::shared_ptr<Node> findTagNodeParent(std::string tag, std::shared_ptr<Node> node);
    virtual std::vector<std::string> getSourceList();
};

#endif


code:
#include "TagNode.h"

TagNode::TagNode() : Node(NodeType::TAG) {
}

// iterator down and extract any src attributes
std::vector<std::string> TagNode::getSourceList() {
    std::vector<std::string> returnVec;

    auto propIter = properties.find("src");
    if (propIter != properties.end()) {
        returnVec.push_back(propIter->second);
    }

    for (std::shared_ptr<Node>& child : children) {
        auto childSrcs = child->getSourceList();
        returnVec.insert(returnVec.end(),
                         childSrcs.begin(),
                         childSrcs.end());
    }

    return returnVec;
}

std::unique_ptr<std::pair<std::string, std::string>> TagNode::getTagNodeNameValue() {
    auto namePropIter = this->properties.find("name");
    if (namePropIter == this->properties.end()) {
        return nullptr;
    }
    auto valuePropIter = this->properties.find("value");
    if (valuePropIter == this->properties.end()) {
        return nullptr;
    }
    return std::make_unique<std::pair<std::string, std::string>>(namePropIter->second, valuePropIter->second);
}


code:
#ifndef TAGNODE_H
#define TAGNODE_H

#include "Node.h"
#include <map>

class TagNode : public Node {
public:
    TagNode();
    std::string tag;
    std::map<std::string, std::string> properties;

    std::vector<std::string> getSourceList() override;
    std::unique_ptr<std::pair<std::string, std::string>> getTagNodeNameValue();
};

#endif


code:
#include "TextNode.h"

TextNode::TextNode() : Node(NodeType::TEXT) {
}


code:
#ifndef TEXTNODE_H
#define TEXTNODE_H

#include "Node.h"

class TextNode : public Node {
public:
    TextNode();
    std::string text;

    std::vector<std::string> getSourceList() override { return {}; };
};

#endif


code:
#include "HTMLParser.h"
#include "../TextNode.h"
#include <algorithm>
#include <iostream>
#include <memory>

// ok=ul, not ok=li
void autoCloseTag(std::shared_ptr<Node> currentNode, std::shared_ptr<Node> rootNode, std::string ok, std::string notok) {
    // are we inside an ul? li?
    // recurse up to parent
    std::shared_ptr<Node> it = currentNode;
    //std::cout << "scanning li for unclosed lis" << std::endl;
    while(it != rootNode) {
        if (it->nodeType == NodeType::TAG) {
            TagNode *pTagNode = dynamic_cast<TagNode*>(it.get());
            if (pTagNode) {
                // tag node
                //std::cout << "scanning: " << pTagNode->tag << std::endl;
                if (pTagNode->tag == ok) {
                    // we're ok, we found UL first
                    it = rootNode; // mark done
                    break;
                }
                if (pTagNode->tag == notok) {
                    // we're not ok, we found UL first
                    //std::cout << "need to close previous LI tag" << std::endl;

                    // set our parent to be our sibling LI's parent

                    // well currentNode is us
                    if (currentNode && pTagNode->parent) {
                        // we need to remove from children
                        for(std::vector<std::shared_ptr<Node>>::iterator it2 = currentNode->parent->children.begin(); it2!=currentNode->parent->children.end(); ++it2) {
                            if (it2->get() == currentNode.get()) {
                                //std::cout << "found us in children" << std::endl;
                                it2 = currentNode->parent->children.erase(it2);
                                break;
                            }
                        }
                        // move node under new parent
                        currentNode->parent = pTagNode->parent;
                        pTagNode->parent->children.push_back(currentNode);
                    } else {
                        std::cout << "HTMLParser::Parse - currentNode or pTagNode->parent - close previous " << notok << " tag" << std::endl;
                    }

                    it = rootNode; // mark done
                    break;
                }
            }
        }
        // recurse up
        it = it->parent;
    }
    //std::cout << "scanned li for unclosed lis" << std::endl;
}

void printNode(const std::shared_ptr<Node> node, const int indent) {
    for (int i = 0; i < indent; i++) {
        std::cout << '\t';
    }

    if (node->nodeType == NodeType::ROOT) {
        std::cout << "ROOT\n" << std::endl;
    }
    else if (node->nodeType == NodeType::TAG) {
        std::cout << "TAG: " << dynamic_cast<TagNode*>(node.get())->tag << std::endl;
        for (const std::pair<std::string, std::string> property : dynamic_cast<TagNode*>(node.get())->properties) {
            for (int i = 0; i < indent; i++) {
                std::cout << '\t';
            }
            std::cout << "  " << property.first << ": " << property.second << std::endl;
        }
    }
    else if (node->nodeType == NodeType::TEXT) {
        std::cout << "TEXT: " << dynamic_cast<TextNode*>(node.get())->text << std::endl;
    }

    for (std::shared_ptr<Node> child : node->children) {
        printNode(child, indent + 1);
    }
}

std::shared_ptr<Node> HTMLParser::parse(const std::string &html) const {
    std::shared_ptr<Node> rootNode = std::make_shared<Node>(NodeType::ROOT);
    std::shared_ptr<Node> currentNode = rootNode;
    std::shared_ptr<Node> startTagLevel = rootNode;
    std::vector<unsigned int> starts;
    unsigned int cursor;
    int state = 0;
    int prependWhiteSpace = false;
    for (cursor = 0; cursor < html.length(); cursor++) { // TODO handle trying to look ahead past string
        if (state == 0) { // Outside tag
            if (html[cursor] == ' ' || html[cursor] == '\t' || html[cursor] == '\r' || html[cursor] == '\n') {
                prependWhiteSpace = true;
                continue;
            }
            else if (html[cursor] == '<') {
                // HTML comments
                if (html[cursor + 1] == '!' && html[cursor + 2] == '-'  && html[cursor + 3] == '-' ) {
                    //std::cout << "HTMLParser::Parse - starting HTML comment at " << cursor << std::endl;
                    cursor += 2; // advance cursor to end of comment start
                    state = 4;
                }
                // close tag
                else if (html[cursor + 1] == '/') {
                    // start closing tag
                    //std::cout << "HTMLParser::Parse - starting closing tag at " << html.substr(cursor, 7)  << std::endl;
                    if (currentNode && currentNode->parent) {
                      // we should snap to the level we started at (as we maybe a couple levels deep

                      // but it's the matching part of this tag
                      currentNode = currentNode->parent;
                    } else {
                      std::cout << "HTMLParser::Parse - currentNode/parent is null - close tag" << std::endl;
                    }
                    state = 1; // ignore closing tags
                }
                // these have never have a closing tag
                else if (
                    (html[cursor + 1] == 'h' && html[cursor + 2] == 'r') ||
                    (html[cursor + 1] == 'b' && html[cursor + 2] == 'r') ||
                    (html[cursor + 1] == 'w' && html[cursor + 2] == 'b' && html[cursor + 3] == 'r') ||
                    (html[cursor + 1] == 'i' && html[cursor + 2] == 'm' && html[cursor + 3] == 'g') ||
                    (html[cursor + 1] == 'l' && html[cursor + 2] == 'i' && html[cursor + 3] == 'n' && html[cursor + 4] == 'k') ||
                    (html[cursor + 1] == 'm' && html[cursor + 2] == 'e' && html[cursor + 3] == 't' && html[cursor + 4] == 'a') ||
                    (html[cursor + 1] == 'i' && html[cursor + 2] == 'n' && html[cursor + 3] == 'p' && html[cursor + 4] == 'u' && html[cursor + 5] == 't')
                    ) {
                    //std::cout << "HTMLParser::Parse - Starting single tag " << html.substr(cursor, 6)  << std::endl;
                    std::shared_ptr<TagNode> tagNode = std::make_shared<TagNode>();
                    if (currentNode) {
                        currentNode->children.push_back(tagNode);
                        tagNode->parent = currentNode;
                    } else {
                        std::cout << "HTMLParser::Parse - currentNode is null - tagNode" << std::endl;
                    }
                    currentNode = tagNode;
                    size_t closeTagPos = html.substr(cursor + 1).find(">");
                    //std::cout << "found closeTagPos at " << closeTagPos << std::endl;
                    if (closeTagPos == std::string::npos) {
                        std::cout << "HTMLParser::Parse - can't find closing tag for single tag" << std::endl;
                        cursor ++;
                    } else {
                        std::string element = html.substr(cursor, closeTagPos + 2);
                        //std::cout << "HTMLParser::Parse - creating element, tag: " << element << std::endl;
                        parseTag(element, *dynamic_cast<TagNode*>(currentNode.get()));
                        cursor += 2 + closeTagPos;
                    }

                    // drop back
                    if (currentNode && currentNode->parent) {
                        currentNode = currentNode->parent;
                    } else {
                        std::cout << "HTMLParser::Parse - currentNode/parent is null - textNode state3" << std::endl;
                    }

                    prependWhiteSpace = false;
                    state = 0;
                }
                // start tag (<bob> <bob part)
                else {
                    //std::cout << "HTMLParser::Parse - start oc tag " << html.substr(cursor, 6) << std::endl;
                    std::shared_ptr<TagNode> tagNode = std::make_shared<TagNode>();
                    if (currentNode) {
                      currentNode->children.push_back(tagNode);
                      tagNode->parent = currentNode;
                    } else {
                      std::cout << "HTMLParser::Parse - currentNode is null - tagNode" << std::endl;
                    }
                    currentNode = tagNode;
                    starts.push_back(cursor);
                    state = 2;
                }
            }
            else { // start text node
                //std::cout << "HTMLParser::Parse - start text node " << html.substr(cursor, 6) << std::endl;
                std::shared_ptr<TextNode> textNode = std::make_shared<TextNode>();
                // not sure why currentNode is null but it is
                if (currentNode) {
                  currentNode->children.push_back(textNode);
                  textNode->parent = currentNode;
                } else {
                  std::cout << "HTMLParser::Parse - currentNode is null - textNode" << std::endl;
                }
                currentNode = textNode;
                starts.push_back(cursor);
                state = 3;
            }
            cursor--;
        }
        else if (state == 1) { // Skip Over Element (used by closing tag)
            if (html[cursor] == '>') {
                //std::cout << "HTMLParser::parse - close tag: " << html.substr(starts.back(), cursor - starts.back() + 1) << std::endl;
                state = 0;
                prependWhiteSpace = false;
            }
        }
        else if (state == 4) { // HTML Comment
            if (html[cursor] == '-' && html[cursor + 1] == '-' && html[cursor + 2] == '>') {
                //std::cout << "HTMLParser::Parse - Found end HTML comment at " << html.substr(cursor, 6) << std::endl;
                state = 0;
                cursor += 2; // advance cursor to end of comment
                prependWhiteSpace = false;
            }
        }
        else if (state == 2) { // Search for end tag node
            if (html[cursor] == '>') { // end tag node
                std::string element = html.substr(starts.back(), cursor - starts.back() + 1);
                //std::cout << "HTMLParser::parse - end open tag: " << element << std::endl;
                if (element == "
") {
                    // this will close previous li before starting a new one
                    autoCloseTag(currentNode, rootNode, "ul", "li");
                    //std::cout << "scanned parents for unclosed lis" << std::endl;
                } else
                if (element == "<option>") { // FIXME: options have attributes
                    // this will close previous option before starting a new one
                    autoCloseTag(currentNode, rootNode, "select", "option");
                    //std::cout << "scanned parents for unclosed options" << std::endl;
                }
                starts.pop_back();
                parseTag(element, *dynamic_cast<TagNode*>(currentNode.get()));
                state = 0;
                prependWhiteSpace = false;
            }
        }
        else if (state == 3) { // End text node
            if (html[cursor + 1] == '<') {
                dynamic_cast<TextNode*>(currentNode.get())->text = (prependWhiteSpace?" ":"") + html.substr(starts.back(), cursor - starts.back() + 1);
                //std::cout << "HTMLParser::parse - end text node: " << html.substr(starts.back(), cursor - starts.back() + 1) << std::endl;
                starts.pop_back();
                if (currentNode && currentNode->parent) {
                  currentNode = currentNode->parent;
                } else {
                  std::cout << "HTMLParser::Parse - currentNode/parent is null - textNode state3" << std::endl;
                }
                state = 0;
                prependWhiteSpace = false;
            }
        }
    }

    //printNode(rootNode, 0);
    return rootNode;
}

void HTMLParser::parseTag(const std::string &element, TagNode &tagNode) const {
    //std::cout << "HTMLParser::parseTag - element [" << element << "]" << std::endl;
    unsigned int cursor;
    unsigned int start = 1; // skip first <
    int state = 0;
    std::string propertyKey;
    for (cursor = 0; cursor < element.length();  cursor++) {
        if (state == 0) {
            // space or end
            if (element[cursor] == ' ' || element[cursor] == '>') {
                // set our tag (type / name, i.e. h1)
                tagNode.tag = element.substr(start, cursor - start);
                // make sure our tag is lowercase
                std::transform(tagNode.tag.begin(), tagNode.tag.end(), tagNode.tag.begin(), tolower);
                start = cursor + 1;
                state = 1;
            }
        }
        else if (state == 1) { // attribute search
            if (element[cursor] == ' ') {
                start = cursor + 1;
            }
            else if (element[cursor] == '=') {
                propertyKey = element.substr(start, cursor - start);
                start = cursor + 1; // start for non quotes
                state = 2;
            }
        }
        else if (state == 2) { // after = of attribute
            if (element[cursor] == '"') {
                start = cursor + 1;
                state = 3;
            }
            else if (element[cursor] == '\'') {
                start = cursor + 1;
                state = 4;
            } else if (element[cursor] == ' ') {
                // we just probably found an end of attribute without quotes
                tagNode.properties.insert(std::pair<std::string, std::string>(propertyKey, element.substr(start, cursor - start)));
                start = cursor + 1;
                state = 1;
            }
        }
        else if (state == 3) {
            if (element[cursor] == '"') {
                // was suggested to use tagNode.properties[propertyKey] = element.substr(start, cursor - start);
                // for better readabiilty
                tagNode.properties.insert(std::pair<std::string, std::string>(propertyKey, element.substr(start, cursor - start)));
                start = cursor + 1;
                state = 1;
            }
        }
        else if (state == 4) {
            if (element[cursor] == '\'') {
                tagNode.properties.insert(std::pair<std::string, std::string>(propertyKey, element.substr(start, cursor - start)));
                start = cursor + 1;
                state = 1;
            }
        }
    }
    // 2 is attribute without quotes, 3/4 is unclosed quote
    if (state == 2 || state == 3 || state ==4) {
        // we were in an atrr=
        tagNode.properties.insert(std::pair<std::string, std::string>(propertyKey, element.substr(start, cursor - start - 1)));
    } else {
        if (state != 1) {
            // so what's ending on state 0 about (somethin about no atttributes and maybe no tag name/type)
            std::cout << "HTMLParser::parseTag ending on state " << state << std::endl;
        }
    }
}


code:
#ifndef HTMLPARSER_H
#define HTMLPARSER_H

#include "../Node.h"
#include "../TagNode.h"
#include <string>

void autoCloseTag(std::shared_ptr<Node> currentNode, std::shared_ptr<Node> rootNode, std::string ok, std::string notok);
void printNode(const std::shared_ptr<Node> node, const int indent);

class HTMLParser {
public:
    std::shared_ptr<Node> parse(const std::string &html) const;
    void parseTag(const std::string &element, TagNode &tagNode) const;
};

#endif


code:
#include "NTRMLParser.h"
#include "../TextNode.h"
#include <algorithm>
#include <iostream>
#include <memory>

std::shared_ptr<Node> NTRMLParser::parse(const std::string &ntrml) const {
    std::shared_ptr<Node> rootNode = std::make_shared<Node>(NodeType::ROOT);
    std::shared_ptr<Node> currentNode = rootNode;
    std::shared_ptr<Node> startTagLevel = rootNode;
    std::vector<unsigned int> starts;
    unsigned int cursor;
    int state = 0;
    int prependWhiteSpace = false;
    for (cursor = 0; cursor < ntrml.length(); cursor++) { // TODO handle trying to look ahead past string
        if (state == 0) { // Outside tag
            if (ntrml[cursor] == ' ' || ntrml[cursor] == '\t' || ntrml[cursor] == '\r' || ntrml[cursor] == '\n') {
                prependWhiteSpace = true;
                continue;
            }
            else if (ntrml[cursor] == '<') {
                // HTML style comments
                if (ntrml[cursor + 1] == '!' && ntrml[cursor + 2] == '-'  && ntrml[cursor + 3] == '-' ) {
                    //std::cout << "NTRMLParser::Parse - starting HTML comment at " << cursor << std::endl;
                    cursor += 3; // advance cursor to end of comment start
                    state = 4;
                }
                // close tag
                else if (ntrml[cursor + 1] == '/') {
                    // start closing tag
                    //std::cout << "NTRMLParser::Parse - starting closing tag at " << ntrml.substr(cursor, 7)  << std::endl;
                    if (currentNode && currentNode->parent) {
                      // we should snap to the level we started at (as we maybe a couple levels deep

                      // but it's the matching part of this tag
                      currentNode = currentNode->parent;
                    } else {
                      std::cout << "NTRMLParser::Parse - currentNode/parent is null - close tag" << std::endl;
                    }
                    state = 1; // ignore closing tags
                }
                // these have never have a closing tag
                else if (
                    /*(ntrml[cursor + 1] == 'h' && ntrml[cursor + 2] == 'r') ||
                    (ntrml[cursor + 1] == 'b' && ntrml[cursor + 2] == 'r') ||
                    (ntrml[cu rsor + 1] == 'w' && ntrml[cursor + 2] == 'b' && ntrml[cursor + 3] == 'r') || */
                    (ntrml[cursor + 1] == 'i' && ntrml[cursor + 2] == 'm' && ntrml[cursor + 3] == 'g') ||
                    /* (ntrml[cursor + 1] == 'l' && ntrml[cursor + 2] == 'i' && ntrml[cursor + 3] == 'n' && ntrml[cursor + 4] == 'k') ||
                    (ntrml[cursor + 1] == 'm' && ntrml[cursor + 2] == 'e' && ntrml[cursor + 3] == 't' && ntrml[cursor + 4] == 'a') || */
                    (ntrml[cursor + 1] == 'i' && ntrml[cursor + 2] == 'n' && ntrml[cursor + 3] == 'p' && ntrml[cursor + 4] == 'u' && ntrml[cursor + 5] == 't')
                    ) {
                    //std::cout << "NTRMLParser::Parse - Starting single tag " << ntrml.substr(cursor, 6)  << std::endl;
                    std::shared_ptr<TagNode> tagNode = std::make_shared<TagNode>();
                    if (currentNode) {
                        currentNode->children.push_back(tagNode);
                        tagNode->parent = currentNode;
                    } else {
                        std::cout << "NTRMLParser::Parse - currentNode is null - tagNode" << std::endl;
                    }
                    currentNode = tagNode;
                    size_t closeTagPos = ntrml.substr(cursor + 1).find(">");
                    //std::cout << "found closeTagPos at " << closeTagPos << std::endl;
                    if (closeTagPos == std::string::npos) {
                        std::cout << "NTRMLParser::Parse - can't find closing tag for single tag" << std::endl;
                        cursor ++;
                    } else {
                        std::string element = ntrml.substr(cursor, closeTagPos + 2);
                        //std::cout << "NTRMLParser::Parse - creating element, tag: " << element << std::endl;
                        parseTag(element, *dynamic_cast<TagNode*>(currentNode.get()));
                        cursor += 2 + closeTagPos;
                    }

                    // drop back
                    if (currentNode && currentNode->parent) {
                        currentNode = currentNode->parent;
                    } else {
                        std::cout << "NTRMLParser::Parse - currentNode/parent is null - textNode state3" << std::endl;
                    }

                    prependWhiteSpace = false;
                    state = 0;
                }
                // start tag (<bob> <bob part)
                else {
                    //std::cout << "NTRMLParser::Parse - start oc tag " << ntrml.substr(cursor, 6) << std::endl;
                    std::shared_ptr<TagNode> tagNode = std::make_shared<TagNode>();
                    if (currentNode) {
                      currentNode->children.push_back(tagNode);
                      tagNode->parent = currentNode;
                    } else {
                      std::cout << "NTRMLParser::Parse - currentNode is null - tagNode" << std::endl;
                    }
                    currentNode = tagNode;
                    starts.push_back(cursor);
                    state = 2;
                }
            }
            else { // start text node
                //std::cout << "NTRMLParser::Parse - start text node " << ntrml.substr(cursor, 6) << std::endl;
                std::shared_ptr<TextNode> textNode = std::make_shared<TextNode>();
                // not sure why currentNode is null but it is
                if (currentNode) {
                  currentNode->children.push_back(textNode);
                  textNode->parent = currentNode;
                } else {
                  std::cout << "NTRMLParser::Parse - currentNode is null - textNode" << std::endl;
                }
                currentNode = textNode;
                starts.push_back(cursor);
                state = 3;
            }
            cursor--;
        }
        else if (state == 1) { // Skip Over Element (used by closing tag)
            if (ntrml[cursor] == '>') {
                //std::cout << "NTRMLParser::parse - close tag: " << ntrml.substr(starts.back(), cursor - starts.back() + 1) << std::endl;
                state = 0;
                prependWhiteSpace = false;
            }
        }
        else if (state == 4) { // HTML style Comment
            if (ntrml[cursor] == '-' && ntrml[cursor + 1] == '-' && ntrml[cursor + 2] == '>') {
                //std::cout << "NTRMLParser::Parse - Found end NTRML comment at " << ntrml.substr(cursor, 6) << std::endl;
                state = 0;
                cursor += 2; // advance cursor to end of comment
                prependWhiteSpace = false;
            }
        }
        else if (state == 2) { // Search for end tag node
            if (ntrml[cursor] == '>') { // end tag node
                std::string element = ntrml.substr(starts.back(), cursor - starts.back() + 1);
                //std::cout << "NTRMLParser::parse - end open tag: " << element << std::endl;
                /*
                if (element == "
") {
                    // this will close previous li before starting a new one
                    autoCloseTag(currentNode, rootNode, "ul", "li");
                    //std::cout << "scanned parents for unclosed lis" << std::endl;
                } else
                if (element == "<option>") { // FIXME: options have attributes
                    // this will close previous option before starting a new one
                    autoCloseTag(currentNode, rootNode, "select", "option");
                    //std::cout << "scanned parents for unclosed options" << std::endl;
                }
                */
                starts.pop_back();
                parseTag(element, *dynamic_cast<TagNode*>(currentNode.get()));
                state = 0;
                prependWhiteSpace = false;
            }
        }
        else if (state == 3) { // End text node
            if (ntrml[cursor + 1] == '<') {
                dynamic_cast<TextNode*>(currentNode.get())->text = (prependWhiteSpace?" ":"") + ntrml.substr(starts.back(), cursor - starts.back() + 1);
                //std::cout << "NTRMLParser::parse - end text node: " << ntrml.substr(starts.back(), cursor - starts.back() + 1) << std::endl;
                starts.pop_back();
                if (currentNode && currentNode->parent) {
                  currentNode = currentNode->parent;
                } else {
                  std::cout << "NTRMLParser::Parse - currentNode/parent is null - textNode state3" << std::endl;
                }
                state = 0;
                prependWhiteSpace = false;
            }
        }
    }

    //printNode(rootNode, 0);
    return rootNode;
}


code:
#ifndef NTRMLPARSER_H
#define NTRMLPARSER_H

#include "../html/HTMLParser.h"

// our parseTag function is similar enough
class NTRMLParser : public HTMLParser {
public:
    std::shared_ptr<Node> parse(const std::string &ntrml) const;
};

#endif


code:
#include "scheduler.h"
#include <GLFW/glfw3.h>
#include <iostream>
#include <algorithm>
#include <stdlib.h>

std::shared_ptr<timer_handle> Scheduler::setTimeout(std::function<void()> callback, unsigned long delay) {
    double now = glfwGetTime() * 1000;
    std::shared_ptr<timer_handle> handle = std::make_shared<timer_handle>();
    handle->callback = callback;
    handle->nextAt = now + delay;
    handle->interval = 0;
    //handle->timeout = true;
    this->timers.push_back(handle);
    return handle;
}

std::shared_ptr<timer_handle> Scheduler::setInterval(std::function<void()> callback, unsigned long delay) {
    double now = glfwGetTime() * 1000;
    //std::cout << "Scheduler::setInterval at " << (int)now << std::endl;
    std::shared_ptr<timer_handle> handle = std::make_shared<timer_handle>();
    handle->callback = callback;
    handle->nextAt = now + delay;
    handle->interval = delay;
    //handle->timeout = false;
    this->timers.push_back(handle);
    //std::cout << "scheduled at " << (int)handle->nextAt << std::endl;
    return handle;
}

unsigned long Scheduler::getNext() {
    unsigned long lowest = LONG_MAX;
    double now = glfwGetTime() * 1000; // it's number of ms since start up
    //std::cout << "there are " << this->timers.size() << std::endl;
    for(std::vector<std::shared_ptr<timer_handle>>::iterator it=this->timers.begin(); it!=this->timers.end(); ++it) {
        //std::cout << "nextAt " << (int)it->get()->nextAt << " long " << (int)(now - it->get()->nextAt) << std::endl;
        //std::cout << "now " << (int)now << " - nextAt: " << (int)it->get()->nextAt << std::endl;
        int diff = it->get()->nextAt - now;
        if (diff < 0) diff = 0;
        //std::cout << "timer fires in " << diff << std::endl;
        lowest = std::min(lowest, static_cast<unsigned long>(diff));
    }
    //std::cout << "returning " << lowest << std::endl;
    return lowest;
}

bool Scheduler::fireTimer(std::shared_ptr<timer_handle> timer, double now) {
    timer->callback();
    if (!timer->interval) {
        return true;
    }
    // schedule the next one
    //std::cout << "Scheduling next timer in " << timer->interval << "+" << now << "=" << (now + timer->interval) << std::endl;
    timer->nextAt = now + timer->interval;
    return false;
}

void Scheduler::fireTimers() {
    double now = glfwGetTime() * 1000;
    size_t unfired = 0;
    int next = INT_MAX;
    for(std::vector<std::shared_ptr<timer_handle>>::iterator it=this->timers.begin(); it!=this->timers.end(); ++it) {
        // if it's the timer time to fire
        int left = abs(static_cast<int>(it->get()->nextAt - now)); // maybe remove the ABS
        if (left <= 10 || it->get()->nextAt < now) {
            // fire it, do we need to clean it up
            if (this->fireTimer(*it, now)) {
                // clean up
                it = this->timers.erase(it);
                if (it == this->timers.end()) break;
            }
        } else {
            //std::cout << "left" << left << std::endl;
            next = std::min(left, next);
            unfired++;
        }
    }
    if (unfired) {
        if (next < 10) {
            std::cout << "There are " << unfired << "/" << this->timers.size() << " unfired timers left, next at " << next << std::endl;
            std::cout << "Scheduler::fireTimers - failed" << std::endl;
        }
    }
}

bool Scheduler::clearInterval(std::shared_ptr<timer_handle> timer) {
    // find and remove it
    //it2 = std::find(this->rootComponent->children.begin(), this->rootComponent->children.end(), it->get()->selectorBox);
    std::vector<std::shared_ptr<timer_handle>>::iterator it = std::find(this->timers.begin(), this->timers.end(), timer);
    if (it != this->timers.end()) {
        //std::cout << "Clearing Interval" << std::endl;
        this->timers.erase(it);
    } else {
        std::cout << "Couldnt find timer" << std::endl;
    }
    return true;
}


code:
#ifndef SCHEDULER_H
#define SCHEDULER_H

#include <memory>
#include <vector>
#include <functional>
#include <limits.h>

class timer_handle {
public:
    unsigned long interval; // in milliseconds
    double nextAt; // timestamp in milliseconds
    //bool timeout; // replaced by interval
    std::function<void()> callback;
};

class Scheduler {
public:
    std::shared_ptr<timer_handle> setTimeout(std::function<void()> callback, unsigned long delay);
    std::shared_ptr<timer_handle> setInterval(std::function<void()> callback, unsigned long delay);
    unsigned long getNext();
    bool fireTimer(std::shared_ptr<timer_handle> timer, double now);
    void fireTimers();
    bool clearInterval(std::shared_ptr<timer_handle> timer);
    std::vector<std::shared_ptr<timer_handle>> timers;
};

#endif


code:
/*
 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
 * All rights reserved
 *
 * "THE BEER-WARE LICENSE" (Revision 42):
 * Sergey Lyubka wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.
 */

 #include <stdio.h>
 #include <assert.h>
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>

 #include "slre.h"

 enum {END, BRANCH, ANY, EXACT, ANYOF, ANYBUT, OPEN, CLOSE, BOL, EOL,
     STAR, PLUS, STARQ, PLUSQ, QUEST, SPACE, NONSPACE, DIGIT};

 static struct {
     const char	*name;
     int		narg;
     const char	*flags;
 } opcodes[] = {
     {"END",		0, ""},		/* End of code block or program	*/
     {"BRANCH",	2, "oo"},	/* Alternative operator, "|"	*/
     {"ANY",		0, ""},		/* Match any character, "."	*/
     {"EXACT",	2, "d"},	/* Match exact string		*/
     {"ANYOF",	2, "D"},	/* Match any from set, "[]"	*/
     {"ANYBUT",	2, "D"},	/* Match any but from set, "[^]"*/
     {"OPEN ",	1, "i"},	/* Capture start, "("		*/
     {"CLOSE",	1, "i"},	/* Capture end, ")"		*/
     {"BOL",		0, ""},		/* Beginning of string, "^"	*/
     {"EOL",		0, ""},		/* End of string, "$"		*/
     {"STAR",	1, "o"},	/* Match zero or more times "*"	*/
     {"PLUS",	1, "o"},	/* Match one or more times, "+"	*/
     {"STARQ",	1, "o"},	/* Non-greedy STAR,  "*?"	*/
     {"PLUSQ",	1, "o"},	/* Non-greedy PLUS, "+?"	*/
     {"QUEST",	1, "o"},	/* Match zero or one time, "?"	*/
     {"SPACE",	0, ""},		/* Match whitespace, "\s"	*/
     {"NONSPACE",	0, ""},		/* Match non-space, "\S"	*/
     {"DIGIT",	0, ""}		/* Match digit, "\d"		*/
 };

 /*
  * Commands and operands are all unsigned char (1 byte long). All code offsets
  * are relative to current address, and positive (always point forward). Data
  * offsets are absolute. Commands with operands:
  *
  * BRANCH offset1 offset2
  *	Try to match the code block that follows the BRANCH instruction
  *	(code block ends with END). If no match, try to match code block that
  *	starts at offset1. If either of these match, jump to offset2.
  *
  * EXACT data_offset data_length
  *	Try to match exact string. String is recorded in data section from
  *	data_offset, and has length data_length.
  *
  * OPEN capture_number
  * CLOSE capture_number
  *	If the user have passed 'struct cap' array for captures, OPEN
  *	records the beginning of the matched substring (cap->ptr), CLOSE
  *	sets the length (cap->len) for respective capture_number.
  *
  * STAR code_offset
  * PLUS code_offset
  * QUEST code_offset
  *	*, +, ?, respectively. Try to gobble as much as possible from the
  *	matched buffer, until code block that follows these instructions
  *	matches. When the longest possible string is matched,
  *	jump to code_offset
  *
  * STARQ, PLUSQ are non-greedy versions of STAR and PLUS.
  */

 static const char *meta_chars = "|.^$*+?()[\\";

 static void
 print_character_set(FILE *fp, const unsigned char *p, int len)
 {
     int	i;

     for (i = 0; i < len; i++) {
         if (i > 0)
             (void) fputc(',', fp);
         if (p[i] == 0) {
             i++;
             if (p[i] == 0)
                 (void) fprintf(fp, "\\x%02x", p[i]);
             else
                 (void) fprintf(fp, "%s", opcodes[p[i]].name);
         } else if (isprint(p[i])) {
             (void) fputc(p[i], fp);
         } else {
             (void) fprintf(fp,"\\x%02x", p[i]);
         }
     }
 }

 void
 slre_dump(const struct slre *r, FILE *fp)
 {
     int	i, j, ch, op, pc;

     for (pc = 0; pc < r->code_size; pc++) {

         op = r->code[pc];
         (void) fprintf(fp, "%3d %s ", pc, opcodes[op].name);

         for (i = 0; opcodes[op].flags[i] != '\0'; i++)
             switch (opcodes[op].flags[i]) {
             case 'i':
                 (void) fprintf(fp, "%d ", r->code[pc + 1]);
                 pc++;
                 break;
             case 'o':
                 (void) fprintf(fp, "%d ",
                     pc + r->code[pc + 1] - i);
                 pc++;
                 break;
             case 'D':
                 print_character_set(fp, r->data +
                     r->code[pc + 1], r->code[pc + 2]);
                 pc += 2;
                 break;
             case 'd':
                 (void) fputc('"', fp);
                 for (j = 0; j < r->code[pc + 2]; j++) {
                     ch = r->data[r->code[pc + 1] + j];
                     if (isprint(ch))
                         (void) fputc(ch, fp);
                     else
                         (void) fprintf(fp,"\\x%02x",ch);
                 }
                 (void) fputc('"', fp);
                 pc += 2;
                 break;
             }

         (void) fputc('\n', fp);
     }
 }

 static void
 set_jump_offset(struct slre *r, int pc, int offset)
 {
     assert(offset < r->code_size);

     if (r->code_size - offset > 0xff) {
         r->err_str = "Jump offset is too big";
     } else {
         r->code[pc] = (unsigned char) (r->code_size - offset);
     }
 }

 static void
 emit(struct slre *r, int code)
 {
     if (r->code_size >= (int) (sizeof(r->code) / sizeof(r->code[0])))
         r->err_str = "RE is too long (code overflow)";
     else
         r->code[r->code_size++] = (unsigned char) code;
 }

 static void
 store_char_in_data(struct slre *r, int ch)
 {
     if (r->data_size >= (int) sizeof(r->data))
         r->err_str = "RE is too long (data overflow)";
     else
         r->data[r->data_size++] = ch;
 }

 static void
 exact(struct slre *r, const char **re)
 {
     int	old_data_size = r->data_size;

     while (**re != '\0' && (strchr(meta_chars, **re)) == NULL)
         store_char_in_data(r, *(*re)++);

     emit(r, EXACT);
     emit(r, old_data_size);
     emit(r, r->data_size - old_data_size);
 }

 static int
 get_escape_char(const char **re)
 {
     int	res;

     switch (*(*re)++) {
     case 'n':	res = '\n';		break;
     case 'r':	res = '\r';		break;
     case 't':	res = '\t';		break;
     case '0':	res = 0;		break;
     case 'S':	res = NONSPACE << 8;	break;
     case 's':	res = SPACE << 8;	break;
     case 'd':	res = DIGIT << 8;	break;
     default:	res = (*re)[-1];	break;
     }

     return (res);
 }

 static void
 anyof(struct slre *r, const char **re)
 {
     int	esc, old_data_size = r->data_size, op = ANYOF;

     if (**re == '^') {
         op = ANYBUT;
         (*re)++;
     }

     while (**re != '\0')

         switch (*(*re)++) {
         case ']':
             emit(r, op);
             emit(r, old_data_size);
             emit(r, r->data_size - old_data_size);
             return;
             /* NOTREACHED */
             break;
         case '\\':
             esc = get_escape_char(re);
             if ((esc & 0xff) == 0) {
                 store_char_in_data(r, 0);
                 store_char_in_data(r, esc >> 8);
             } else {
                 store_char_in_data(r, esc);
             }
             break;
         default:
             store_char_in_data(r, (*re)[-1]);
             break;
         }

     r->err_str = "No closing ']' bracket";
 }

 static void
 relocate(struct slre *r, int begin, int shift)
 {
     emit(r, END);
     memmove(r->code + begin + shift, r->code + begin, r->code_size - begin);
     r->code_size += shift;
 }

 static void
 quantifier(struct slre *r, int prev, int op)
 {
     if (r->code[prev] == EXACT && r->code[prev + 2] > 1) {
         r->code[prev + 2]--;
         emit(r, EXACT);
         emit(r, r->code[prev + 1] + r->code[prev + 2]);
         emit(r, 1);
         prev = r->code_size - 3;
     }
     relocate(r, prev, 2);
     r->code[prev] = op;
     set_jump_offset(r, prev + 1, prev);
 }

 static void
 exact_one_char(struct slre *r, int ch)
 {
     emit(r, EXACT);
     emit(r, r->data_size);
     emit(r, 1);
     store_char_in_data(r, ch);
 }

 static void
 fixup_branch(struct slre *r, int fixup)
 {
     if (fixup > 0) {
         emit(r, END);
         set_jump_offset(r, fixup, fixup - 2);
     }
 }

 static void
 compile(struct slre *r, const char **re)
 {
     int	op, esc, branch_start, last_op, fixup, cap_no, level;

     fixup = 0;
     level = r->num_caps;
     branch_start = last_op = r->code_size;

     for (;;)
         switch (*(*re)++) {
         case '\0':
             (*re)--;
             return;
             /* NOTREACHED */
             break;
         case '^':
             emit(r, BOL);
             break;
         case '$':
             emit(r, EOL);
             break;
         case '.':
             last_op = r->code_size;
             emit(r, ANY);
             break;
         case '[':
             last_op = r->code_size;
             anyof(r, re);
             break;
         case '\\':
             last_op = r->code_size;
             esc = get_escape_char(re);
             if (esc & 0xff00) {
                 emit(r, esc >> 8);
             } else {
                 exact_one_char(r, esc);
             }
             break;
         case '(':
             last_op = r->code_size;
             cap_no = ++r->num_caps;
             emit(r, OPEN);
             emit(r, cap_no);

             compile(r, re);
             if (*(*re)++ != ')') {
                 r->err_str = "No closing bracket";
                 return;
             }

             emit(r, CLOSE);
             emit(r, cap_no);
             break;
         case ')':
             (*re)--;
             fixup_branch(r, fixup);
             if (level == 0) {
                 r->err_str = "Unbalanced brackets";
                 return;
             }
             return;
             /* NOTREACHED */
             break;
         case '+':
         case '*':
             op = (*re)[-1] == '*' ? STAR: PLUS;
             if (**re == '?') {
                 (*re)++;
                 op = op == STAR ? STARQ : PLUSQ;
             }
             quantifier(r, last_op, op);
             break;
         case '?':
             quantifier(r, last_op, QUEST);
             break;
         case '|':
             fixup_branch(r, fixup);
             relocate(r, branch_start, 3);
             r->code[branch_start] = BRANCH;
             set_jump_offset(r, branch_start + 1, branch_start);
             fixup = branch_start + 2;
             r->code[fixup] = 0xff;
             break;
         default:
             (*re)--;
             last_op = r->code_size;
             exact(r, re);
             break;
         }
 }

 int
 slre_compile(struct slre *r, const char *re)
 {
     r->err_str = NULL;
     r->code_size = r->data_size = r->num_caps = r->anchored = 0;

     if (*re == '^')
         r->anchored++;

     emit(r, OPEN);	/* This will capture what matches full RE */
     emit(r, 0);

     while (*re != '\0')
         compile(r, &re);

     if (r->code[2] == BRANCH)
         fixup_branch(r, 4);

     emit(r, CLOSE);
     emit(r, 0);
     emit(r, END);

     return (r->err_str == NULL ? 1 : 0);
 }

 static int match(const struct slre *, int,
         const char *, int, int *, struct cap *);

 static void
 loop_greedy(const struct slre *r, int pc, const char *s, int len, int *ofs)
 {
     int	saved_offset, matched_offset;

     saved_offset = matched_offset = *ofs;

     while (match(r, pc + 2, s, len, ofs, NULL)) {
         saved_offset = *ofs;
         if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL))
             matched_offset = saved_offset;
         *ofs = saved_offset;
     }

     *ofs = matched_offset;
 }

 static void
 loop_non_greedy(const struct slre *r, int pc, const char *s,int len, int *ofs)
 {
     int	saved_offset = *ofs;

     while (match(r, pc + 2, s, len, ofs, NULL)) {
         saved_offset = *ofs;
         if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL))
             break;
     }

     *ofs = saved_offset;
 }

 static int
 is_any_of(const unsigned char *p, int len, const char *s, int *ofs)
 {
     int	i, ch;

     ch = s[*ofs];

     for (i = 0; i < len; i++)
         if (p[i] == ch) {
             (*ofs)++;
             return (1);
         }

     return (0);
 }

 static int
 is_any_but(const unsigned char *p, int len, const char *s, int *ofs)
 {
     int	i, ch;

     ch = s[*ofs];

     for (i = 0; i < len; i++)
         if (p[i] == ch)
             return (0);

     (*ofs)++;
     return (1);
 }

 static int
 match(const struct slre *r, int pc, const char *s, int len,
         int *ofs, struct cap *caps)
 {
     int	n, saved_offset, res = 1;

     while (res && r->code[pc] != END) {

         assert(pc < r->code_size);
         assert(pc < (int) (sizeof(r->code) / sizeof(r->code[0])));

         switch (r->code[pc]) {
         case BRANCH:
             saved_offset = *ofs;
             res = match(r, pc + 3, s, len, ofs, caps);
             if (res == 0) {
                 *ofs = saved_offset;
                 res = match(r, pc + r->code[pc + 1],
                     s, len, ofs, caps);
             }
             pc += r->code[pc + 2];
             break;
         case EXACT:
             res = 0;
             n = r->code[pc + 2];	/* String length */
             if (n <= len - *ofs && !memcmp(s + *ofs, r->data +
                 r->code[pc + 1], n)) {
                 (*ofs) += n;
                 res = 1;
             }
             pc += 3;
             break;
         case QUEST:
             res = 1;
             saved_offset = *ofs;
             if (!match(r, pc + 2, s, len, ofs, caps))
                 *ofs = saved_offset;
             pc += r->code[pc + 1];
             break;
         case STAR:
             res = 1;
             loop_greedy(r, pc, s, len, ofs);
             pc += r->code[pc + 1];
             break;
         case STARQ:
             res = 1;
             loop_non_greedy(r, pc, s, len, ofs);
             pc += r->code[pc + 1];
             break;
         case PLUS:
             if ((res = match(r, pc + 2, s, len, ofs, caps)) == 0)
                 break;

             loop_greedy(r, pc, s, len, ofs);
             pc += r->code[pc + 1];
             break;
         case PLUSQ:
             if ((res = match(r, pc + 2, s, len, ofs, caps)) == 0)
                 break;

             loop_non_greedy(r, pc, s, len, ofs);
             pc += r->code[pc + 1];
             break;
         case SPACE:
             res = 0;
             if (*ofs < len && isspace(((unsigned char *)s)[*ofs])) {
                 (*ofs)++;
                 res = 1;
             }
             pc++;
             break;
         case NONSPACE:
             res = 0;
             if (*ofs <len && !isspace(((unsigned char *)s)[*ofs])) {
                 (*ofs)++;
                 res = 1;
             }
             pc++;
             break;
         case DIGIT:
             res = 0;
             if (*ofs < len && isdigit(((unsigned char *)s)[*ofs])) {
                 (*ofs)++;
                 res = 1;
             }
             pc++;
             break;
         case ANY:
             res = 0;
             if (*ofs < len) {
                 (*ofs)++;
                 res = 1;
             }
             pc++;
             break;
         case ANYOF:
             res = 0;
             if (*ofs < len)
                 res = is_any_of(r->data + r->code[pc + 1],
                     r->code[pc + 2], s, ofs);
             pc += 3;
             break;
         case ANYBUT:
             res = 0;
             if (*ofs < len)
                 res = is_any_but(r->data + r->code[pc + 1],
                     r->code[pc + 2], s, ofs);
             pc += 3;
             break;
         case BOL:
             res = *ofs == 0 ? 1 : 0;
             pc++;
             break;
         case EOL:
             res = *ofs == len ? 1 : 0;
             pc++;
             break;
         case OPEN:
             if (caps != NULL)
                 caps[r->code[pc + 1]].ptr = s + *ofs;
             pc += 2;
             break;
         case CLOSE:
             if (caps != NULL)
                 caps[r->code[pc + 1]].len = (s + *ofs) -
                     caps[r->code[pc + 1]].ptr;
             pc += 2;
             break;
         case END:
             pc++;
             break;
         default:
             printf("unknown cmd (%d) at %d\n", r->code[pc], pc);
             assert(0);
             break;
         }
     }

     return (res);
 }

 int
 slre_match(const struct slre *r, const char *buf, int len,
         struct cap *caps)
 {
     int	i, ofs = 0, res = 0;

     if (r->anchored) {
         res = match(r, 0, buf, len, &ofs, caps);
     } else {
         for (i = 0; i < len && res == 0; i++) {
             ofs = i;
             res = match(r, 0, buf, len, &ofs, caps);
         }
     }

     return (res);
 }

 #ifdef TEST
 int main(int argc, char *argv[])
 {
     struct slre	slre;
     struct cap	caps[20];
     char		data[1 * 1024 * 1024];
     FILE		*fp;
     int		i, count, res, len;

     if (argc < 3) {
         printf("Usage: %s 'slre' <file> [count]\n", argv[0]);
     } else if ((fp = fopen(argv[2], "rb")) == NULL) {
         printf("Error: cannot open %s:%s\n", argv[2], strerror(errno));
     } else if (!slre_compile(&slre, argv[1])) {
         printf("Error compiling slre: %s\n", slre.err_str);
     } else {
         slre_dump(&slre, stderr);

         (void) memset(caps, 0, sizeof(caps));

         /* Read first 128K of file */
         len = fread(data, 1, sizeof(data), fp);
         (void) fclose(fp);

         res = 0;
         count = argc > 3 ? atoi(argv[3]) : 1;
         for (i = 0; i < count; i++)
             res = slre_match(&slre, data, len, caps);

         printf("Result: %d\n", res);

         for (i = 0; i < 20; i++)
             if (caps[i].len > 0)
                 printf("Substring %d: [%.*s]\n", i,
                     caps[i].len, caps[i].ptr);
     }

     return (0);
 }
 #endif /* TEST */


code:
/*
 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
 * All rights reserved
 *
 * "THE BEER-WARE LICENSE" (Revision 42):
 * Sergey Lyubka wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.
 */

/*
 * This is a regular expression library that implements a subset of Perl RE.
 * Please refer to http://slre.sourceforge.net for detailed description.
 *
 * Usage example (parsing HTTP request):
 *
 * struct slre	slre;
 * struct cap	captures[4 + 1];  // Number of braket pairs + 1
 * ...
 *
 * slre_compile(&slre,"^(GET|POST) (\S+) HTTP/(\S+?)\r\n");
 *
 * if (slre_match(&slre, buf, len, captures)) {
 *	printf("Request line length: %d\n", captures[0].len);
 *	printf("Method: %.*s\n", captures[1].len, captures[1].ptr);
 *	printf("URI: %.*s\n", captures[2].len, captures[2].ptr);
 * }
 *
 * Supported syntax:
 *	^		Match beginning of a buffer
 *	$		Match end of a buffer
 *	()		Grouping and substring capturing
 *	[...]		Match any character from set
 *	[^...]		Match any character but ones from set
 *	\s		Match whitespace
 *	\S		Match non-whitespace
 *	\d		Match decimal digit
 *	\r		Match carriage return
 *	\n		Match newline
 *	+		Match one or more times (greedy)
 *	+?		Match one or more times (non-greedy)
 *	*		Match zero or more times (greedy)
 *	*?		Match zero or more times (non-greedy)
 *	?		Match zero or once
 *	\xDD		Match byte with hex value 0xDD
 *	\meta		Match one of the meta character: ^$().[*+?\
 */

#ifndef SLRE_HEADER_DEFINED
#define	SLRE_HEADER_DEFINED

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Compiled regular expression
 */
struct slre {
	unsigned char	code[256];
	unsigned char	data[256];
	int		code_size;
	int		data_size;
	int		num_caps;	/* Number of bracket pairs	*/
	int		anchored;	/* Must match from string start	*/
	const char	*err_str;	/* Error string			*/
};

/*
 * Captured substring
 */
struct cap {
	const char	*ptr;		/* Pointer to the substring	*/
	int		len;		/* Substring length		*/
};

/*
 * Compile regular expression. If success, 1 is returned.
 * If error, 0 is returned and slre.err_str points to the error message.
 */
int slre_compile(struct slre *, const char *re);

/*
 * Return 1 if match, 0 if no match.
 * If `captured_substrings' array is not NULL, then it is filled with the
 * values of captured substrings. captured_substrings[0] element is always
 * a full matched substring. The round bracket captures start from
 * captured_substrings[1].
 * It is assumed that the size of captured_substrings array is enough to
 * hold all captures. The caller function must make sure it is! So, the
 * array_size = number_of_round_bracket_pairs + 1
 */
int slre_match(const struct slre *, const char *buf, int buf_len,
    struct cap *captured_substrings);

#ifdef __cplusplus
}
#endif

#endif /* SLRE_HEADER_DEFINED */


code:
#ifndef _TARGET_H_
#define _TARGET_H_

#include <pthread.h>

#define TLSF_MLOCK_T            pthread_mutex_t
#define TLSF_CREATE_LOCK(l)     pthread_mutex_init (l, NULL)
#define TLSF_DESTROY_LOCK(l)    pthread_mutex_destroy(l)
#define TLSF_ACQUIRE_LOCK(l)    pthread_mutex_lock(l)
#define TLSF_RELEASE_LOCK(l)    pthread_mutex_unlock(l)

#endif


code:
/* Heap management routines for NetRunner on Windows NT.

This file was taken from GNU Emacs.
Copyright (C) 1994, 2001, 2002, 2003, 2004, 2005,
2006, 2007, 2008, 2009  Free Software Foundation, Inc.
*/

#ifndef NTHEAP_H_
#define NTHEAP_H_

#include <windows.h>

#define ROUND_UP(p, align)   (((DWORD)(p) + (align)-1) & ~((align)-1))
#define ROUND_DOWN(p, align) ((DWORD)(p) & ~((align)-1))

/*
 * Heap related stuff.
 */
#define get_reserved_heap_size()    reserved_heap_size
#define get_committed_heap_size()   (get_data_end () - get_data_start ())
#define get_heap_start()        get_data_start ()
#define get_heap_end()          get_data_end ()
#define get_page_size()         nt_sysinfo.dwPageSize
#define get_allocation_unit()       nt_sysinfo.dwAllocationGranularity
#define get_processor_type()        nt_sysinfo.dwProcessorType
#define get_w32_major_version()     nt_major_version
#define get_w32_minor_version()     nt_minor_version

extern unsigned char *get_data_start();
extern unsigned char *get_data_end();
extern unsigned long  reserved_heap_size;
extern SYSTEM_INFO    nt_sysinfo;
extern OSVERSIONINFO  nt_apilevel;
extern BOOL           using_dynamic_heap;
extern int            nt_major_version;
extern int            nt_minor_version;
extern int            nt_build_number;

enum {
  OS_WIN95 = 1, // cus someone demanded Win32s support, arrrgh (yes, this is a C99 compliant comment)
  OS_NT
};

extern int os_subtype;

/* Emulation of Unix sbrk().  */
extern void *sbrk (unsigned long size);

/* Initialize heap structures for sbrk on startup.  */
extern void init_heap ();

/* Round the heap to this size.  */
extern void round_heap (unsigned long size);

/* Cache system info, e.g., the NT page size.  */
extern void cache_system_info (void);

/* ----------------------------------------------------------------- */
/* Useful routines for manipulating memory-mapped files. */

typedef struct file_data {
    char          *name;
    unsigned long  size;
    HANDLE         file;
    HANDLE         file_mapping;
    unsigned char *file_base;
} file_data;

int open_input_file (file_data *p_file, char *name);
int open_output_file (file_data *p_file, char *name, unsigned long size);
void close_file_data (file_data *p_file);

/* Return pointer to section header for named section. */
IMAGE_SECTION_HEADER * find_section (char * name, IMAGE_NT_HEADERS * nt_header);

/* Return pointer to section header for section containing the given
   relative virtual address. */
IMAGE_SECTION_HEADER * rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header);

#define RVA_TO_PTR(rva) ((unsigned char *)((DWORD)(rva) + (DWORD)GetModuleHandle(NULL)))
#ifndef VALBITS
#define VALBITS (32 - 3)
#endif
#define VALMASK ((((int) 1) << VALBITS) - 1)
#endif /* NTHEAP_H_ */