<commit_before>//
//  src/main_utils/parse_list_argument.h
//  tbd
//
//  Created by inoahdev on 1/26/18.
//  Copyright © 2018 inoahdev. All rights reserved.
//

#include <cerrno>

#include "../mach-o/utils/tbd.h"

#include "../misc/current_directory.h"
#include "../misc/recurse.h"

#include "parse_list_argument.h"

#include "tbd_print_field_information.h"
#include "tbd_with_options.h"

namespace main_utils {
    bool parse_list_argument(const char *argument, int &index, int argc, const char *argv[]) noexcept {
        auto option = &argument[1];
        if (option[0] == '-') {
            option++;
        }

        if (strcmp(option, "list-architectures") == 0) {
            if (index != 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself or with a path to a mach-o file\n", argument);
                return 1;
            }

            // Two modes exist for --list-architectures, either list out the
            // architecture-info table, or list the architectures of a single
            // provided path to a mach-o file

            if (index == argc - 1) {
                auto architecture_info = macho::get_architecture_info_table();

                fputs(architecture_info->name, stdout);
                architecture_info++;

                while (architecture_info->name != nullptr) {
                    fprintf(stdout, ", %s", architecture_info->name);
                    architecture_info++;
                }
            } else {
                index++;

                // Don't allow other arguments
                // to --list-architectures

                if (index + 2 <= argc) {
                    fprintf(stderr, "Unrecognized argument: %s\n", argv[index + 1]);
                    return 1;
                }

                auto file = macho::file();
                auto path = misc::path_with_current_directory(argv[index]);

                struct stat sbuf;
                if (stat(path.c_str(), &sbuf) != 0) {
                    fprintf(stderr, "Failed to retrieve information on object at provided path, failing with error: %s\n", strerror(errno));
                    return 1;
                }

                if (!S_ISREG(sbuf.st_mode)) {
                    fputs("Object at provided path is not a regular file\n", stderr);
                    return 1;
                }

                switch (file.open(path.c_str())) {
                    case macho::file::open_result::ok:
                        break;

                    case macho::file::open_result::not_a_macho:
                        fputs("File at provided path is not a mach-o\n", stderr);
                        return 1;

                    case macho::file::open_result::invalid_macho:
                        fputs("File at provided path is an invalid mach-o\n", stderr);
                        return 1;

                    case macho::file::open_result::failed_to_open_stream:
                        fprintf(stderr, "Failed to open stream for file at provided path, failing with error: %s\n", strerror(errno));
                        return 1;

                    case macho::file::open_result::failed_to_retrieve_information:
                        fprintf(stderr, "Failed to retrieve information on object at provided path, failing with error: %s\n", strerror(errno));
                        return 1;

                    case macho::file::open_result::stream_seek_error:
                    case macho::file::open_result::stream_read_error:
                        fputs("Encountered an error while parsing file at provided path\n", stderr);
                        return 1;

                    case macho::file::open_result::zero_containers:
                        fputs("Mach-o file at provided path has zero architectures\n", stderr);
                        return 1;

                    case macho::file::open_result::too_many_containers:
                        fputs("Mach-o file at provided path has too many architectures for its file-size\n", stderr);
                        return 1;

                    case macho::file::open_result::containers_goes_past_end_of_file:
                        fputs("Mach-o file at provided path's architectures goes past end of file\n", stderr);
                        return 1;

                    case macho::file::open_result::overlapping_containers:
                        fputs("Mach-o file at provided path has overlapping architectures\n", stderr);
                        return 1;

                    case macho::file::open_result::invalid_container:
                        fputs("Mach-o file at provided path has an invalid architecture\n", stderr);
                        return 1;
                }

                // Store architecture names in a vector before printing
                // so we can handle any errors encountered first

                auto cndex = 0;
                auto names = std::vector<const char *>();

                for (const auto &container : file.containers) {
                    const auto container_subtype = macho::subtype_from_cputype(macho::cputype(container.header.cputype), container.header.cpusubtype);
                    if (container_subtype == macho::subtype::none) {
                        fprintf(stderr, "Unrecognized cpu-subtype for architecture at index %d\n", cndex);
                        return 1;
                    }

                    const auto architecture_info = macho::architecture_info_from_cputype(macho::cputype(container.header.cputype), container_subtype);
                    if (!architecture_info) {
                        fprintf(stderr, "Unrecognized cputype information for architecture at index %d\n", cndex);
                        return 1;
                    }

                    cndex++;
                }

                fputs(names.front(), stdout);
                for (auto iter = names.cbegin() + 1; iter != names.cend(); iter++) {
                    fprintf(stdout, ", %s", *iter);
                }
            }

            fputc('\n', stdout);
            return 0;
        } else if (strcmp(option, "list-macho-dynamic-libraries") == 0) {
            if (index != 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself or with a path to a mach-o file\n", argument);
                return 1;
            }

            // Two different modes exist for --list-macho-dynamic-libraries;
            // either recurse current-directory with default options, or
            // recurse provided director(ies) with provided options

            index++;
            if (index != argc) {
                auto paths = std::vector<std::pair<struct main_utils::tbd_with_options::options, std::string>>();
                struct main_utils::tbd_with_options::options options;

                options.recurse_directories_at_path = true;

                for (; index != argc; index++) {
                    const auto &argument = argv[index];
                    const auto &argument_front = argument[0];

                    if (argument_front == '-') {
                        auto option = &argument[1];
                        if (option[0] == '\0') {
                            fputs("Please provide a valid option\n", stderr);
                        }

                        if (option[0] == '-') {
                            option++;
                        }

                        if (strcmp(option, "dont-print-warnings") == 0) {
                            options.ignore_warnings = true;
                        } else if (strcmp(option, "r") == 0) {
                            if (index + 1 != argc) {
                                if (strcmp(argv[index + 1], "once") == 0) {
                                    index++;
                                } else if (strcmp(argv[index + 1], "all") == 0) {
                                    options.recurse_subdirectories_at_path = true;
                                    index++;
                                }
                            }
                        } else {
                            fprintf(stderr, "Unrecognized argument: %s\n", argument);
                            return 1;
                        }

                        continue;
                    }

                    auto path = misc::path_with_current_directory(argv[index]);

                    struct stat sbuf;
                    if (stat(path.c_str(), &sbuf) != 0) {
                        if (index == argc - 1) {
                            fprintf(stderr, "Failed to retrieve information on file at provided path, failing with error: %s\n", strerror(errno));
                        } else {
                            fprintf(stderr, "Failed to retrieve information on file (at path %s), failing with error: %s\n", path.c_str(), strerror(errno));
                        }

                        return 1;
                    }

                    if (!S_ISDIR(sbuf.st_mode)) {
                        if (index == argc - 1) {
                            fputs("Object at provided path is not a directory\n", stderr);
                        } else {
                            fprintf(stderr, "Object (at path %s) is not a directory\n", path.c_str());
                        }

                        return 1;
                    }

                    paths.emplace_back(options, std::move(path));
                    options.clear();
                }

                if (paths.empty()) {
                    fputs("No directories have been provided to recurse in\n", stderr);
                    return 1;
                }

                const auto &back = paths.back();
                for (const auto &pair : paths) {
                    const auto &options = pair.first;
                    const auto &path = pair.second;

                    auto recurse_options = misc::recurse::options();
                    if (!options.ignore_warnings) {
                        recurse_options.print_warnings = true;
                    }

                    if (options.recurse_subdirectories_at_path) {
                        recurse_options.recurse_subdirectories = true;
                    }

                    auto filetypes = misc::recurse::filetypes();
                    filetypes.dynamic_library = true;

                    const auto recursion_result = misc::recurse::macho_files(path.c_str(), filetypes, recurse_options, [](const macho::file &file, const std::string &path) {
                        fprintf(stderr, "%s\n", path.c_str());
                        return true;
                    });

                    switch (recursion_result) {
                        case misc::recurse::operation_result::ok:
                            break;

                        case misc::recurse::operation_result::failed_to_open_directory:
                            if (paths.size() != 1) {
                                fprintf(stderr, "Failed to open directory (at path %s), failing with error: %s\n", path.c_str(), strerror(errno));
                            } else {
                                fprintf(stderr, "Failed to open directory at provided path, failing with error: %s\n", strerror(errno));
                            }

                            break;

                        case misc::recurse::operation_result::found_no_matching_files:
                            if (options.recurse_subdirectories_at_path) {
                                if (paths.size() != 1) {
                                    fprintf(stderr, "Found no mach-o dynamic library files while recursing through directory and its sub-directories at path: %s\n", path.c_str());
                                } else {
                                    fputs("Found no mach-o dynamic library files while recursing through directory and its sub-directories at provided path\n", stderr);
                                }
                            } else {
                                if (paths.size() != 1) {
                                    fprintf(stderr, "Found no mach-o dynamic library files while recursing through directory at path: %s\n", path.c_str());
                                } else {
                                    fputs("Found no mach-o dynamic library files while recursing through directory at provided path\n", stderr);
                                }
                            }

                            break;

                        default:
                            break;
                    }

                    // Print a newline between each pair
                    if (pair != back) {
                        fputc('\n', stdout);
                    }
                }
            } else {
                auto path = misc::retrieve_current_directory();
                auto recurse_options = misc::recurse::options();

                recurse_options.print_warnings = true;
                recurse_options.recurse_subdirectories = true;

                auto filetypes = misc::recurse::filetypes();
                filetypes.dynamic_library = true;

                const auto recursion_result = misc::recurse::macho_files(path, filetypes, recurse_options, [](const macho::file &file, const std::string &path) {
                    fprintf(stderr, "%s\n", path.c_str());
                    return true;
                });

                switch (recursion_result) {
                    case misc::recurse::operation_result::ok:
                        break;

                    case misc::recurse::operation_result::failed_to_open_directory:
                        fprintf(stderr, "Failed to open directory at current-directory, failing with error: %s\n", strerror(errno));
                        break;

                    case misc::recurse::operation_result::found_no_matching_files:
                        fputs("Found no mach-o dynamic library files while recursing through directory and its sub-directories at provided path\n", stderr);
                        break;

                    default:
                        break;
                }
            }

            return 0;
        } else if (strcmp(option, "list-objc-constraint") == 0) {
            if (index != 1 || index != argc - 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself\n", argument);
                return 1;
            }

            fputs("none\nretain_release\nretain_release_or_gc\nretain_release_for_simulator\ngc\n", stderr);
            return 0;
        } else if (strcmp(option, "list-platform") == 0) {
            if (index != 1 || index != argc - 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself\n", argument);
                return 1;
            }

            main_utils::print_tbd_platforms();
            return 0;
        } else if (strcmp(option, "list-recurse") == 0) {
            if (index != 1 || index != argc - 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself\n", argument);
                return 1;
            }

            fputs("once, Recurse through all of a directory's files (default)\n", stdout);
            fputs("all,  Recurse through all of a directory's files and sub-directories\n", stdout);

            return 0;
        } else if (strcmp(option, "list-tbd-flags") == 0) {
            if (index != 1 || index != argc - 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself\n", argument);
                return 1;
            }

            fputs("flat_namespace\n", stdout);
            fputs("not_app_extension_safe\n", stdout);
            return  0;
        } else if (strcmp(option, "list-tbd-versions") == 0) {
            if (index != 1 || index != argc - 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself\n", argument);
                return 1;
            }

            main_utils::print_tbd_versions();
            return 0;
        } else {
            return false;
        }

        return true;
    }
}
<commit_msg>Fix handling of return values and errors when parsing list arguments<commit_after>//
//  src/main_utils/parse_list_argument.h
//  tbd
//
//  Created by inoahdev on 1/26/18.
//  Copyright © 2018 inoahdev. All rights reserved.
//

#include <cerrno>

#include "../mach-o/utils/tbd.h"

#include "../misc/current_directory.h"
#include "../misc/recurse.h"

#include "parse_list_argument.h"

#include "tbd_print_field_information.h"
#include "tbd_with_options.h"

namespace main_utils {
    bool parse_list_argument(const char *argument, int &index, int argc, const char *argv[]) noexcept {
        auto option = &argument[1];
        if (option[0] == '-') {
            option++;
        }

        if (strcmp(option, "list-architectures") == 0) {
            if (index != 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself or with a path to a mach-o file\n", argument);
                exit(1);
            }

            // Two modes exist for --list-architectures, either list out the
            // architecture-info table, or list the architectures of a single
            // provided path to a mach-o file

            if (index == argc - 1) {
                auto architecture_info = macho::get_architecture_info_table();

                fputs(architecture_info->name, stdout);
                architecture_info++;

                while (architecture_info->name != nullptr) {
                    fprintf(stdout, ", %s", architecture_info->name);
                    architecture_info++;
                }
            } else {
                index++;

                // Don't allow other arguments
                // to --list-architectures

                if (index + 2 <= argc) {
                    fprintf(stderr, "Unrecognized argument: %s\n", argv[index + 1]);
                    exit(1);
                }

                auto file = macho::file();
                auto path = misc::path_with_current_directory(argv[index]);

                struct stat sbuf;
                if (stat(path.c_str(), &sbuf) != 0) {
                    fprintf(stderr, "Failed to retrieve information on object at provided path, failing with error: %s\n", strerror(errno));
                    exit(1);
                }

                if (!S_ISREG(sbuf.st_mode)) {
                    fputs("Object at provided path is not a regular file\n", stderr);
                    exit(1);
                }

                switch (file.open(path.c_str())) {
                    case macho::file::open_result::ok:
                        break;

                    case macho::file::open_result::not_a_macho:
                        fputs("File at provided path is not a mach-o\n", stderr);
                        exit(1);

                    case macho::file::open_result::invalid_macho:
                        fputs("File at provided path is an invalid mach-o\n", stderr);
                        exit(1);

                    case macho::file::open_result::failed_to_open_stream:
                        fprintf(stderr, "Failed to open stream for file at provided path, failing with error: %s\n", strerror(errno));
                        exit(1);

                    case macho::file::open_result::failed_to_retrieve_information:
                        fprintf(stderr, "Failed to retrieve information on object at provided path, failing with error: %s\n", strerror(errno));
                        exit(1);

                    case macho::file::open_result::stream_seek_error:
                    case macho::file::open_result::stream_read_error:
                        fputs("Encountered an error while parsing file at provided path\n", stderr);
                        exit(1);

                    case macho::file::open_result::zero_containers:
                        fputs("Mach-o file at provided path has zero architectures\n", stderr);
                        exit(1);

                    case macho::file::open_result::too_many_containers:
                        fputs("Mach-o file at provided path has too many architectures for its file-size\n", stderr);
                        exit(1);

                    case macho::file::open_result::containers_goes_past_end_of_file:
                        fputs("Mach-o file at provided path's architectures goes past end of file\n", stderr);
                        exit(1);

                    case macho::file::open_result::overlapping_containers:
                        fputs("Mach-o file at provided path has overlapping architectures\n", stderr);
                        exit(1);

                    case macho::file::open_result::invalid_container:
                        fputs("Mach-o file at provided path has an invalid architecture\n", stderr);
                        exit(1);
                }

                // Store architecture names in a vector before printing
                // so we can handle any errors encountered first

                auto cndex = 0;
                auto names = std::vector<const char *>();

                for (const auto &container : file.containers) {
                    const auto container_subtype = macho::subtype_from_cputype(macho::cputype(container.header.cputype), container.header.cpusubtype);
                    if (container_subtype == macho::subtype::none) {
                        fprintf(stderr, "Unrecognized cpu-subtype for architecture at index %d\n", cndex);
                        exit(1);
                    }

                    const auto architecture_info = macho::architecture_info_from_cputype(macho::cputype(container.header.cputype), container_subtype);
                    if (!architecture_info) {
                        fprintf(stderr, "Unrecognized cputype information for architecture at index %d\n", cndex);
                        exit(1);
                    }

                    cndex++;
                }

                fputs(names.front(), stdout);
                for (auto iter = names.cbegin() + 1; iter != names.cend(); iter++) {
                    fprintf(stdout, ", %s", *iter);
                }
            }

            fputc('\n', stdout);
        } else if (strcmp(option, "list-macho-dynamic-libraries") == 0) {
            if (index != 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself or with a path to a mach-o file\n", argument);
                exit(1);
            }

            // Two different modes exist for --list-macho-dynamic-libraries;
            // either recurse current-directory with default options, or
            // recurse provided director(ies) with provided options

            index++;
            if (index != argc) {
                auto paths = std::vector<std::pair<struct main_utils::tbd_with_options::options, std::string>>();
                struct main_utils::tbd_with_options::options options;

                options.recurse_directories_at_path = true;

                for (; index != argc; index++) {
                    const auto &argument = argv[index];
                    const auto &argument_front = argument[0];

                    if (argument_front == '-') {
                        auto option = &argument[1];
                        if (option[0] == '\0') {
                            fputs("Please provide a valid option\n", stderr);
                        }

                        if (option[0] == '-') {
                            option++;
                        }

                        if (strcmp(option, "dont-print-warnings") == 0) {
                            options.ignore_warnings = true;
                        } else if (strcmp(option, "r") == 0) {
                            if (index + 1 != argc) {
                                if (strcmp(argv[index + 1], "once") == 0) {
                                    index++;
                                } else if (strcmp(argv[index + 1], "all") == 0) {
                                    options.recurse_subdirectories_at_path = true;
                                    index++;
                                }
                            }
                        } else {
                            fprintf(stderr, "Unrecognized argument: %s\n", argument);
                            exit(1);
                        }

                        continue;
                    }

                    auto path = misc::path_with_current_directory(argv[index]);

                    struct stat sbuf;
                    if (stat(path.c_str(), &sbuf) != 0) {
                        if (index == argc - 1) {
                            fprintf(stderr, "Failed to retrieve information on file at provided path, failing with error: %s\n", strerror(errno));
                        } else {
                            fprintf(stderr, "Failed to retrieve information on file (at path %s), failing with error: %s\n", path.c_str(), strerror(errno));
                        }

                        exit(1);
                    }

                    if (!S_ISDIR(sbuf.st_mode)) {
                        if (index == argc - 1) {
                            fputs("Object at provided path is not a directory\n", stderr);
                        } else {
                            fprintf(stderr, "Object (at path %s) is not a directory\n", path.c_str());
                        }

                        exit(1);
                    }

                    paths.emplace_back(options, std::move(path));
                    options.clear();
                }

                if (paths.empty()) {
                    fputs("No directories have been provided to recurse in\n", stderr);
                    exit(1);
                }

                const auto &back = paths.back();
                for (const auto &pair : paths) {
                    const auto &options = pair.first;
                    const auto &path = pair.second;

                    auto recurse_options = misc::recurse::options();
                    if (!options.ignore_warnings) {
                        recurse_options.print_warnings = true;
                    }

                    if (options.recurse_subdirectories_at_path) {
                        recurse_options.recurse_subdirectories = true;
                    }

                    auto filetypes = misc::recurse::filetypes();
                    filetypes.dynamic_library = true;

                    const auto recursion_result = misc::recurse::macho_files(path.c_str(), filetypes, recurse_options, [](const macho::file &file, const std::string &path) {
                        fprintf(stderr, "%s\n", path.c_str());
                        return true;
                    });

                    switch (recursion_result) {
                        case misc::recurse::operation_result::ok:
                            break;

                        case misc::recurse::operation_result::failed_to_open_directory:
                            if (paths.size() != 1) {
                                fprintf(stderr, "Failed to open directory (at path %s), failing with error: %s\n", path.c_str(), strerror(errno));
                            } else {
                                fprintf(stderr, "Failed to open directory at provided path, failing with error: %s\n", strerror(errno));
                            }

                            break;

                        case misc::recurse::operation_result::found_no_matching_files:
                            if (options.recurse_subdirectories_at_path) {
                                if (paths.size() != 1) {
                                    fprintf(stderr, "Found no mach-o dynamic library files while recursing through directory and its sub-directories at path: %s\n", path.c_str());
                                } else {
                                    fputs("Found no mach-o dynamic library files while recursing through directory and its sub-directories at provided path\n", stderr);
                                }
                            } else {
                                if (paths.size() != 1) {
                                    fprintf(stderr, "Found no mach-o dynamic library files while recursing through directory at path: %s\n", path.c_str());
                                } else {
                                    fputs("Found no mach-o dynamic library files while recursing through directory at provided path\n", stderr);
                                }
                            }

                            break;

                        default:
                            break;
                    }

                    // Print a newline between each pair
                    if (pair != back) {
                        fputc('\n', stdout);
                    }
                }
            } else {
                auto path = misc::retrieve_current_directory();
                auto recurse_options = misc::recurse::options();

                recurse_options.print_warnings = true;
                recurse_options.recurse_subdirectories = true;

                auto filetypes = misc::recurse::filetypes();
                filetypes.dynamic_library = true;

                const auto recursion_result = misc::recurse::macho_files(path, filetypes, recurse_options, [](const macho::file &file, const std::string &path) {
                    fprintf(stderr, "%s\n", path.c_str());
                    return true;
                });

                switch (recursion_result) {
                    case misc::recurse::operation_result::ok:
                        break;

                    case misc::recurse::operation_result::failed_to_open_directory:
                        fprintf(stderr, "Failed to open directory at current-directory, failing with error: %s\n", strerror(errno));
                        break;

                    case misc::recurse::operation_result::found_no_matching_files:
                        fputs("Found no mach-o dynamic library files while recursing through directory and its sub-directories at provided path\n", stderr);
                        break;

                    default:
                        break;
                }
            }
        } else if (strcmp(option, "list-objc-constraint") == 0) {
            if (index != 1 || index != argc - 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself\n", argument);
                exit(1);
            }

            fputs("none\nretain_release\nretain_release_or_gc\nretain_release_for_simulator\ngc\n", stderr);
        } else if (strcmp(option, "list-platform") == 0) {
            if (index != 1 || index != argc - 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself\n", argument);
                exit(1);
            }

            main_utils::print_tbd_platforms();
        } else if (strcmp(option, "list-recurse") == 0) {
            if (index != 1 || index != argc - 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself\n", argument);
                exit(1);
            }

            fputs("once, Recurse through all of a directory's files (default)\n", stdout);
            fputs("all,  Recurse through all of a directory's files and sub-directories\n", stdout);
        } else if (strcmp(option, "list-tbd-flags") == 0) {
            if (index != 1 || index != argc - 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself\n", argument);
                exit(1);
            }

            fputs("flat_namespace\n", stdout);
            fputs("not_app_extension_safe\n", stdout);
        } else if (strcmp(option, "list-tbd-versions") == 0) {
            if (index != 1 || index != argc - 1) {
                fprintf(stderr, "Option (%s) needs to be run by itself\n", argument);
                exit(1);
            }

            main_utils::print_tbd_versions();
        } else {
            return false;
        }

        return true;
    }
}
<|endoftext|>


<commit_before>#include "yuyvtoyuv420.h"

YUYVtoYUV420::YUYVtoYUV420(QString id, StatisticsInterface *stats,
                           std::shared_ptr<HWResourceManager> hwResources) :
      Filter(id, "YUYVtoYUV420", stats, hwResources, YUYVVIDEO, YUV420VIDEO)
{}

void YUYVtoYUV420::process()
{
  std::unique_ptr<Data> input = getInput();

  while(input)
  {
    uint32_t finalDataSize = input->width*input->height*2;
    std::unique_ptr<uchar[]> yuyv_frame(new uchar[finalDataSize]);

    yuyv2yuv420_cpu(input->data.get(), yuyv_frame.get(), input->width, input->height);

    input->type = YUYVVIDEO;
    input->data = std::move(yuyv_frame);
    input->data_size = finalDataSize;
    sendOutput(std::move(input));

    input = getInput();
  }
}

void YUYVtoYUV420::yuyv2yuv420_cpu(uint8_t* input, uint8_t* output,
                                   uint16_t width, uint16_t height)
{

}
<commit_msg>feature(Processing): Convert luma pixels from YUYV to YUV420<commit_after>#include "yuyvtoyuv420.h"

YUYVtoYUV420::YUYVtoYUV420(QString id, StatisticsInterface *stats,
                           std::shared_ptr<HWResourceManager> hwResources) :
      Filter(id, "YUYVtoYUV420", stats, hwResources, YUYVVIDEO, YUV420VIDEO)
{}

void YUYVtoYUV420::process()
{
  std::unique_ptr<Data> input = getInput();

  while(input)
  {
    uint32_t finalDataSize = input->width*input->height + input->width*input->height/2;
    std::unique_ptr<uchar[]> yuyv_frame(new uchar[finalDataSize]);

    yuyv2yuv420_cpu(input->data.get(), yuyv_frame.get(), input->width, input->height);

    input->type = YUYVVIDEO;
    input->data = std::move(yuyv_frame);
    input->data_size = finalDataSize;
    sendOutput(std::move(input));

    input = getInput();
  }
}

void YUYVtoYUV420::yuyv2yuv420_cpu(uint8_t* input, uint8_t* output,
                                   uint16_t width, uint16_t height)
{
  // Luma pixels
  for(int i = 0; i < width*height; i += 2)
  {
    output[i] = input[i*2];
    output[i + 1] = input[i*2 + 2];
  }
}
<|endoftext|>


<commit_before>#include <string>

#include <nanogui/theme.h>
#include <nanogui/widget.h>

#include "dialogwindow.h"
#include "editorgui.h"
#include "helper.h"
#include "editorwidget.h"
#include "namedobject.h"
#include "widgetfactory.h"

DialogWindow::DialogWindow(EditorGUI *screen, nanogui::Theme *theme) : nanogui::Window(screen), gui(screen) {
	using namespace nanogui;
	setTheme(theme);
	setFixedSize(Vector2i(screen->width()/2, screen->height()/2));
	setSize(Vector2i(180,240));
	setPosition(Vector2i(screen->width()/4, screen->height()/4));
	setTitle("Dialog");
	setVisible(true);
}

void DialogWindow::clear() {
	int n = childCount();
	int idx = 0;
	while (n--) {
		NamedObject *no = dynamic_cast<NamedObject *>(childAt(idx));
		EditorWidget *ew = dynamic_cast<EditorWidget*>(no);
		if (ew && ew->getRemote()) {
			ew->getRemote()->unlink(ew);
		}
		removeChild(idx);
	}
}

void DialogWindow::setStructure( Structure *s) {
	if (!s) return;

	StructureClass *sc = findClass(s->getKind());
	if (!sc) {
		std::cerr << "no structure class '" << s->getKind() << "' found\n";
		return;
	}
	if ( s->getKind() != "SCREEN" && (!sc || sc->getBase() != "SCREEN") ) return;
	clear();
	loadStructure(s);
	current_structure = s;
	gui->performLayout();
}

void DialogWindow::loadStructure(Structure *s) {
	StructureClass *sc = findClass(s->getKind());
	if (sc && (s->getKind() == "SCREEN" || sc->getBase() == "SCREEN") ) {
		if (sc && !s->getStructureDefinition())
			s->setStructureDefinition(sc);
		int pnum = 0;
		nanogui::Vector2i offset;
		nanogui::Vector2i frame_size;
		for (auto param : sc->getLocals()) {
			++pnum;
			Structure *element = param.machine;
			if (!element) {
				continue;
			}
			std::string kind = element->getKind();
			if (kind == "FRAME") {
				auto properties = element->getProperties();
				Value vx = properties.find("pos_x");
				Value vy = properties.find("pos_y");
				Value w = properties.find("width");
				Value h = properties.find("height");
				long x, y;
				if (vx.asInteger(x) && vy.asInteger(y)) {
					offset = nanogui::Vector2i(x,y);
				}
				if (w.asInteger(x) && h.asInteger(y)) {
					frame_size = nanogui::Vector2i(x, y);
					setFixedSize(frame_size);
					setSize(frame_size);

				}
				break;
			}
		}
		pnum = 0;
		for (auto param : sc->getLocals()) {
			++pnum;
			Structure *element = param.machine;
			if (!element) {
				std::cout << "Warning: no structure for parameter " << pnum << "of " << s->getName() << "\n";
				continue;
			}
			std::string kind = element->getKind();
			StructureClass *element_class = findClass(kind);

			WidgetParams params(s, this, element, gui, offset);

			if (kind == "LABEL") {
				createLabel(params);
			}
			if (kind == "IMAGE") {
				createImage(params);
			}
			if (kind == "PROGRESS") {
				createProgress(params);
			}
			if (kind == "TEXT") {
				createText(params);
			}
			else if (kind == "PLOT" || (element_class &&element_class->getBase() == "PLOT") ) {
				createPlot(params);
			}
			else if (kind == "BUTTON" || kind == "INDICATOR") {
				createButton(params);
			}
		}
	}
}

<commit_msg>automatically centre dialogs within the current window<commit_after>#include <string>

#include <nanogui/theme.h>
#include <nanogui/widget.h>

#include "dialogwindow.h"
#include "editorgui.h"
#include "helper.h"
#include "editorwidget.h"
#include "namedobject.h"
#include "widgetfactory.h"

DialogWindow::DialogWindow(EditorGUI *screen, nanogui::Theme *theme) : nanogui::Window(screen), gui(screen) {
	using namespace nanogui;
	setTheme(theme);
	setFixedSize(Vector2i(gui->width()/2, gui->height()/2));
	setSize(Vector2i(180,240));
	setPosition(Vector2i(gui->width()/4, gui->height()/4));
	setTitle("Dialog");
	setVisible(true);
}

void DialogWindow::clear() {
	int n = childCount();
	int idx = 0;
	while (n--) {
		NamedObject *no = dynamic_cast<NamedObject *>(childAt(idx));
		EditorWidget *ew = dynamic_cast<EditorWidget*>(no);
		if (ew && ew->getRemote()) {
			ew->getRemote()->unlink(ew);
		}
		removeChild(idx);
	}
}

void DialogWindow::setStructure( Structure *s) {
	if (!s) return;

	StructureClass *sc = findClass(s->getKind());
	if (!sc) {
		std::cerr << "no structure class '" << s->getKind() << "' found\n";
		return;
	}
	if ( s->getKind() != "SCREEN" && (!sc || sc->getBase() != "SCREEN") ) return;
	clear();
	loadStructure(s);
	current_structure = s;
	gui->performLayout();
}

void DialogWindow::loadStructure(Structure *s) {
	StructureClass *sc = findClass(s->getKind());
	if (sc && (s->getKind() == "SCREEN" || sc->getBase() == "SCREEN") ) {
		if (sc && !s->getStructureDefinition())
			s->setStructureDefinition(sc);
		int pnum = 0;
		nanogui::Vector2i offset;
		nanogui::Vector2i frame_size;
		for (auto param : sc->getLocals()) {
			++pnum;
			Structure *element = param.machine;
			if (!element) {
				continue;
			}
			std::string kind = element->getKind();
			if (kind == "FRAME") {
				auto properties = element->getProperties();
				Value vx = properties.find("pos_x");
				Value vy = properties.find("pos_y");
				Value w = properties.find("width");
				Value h = properties.find("height");
				long x, y;
				if (vx.asInteger(x) && vy.asInteger(y)) {
					offset = nanogui::Vector2i(x,y);
				}
				if (w.asInteger(x) && h.asInteger(y)) {
					frame_size = nanogui::Vector2i(x, y);
					setFixedSize(frame_size);
					setSize(frame_size);
					auto pos = nanogui::Vector2i((gui->width() - frame_size.x())/2, (gui->height() - frame_size.y())/2);
					setPosition(pos);

				}
				break;
			}
		}
		pnum = 0;
		for (auto param : sc->getLocals()) {
			++pnum;
			Structure *element = param.machine;
			if (!element) {
				std::cout << "Warning: no structure for parameter " << pnum << "of " << s->getName() << "\n";
				continue;
			}
			std::string kind = element->getKind();
			StructureClass *element_class = findClass(kind);

			WidgetParams params(s, this, element, gui, offset);

			if (kind == "LABEL") {
				createLabel(params);
			}
			if (kind == "IMAGE") {
				createImage(params);
			}
			if (kind == "PROGRESS") {
				createProgress(params);
			}
			if (kind == "TEXT") {
				createText(params);
			}
			else if (kind == "PLOT" || (element_class &&element_class->getBase() == "PLOT") ) {
				createPlot(params);
			}
			else if (kind == "BUTTON" || kind == "INDICATOR") {
				createButton(params);
			}
		}
	}
}

<|endoftext|>


<commit_before>/**
 * @file lars_main.cpp
 * @author Nishant Mehta
 *
 * Executable for LARS.
 */
#include <mlpack/core.hpp>

#include "lars.hpp"

PROGRAM_INFO("LARS", "An implementation of LARS: Least Angle Regression "
    "(Stagewise/laSso).  This is a stage-wise homotopy-based algorithm for "
    "L1-regularized linear regression (LASSO) and L1+L2-regularized linear "
    "regression (Elastic Net).\n"
    "\n"
    "Let X be a matrix where each row is a point and each column is a "
    "dimension, and let y be a vector of targets.\n"
    "\n"
    "The Elastic Net problem is to solve\n\n"
    "  min_beta 0.5 || X * beta - y ||_2^2 + lambda_1 ||beta||_1 +\n"
    "      0.5 lambda_2 ||beta||_2^2\n\n"
    "If lambda_1 > 0 and lambda_2 = 0, the problem is the LASSO.\n"
    "If lambda_1 > 0 and lambda_2 > 0, the problem is the Elastic Net.\n"
    "If lambda_1 = 0 and lambda_2 > 0, the problem is ridge regression.\n"
    "If lambda_1 = 0 and lambda_2 = 0, the problem is unregularized linear "
    "regression.\n"
    "\n"
    "For efficiency reasons, it is not recommended to use this algorithm with "
    "lambda_1 = 0.  In that case, use the 'linear_regression' program, which "
    "implements both unregularized linear regression and ridge regression.\n");

PARAM_STRING_REQ("input_file", "File containing covariates (X).",
    "i");
PARAM_STRING_REQ("responses_file", "File containing y "
    "(responses/observations).", "r");

PARAM_STRING("output_file", "File to save beta (linear estimator) to.", "o",
    "output.csv");

PARAM_DOUBLE("lambda1", "Regularization parameter for l1-norm penalty.", "l",
    0);
PARAM_DOUBLE("lambda2", "Regularization parameter for l2-norm penalty.", "L",
    0);
PARAM_FLAG("use_cholesky", "Use Cholesky decomposition during computation "
    "rather than explicitly computing the full Gram matrix.", "c");

using namespace arma;
using namespace std;
using namespace mlpack;
using namespace mlpack::regression;

int main(int argc, char* argv[])
{
  // Handle parameters,
  CLI::ParseCommandLine(argc, argv);

  double lambda1 = CLI::GetParam<double>("lambda1");
  double lambda2 = CLI::GetParam<double>("lambda2");
  bool useCholesky = CLI::HasParam("use_cholesky");

  // Load covariates.  We can avoid LARS transposing our data by choosing to not
  // transpose this data.
  const string matXFilename = CLI::GetParam<string>("input_file");
  mat matX;
  data::Load(matXFilename, matX, true, false);

  // Load responses.  The responses should be a one-dimensional vector, and it
  // seems more likely that these will be stored with one response per line (one
  // per row).  So we should not transpose upon loading.
  const string yFilename = CLI::GetParam<string>("responses_file");
  mat matY; // Will be a vector.
  data::Load(yFilename, matY, true, false);

  // Make sure y is oriented the right way.
  if (matY.n_rows == 1)
    matY = trans(matY);
  if (matY.n_cols > 1)
    Log::Fatal << "Only one column or row allowed in responses file!" << endl;

  if (matY.n_elem != matX.n_rows)
    Log::Fatal << "Number of responses must be equal to number of rows of X!"
        << endl;

  // Do LARS.
  LARS lars(useCholesky, lambda1, lambda2);
  vec beta;
  lars.Regress(matX, matY.unsafe_col(0), beta, false /* do not transpose */);

  const string betaFilename = CLI::GetParam<string>("output_file");
  beta.save(betaFilename, raw_ascii);
}
<commit_msg>Add option to predict values on test points.<commit_after>/**
 * @file lars_main.cpp
 * @author Nishant Mehta
 *
 * Executable for LARS.
 */
#include <mlpack/core.hpp>

#include "lars.hpp"

PROGRAM_INFO("LARS", "An implementation of LARS: Least Angle Regression "
    "(Stagewise/laSso).  This is a stage-wise homotopy-based algorithm for "
    "L1-regularized linear regression (LASSO) and L1+L2-regularized linear "
    "regression (Elastic Net).\n"
    "\n"
    "Let X be a matrix where each row is a point and each column is a "
    "dimension, and let y be a vector of targets.\n"
    "\n"
    "The Elastic Net problem is to solve\n\n"
    "  min_beta 0.5 || X * beta - y ||_2^2 + lambda_1 ||beta||_1 +\n"
    "      0.5 lambda_2 ||beta||_2^2\n\n"
    "If lambda_1 > 0 and lambda_2 = 0, the problem is the LASSO.\n"
    "If lambda_1 > 0 and lambda_2 > 0, the problem is the Elastic Net.\n"
    "If lambda_1 = 0 and lambda_2 > 0, the problem is ridge regression.\n"
    "If lambda_1 = 0 and lambda_2 = 0, the problem is unregularized linear "
    "regression.\n"
    "\n"
    "For efficiency reasons, it is not recommended to use this algorithm with "
    "lambda_1 = 0.  In that case, use the 'linear_regression' program, which "
    "implements both unregularized linear regression and ridge regression.\n");

PARAM_STRING_REQ("input_file", "File containing covariates (X).",
    "i");
PARAM_STRING_REQ("responses_file", "File containing y "
    "(responses/observations).", "r");

PARAM_STRING("output_file", "File to save beta (linear estimator) to.", "o",
    "output.csv");

PARAM_STRING("test_file", "File containing points to regress on (test points).",
    "t", "");
PARAM_STRING("output_predictions", "If --test_file is specified, this file is "
    "where the predicted responses will be saved.", "p", "predictions.csv");

PARAM_DOUBLE("lambda1", "Regularization parameter for l1-norm penalty.", "l",
    0);
PARAM_DOUBLE("lambda2", "Regularization parameter for l2-norm penalty.", "L",
    0);
PARAM_FLAG("use_cholesky", "Use Cholesky decomposition during computation "
    "rather than explicitly computing the full Gram matrix.", "c");

using namespace arma;
using namespace std;
using namespace mlpack;
using namespace mlpack::regression;

int main(int argc, char* argv[])
{
  // Handle parameters,
  CLI::ParseCommandLine(argc, argv);

  double lambda1 = CLI::GetParam<double>("lambda1");
  double lambda2 = CLI::GetParam<double>("lambda2");
  bool useCholesky = CLI::HasParam("use_cholesky");

  // Load covariates.  We can avoid LARS transposing our data by choosing to not
  // transpose this data.
  const string matXFilename = CLI::GetParam<string>("input_file");
  mat matX;
  data::Load(matXFilename, matX, true, false);

  // Load responses.  The responses should be a one-dimensional vector, and it
  // seems more likely that these will be stored with one response per line (one
  // per row).  So we should not transpose upon loading.
  const string yFilename = CLI::GetParam<string>("responses_file");
  mat matY; // Will be a vector.
  data::Load(yFilename, matY, true, false);

  // Make sure y is oriented the right way.
  if (matY.n_rows == 1)
    matY = trans(matY);
  if (matY.n_cols > 1)
    Log::Fatal << "Only one column or row allowed in responses file!" << endl;

  if (matY.n_elem != matX.n_rows)
    Log::Fatal << "Number of responses must be equal to number of rows of X!"
        << endl;

  // Do LARS.
  LARS lars(useCholesky, lambda1, lambda2);
  vec beta;
  lars.Regress(matX, matY.unsafe_col(0), beta, false /* do not transpose */);

  const string betaFilename = CLI::GetParam<string>("output_file");
  beta.save(betaFilename, raw_ascii);

  if (CLI::HasParam("test_file"))
  {
    Log::Info << "Regressing on test points." << endl;
    const string testFile = CLI::GetParam<string>("test_file");
    const string outputPredictionsFile =
        CLI::GetParam<string>("output_predictions");

    // Load test points.
    mat testPoints;
    data::Load(testFile, testPoints, true, false);

    arma::vec predictions;
    lars.Predict(testPoints.t(), predictions, false);

    // Save test predictions.  One per line, so, we need a rowvec.
    arma::rowvec predToSave = predictions.t();
    data::Save(outputPredictionsFile, predToSave);
  }
}
<|endoftext|>


<commit_before>// sdl_main.cpp

#ifdef _WIN32
#  define WINDOWS_LEAN_AND_MEAN
#  define NOMINMAX
#  include <windows.h>
#endif

#include <sstream>

#include <GL/glew.h>
#include <SDL.h>
#include <SDL_syswm.h>
#undef main

#include <glm/gtc/type_ptr.hpp>

#ifdef USE_ANTTWEAKBAR
#  include <AntTweakBar.h>
#endif

#include <stdio.h>
#include <string.h>
#include <sstream>

#include "ShaderFunctions.h"
#include "Timer.h"

Timer g_timer;
int winw = 800;
int winh = 600;

struct Shadertoy {
    GLuint prog;
    GLint uloc_iResolution;
    GLint uloc_iGlobalTime;
};

Shadertoy g_toy;

void PollEvents()
{
    SDL_Event event;
    while (SDL_PollEvent(&event))
    {
        switch(event.type)
        {
        case SDL_KEYDOWN:
        case SDL_KEYUP:
            break;

        case SDL_MOUSEBUTTONDOWN:
        case SDL_MOUSEBUTTONUP:
            break;

        case SDL_MOUSEMOTION:
            break;

        case SDL_MOUSEWHEEL:
            break;

        case SDL_WINDOWEVENT:
            break;

        case SDL_QUIT:
            exit(0);
            break;

        default:
            break;
        }
    }
}

void display()
{
    glUseProgram(g_toy.prog);
    if (g_toy.uloc_iResolution > -1) glUniform3f(g_toy.uloc_iResolution, (float)winw, (float)winh, 1.f);
    if (g_toy.uloc_iGlobalTime > -1) glUniform1f(g_toy.uloc_iGlobalTime, g_timer.seconds());
    glRecti(-1,-1,1,1);
}

int main(void)
{
    ///@todo cmd line aargs

    if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
    {
        return false;
    }

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

    int winw = 800;
    int winh = 600;

    SDL_Window* pWindow = SDL_CreateWindow(
        "kinderegg",
        100,100,
        winw, winh,
        SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);

    // thank you http://www.brandonfoltz.com/2013/12/example-using-opengl-3-0-with-sdl2-and-glew/
    SDL_GLContext glContext = SDL_GL_CreateContext(pWindow);
    if (glContext == NULL)
    {
        printf("There was an error creating the OpenGL context!\n");
        return 0;
    }

    const unsigned char *version = glGetString(GL_VERSION);
    if (version == NULL)
    {
        printf("There was an error creating the OpenGL context!\n");
        return 1;
    }

    SDL_GL_MakeCurrent(pWindow, glContext);

    // Don't forget to initialize Glew, turn glewExperimental on to
    // avoid problems fetching function pointers...
    glewExperimental = GL_TRUE;
    const GLenum l_Result = glewInit();
    if (l_Result != GLEW_OK)
    {
        exit(EXIT_FAILURE);
    }

    g_toy.prog = makeShaderByName("basic");
    g_toy.uloc_iResolution = glGetUniformLocation(g_toy.prog, "iResolution");
    g_toy.uloc_iGlobalTime = glGetUniformLocation(g_toy.prog, "iGlobalTime");

    int quit = 0;
    while (quit == 0)
    {
        PollEvents();
        display();
        SDL_GL_SwapWindow(pWindow);
    }

    SDL_GL_DeleteContext(glContext);
    SDL_DestroyWindow(pWindow);

    SDL_Quit();
}
<commit_msg>Remove some extraneous includes.<commit_after>// sdl_main.cpp

#ifdef _WIN32
#  define WINDOWS_LEAN_AND_MEAN
#  define NOMINMAX
#  include <windows.h>
#endif

#include <GL/glew.h>
#include <SDL.h>
#include <SDL_syswm.h>
#undef main

#include "ShaderFunctions.h"
#include "Timer.h"

Timer g_timer;
int winw = 800;
int winh = 600;

struct Shadertoy {
    GLuint prog;
    GLint uloc_iResolution;
    GLint uloc_iGlobalTime;
};

Shadertoy g_toy;

void PollEvents()
{
    SDL_Event event;
    while (SDL_PollEvent(&event))
    {
        switch(event.type)
        {
        case SDL_KEYDOWN:
        case SDL_KEYUP:
            break;

        case SDL_MOUSEBUTTONDOWN:
        case SDL_MOUSEBUTTONUP:
            break;

        case SDL_MOUSEMOTION:
            break;

        case SDL_MOUSEWHEEL:
            break;

        case SDL_WINDOWEVENT:
            break;

        case SDL_QUIT:
            exit(0);
            break;

        default:
            break;
        }
    }
}

void display()
{
    glUseProgram(g_toy.prog);
    if (g_toy.uloc_iResolution > -1) glUniform3f(g_toy.uloc_iResolution, (float)winw, (float)winh, 1.f);
    if (g_toy.uloc_iGlobalTime > -1) glUniform1f(g_toy.uloc_iGlobalTime, g_timer.seconds());
    glRecti(-1,-1,1,1);
}

int main(void)
{
    ///@todo cmd line aargs

    if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
    {
        return false;
    }

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

    int winw = 800;
    int winh = 600;

    SDL_Window* pWindow = SDL_CreateWindow(
        "kinderegg",
        100,100,
        winw, winh,
        SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);

    // thank you http://www.brandonfoltz.com/2013/12/example-using-opengl-3-0-with-sdl2-and-glew/
    SDL_GLContext glContext = SDL_GL_CreateContext(pWindow);
    if (glContext == NULL)
    {
        printf("There was an error creating the OpenGL context!\n");
        return 0;
    }

    const unsigned char *version = glGetString(GL_VERSION);
    if (version == NULL)
    {
        printf("There was an error creating the OpenGL context!\n");
        return 1;
    }

    SDL_GL_MakeCurrent(pWindow, glContext);

    // Don't forget to initialize Glew, turn glewExperimental on to
    // avoid problems fetching function pointers...
    glewExperimental = GL_TRUE;
    const GLenum l_Result = glewInit();
    if (l_Result != GLEW_OK)
    {
        exit(EXIT_FAILURE);
    }

    g_toy.prog = makeShaderByName("basic");
    g_toy.uloc_iResolution = glGetUniformLocation(g_toy.prog, "iResolution");
    g_toy.uloc_iGlobalTime = glGetUniformLocation(g_toy.prog, "iGlobalTime");

    int quit = 0;
    while (quit == 0)
    {
        PollEvents();
        display();
        SDL_GL_SwapWindow(pWindow);
    }

    SDL_GL_DeleteContext(glContext);
    SDL_DestroyWindow(pWindow);

    SDL_Quit();
}
<|endoftext|>


<commit_before>/*************************************************
* Startup Self Tests Source File                 *
* (C) 1999-2007 Jack Lloyd                       *
*************************************************/

#include <botan/selftest.h>
#include <botan/lookup.h>

namespace Botan {

namespace {

/*************************************************
* Perform a Known Answer Test                    *
*************************************************/
void do_kat(const std::string& in, const std::string& out,
            const std::string& algo_name, Filter* filter)
   {
   if(out.length())
      {
      Pipe pipe(new Hex_Decoder, filter, new Hex_Encoder);
      pipe.process_msg(in);

      if(out != pipe.read_all_as_string())
         throw Self_Test_Failure("FIPS-140 " + algo_name + " test");
      }
   }

/*************************************************
* Perform a KAT for a cipher                     *
*************************************************/
void cipher_kat(const std::string& in, const std::string& out,
                  const std::string& key, const std::string& iv,
                  const std::string& cipher)
   {
   do_kat(in, out, cipher, get_cipher(cipher, key, iv, ENCRYPTION));
   do_kat(out, in, cipher, get_cipher(cipher, key, iv, DECRYPTION));
   }

/*************************************************
* Perform a KAT for a cipher                     *
*************************************************/
void cipher_kat(const std::string& cipher, const std::string& key,
                  const std::string& iv, const std::string& in,
                  const std::string& ecb_out, const std::string& cbc_out,
                  const std::string& cfb_out, const std::string& ofb_out,
                  const std::string& ctr_out)
   {
   if(!have_block_cipher(cipher))
      return;

   cipher_kat(in, ecb_out, key, "", cipher + "/ECB");
   cipher_kat(in, cbc_out, key, iv, cipher + "/CBC/NoPadding");
   cipher_kat(in, cfb_out, key, iv, cipher + "/CFB");
   cipher_kat(in, ofb_out, key, iv, cipher + "/OFB");
   cipher_kat(in, ctr_out, key, iv, cipher + "/CTR-BE");
   }

/*************************************************
* Perform a KAT for a hash                       *
*************************************************/
void hash_kat(const std::string& hash, const std::string& in,
                const std::string& out)
   {
   if(!have_hash(hash))
      return;
   do_kat(in, out, hash, new Hash_Filter(hash));
   }

/*************************************************
* Perform a KAT for a MAC                        *
*************************************************/
void mac_kat(const std::string& mac, const std::string& in,
               const std::string& out, const std::string& key)
   {
   if(!have_mac(mac))
      return;
   do_kat(in, out, mac, new MAC_Filter(mac, key));
   }

}

/*************************************************
* Perform FIPS 140 Self Tests                    *
*************************************************/
bool passes_self_tests()
  {
  try {
     cipher_kat("DES", "0123456789ABCDEF", "1234567890ABCDEF",
                "4E6F77206973207468652074696D6520666F7220616C6C20",
                "3FA40E8A984D48156A271787AB8883F9893D51EC4B563B53",
                "E5C7CDDE872BF27C43E934008C389C0F683788499A7C05F6",
                "F3096249C7F46E51A69E839B1A92F78403467133898EA622",
                "F3096249C7F46E5135F24A242EEB3D3F3D6D5BE3255AF8C3",
                "F3096249C7F46E51163A8CA0FFC94C27FA2F80F480B86F75");

     cipher_kat("TripleDES",
                "385D7189A5C3D485E1370AA5D408082B5CCCCB5E19F2D90E",
                "C141B5FCCD28DC8A",
                "6E1BD7C6120947A464A6AAB293A0F89A563D8D40D3461B68",
                "64EAAD4ACBB9CEAD6C7615E7C7E4792FE587D91F20C7D2F4",
                "6235A461AFD312973E3B4F7AA7D23E34E03371F8E8C376C9",
                "E26BA806A59B0330DE40CA38E77A3E494BE2B212F6DD624B",
                "E26BA806A59B03307DE2BCC25A08BA40A8BA335F5D604C62",
                "E26BA806A59B03303C62C2EFF32D3ACDD5D5F35EBCC53371");

     cipher_kat("AES",
                "2B7E151628AED2A6ABF7158809CF4F3C",
                "000102030405060708090A0B0C0D0E0F",
                "6BC1BEE22E409F96E93D7E117393172A"
                "AE2D8A571E03AC9C9EB76FAC45AF8E51",
                "3AD77BB40D7A3660A89ECAF32466EF97"
                "F5D3D58503B9699DE785895A96FDBAAF",
                "7649ABAC8119B246CEE98E9B12E9197D"
                "5086CB9B507219EE95DB113A917678B2",
                "3B3FD92EB72DAD20333449F8E83CFB4A"
                "C8A64537A0B3A93FCDE3CDAD9F1CE58B",
                "3B3FD92EB72DAD20333449F8E83CFB4A"
                "7789508D16918F03F53C52DAC54ED825",
                "3B3FD92EB72DAD20333449F8E83CFB4A"
                "010C041999E03F36448624483E582D0E");

     hash_kat("SHA-1", "", "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709");
     hash_kat("SHA-1", "616263", "A9993E364706816ABA3E25717850C26C9CD0D89D");
     hash_kat("SHA-1",
              "6162636462636465636465666465666765666768666768696768696A"
              "68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071",
              "84983E441C3BD26EBAAE4AA1F95129E5E54670F1");

     hash_kat("SHA-256", "",
              "E3B0C44298FC1C149AFBF4C8996FB924"
              "27AE41E4649B934CA495991B7852B855");
     hash_kat("SHA-256", "616263",
              "BA7816BF8F01CFEA414140DE5DAE2223"
              "B00361A396177A9CB410FF61F20015AD");
     hash_kat("SHA-256",
              "6162636462636465636465666465666765666768666768696768696A"
              "68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071",
              "248D6A61D20638B8E5C026930C3E6039"
              "A33CE45964FF2167F6ECEDD419DB06C1");

     mac_kat("HMAC(SHA-1)", "4869205468657265",
             "B617318655057264E28BC0B6FB378C8EF146BE00",
             "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B");

     mac_kat("HMAC(SHA-256)", "4869205468657265",
             "198A607EB44BFBC69903A0F1CF2BBDC5"
             "BA0AA3F3D9AE3C1C7A3B1696A0B68CF7",
             "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B"
             "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B");
  }
  catch(std::exception& e)
     {
     printf("%s\n", e.what());
     return false;
     }

  return true;
  }

}
<commit_msg>Remove printf in catch block<commit_after>/*************************************************
* Startup Self Tests Source File                 *
* (C) 1999-2007 Jack Lloyd                       *
*************************************************/

#include <botan/selftest.h>
#include <botan/lookup.h>

namespace Botan {

namespace {

/*************************************************
* Perform a Known Answer Test                    *
*************************************************/
void do_kat(const std::string& in, const std::string& out,
            const std::string& algo_name, Filter* filter)
   {
   if(out.length())
      {
      Pipe pipe(new Hex_Decoder, filter, new Hex_Encoder);
      pipe.process_msg(in);

      if(out != pipe.read_all_as_string())
         throw Self_Test_Failure("FIPS-140 " + algo_name + " test");
      }
   }

/*************************************************
* Perform a KAT for a cipher                     *
*************************************************/
void cipher_kat(const std::string& in, const std::string& out,
                  const std::string& key, const std::string& iv,
                  const std::string& cipher)
   {
   do_kat(in, out, cipher, get_cipher(cipher, key, iv, ENCRYPTION));
   do_kat(out, in, cipher, get_cipher(cipher, key, iv, DECRYPTION));
   }

/*************************************************
* Perform a KAT for a cipher                     *
*************************************************/
void cipher_kat(const std::string& cipher, const std::string& key,
                  const std::string& iv, const std::string& in,
                  const std::string& ecb_out, const std::string& cbc_out,
                  const std::string& cfb_out, const std::string& ofb_out,
                  const std::string& ctr_out)
   {
   if(!have_block_cipher(cipher))
      return;

   cipher_kat(in, ecb_out, key, "", cipher + "/ECB");
   cipher_kat(in, cbc_out, key, iv, cipher + "/CBC/NoPadding");
   cipher_kat(in, cfb_out, key, iv, cipher + "/CFB");
   cipher_kat(in, ofb_out, key, iv, cipher + "/OFB");
   cipher_kat(in, ctr_out, key, iv, cipher + "/CTR-BE");
   }

/*************************************************
* Perform a KAT for a hash                       *
*************************************************/
void hash_kat(const std::string& hash, const std::string& in,
                const std::string& out)
   {
   if(!have_hash(hash))
      return;
   do_kat(in, out, hash, new Hash_Filter(hash));
   }

/*************************************************
* Perform a KAT for a MAC                        *
*************************************************/
void mac_kat(const std::string& mac, const std::string& in,
               const std::string& out, const std::string& key)
   {
   if(!have_mac(mac))
      return;
   do_kat(in, out, mac, new MAC_Filter(mac, key));
   }

}

/*************************************************
* Perform FIPS 140 Self Tests                    *
*************************************************/
bool passes_self_tests()
  {
  try {
     cipher_kat("DES", "0123456789ABCDEF", "1234567890ABCDEF",
                "4E6F77206973207468652074696D6520666F7220616C6C20",
                "3FA40E8A984D48156A271787AB8883F9893D51EC4B563B53",
                "E5C7CDDE872BF27C43E934008C389C0F683788499A7C05F6",
                "F3096249C7F46E51A69E839B1A92F78403467133898EA622",
                "F3096249C7F46E5135F24A242EEB3D3F3D6D5BE3255AF8C3",
                "F3096249C7F46E51163A8CA0FFC94C27FA2F80F480B86F75");

     cipher_kat("TripleDES",
                "385D7189A5C3D485E1370AA5D408082B5CCCCB5E19F2D90E",
                "C141B5FCCD28DC8A",
                "6E1BD7C6120947A464A6AAB293A0F89A563D8D40D3461B68",
                "64EAAD4ACBB9CEAD6C7615E7C7E4792FE587D91F20C7D2F4",
                "6235A461AFD312973E3B4F7AA7D23E34E03371F8E8C376C9",
                "E26BA806A59B0330DE40CA38E77A3E494BE2B212F6DD624B",
                "E26BA806A59B03307DE2BCC25A08BA40A8BA335F5D604C62",
                "E26BA806A59B03303C62C2EFF32D3ACDD5D5F35EBCC53371");

     cipher_kat("AES",
                "2B7E151628AED2A6ABF7158809CF4F3C",
                "000102030405060708090A0B0C0D0E0F",
                "6BC1BEE22E409F96E93D7E117393172A"
                "AE2D8A571E03AC9C9EB76FAC45AF8E51",
                "3AD77BB40D7A3660A89ECAF32466EF97"
                "F5D3D58503B9699DE785895A96FDBAAF",
                "7649ABAC8119B246CEE98E9B12E9197D"
                "5086CB9B507219EE95DB113A917678B2",
                "3B3FD92EB72DAD20333449F8E83CFB4A"
                "C8A64537A0B3A93FCDE3CDAD9F1CE58B",
                "3B3FD92EB72DAD20333449F8E83CFB4A"
                "7789508D16918F03F53C52DAC54ED825",
                "3B3FD92EB72DAD20333449F8E83CFB4A"
                "010C041999E03F36448624483E582D0E");

     hash_kat("SHA-1", "", "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709");
     hash_kat("SHA-1", "616263", "A9993E364706816ABA3E25717850C26C9CD0D89D");
     hash_kat("SHA-1",
              "6162636462636465636465666465666765666768666768696768696A"
              "68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071",
              "84983E441C3BD26EBAAE4AA1F95129E5E54670F1");

     hash_kat("SHA-256", "",
              "E3B0C44298FC1C149AFBF4C8996FB924"
              "27AE41E4649B934CA495991B7852B855");
     hash_kat("SHA-256", "616263",
              "BA7816BF8F01CFEA414140DE5DAE2223"
              "B00361A396177A9CB410FF61F20015AD");
     hash_kat("SHA-256",
              "6162636462636465636465666465666765666768666768696768696A"
              "68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071",
              "248D6A61D20638B8E5C026930C3E6039"
              "A33CE45964FF2167F6ECEDD419DB06C1");

     mac_kat("HMAC(SHA-1)", "4869205468657265",
             "B617318655057264E28BC0B6FB378C8EF146BE00",
             "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B");

     mac_kat("HMAC(SHA-256)", "4869205468657265",
             "198A607EB44BFBC69903A0F1CF2BBDC5"
             "BA0AA3F3D9AE3C1C7A3B1696A0B68CF7",
             "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B"
             "0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B");
  }
  catch(std::exception& e)
     {
     return false;
     }

  return true;
  }

}
<|endoftext|>


<commit_before><commit_msg>Fixed a crashbug in shutdown command<commit_after><|endoftext|>


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

#include <core/CHIPSafeCasts.h>
#include <support/CodeUtils.h>
#include <support/ErrorStr.h>
#include <support/SafeInt.h>
#include <transport/RendezvousSession.h>

#if CONFIG_DEVICE_LAYER
#include <platform/CHIPDeviceLayer.h>
#endif

#if CONFIG_NETWORK_LAYER_BLE
#include <transport/BLE.h>
#endif // CONFIG_NETWORK_LAYER_BLE

static const size_t kMax_SecureSDU_Length          = 1024;
static constexpr uint32_t kSpake2p_Iteration_Count = 50000;
static const char * kSpake2pKeyExchangeSalt        = "SPAKE2P Key Exchange Salt";

namespace chip {

enum NetworkProvisioningMsgTypes : uint8_t
{
    kWiFiAssociationRequest = 0,
    kIPAddressAssigned      = 1,
};

CHIP_ERROR RendezvousSession::Init()
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    mParams = params;
    VerifyOrExit(mDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(mParams.HasLocalNodeId(), err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(mParams.HasSetupPINCode(), err = CHIP_ERROR_INVALID_ARGUMENT);

    err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
#if CONFIG_NETWORK_LAYER_BLE
    {
        Transport::BLE * transport = new Transport::BLE();
        err                        = transport->Init(this, mParams);
        mTransport                 = transport;
        mTransport->Retain();
        transport->Release();
    }
#endif // CONFIG_NETWORK_LAYER_BLE
    SuccessOrExit(err);

    if (mParams.HasDiscriminator() == false)
    {
        err = WaitForPairing(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
#if CONFIG_DEVICE_LAYER
        DeviceLayer::PlatformMgr().AddEventHandler(ConnectivityHandler, reinterpret_cast<intptr_t>(this));
#endif
    }

exit:
    return err;
}

RendezvousSession::~RendezvousSession()
{
    if (mTransport)
    {
        mTransport->Release();
        mTransport = nullptr;
    }

    mDelegate = nullptr;
}

CHIP_ERROR RendezvousSession::SendMessage(System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = mPairingInProgress ? SendPairingMessage(msgBuf)
                                        : SendSecureMessage(Protocols::kChipProtocol_NetworkProvisioning,
                                                            NetworkProvisioningMsgTypes::kWiFiAssociationRequest, msgBuf);
    SuccessOrExit(err);

exit:
    if (err != CHIP_NO_ERROR)
    {
        mPairingInProgress ? OnPairingError(err) : OnRendezvousError(err);
    }
    return err;
}
CHIP_ERROR RendezvousSession::SendPairingMessage(System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader header;
    uint16_t headerSize = 0;

    VerifyOrExit(msgBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(msgBuf->Next() == nullptr, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);

    err = header.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);

    msgBuf->ConsumeHead(headerSize);
    err = mTransport->SendMessage(header, Header::Flags::None(), Transport::PeerAddress::BLE(), msgBuf);
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR RendezvousSession::SendSecureMessage(Protocols::CHIPProtocolId protocol, uint8_t msgType, System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    PayloadHeader payloadHeader;
    MessageAuthenticationCode mac;
    const uint16_t headerSize = payloadHeader.EncodeSizeBytes();
    uint16_t actualEncodedHeaderSize;
    uint8_t * data    = nullptr;
    uint16_t totalLen = 0;
    uint16_t taglen   = 0;

    VerifyOrExit(msgBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(msgBuf->Next() == nullptr, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    VerifyOrExit(msgBuf->TotalLength() < kMax_SecureSDU_Length, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    VerifyOrExit(CanCastTo<uint16_t>(headerSize + msgBuf->TotalLength()), err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);

    packetHeader
        .SetSourceNodeId(mParams.GetLocalNodeId())           //
        .SetMessageId(mSecureMessageIndex)                   //
        .SetEncryptionKeyID(mPairingSession.GetLocalKeyId()) //
        .SetPayloadLength(static_cast<uint16_t>(headerSize + msgBuf->TotalLength()));

    payloadHeader.SetProtocolID(protocol).SetMessageType(msgType);

    VerifyOrExit(msgBuf->EnsureReservedSize(headerSize), err = CHIP_ERROR_NO_MEMORY);

    msgBuf->SetStart(msgBuf->Start() - headerSize);
    data     = msgBuf->Start();
    totalLen = msgBuf->TotalLength();

    err = payloadHeader.Encode(data, totalLen, &actualEncodedHeaderSize);
    SuccessOrExit(err);

    err = mSecureSession.Encrypt(data, totalLen, data, packetHeader, payloadHeader.GetEncodePacketFlags(), mac);
    SuccessOrExit(err);

    err = mac.Encode(packetHeader, &data[totalLen], kMaxTagLen, &taglen);
    SuccessOrExit(err);

    VerifyOrExit(CanCastTo<uint16_t>(totalLen + taglen), err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    msgBuf->SetDataLength(static_cast<uint16_t>(totalLen + taglen));

    err = mTransport->SendMessage(packetHeader, payloadHeader.GetEncodePacketFlags(), Transport::PeerAddress::BLE(), msgBuf);
    SuccessOrExit(err);

    mSecureMessageIndex++;
    msgBuf = nullptr;

exit:
    return err;
}

void RendezvousSession::OnPairingError(CHIP_ERROR err)
{
    mPairingInProgress = false;
    mDelegate->OnRendezvousError(err);
    mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::SecurePairingFailed);
}

void RendezvousSession::OnPairingComplete()
{
    mPairingInProgress = false;

    CHIP_ERROR err = mPairingSession.DeriveSecureSession((const unsigned char *) kSpake2pI2RSessionInfo,
                                                         strlen(kSpake2pI2RSessionInfo), mSecureSession);
    VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Ble, "Failed to initialize a secure session: %s", ErrorStr(err)));

    mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::SecurePairingSuccess);
    mDelegate->OnRendezvousConnectionOpened();

exit:
    return;
}

void RendezvousSession::OnRendezvousConnectionOpened()
{
    if (mParams.HasDiscriminator())
    {
        CHIP_ERROR err = Pair(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
        VerifyOrExit(err == CHIP_NO_ERROR, OnPairingError(err));
    }

exit:
    return;
}

void RendezvousSession::OnRendezvousConnectionClosed()
{
    mDelegate->OnRendezvousConnectionClosed();

    if (!mParams.HasDiscriminator() && !mParams.HasConnectionObject())
    {
        mSecureSession.Reset();
        CHIP_ERROR err = WaitForPairing(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
        VerifyOrExit(err == CHIP_NO_ERROR, OnPairingError(err));
    }

exit:
    return;
}

void RendezvousSession::OnRendezvousError(CHIP_ERROR err)
{
    mDelegate->OnRendezvousError(err);
}

void RendezvousSession::OnRendezvousMessageReceived(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    err = mPairingInProgress ? HandlePairingMessage(msgBuf) : HandleSecureMessage(msgBuf);
    SuccessOrExit(err);

exit:
    if (err != CHIP_NO_ERROR)
    {
        mPairingInProgress ? OnPairingError(err) : OnRendezvousError(err);
    }
}

CHIP_ERROR RendezvousSession::HandlePairingMessage(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    uint16_t headerSize = 0;

    err = packetHeader.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);

    msgBuf->ConsumeHead(headerSize);

    err = mPairingSession.HandlePeerMessage(packetHeader, msgBuf);
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR RendezvousSession::HandleSecureMessage(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    PayloadHeader payloadHeader;
    MessageAuthenticationCode mac;
    uint16_t headerSize            = 0;
    uint8_t * data                 = nullptr;
    uint8_t * plainText            = nullptr;
    uint16_t len                   = 0;
    uint16_t decodedSize           = 0;
    uint16_t taglen                = 0;
    System::PacketBuffer * origMsg = nullptr;

    err = packetHeader.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);
    msgBuf->ConsumeHead(headerSize);

    headerSize = payloadHeader.EncodeSizeBytes();
    data       = msgBuf->Start();
    len        = msgBuf->TotalLength();

#if CHIP_SYSTEM_CONFIG_USE_LWIP
    /* This is a workaround for the case where PacketBuffer payload is not
       allocated as an inline buffer to PacketBuffer structure */
    origMsg = msgBuf;
    msgBuf  = PacketBuffer::NewWithAvailableSize(len);
    msgBuf->SetDataLength(len, msgBuf);
#endif
    plainText = msgBuf->Start();

    // TODO: We need length checks here!  https://github.com/project-chip/connectedhomeip/issues/2928
    err = mac.Decode(packetHeader, &data[packetHeader.GetPayloadLength()], kMaxTagLen, &taglen);
    SuccessOrExit(err);

    len = static_cast<uint16_t>(len - taglen);
    msgBuf->SetDataLength(len);

    err = mSecureSession.Decrypt(data, len, plainText, packetHeader, payloadHeader.GetEncodePacketFlags(), mac);
    SuccessOrExit(err);

    err = payloadHeader.Decode(packetHeader.GetFlags(), plainText, headerSize, &decodedSize);
    SuccessOrExit(err);
    VerifyOrExit(headerSize == decodedSize, err = CHIP_ERROR_INCORRECT_STATE);

    msgBuf->ConsumeHead(headerSize);

    if (payloadHeader.GetProtocolID() == Protocols::kChipProtocol_NetworkProvisioning &&
        payloadHeader.GetMessageType() == NetworkProvisioningMsgTypes::kIPAddressAssigned)
    {
        if (!IPAddress::FromString(Uint8::to_const_char(msgBuf->Start()), msgBuf->DataLength(), mDeviceAddress))
        {
            mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::NetworkProvisioningFailed);
            ExitNow(err = CHIP_ERROR_INVALID_ADDRESS);
        }
        mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::NetworkProvisioningSuccess);
    }
    // else .. TBD once application dependency on this message has been removed, enable the else condition
    {
        mDelegate->OnRendezvousMessageReceived(msgBuf);
    }

    msgBuf = nullptr;

exit:
    if (origMsg != nullptr)
    {
        PacketBuffer::Free(origMsg);
    }

    return err;
}

CHIP_ERROR RendezvousSession::WaitForPairing(Optional<NodeId> nodeId, uint32_t setupPINCode)
{
    mPairingInProgress = true;
    return mPairingSession.WaitForPairing(setupPINCode, kSpake2p_Iteration_Count, (const unsigned char *) kSpake2pKeyExchangeSalt,
                                          strlen(kSpake2pKeyExchangeSalt), nodeId, 0, this);
}

CHIP_ERROR RendezvousSession::Pair(Optional<NodeId> nodeId, uint32_t setupPINCode)
{
    mPairingInProgress = true;
    return mPairingSession.Pair(setupPINCode, kSpake2p_Iteration_Count, (const unsigned char *) kSpake2pKeyExchangeSalt,
                                strlen(kSpake2pKeyExchangeSalt), nodeId, mNextKeyId++, this);
}

void RendezvousSession::SendIPAddress(IPAddress & addr)
{
    CHIP_ERROR err                = CHIP_NO_ERROR;
    System::PacketBuffer * buffer = System::PacketBuffer::New();
    char * addrStr                = addr.ToString(Uint8::to_char(buffer->Start()), buffer->AvailableDataLength());

    VerifyOrExit(addrStr != nullptr, err = CHIP_ERROR_INVALID_ADDRESS);
    VerifyOrExit(mPairingInProgress == false, err = CHIP_ERROR_INCORRECT_STATE);

    buffer->SetDataLength(strlen(addrStr) + 1);

    err = SendSecureMessage(Protocols::kChipProtocol_NetworkProvisioning, NetworkProvisioningMsgTypes::kIPAddressAssigned, buffer);
    SuccessOrExit(err);

exit:
    if (CHIP_NO_ERROR != err)
    {
        OnRendezvousError(err);
        PacketBuffer::Free(buffer);
    }
}

#if CONFIG_DEVICE_LAYER
void RendezvousSession::ConnectivityHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg)
{
    RendezvousSession * session = reinterpret_cast<RendezvousSession *>(arg);

    VerifyOrExit(session != nullptr, /**/);
    VerifyOrExit(event->Type == DeviceLayer::DeviceEventType::kInternetConnectivityChange, /**/);
    VerifyOrExit(event->InternetConnectivityChange.IPv4 == DeviceLayer::kConnectivity_Established, /**/);

    IPAddress addr;
    IPAddress::FromString(event->InternetConnectivityChange.address, addr);
    session->SendIPAddress(addr);

exit:
    return;
}
#endif

} // namespace chip
<commit_msg>Fix post rebase build issues<commit_after>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <core/CHIPSafeCasts.h>
#include <support/CodeUtils.h>
#include <support/ErrorStr.h>
#include <support/SafeInt.h>
#include <transport/RendezvousSession.h>

#if CONFIG_DEVICE_LAYER
#include <platform/CHIPDeviceLayer.h>
#endif

#if CONFIG_NETWORK_LAYER_BLE
#include <transport/BLE.h>
#endif // CONFIG_NETWORK_LAYER_BLE

static const size_t kMax_SecureSDU_Length          = 1024;
static constexpr uint32_t kSpake2p_Iteration_Count = 50000;
static const char * kSpake2pKeyExchangeSalt        = "SPAKE2P Key Exchange Salt";

namespace chip {

enum NetworkProvisioningMsgTypes : uint8_t
{
    kWiFiAssociationRequest = 0,
    kIPAddressAssigned      = 1,
};

CHIP_ERROR RendezvousSession::Init(const RendezvousParameters & params)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    mParams = params;
    VerifyOrExit(mDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    VerifyOrExit(mParams.HasLocalNodeId(), err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(mParams.HasSetupPINCode(), err = CHIP_ERROR_INVALID_ARGUMENT);

    err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
#if CONFIG_NETWORK_LAYER_BLE
    {
        Transport::BLE * transport = new Transport::BLE();
        err                        = transport->Init(this, mParams);
        mTransport                 = transport;
        mTransport->Retain();
        transport->Release();
    }
#endif // CONFIG_NETWORK_LAYER_BLE
    SuccessOrExit(err);

    if (mParams.HasDiscriminator() == false)
    {
        err = WaitForPairing(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
#if CONFIG_DEVICE_LAYER
        DeviceLayer::PlatformMgr().AddEventHandler(ConnectivityHandler, reinterpret_cast<intptr_t>(this));
#endif
    }

exit:
    return err;
}

RendezvousSession::~RendezvousSession()
{
    if (mTransport)
    {
        mTransport->Release();
        mTransport = nullptr;
    }

    mDelegate = nullptr;
}

CHIP_ERROR RendezvousSession::SendMessage(System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = mPairingInProgress ? SendPairingMessage(msgBuf)
                                        : SendSecureMessage(Protocols::kChipProtocol_NetworkProvisioning,
                                                            NetworkProvisioningMsgTypes::kWiFiAssociationRequest, msgBuf);
    SuccessOrExit(err);

exit:
    if (err != CHIP_NO_ERROR)
    {
        mPairingInProgress ? OnPairingError(err) : OnRendezvousError(err);
    }
    return err;
}
CHIP_ERROR RendezvousSession::SendPairingMessage(System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader header;
    uint16_t headerSize = 0;

    VerifyOrExit(msgBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(msgBuf->Next() == nullptr, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);

    err = header.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);

    msgBuf->ConsumeHead(headerSize);
    err = mTransport->SendMessage(header, Header::Flags::None(), Transport::PeerAddress::BLE(), msgBuf);
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR RendezvousSession::SendSecureMessage(Protocols::CHIPProtocolId protocol, uint8_t msgType, System::PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    PayloadHeader payloadHeader;
    MessageAuthenticationCode mac;
    const uint16_t headerSize = payloadHeader.EncodeSizeBytes();
    uint16_t actualEncodedHeaderSize;
    uint8_t * data    = nullptr;
    uint16_t totalLen = 0;
    uint16_t taglen   = 0;

    VerifyOrExit(msgBuf != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(msgBuf->Next() == nullptr, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    VerifyOrExit(msgBuf->TotalLength() < kMax_SecureSDU_Length, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    VerifyOrExit(CanCastTo<uint16_t>(headerSize + msgBuf->TotalLength()), err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);

    packetHeader
        .SetSourceNodeId(mParams.GetLocalNodeId())           //
        .SetMessageId(mSecureMessageIndex)                   //
        .SetEncryptionKeyID(mPairingSession.GetLocalKeyId()) //
        .SetPayloadLength(static_cast<uint16_t>(headerSize + msgBuf->TotalLength()));

    payloadHeader.SetProtocolID(protocol).SetMessageType(msgType);

    VerifyOrExit(msgBuf->EnsureReservedSize(headerSize), err = CHIP_ERROR_NO_MEMORY);

    msgBuf->SetStart(msgBuf->Start() - headerSize);
    data     = msgBuf->Start();
    totalLen = msgBuf->TotalLength();

    err = payloadHeader.Encode(data, totalLen, &actualEncodedHeaderSize);
    SuccessOrExit(err);

    err = mSecureSession.Encrypt(data, totalLen, data, packetHeader, payloadHeader.GetEncodePacketFlags(), mac);
    SuccessOrExit(err);

    err = mac.Encode(packetHeader, &data[totalLen], kMaxTagLen, &taglen);
    SuccessOrExit(err);

    VerifyOrExit(CanCastTo<uint16_t>(totalLen + taglen), err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
    msgBuf->SetDataLength(static_cast<uint16_t>(totalLen + taglen));

    err = mTransport->SendMessage(packetHeader, payloadHeader.GetEncodePacketFlags(), Transport::PeerAddress::BLE(), msgBuf);
    SuccessOrExit(err);

    mSecureMessageIndex++;
    msgBuf = nullptr;

exit:
    return err;
}

void RendezvousSession::OnPairingError(CHIP_ERROR err)
{
    mPairingInProgress = false;
    mDelegate->OnRendezvousError(err);
    mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::SecurePairingFailed);
}

void RendezvousSession::OnPairingComplete()
{
    mPairingInProgress = false;

    CHIP_ERROR err = mPairingSession.DeriveSecureSession((const unsigned char *) kSpake2pI2RSessionInfo,
                                                         strlen(kSpake2pI2RSessionInfo), mSecureSession);
    VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Ble, "Failed to initialize a secure session: %s", ErrorStr(err)));

    mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::SecurePairingSuccess);
    mDelegate->OnRendezvousConnectionOpened();

exit:
    return;
}

void RendezvousSession::OnRendezvousConnectionOpened()
{
    if (mParams.HasDiscriminator())
    {
        CHIP_ERROR err = Pair(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
        VerifyOrExit(err == CHIP_NO_ERROR, OnPairingError(err));
    }

exit:
    return;
}

void RendezvousSession::OnRendezvousConnectionClosed()
{
    mDelegate->OnRendezvousConnectionClosed();

    if (!mParams.HasDiscriminator() && !mParams.HasConnectionObject())
    {
        mSecureSession.Reset();
        CHIP_ERROR err = WaitForPairing(mParams.GetLocalNodeId(), mParams.GetSetupPINCode());
        VerifyOrExit(err == CHIP_NO_ERROR, OnPairingError(err));
    }

exit:
    return;
}

void RendezvousSession::OnRendezvousError(CHIP_ERROR err)
{
    mDelegate->OnRendezvousError(err);
}

void RendezvousSession::OnRendezvousMessageReceived(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    err = mPairingInProgress ? HandlePairingMessage(msgBuf) : HandleSecureMessage(msgBuf);
    SuccessOrExit(err);

exit:
    if (err != CHIP_NO_ERROR)
    {
        mPairingInProgress ? OnPairingError(err) : OnRendezvousError(err);
    }
}

CHIP_ERROR RendezvousSession::HandlePairingMessage(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    uint16_t headerSize = 0;

    err = packetHeader.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);

    msgBuf->ConsumeHead(headerSize);

    err = mPairingSession.HandlePeerMessage(packetHeader, msgBuf);
    SuccessOrExit(err);

exit:
    return err;
}

CHIP_ERROR RendezvousSession::HandleSecureMessage(PacketBuffer * msgBuf)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PacketHeader packetHeader;
    PayloadHeader payloadHeader;
    MessageAuthenticationCode mac;
    uint16_t headerSize            = 0;
    uint8_t * data                 = nullptr;
    uint8_t * plainText            = nullptr;
    uint16_t len                   = 0;
    uint16_t decodedSize           = 0;
    uint16_t taglen                = 0;
    System::PacketBuffer * origMsg = nullptr;

    err = packetHeader.Decode(msgBuf->Start(), msgBuf->DataLength(), &headerSize);
    SuccessOrExit(err);
    msgBuf->ConsumeHead(headerSize);

    headerSize = payloadHeader.EncodeSizeBytes();
    data       = msgBuf->Start();
    len        = msgBuf->TotalLength();

#if CHIP_SYSTEM_CONFIG_USE_LWIP
    /* This is a workaround for the case where PacketBuffer payload is not
       allocated as an inline buffer to PacketBuffer structure */
    origMsg = msgBuf;
    msgBuf  = PacketBuffer::NewWithAvailableSize(len);
    msgBuf->SetDataLength(len, msgBuf);
#endif
    plainText = msgBuf->Start();

    // TODO: We need length checks here!  https://github.com/project-chip/connectedhomeip/issues/2928
    err = mac.Decode(packetHeader, &data[packetHeader.GetPayloadLength()], kMaxTagLen, &taglen);
    SuccessOrExit(err);

    len = static_cast<uint16_t>(len - taglen);
    msgBuf->SetDataLength(len);

    err = mSecureSession.Decrypt(data, len, plainText, packetHeader, payloadHeader.GetEncodePacketFlags(), mac);
    SuccessOrExit(err);

    err = payloadHeader.Decode(packetHeader.GetFlags(), plainText, headerSize, &decodedSize);
    SuccessOrExit(err);
    VerifyOrExit(headerSize == decodedSize, err = CHIP_ERROR_INCORRECT_STATE);

    msgBuf->ConsumeHead(headerSize);

    if (payloadHeader.GetProtocolID() == Protocols::kChipProtocol_NetworkProvisioning &&
        payloadHeader.GetMessageType() == NetworkProvisioningMsgTypes::kIPAddressAssigned)
    {
        if (!IPAddress::FromString(Uint8::to_const_char(msgBuf->Start()), msgBuf->DataLength(), mDeviceAddress))
        {
            mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::NetworkProvisioningFailed);
            ExitNow(err = CHIP_ERROR_INVALID_ADDRESS);
        }
        mDelegate->OnRendezvousStatusUpdate(RendezvousSessionDelegate::NetworkProvisioningSuccess);
    }
    // else .. TBD once application dependency on this message has been removed, enable the else condition
    {
        mDelegate->OnRendezvousMessageReceived(msgBuf);
    }

    msgBuf = nullptr;

exit:
    if (origMsg != nullptr)
    {
        PacketBuffer::Free(origMsg);
    }

    return err;
}

CHIP_ERROR RendezvousSession::WaitForPairing(Optional<NodeId> nodeId, uint32_t setupPINCode)
{
    mPairingInProgress = true;
    return mPairingSession.WaitForPairing(setupPINCode, kSpake2p_Iteration_Count, (const unsigned char *) kSpake2pKeyExchangeSalt,
                                          strlen(kSpake2pKeyExchangeSalt), nodeId, 0, this);
}

CHIP_ERROR RendezvousSession::Pair(Optional<NodeId> nodeId, uint32_t setupPINCode)
{
    mPairingInProgress = true;
    return mPairingSession.Pair(setupPINCode, kSpake2p_Iteration_Count, (const unsigned char *) kSpake2pKeyExchangeSalt,
                                strlen(kSpake2pKeyExchangeSalt), nodeId, mNextKeyId++, this);
}

void RendezvousSession::SendIPAddress(IPAddress & addr)
{
    CHIP_ERROR err                = CHIP_NO_ERROR;
    System::PacketBuffer * buffer = System::PacketBuffer::New();
    char * addrStr                = addr.ToString(Uint8::to_char(buffer->Start()), buffer->AvailableDataLength());

    VerifyOrExit(addrStr != nullptr, err = CHIP_ERROR_INVALID_ADDRESS);
    VerifyOrExit(mPairingInProgress == false, err = CHIP_ERROR_INCORRECT_STATE);

    buffer->SetDataLength(strlen(addrStr) + 1);

    err = SendSecureMessage(Protocols::kChipProtocol_NetworkProvisioning, NetworkProvisioningMsgTypes::kIPAddressAssigned, buffer);
    SuccessOrExit(err);

exit:
    if (CHIP_NO_ERROR != err)
    {
        OnRendezvousError(err);
        PacketBuffer::Free(buffer);
    }
}

#if CONFIG_DEVICE_LAYER
void RendezvousSession::ConnectivityHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg)
{
    RendezvousSession * session = reinterpret_cast<RendezvousSession *>(arg);

    VerifyOrExit(session != nullptr, /**/);
    VerifyOrExit(event->Type == DeviceLayer::DeviceEventType::kInternetConnectivityChange, /**/);
    VerifyOrExit(event->InternetConnectivityChange.IPv4 == DeviceLayer::kConnectivity_Established, /**/);

    IPAddress addr;
    IPAddress::FromString(event->InternetConnectivityChange.address, addr);
    session->SendIPAddress(addr);

exit:
    return;
}
#endif

} // namespace chip
<|endoftext|>