while (std::getline(in, str)) {
                    if (str.size() > 0) {
                        if (std::regex_search(str, cheats_expr)) {
                            (*cheatsList)->addView(new brls::ListItem(str));
                            res = true;
                        }
                    }
                }

#include "download_cheats_page.hpp"

#include <filesystem>
#include <fstream>

#include "constants.hpp"
#include "current_cfw.hpp"
#include "download.hpp"
#include "extract.hpp"
#include "fs.hpp"
#include "utils.hpp"

namespace i18n = brls::i18n;
using namespace i18n::literals;
using json = nlohmann::json;

namespace show_cheats {

    void ShowCheatSheet(u64 tid, const std::string& bid, const std::string& name)
    {
        std::string path = fmt::format("{}{}/cheats/{}.txt", util::getContentsPath(), util::formatApplicationId(tid), bid);
        brls::AppletFrame* appView = new brls::AppletFrame(true, true);
        brls::List* cheatsList = new brls::List();
        if (std::filesystem::exists(path) && CreateCheatList(path, &cheatsList)) {
            appView->setContentView(cheatsList);
            appView->registerAction("menus/cheats/delete_file"_i18n, brls::Key::X, [tid, bid] {
                DeleteCheats(tid, bid);
                brls::Dialog* dialog = new brls::Dialog("menus/common/all_done"_i18n);
                brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
                    dialog->close();
                };
                dialog->addButton("menus/common/ok"_i18n, callback);
                dialog->setCancelable(true);
                dialog->open();
                return true;
            });
            brls::PopupFrame::open(name, appView, "");
        }
        else {
            NoCheatsFoundPopup();
        }
    }

    void ShowCheatFiles(u64 tid, const std::string& name)
    {
        std::string path = util::getContentsPath();
        path += util::formatApplicationId(tid) + "/cheats/";

        brls::TabFrame* appView = new brls::TabFrame();
        bool is_populated = false;
        if (std::filesystem::exists(path)) {
            for (const auto& cheatFile : std::filesystem::directory_iterator(path)) {
                brls::List* cheatsList = new brls::List();
                is_populated |= CreateCheatList(cheatFile.path(), &cheatsList);
                if (is_populated) {
                    appView->addTab(util::upperCase(cheatFile.path().stem()), cheatsList);
                }
            }
        }
        if (is_populated) {
            brls::PopupFrame::open(name, appView, "");
        }
        else {
            NoCheatsFoundPopup();
        }
    }

    void NoCheatsFoundPopup()
    {
        brls::Dialog* dialog = new brls::Dialog("menus/cheats/not_found"_i18n);
        brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
            dialog->close();
        };
        dialog->addButton("menus/common/ok"_i18n, callback);
        dialog->setCancelable(true);
        dialog->open();
    }

    bool CreateCheatList(const std::filesystem::path& path, brls::List** cheatsList)
    {
        bool res = false;
        if (extract::isBID(path.filename().stem())) {
            (*cheatsList)->addView(new brls::Label(brls::LabelStyle::DESCRIPTION, fmt::format("menus/cheats/cheatfile_label"_i18n, path.filename().string()), true));

            std::string str;
            std::regex cheats_expr(R"(\[.+\]|\{.+\})");
            std::ifstream in(path);
            if (in) {

            }
        }
        return res;
    }

    void DeleteCheats(u64 tid, const std::string& bid)
    {
        std::filesystem::remove(fmt::format("{}{:016X}/cheats/{}.txt", util::getContentsPath(), tid, bid));
    }
}  // namespace show_cheats

DownloadCheatsPage::DownloadCheatsPage(uint64_t tid, const std::string& name) : AppletFrame(true, true), tid(tid), name(name)
{
    this->list = new brls::List();
    this->GetVersion();
    this->GetBuildID();
    this->setTitle(this->name);
    this->setFooterText("v" + std::to_string(this->version / 0x10000));
    this->brls::AppletFrame::registerAction("menus/cheats/show_existing"_i18n, brls::Key::X, [this] {
        show_cheats::ShowCheatSheet(this->tid, this->bid, this->name);
        return true;
    });
    this->rebuildHints();
}

void DownloadCheatsPage::GetBuildID()
{
    if (CurrentCfw::running_cfw == CFW::ams)
        this->GetBuildIDFromDmnt();
    if (this->bid == "")
        this->GetBuildIDFromFile();
}

void DownloadCheatsPage::GetBuildIDFromDmnt()
{
    static Service g_dmntchtSrv;
    DmntCheatProcessMetadata metadata;
    smGetService(&g_dmntchtSrv, "dmnt:cht");
    serviceDispatch(&g_dmntchtSrv, 65003);
    serviceDispatchOut(&g_dmntchtSrv, 65002, metadata);
    serviceClose(&g_dmntchtSrv);
    if (metadata.title_id == this->tid) {
        u64 buildID = 0;
        memcpy(&buildID, metadata.main_nso_build_id, sizeof(u64));
        this->bid = fmt::format("{:016X}", __builtin_bswap64(buildID));
    }
}

void DownloadCheatsPage::GetVersion()
{
    NsApplicationContentMetaStatus* MetaSatus = new NsApplicationContentMetaStatus[100U];
    s32 out;
    nsListApplicationContentMetaStatus(this->tid, 0, MetaSatus, 100, &out);
    for (int i = 0; i < out; i++) {
        if (version < MetaSatus[i].version) this->version = MetaSatus[i].version;
    }
}

void DownloadCheatsPage::GetBuildIDFromFile()
{
    nlohmann::ordered_json versions_json;
    download::getRequest(VERSIONS_DIRECTORY + util::formatApplicationId(this->tid) + ".json", versions_json);

    std::string version_str = std::to_string(this->version);
    if (versions_json.find(version_str) != versions_json.end()) {
        this->bid = versions_json[version_str];
    }
    else {
        this->bid = "";
    }
}

void DownloadCheatsPage::WriteCheats(const std::string& cheatContent)
{
    std::string path = util::getContentsPath() + util::formatApplicationId(this->tid) + "/cheats/";
    fs::createTree(path);
    std::ofstream cheatFile(path + this->bid + ".txt", std::ios::app);
    cheatFile << "\n\n"
              << cheatContent;
}

void DownloadCheatsPage::AddCheatsfileListItem()
{
    brls::ListItem* item = new brls::ListItem("menus/cheats/show_cheat_files"_i18n);
    item->getClickEvent()->subscribe([this](brls::View* view) {
        show_cheats::ShowCheatFiles(this->tid, this->name);
    });
    this->list->addView(item);
}

DownloadCheatsPage_CheatSlips::DownloadCheatsPage_CheatSlips(uint64_t tid, const std::string& name) : DownloadCheatsPage(tid, name)
{
    this->label = new brls::Label(
        brls::LabelStyle::DESCRIPTION,
        "menus/cheats/cheatslips_dl"_i18n + "\n\uE016  Build ID: " + this->bid,
        true);
    this->list->addView(this->label);

    if (this->bid != "") {
        std::vector<std::string> headers = {"accept: application/json"};
        nlohmann::ordered_json cheatsInfo;
        download::getRequest(CHEATSLIPS_CHEATS_URL + util::formatApplicationId(this->tid) + "/" + this->bid, cheatsInfo, headers);
        if (cheatsInfo.find("cheats") != cheatsInfo.end()) {
            for (const auto& p : cheatsInfo.at("cheats").items()) {
                json cheat = p.value();
                listItem = new brls::ToggleListItem(GetCheatsTitle(cheat), 0, "", "\uE016", "o");
                this->listItem->registerAction("menus/cheats/cheatslips_see_more"_i18n, brls::Key::Y, [this, cheat] {
                    if (cheat.find("titles") != cheat.end()) {
                        ShowCheatsContent(cheat.at("titles"));
                    }
                    return true;
                });
                this->toggles.push_back(std::make_pair(listItem, cheat.at("id")));
                list->addView(listItem);
            }
            if (this->list->getViewsCount() > 1)
                this->list->addView(new brls::ListItemGroupSpacing(true));
        }
    }

    else {
        this->label = new brls::Label(
            brls::LabelStyle::REGULAR,
            "menus/cheats/bid_not_found"_i18n,
            true);
        this->list->addView(label);
    }

    this->list->registerAction((this->bid != "") ? "menus/cheats/cheatslips_dl_cheats"_i18n : "brls/hints/back"_i18n, brls::Key::B, [this] {
        std::vector<int> ids;
        for (auto& e : toggles) {
            if (e.first->getToggleState()) {
                ids.push_back(e.second);
            }
        }
        int error = 0;
        if (!ids.empty()) {
            json token;
            std::ifstream tokenFile(TOKEN_PATH);
            tokenFile >> token;
            tokenFile.close();
            std::vector<std::string> headers = {"accept: application/json"};
            if (token.find("token") != token.end()) {
                headers.push_back("X-API-TOKEN: " + token.at("token").get<std::string>());
            }
            nlohmann::ordered_json cheatsInfo;
            download::getRequest("http://example.com" + util::formatApplicationId(this->tid) + "/" + this->bid, cheatsInfo, headers);
            if (cheatsInfo.find("cheats") != cheatsInfo.end()) {
                for (const auto& p : cheatsInfo.at("cheats").items()) {
                    if (std::find(ids.begin(), ids.end(), p.value().at("id")) != ids.end()) {
                        if (p.value().at("content").get<std::string>() == "Quota exceeded for today !") {
                            error = 1;
                        }
                        else {
                            WriteCheats(p.value().at("content"));
                        }
                    }
                }
            }
            else {
                error = 2;
            }

            if (error != 0) {
                brls::Dialog* dialog;
                switch (error) {
                    case 1:
                        dialog = new brls::Dialog("menus/cheats/quota"_i18n);
                        break;
                    case 2:
                        dialog = new brls::Dialog("menus/cheats/cheatslips_error"_i18n);
                        break;
                }
                brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
                    dialog->close();
                };
                dialog->addButton("menus/common/ok"_i18n, callback);
                dialog->setCancelable(true);
                dialog->open();
            }
        }
        if (error == 0) {
            /*  brls::Dialog* dialog = new brls::Dialog("menus/cheatslips_success"_i18n);
            bool dialogResult = false;
            bool result = false;
            brls::GenericEvent::Callback callback = [dialog, &dialogResult](brls::View* view) {
                dialogResult = true;
                dialog->close();
            };
            dialog->addButton("menus/common/ok"_i18n, callback);
            dialog->setCancelable(true);
            dialog->open();
            while(result == false){
                usleep(1);
                result = dialogResult;
            }
            dialogResult = false; */
            brls::Application::popView();
        }
        return true;
    });
    this->AddCheatsfileListItem();
    this->setContentView(list);
}

std::string DownloadCheatsPage_CheatSlips::GetCheatsTitle(json cheat)
{
    std::string res = "";
    if (cheat.find("titles") != cheat.end()) {
        for (auto& p : cheat.at("titles")) {
            res += "[" + p.get<std::string>() + "]" + " - ";
        }
    }
    return res;
}

void DownloadCheatsPage_CheatSlips::ShowCheatsContent(nlohmann::ordered_json titles)
{
    brls::AppletFrame* appView = new brls::AppletFrame(true, true);
    brls::List* list = new brls::List();
    brls::ListItem* titlesItem;
    for (auto& p : titles) {
        titlesItem = new brls::ListItem(p.get<std::string>());
        titlesItem->registerAction("", brls::Key::A, [this] {
            return true;
        });
        list->addView(titlesItem);
    }
    appView->setContentView(list);
    brls::PopupFrame::open("menus/cheats/sheet_content"_i18n, appView, "", "");
}

DownloadCheatsPage_GbaTemp::DownloadCheatsPage_GbaTemp(uint64_t tid, const std::string& name) : DownloadCheatsPage(tid, name)
{
    this->label = new brls::Label(
        brls::LabelStyle::DESCRIPTION,
        fmt::format("menus/cheats/gbatemp_dl"_i18n, this->bid),
        true);
    this->list->addView(label);

    if (this->bid != "") {
        nlohmann::ordered_json cheatsJson;
        download::getRequest(CHEATS_DIRECTORY + util::formatApplicationId(this->tid) + ".json", cheatsJson);
        if (cheatsJson.find(this->bid) != cheatsJson.end()) {
            for (const auto& p : cheatsJson[this->bid].items()) {
                json cheat = p.value();
                this->listItem = new brls::ListItem(cheat.at("title"));
                listItem->registerAction("menus/cheats/gbatemp_dl_cheatcode"_i18n, brls::Key::A, [this, cheat] {
                    WriteCheats(cheat.at("content"));
                    brls::Dialog* dialog = new brls::Dialog(fmt::format("menus/cheats/gbatemp_dl_successful_dl"_i18n, cheat.at("title")));
                    brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
                        dialog->close();
                    };
                    dialog->addButton("menus/common/ok"_i18n, callback);
                    dialog->setCancelable(true);
                    dialog->open();
                    return true;
                });
                this->list->addView(listItem);
            }
            this->list->addView(new brls::ListItemGroupSpacing(true));
        }
    }

    else {
        label = new brls::Label(
            brls::LabelStyle::REGULAR,
            "menus/cheats/bid_not_found"_i18n,
            true);
        list->addView(label);
    }
    this->AddCheatsfileListItem();
    this->setContentView(this->list);
}


#include "download_cheats_page.hpp"

#include <filesystem>
#include <fstream>

#include "constants.hpp"
#include "current_cfw.hpp"
#include "download.hpp"
#include "extract.hpp"
#include "fs.hpp"
#include "utils.hpp"

namespace i18n = brls::i18n;
using namespace i18n::literals;
using json = nlohmann::json;

namespace show_cheats {

    void ShowCheatSheet(u64 tid, const std::string& bid, const std::string& name)
    {
        std::string path = fmt::format("{}{}/cheats/{}.txt", util::getContentsPath(), util::formatApplicationId(tid), bid);
        brls::AppletFrame* appView = new brls::AppletFrame(true, true);
        brls::List* cheatsList = new brls::List();
        if (std::filesystem::exists(path) && CreateCheatList(path, &cheatsList)) {
            appView->setContentView(cheatsList);
            appView->registerAction("menus/cheats/delete_file"_i18n, brls::Key::X, [tid, bid] {
                DeleteCheats(tid, bid);
                brls::Dialog* dialog = new brls::Dialog("menus/common/all_done"_i18n);
                brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
                    dialog->close();
                };
                dialog->addButton("menus/common/ok"_i18n, callback);
                dialog->setCancelable(true);
                dialog->open();
                return true;
            });
            brls::PopupFrame::open(name, appView, "");
        }
        else {
            NoCheatsFoundPopup();
        }
    }

    void ShowCheatFiles(u64 tid, const std::string& name)
    {
        std::string path = util::getContentsPath();
        path += util::formatApplicationId(tid) + "/cheats/";

        brls::TabFrame* appView = new brls::TabFrame();
        bool is_populated = false;
        if (std::filesystem::exists(path)) {
            for (const auto& cheatFile : std::filesystem::directory_iterator(path)) {
                brls::List* cheatsList = new brls::List();
                is_populated |= CreateCheatList(cheatFile.path(), &cheatsList);
                if (is_populated) {
                    appView->addTab(util::upperCase(cheatFile.path().stem()), cheatsList);
                }
            }
        }
        if (is_populated) {
            brls::PopupFrame::open(name, appView, "");
        }
        else {
            NoCheatsFoundPopup();
        }
    }

    void NoCheatsFoundPopup()
    {
        brls::Dialog* dialog = new brls::Dialog("menus/cheats/not_found"_i18n);
        brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
            dialog->close();
        };
        dialog->addButton("menus/common/ok"_i18n, callback);
        dialog->setCancelable(true);
        dialog->open();
    }

    bool CreateCheatList(const std::filesystem::path& path, brls::List** cheatsList)
    {
        bool res = false;
        if (extract::isBID(path.filename().stem())) {
            (*cheatsList)->addView(new brls::Label(brls::LabelStyle::DESCRIPTION, fmt::format("menus/cheats/cheatfile_label"_i18n, path.filename().string()), true));

            std::string str;
            std::regex cheats_expr(R"(\[.+\]|\{.+\})");
            std::ifstream in(path);
            if (in) {
                while (std::getline(in, str)) {
                    if (str.size() > 0) {
                        if (std::regex_search(str, cheats_expr)) {
                            (*cheatsList)->addView(new brls::ListItem(str));
                            res = true;
                        }
                    }
                }
            }
        }
        return res;
    }

    void DeleteCheats(u64 tid, const std::string& bid)
    {
        std::filesystem::remove(fmt::format("{}{:016X}/cheats/{}.txt", util::getContentsPath(), tid, bid));
    }
}  // namespace show_cheats

DownloadCheatsPage::DownloadCheatsPage(uint64_t tid, const std::string& name) : AppletFrame(true, true), tid(tid), name(name)
{
    this->list = new brls::List();
    this->GetVersion();
    this->GetBuildID();
    this->setTitle(this->name);
    this->setFooterText("v" + std::to_string(this->version / 0x10000));
    this->brls::AppletFrame::registerAction("menus/cheats/show_existing"_i18n, brls::Key::X, [this] {
        show_cheats::ShowCheatSheet(this->tid, this->bid, this->name);
        return true;
    });
    this->rebuildHints();
}

void DownloadCheatsPage::GetBuildID()
{
    if (CurrentCfw::running_cfw == CFW::ams)
        this->GetBuildIDFromDmnt();
    if (this->bid == "")
        this->GetBuildIDFromFile();
}

void DownloadCheatsPage::GetBuildIDFromDmnt()
{
    static Service g_dmntchtSrv;
    DmntCheatProcessMetadata metadata;
    smGetService(&g_dmntchtSrv, "dmnt:cht");
    serviceDispatch(&g_dmntchtSrv, 65003);
    serviceDispatchOut(&g_dmntchtSrv, 65002, metadata);
    serviceClose(&g_dmntchtSrv);
    if (metadata.title_id == this->tid) {
        u64 buildID = 0;
        memcpy(&buildID, metadata.main_nso_build_id, sizeof(u64));
        this->bid = fmt::format("{:016X}", __builtin_bswap64(buildID));
    }
}

void DownloadCheatsPage::GetVersion()
{
    NsApplicationContentMetaStatus* MetaSatus = new NsApplicationContentMetaStatus[100U];
    s32 out;
    nsListApplicationContentMetaStatus(this->tid, 0, MetaSatus, 100, &out);
    for (int i = 0; i < out; i++) {
        if (version < MetaSatus[i].version) this->version = MetaSatus[i].version;
    }
}

void DownloadCheatsPage::GetBuildIDFromFile()
{
    nlohmann::ordered_json versions_json;
    download::getRequest(VERSIONS_DIRECTORY + util::formatApplicationId(this->tid) + ".json", versions_json);

    std::string version_str = std::to_string(this->version);
    if (versions_json.find(version_str) != versions_json.end()) {
        this->bid = versions_json[version_str];
    }
    else {
        this->bid = "";
    }
}

void DownloadCheatsPage::WriteCheats(const std::string& cheatContent)
{
    std::string path = util::getContentsPath() + util::formatApplicationId(this->tid) + "/cheats/";
    fs::createTree(path);
    std::ofstream cheatFile(path + this->bid + ".txt", std::ios::app);
    cheatFile << "\n\n"
              << cheatContent;
}

void DownloadCheatsPage::AddCheatsfileListItem()
{
    brls::ListItem* item = new brls::ListItem("menus/cheats/show_cheat_files"_i18n);
    item->getClickEvent()->subscribe([this](brls::View* view) {
        show_cheats::ShowCheatFiles(this->tid, this->name);
    });
    this->list->addView(item);
}

DownloadCheatsPage_CheatSlips::DownloadCheatsPage_CheatSlips(uint64_t tid, const std::string& name) : DownloadCheatsPage(tid, name)
{
    this->label = new brls::Label(
        brls::LabelStyle::DESCRIPTION,
        "menus/cheats/cheatslips_dl"_i18n + "\n\uE016  Build ID: " + this->bid,
        true);
    this->list->addView(this->label);

    if (this->bid != "") {
        std::vector<std::string> headers = {"accept: application/json"};
        nlohmann::ordered_json cheatsInfo;
        download::getRequest(CHEATSLIPS_CHEATS_URL + util::formatApplicationId(this->tid) + "/" + this->bid, cheatsInfo, headers);
        if (cheatsInfo.find("cheats") != cheatsInfo.end()) {
            for (const auto& p : cheatsInfo.at("cheats").

items()) {
                json cheat = p.value();
                listItem = new brls::ToggleListItem(GetCheatsTitle(cheat), 0, "", "\uE016", "o");
                this->listItem->registerAction("menus/cheats/cheatslips_see_more"_i18n, brls::Key::Y, [this, cheat] {
                    if (cheat.find("titles") != cheat.end()) {
                        ShowCheatsContent(cheat.at("titles"));
                    }
                    return true;
                });
                this->toggles.push_back(std::make_pair(listItem, cheat.at("id")));
                list->addView(listItem);
            }
            if (this->list->getViewsCount() > 1)
                this->list->addView(new brls::ListItemGroupSpacing(true));
        }
    }

    else {
        this->label = new brls::Label(
            brls::LabelStyle::REGULAR,
            "menus/cheats/bid_not_found"_i18n,
            true);
        this->list->addView(label);
    }

    this->list->registerAction((this->bid != "") ? "menus/cheats/cheatslips_dl_cheats"_i18n : "brls/hints/back"_i18n, brls::Key::B, [this] {
        std::vector<int> ids;
        for (auto& e : toggles) {
            if (e.first->getToggleState()) {
                ids.push_back(e.second);
            }
        }
        int error = 0;
        if (!ids.empty()) {
            json token;
            std::ifstream tokenFile(TOKEN_PATH);
            tokenFile >> token;
            tokenFile.close();
            std::vector<std::string> headers = {"accept: application/json"};
            if (token.find("token") != token.end()) {
                headers.push_back("X-API-TOKEN: " + token.at("token").get<std::string>());
            }
            nlohmann::ordered_json cheatsInfo;
            download::getRequest("http://example.com" + util::formatApplicationId(this->tid) + "/" + this->bid, cheatsInfo, headers);
            if (cheatsInfo.find("cheats") != cheatsInfo.end()) {
                for (const auto& p : cheatsInfo.at("cheats").items()) {
                    if (std::find(ids.begin(), ids.end(), p.value().at("id")) != ids.end()) {
                        if (p.value().at("content").get<std::string>() == "Quota exceeded for today !") {
                            error = 1;
                        }
                        else {
                            WriteCheats(p.value().at("content"));
                        }
                    }
                }
            }
            else {
                error = 2;
            }

            if (error != 0) {
                brls::Dialog* dialog;
                switch (error) {
                    case 1:
                        dialog = new brls::Dialog("menus/cheats/quota"_i18n);
                        break;
                    case 2:
                        dialog = new brls::Dialog("menus/cheats/cheatslips_error"_i18n);
                        break;
                }
                brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
                    dialog->close();
                };
                dialog->addButton("menus/common/ok"_i18n, callback);
                dialog->setCancelable(true);
                dialog->open();
            }
        }
        if (error == 0) {
            /*  brls::Dialog* dialog = new brls::Dialog("menus/cheatslips_success"_i18n);
            bool dialogResult = false;
            bool result = false;
            brls::GenericEvent::Callback callback = [dialog, &dialogResult](brls::View* view) {
                dialogResult = true;
                dialog->close();
            };
            dialog->addButton("menus/common/ok"_i18n, callback);
            dialog->setCancelable(true);
            dialog->open();
            while(result == false){
                usleep(1);
                result = dialogResult;
            }
            dialogResult = false; */
            brls::Application::popView();
        }
        return true;
    });
    this->AddCheatsfileListItem();
    this->setContentView(list);
}

std::string DownloadCheatsPage_CheatSlips::GetCheatsTitle(json cheat)
{
    std::string res = "";
    if (cheat.find("titles") != cheat.end()) {
        for (auto& p : cheat.at("titles")) {
            res += "[" + p.get<std::string>() + "]" + " - ";
        }
    }
    return res;
}

void DownloadCheatsPage_CheatSlips::ShowCheatsContent(nlohmann::ordered_json titles)
{
    brls::AppletFrame* appView = new brls::AppletFrame(true, true);
    brls::List* list = new brls::List();
    brls::ListItem* titlesItem;
    for (auto& p : titles) {
        titlesItem = new brls::ListItem(p.get<std::string>());
        titlesItem->registerAction("", brls::Key::A, [this] {
            return true;
        });
        list->addView(titlesItem);
    }
    appView->setContentView(list);
    brls::PopupFrame::open("menus/cheats/sheet_content"_i18n, appView, "", "");
}

DownloadCheatsPage_GbaTemp::DownloadCheatsPage_GbaTemp(uint64_t tid, const std::string& name) : DownloadCheatsPage(tid, name)
{
    this->label = new brls::Label(
        brls::LabelStyle::DESCRIPTION,
        fmt::format("menus/cheats/gbatemp_dl"_i18n, this->bid),
        true);
    this->list->addView(label);

    if (this->bid != "") {
        nlohmann::ordered_json cheatsJson;
        download::getRequest(CHEATS_DIRECTORY + util::formatApplicationId(this->tid) + ".json", cheatsJson);
        if (cheatsJson.find(this->bid) != cheatsJson.end()) {
            for (const auto& p : cheatsJson[this->bid].items()) {
                json cheat = p.value();
                this->listItem = new brls::ListItem(cheat.at("title"));
                listItem->registerAction("menus/cheats/gbatemp_dl_cheatcode"_i18n, brls::Key::A, [this, cheat] {
                    WriteCheats(cheat.at("content"));
                    brls::Dialog* dialog = new brls::Dialog(fmt::format("menus/cheats/gbatemp_dl_successful_dl"_i18n, cheat.at("title")));
                    brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
                        dialog->close();
                    };
                    dialog->addButton("menus/common/ok"_i18n, callback);
                    dialog->setCancelable(true);
                    dialog->open();
                    return true;
                });
                this->list->addView(listItem);
            }
            this->list->addView(new brls::ListItemGroupSpacing(true));
        }
    }

    else {
        label = new brls::Label(
            brls::LabelStyle::REGULAR,
            "menus/cheats/bid_not_found"_i18n,
            true);
        list->addView(label);
    }
    this->AddCheatsfileListItem();
    this->setContentView(this->list);
}


cplus/github/splucs/Competitive-Programming/Codeforces/Gym/101670 2017-2018 CTU Open Contest/I.cpp

#include <bits/stdc++.h>
using namespace std;
#define MAXN 200009
#define FOR(i, n) for(int i = 0; i < n; i++)
#define REP(i, n) for(int i = n-1; i >= 0; i--)
#define FOR1(i, n) for(int i = 1; i <= n; i++)
#define REP1(i, n) for(int i = n; i > 0; i--)
#define fi first
#define se second
typedef long long ll;
typedef pair<int, int> ii;

{
	int n;
	while(scanf("%d", &n) != EOF) {
		map<int, int> p, q;
		FOR1(i, n) {
			int x, y;
			scanf("%d %d", &x, &y);
			p[x+y]++;
			p[x-y]++;
		}
		ll ans = 0;
		for(ii pp : p) {
			ans += pp.se*(pp.se-1LL);
		}
		for(ii pp : q) {
			ans += pp.se*(pp.se-1LL);
		}
		ll tot = (n*1LL*n);
		printf("%.20f\n", ans*1.0/tot);
	}
	return 0;
}


{
	int n;
	while(scanf("%d", &n) != EOF) {
		map<int, int> p, q;
		FOR1(i, n) {
			int x, y;
			scanf("%d %d", &x, &y);
			p[x+y]++;
			p[x-y]++;
		}
		ll ans = 0;
		for(ii pp : p) {
			ans += pp.se*(pp.se-1LL);
		}
		for(ii pp : q) {
			ans += pp.se*(pp.se-1LL);
		}
		ll tot = (n*1LL*n);
		printf("%.20f\n", ans*1.0/tot);
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define MAXN 200009
#define FOR(i, n) for(int i = 0; i < n; i++)
#define REP(i, n) for(int i = n-1; i >= 0; i--)
#define FOR1(i, n) for(int i = 1; i <= n; i++)
#define REP1(i, n) for(int i = n; i > 0; i--)
#define fi first
#define se second
typedef long long ll;
typedef pair<int, int> ii;

int main()


	while(scanf("%d", &n) != EOF) {
		map<int, int> p, q;
		FOR1(i, n) {
			int x, y;
			scanf("%d %d", &x, &y);
			p[x+y]++;
			p[x-y]++;
		}
		ll ans = 0;
		for(ii pp : p) {
			ans += pp.se*(pp.se-1LL);
		}
		for(ii pp : q) {
			ans += pp.se*(pp.se-1LL);
		}
		ll tot = (n*1LL*n);
		printf("%.20f\n", ans*1.0/tot);
	}
	return 0;
}


while(scanf("%d", &n) != EOF) {
		map<int, int> p, q;
		FOR1(i, n) {
			int x, y;
			scanf("%d %d", &x, &y);
			p[x+y]++;
			p[x-y]++;
		}
		ll ans = 0;
		for(ii pp : p) {
			ans += pp.se*(pp.se-1LL);
		}
		for(ii pp : q) {
			ans += pp.se*(pp.se-1LL);
		}
		ll tot = (n*1LL*n);
		printf("%.20f\n", ans*1.0/tot);
	}

#include <bits/stdc++.h>
using namespace std;
#define MAXN 200009
#define FOR(i, n) for(int i = 0; i < n; i++)
#define REP(i, n) for(int i = n-1; i >= 0; i--)
#define FOR1(i, n) for(int i = 1; i <= n; i++)
#define REP1(i, n) for(int i = n; i > 0; i--)
#define fi first
#define se second
typedef long long ll;
typedef pair<int, int> ii;

int main() {
	int n;


#include <bits/stdc++.h>
using namespace std;
#define MAXN 200009
#define FOR(i, n) for(int i = 0; i < n; i++)
#define REP(i, n) for(int i = n-1; i >= 0; i--)
#define FOR1(i, n) for(int i = 1; i <= n; i++)
#define REP1(i, n) for(int i = n; i > 0; i--)
#define fi first
#define se second
typedef long long ll;
typedef pair<int, int> ii;

int main() {
	int n;
	while(scanf("%d", &n) != EOF) {
		map<int, int> p, q;
		FOR1(i, n) {
			int x, y;
			scanf("%d %d", &x, &y);
			p[x+y]++;
			p[x-y]++;
		}
		ll ans = 0;
		for(ii pp : p) {
			ans += pp.se*(pp.se-1LL);
		}
		for(ii pp : q) {
			ans += pp.se*(pp.se-1LL);
		}
		ll tot = (n*1LL*n);
		printf("%.20f\n", ans*1.0/tot);
	}


#include <bits/stdc++.h>
using namespace std;
#define MAXN 200009
#define FOR(i, n) for(int i = 0; i < n; i++)
#define REP(i, n) for(int i = n-1; i >= 0; i--)
#define FOR1(i, n) for(int i = 1; i <= n; i++)
#define REP1(i, n) for(int i = n; i > 0; i--)
#define fi first
#define se second
typedef long long ll;
typedef pair<int, int> ii;

int main() {
	int n;
	while(scanf("%d", &n) != EOF) {
		map<int, int> p, q;
		FOR1(i, n) {
			int x, y;
			scanf("%d %d", &x, &y);
			p[x

			p[x-y]++;
		}
		ll ans = 0;
		for(ii pp : p) {
			ans += pp.se*(pp.se-1LL);
		}
		for(ii pp : q) {
			ans += pp.se*(pp.se-1LL);
		}
		ll tot = (n*1LL*n);
		printf("%.20f\n", ans*1.0/tot);
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define MAXN 200009
#define FOR(i, n) for(int i =

 0; i < n; i++)
#define REP(i, n) for(int i = n-1; i >= 0; i--)
#define FOR1(i, n) for(int i = 1; i <= n; i++)
#define REP1(i, n) for(int i = n; i > 0; i--)
#define fi first
#define se second
typedef long long ll;
typedef pair<int, int> ii;

int main() {
	int n;
	while(scanf("%d", &n) != EOF) {
		map<int, int> p, q;
		FOR1(i, n) {
			int x, y;
			scanf("%d %d", &x, &y);
			p[x+y]++;
			p[x-y]++;
		}
		ll ans = 0;
		for(ii pp : p) {
			ans += pp.se*(pp.se-1LL);
		}
		for(ii pp : q) {
			ans += pp.se*(pp.se-1LL);
		}
		ll tot = (n*1LL*n);
		printf("%.20f\n", ans*1.0/tot);
	}
	return 0;
}


void md5_result(BYTE *digest,md5_ctxt *ctxt)

/*	$FreeBSD: src/sys/crypto/md5.c,v 1.1.2.2 2001/07/03 11:01:27 ume Exp $	*/
/*	$KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $	*/

/*
 * All rights reserved.
 *
 */

#include <wtypes.h>
#include "stdlib.h"
#include "StdAfx.h"
#include "md5.h"

NAMESPACE_BEGIN(util)

#define LITTLE_ENDIAN 4321
#define BIG_ENDIAN 1234
#define BYTE_ORDER LITTLE_ENDIAN
#pragma intrinsic(_rotl)
#define SHIFT(X, s) _rotl(X, s)
#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))

#define ROUND1(a, b, c, d, k, s, i) { \
	(a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND2(a, b, c, d, k, s, i) { \
	(a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND3(a, b, c, d, k, s, i) { \
	(a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND4(a, b, c, d, k, s, i) { \
	(a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define Sa	 7
#define Sb	12
#define Sc	17
#define Sd	22

#define Se	 5
#define Sf	 9
#define Sg	14
#define Sh	20

#define Si	 4
#define Sj	11
#define Sk	16
#define Sl	23

#define Sm	 6
#define Sn	10
#define So	15
#define Sp	21

#define MD5_A0	0x67452301
#define MD5_B0	0xefcdab89
#define MD5_C0	0x98badcfe
#define MD5_D0	0x10325476

/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
static const DWORD T[65] = {
	0,
	0xd76aa478, 	0xe8c7b756,	0x242070db,	0xc1bdceee,
	0xf57c0faf,	0x4787c62a, 	0xa8304613,	0xfd469501,
	0x698098d8,	0x8b44f7af,	0xffff5bb1,	0x895cd7be,
	0x6b901122, 	0xfd987193, 	0xa679438e,	0x49b40821,

	0xf61e2562,	0xc040b340, 	0x265e5a51, 	0xe9b6c7aa,
	0xd62f105d,	0x2441453,	0xd8a1e681,	0xe7d3fbc8,
	0x21e1cde6,	0xc33707d6, 	0xf4d50d87, 	0x455a14ed,
	0xa9e3e905,	0xfcefa3f8, 	0x676f02d9, 	0x8d2a4c8a,

	0xfffa3942,	0x8771f681, 	0x6d9d6122, 	0xfde5380c,
	0xa4beea44, 	0x4bdecfa9, 	0xf6bb4b60, 	0xbebfbc70,
	0x289b7ec6, 	0xeaa127fa, 	0xd4ef3085,	0x4881d05,
	0xd9d4d039, 	0xe6db99e5, 	0x1fa27cf8, 	0xc4ac5665,

	0xf4292244, 	0x432aff97, 	0xab9423a7, 	0xfc93a039,
	0x655b59c3, 	0x8f0ccc92, 	0xffeff47d, 	0x85845dd1,
	0x6fa87e4f, 	0xfe2ce6e0, 	0xa3014314, 	0x4e0811a1,
	0xf7537e82, 	0xbd3af235, 	0x2ad7d2bb, 	0xeb86d391,
};

static const BYTE md5_paddat[MD5_BUFLEN] = {
	0x80,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
};

static void md5_calc (BYTE *, md5_ctxt *);

void md5_init(md5_ctxt *ctxt)
{
	ctxt->md5_n = 0;
	ctxt->md5_i = 0;
	ctxt->md5_sta = MD5_A0;
	ctxt->md5_stb = MD5_B0;
	ctxt->md5_stc = MD5_C0;
	ctxt->md5_std = MD5_D0;
	memset(ctxt->md5_buf, 0, sizeof(ctxt->md5_buf));
}
#define bcopy(src, dst, len) memcpy(dst, src, len)
void md5_loop(md5_ctxt *ctxt,BYTE *input,DWORD len) /* number of bytes */
{
	DWORD gap, i;

	ctxt->md5_n += len * 8; /* byte to bit */
	gap = MD5_BUFLEN - ctxt->md5_i;

	if (len >= gap) {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);

		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
			md5_calc((BYTE *)(input + i), ctxt);
		}

		ctxt->md5_i = len - i;
		bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
	} else {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			len);
		ctxt->md5_i += len;
	}
}

void md5_pad(md5_ctxt *ctxt)
{
	DWORD gap;

	/* Don't count up padding. Keep md5_n. */
	gap = MD5_BUFLEN - ctxt->md5_i;
	if (gap > 8) {
		bcopy((void *)md5_paddat,
		      (void *)(ctxt->md5_buf + ctxt->md5_i),
		      gap - sizeof(ctxt->md5_n));
	} else {
		/* including gap == 8 */
		bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);
		bcopy((void *)(md5_paddat + gap),
		      (void *)ctxt->md5_buf,
		      MD5_BUFLEN - sizeof(ctxt->md5_n));
	}

	/* 8 byte word */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	ctxt->md5_buf[56] = ctxt->md5_n8[7];
	ctxt->md5_buf[57] = ctxt->md5_n8[6];
	ctxt->md5_buf[58] = ctxt->md5_n8[5];
	ctxt->md5_buf[59] = ctxt->md5_n8[4];
	ctxt->md5_buf[60] = ctxt->md5_n8[3];
	ctxt->md5_buf[61] = ctxt->md5_n8[2];
	ctxt->md5_buf[62] = ctxt->md5_n8[1];
	ctxt->md5_buf[63] = ctxt->md5_n8[0];
#endif

	md5_calc(ctxt->md5_buf, ctxt);
}


{
	ctxt->md5_n = 0;
	ctxt->md5_i = 0;
	ctxt->md5_sta = MD5_A0;
	ctxt->md5_stb = MD5_B0;
	ctxt->md5_stc = MD5_C0;
	ctxt->md5_std = MD5_D0;
	memset(ctxt->md5_buf, 0, sizeof(ctxt->md5_buf));
}

/*	$FreeBSD: src/sys/crypto/md5.c,v 1.1.2.2 2001/07/03 11:01:27 ume Exp $	*/
/*	$KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $	*/

/*
 * All rights reserved.
 *
 */

#include <wtypes.h>
#include "stdlib.h"
#include "StdAfx.h"
#include "md5.h"

NAMESPACE_BEGIN(util)

#define LITTLE_ENDIAN 4321
#define BIG_ENDIAN 1234
#define BYTE_ORDER LITTLE_ENDIAN
#pragma intrinsic(_rotl)
#define SHIFT(X, s) _rotl(X, s)
#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))

#define ROUND1(a, b, c, d, k, s, i) { \
	(a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND2(a, b, c, d, k, s, i) { \
	(a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND3(a, b, c, d, k, s, i) { \
	(a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND4(a, b, c, d, k, s, i) { \
	(a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define Sa	 7
#define Sb	12
#define Sc	17
#define Sd	22

#define Se	 5
#define Sf	 9
#define Sg	14
#define Sh	20

#define Si	 4
#define Sj	11
#define Sk	16
#define Sl	23

#define Sm	 6
#define Sn	10
#define So	15
#define Sp	21

#define MD5_A0	0x67452301
#define MD5_B0	0xefcdab89
#define MD5_C0	0x98badcfe
#define MD5_D0	0x10325476

/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
static const DWORD T[65] = {
	0,
	0xd76aa478, 	0xe8c7b756,	0x242070db,	0xc1bdceee,
	0xf57c0faf,	0x4787c62a, 	0xa8304613,	0xfd469501,
	0x698098d8,	0x8b44f7af,	0xffff5bb1,	0x895cd7be,
	0x6b901122, 	0xfd987193, 	0xa679438e,	0x49b40821,

	0xf61e2562,	0xc040b340, 	0x265e5a51, 	0xe9b6c7aa,
	0xd62f105d,	0x2441453,	0xd8a1e681,	0xe7d3fbc8,
	0x21e1cde6,	0xc33707d6, 	0xf4d50d87, 	0x455a14ed,
	0xa9e3e905,	0xfcefa3f8, 	0x676f02d9, 	0x8d2a4c8a,

	0xfffa3942,	0x8771f681, 	0x6d9d6122, 	0xfde5380c,
	0xa4beea44, 	0x4bdecfa9, 	0xf6bb4b60, 	0xbebfbc70,
	0x289b7ec6, 	0xeaa127fa, 	0xd4ef3085,	0x4881d05,
	0xd9d4d039, 	0xe6db99e5, 	0x1fa27cf8, 	0xc4ac5665,

	0xf4292244, 	0x432aff97, 	0xab9423a7, 	0xfc93a039,
	0x655b59c3, 	0x8f0ccc92, 	0xffeff47d, 	0x85845dd1,
	0x6fa87e4f, 	0xfe2ce6e0, 	0xa3014314, 	0x4e0811a1,
	0xf7537e82, 	0xbd3af235, 	0x2ad7d2bb, 	0xeb86d391,
};

static const BYTE md5_paddat[MD5_BUFLEN] = {
	0x80,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
};

static void md5_calc (BYTE *, md5_ctxt *);

void md5_init(md5_ctxt *ctxt)

#define bcopy(src, dst, len) memcpy(dst, src, len)
void md5_loop(md5_ctxt *ctxt,BYTE *input,DWORD len) /* number of bytes */
{
	DWORD gap, i;

	ctxt->md5_n += len * 8; /* byte to bit */
	gap = MD5_BUFLEN - ctxt->md5_i;

	if (len >= gap) {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);

		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
			md5_calc((BYTE *)(input + i), ctxt);
		}

		ctxt->md5_i = len - i;
		bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
	} else {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			len);
		ctxt->md5_i += len;
	}
}

void md5_pad(md5_ctxt *ctxt)
{
	DWORD gap;

	/* Don't count up padding. Keep md5_n. */
	gap = MD5_BUFLEN - ctxt->md5_i;
	if (gap > 8) {
		bcopy((void *)md5_paddat,
		      (void *)(ctxt->md5_buf + ctxt->md5_i),
		      gap - sizeof(ctxt->md5_n));
	} else {
		/* including gap == 8 */
		bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);
		bcopy((void *)(md5_paddat + gap),
		      (void *)ctxt->md5_buf,
		      MD5_BUFLEN - sizeof(ctxt->md5_n));
	}

	/* 8 byte word */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	ctxt->md5_buf[56] = ctxt->md5_n8[7];
	ctxt->md5_buf[57] = ctxt->md5_n8[6];
	ctxt->md5_buf[58] = ctxt->md5_n8[5];
	ctxt->md5_buf[59] = ctxt->md5_n8[4];
	ctxt->md5_buf[60] = ctxt->md5_n8[3];
	ctxt->md5_buf[61] = ctxt->md5_n8[2];
	ctxt->md5_buf[62] = ctxt->md5_n8[1];
	ctxt->md5_buf[63] = ctxt->md5_n8[0];
#endif

	md5_calc(ctxt->md5_buf, ctxt);
}

void md5_result(BYTE *digest,md5_ctxt *ctxt)
{
	/* 4 byte words */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_st8[0], digest, 16);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2];
	digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0];
	digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6];
	digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4];
	digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10];
	digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8];
	digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14];
	digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12];
#endif
}

#if BYTE_ORDER == BIG_ENDIAN
DWORD X[16];
#endif

static void md5_calc(BYTE *b64,md5_ctxt *ctxt)
{
	DWORD A = ctxt->md5_sta;
	DWORD B = ctxt->md5_stb;
	DWORD C = ctxt->md5_stc;
	DWORD D = ctxt->md5_std;
#if BYTE_ORDER == LITTLE_ENDIAN
	DWORD *X = (DWORD *)b64;
#endif
#if BYTE_ORDER == BIG_ENDIAN
	/* 4 byte words */
	/* what a brute force but fast! */
	BYTE *y = (BYTE *)X;
	y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0];
	y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4];
	y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8];
	y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12];
	y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16];
	y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20];
	y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24];
	y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28];
	y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32];
	y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36];
	y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40];
	y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44];
	y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48];
	y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52];
	y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56];
	y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60];
#endif

	ROUND1(A, B, C, D,  0, Sa,  1); ROUND1(D, A, B, C,  1, Sb,  2);
	ROUND1(C, D, A, B,  2, Sc,  3); ROUND1(B, C, D, A,  3, Sd,  4);
	ROUND1(A, B, C, D,  4, Sa,  5); ROUND1(D, A, B, C,  5, Sb,  6);
	ROUND1(C, D, A, B,  6, Sc,  7); ROUND1(B, C, D, A,  7, Sd,  8);
	ROUND1(A, B, C, D,  8, Sa,  9); ROUND1(D, A, B, C,  9, Sb, 10);
	ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12);
	ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14);
	ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16);

	ROUND2(A, B, C, D,  1, Se, 17); ROUND2(D, A, B, C,  6, Sf, 18);
	ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A,  0, Sh, 20);
	ROUND2(A, B, C, D,  5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22);
	ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A,  4, Sh, 24);
	ROUND2(A, B, C, D,  9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26);
	ROUND2(C, D, A, B,  3, Sg, 27); ROUND2(B, C, D, A,  8, Sh, 28);
	ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C,  2, Sf, 30);
	ROUND2(C, D, A, B,  7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32);

	ROUND3(A, B, C, D,  5, Si, 33); ROUND3(D, A, B, C,  8, Sj, 34);
	ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36);
	ROUND3(A, B, C, D,  1, Si, 37); ROUND3(D, A, B, C,  4, Sj, 38);
	ROUND3(C, D, A, B,  7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40);
	ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C,  0, Sj, 42);
	ROUND3(C, D, A, B,  3, Sk, 43); ROUND3(B, C, D, A,  6, Sl, 44);
	ROUND3(A, B, C, D,  9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46);
	ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A,  2, Sl, 48);

	ROUND4(A, B, C, D,  0, Sm, 49); ROUND4(D, A, B, C,  7, Sn, 50);
	ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A,  5, Sp, 52);
	ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C,  3, Sn, 54);
	ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A,  1, Sp, 56);
	ROUND4(A, B, C, D,  8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58);
	ROUND4(C, D, A, B,  6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60);
	ROUND4(A, B, C, D,  4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62);
	ROUND4(C, D, A, B,  2, So, 63); ROUND4(B, C, D, A,  9, Sp, 64);

	ctxt->md5_sta += A;
	ctxt->md5_stb += B;
	ctxt->md5_stc += C;
	ctxt->md5_std += D;
}

NAMESPACE_END(util)


{
	DWORD gap, i;

	ctxt->md5_n += len * 8;

/*	$FreeBSD: src/sys/crypto/md5.c,v 1.1.2.2 2001/07/03 11:01:27 ume Exp $	*/
/*	$KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $	*/

/*
 * All rights reserved.
 *
 */

#include <wtypes.h>
#include "stdlib.h"
#include "StdAfx.h"
#include "md5.h"

NAMESPACE_BEGIN(util)

#define LITTLE_ENDIAN 4321
#define BIG_ENDIAN 1234
#define BYTE_ORDER LITTLE_ENDIAN
#pragma intrinsic(_rotl)
#define SHIFT(X, s) _rotl(X, s)
#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))

#define ROUND1(a, b, c, d, k, s, i) { \
	(a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND2(a, b, c, d, k, s, i) { \
	(a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND3(a, b, c, d, k, s, i) { \
	(a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND4(a, b, c, d, k, s, i) { \
	(a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define Sa	 7
#define Sb	12
#define Sc	17
#define Sd	22

#define Se	 5
#define Sf	 9
#define Sg	14
#define Sh	20

#define Si	 4
#define Sj	11
#define Sk	16
#define Sl	23

#define Sm	 6
#define Sn	10
#define So	15
#define Sp	21

#define MD5_A0	0x67452301
#define MD5_B0	0xefcdab89
#define MD5_C0	0x98badcfe
#define MD5_D0	0x10325476

/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
static const DWORD T[65] = {
	0,
	0xd76aa478, 	0xe8c7b756,	0x242070db,	0xc1bdceee,
	0xf57c0faf,	0x4787c62a, 	0xa8304613,	0xfd469501,
	0x698098d8,	0x8b44f7af,	0xffff5bb1,	0x895cd7be,
	0x6b901122, 	0xfd987193, 	0xa679438e,	0x49b40821,

	0xf61e2562,	0xc040b340, 	0x265e5a51, 	0xe9b6c7aa,
	0xd62f105d,	0x2441453,	0xd8a1e681,	0xe7d3fbc8,
	0x21e1cde6,	0xc33707d6, 	0xf4d50d87, 	0x455a14ed,
	0xa9e3e905,	0xfcefa3f8, 	0x676f02d9, 	0x8d2a4c8a,

	0xfffa3942,	0x8771f681, 	0x6d9d6122, 	0xfde5380c,
	0xa4beea44, 	0x4bdecfa9, 	0xf6bb4b60, 	0xbebfbc70,
	0x289b7ec6, 	0xeaa127fa, 	0xd4ef3085,	0x4881d05,
	0xd9d4d039, 	0xe6db99e5, 	0x1fa27cf8, 	0xc4ac5665,

	0xf4292244, 	0x432aff97, 	0xab9423a7, 	0xfc93a039,
	0x655b59c3, 	0x8f0ccc92, 	0xffeff47d, 	0x85845dd1,
	0x6fa87e4f, 	0xfe2ce6e0, 	0xa3014314, 	0x4e0811a1,
	0xf7537e82, 	0xbd3af235, 	0x2ad7d2bb, 	0xeb86d391,
};

static const BYTE md5_paddat[MD5_BUFLEN] = {
	0x80,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
};

static void md5_calc (BYTE *, md5_ctxt *);

void md5_init(md5_ctxt *ctxt)
{
	ctxt->md5_n = 0;
	ctxt->md5_i = 0;
	ctxt->md5_sta = MD5_A0;
	ctxt->md5_stb = MD5_B0;
	ctxt->md5_stc = MD5_C0;
	ctxt->md5_std = MD5_D0;
	memset(ctxt->md5_buf, 0, sizeof(ctxt->md5_buf));
}
#define bcopy(src, dst, len) memcpy(dst, src, len)
void md5_loop(md5_ctxt *ctxt,BYTE *input,DWORD len) /* number of bytes */

 /* byte to bit */
	gap = MD5_BUFLEN - ctxt->md5_i;

	if (len >= gap) {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);

		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
			md5_calc((BYTE *)(input + i), ctxt);
		}

		ctxt->md5_i = len - i;
		bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
	} else {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			len);
		ctxt->md5_i += len;
	}
}

void md5_pad(md5_ctxt *ctxt)
{
	DWORD gap;

	/* Don't count up padding. Keep md5_n. */
	gap = MD5_BUFLEN - ctxt->md5_i;
	if (gap > 8) {
		bcopy((void *)md5_paddat,
		      (void *)(ctxt->md5_buf + ctxt->md5_i),
		      gap - sizeof(ctxt->md5_n));
	} else {
		/* including gap == 8 */
		bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);
		bcopy((void *)(md5_paddat + gap),
		      (void *)ctxt->md5_buf,
		      MD5_BUFLEN - sizeof(ctxt->md5_n));
	}

	/* 8 byte word */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	ctxt->md5_buf[56] = ctxt->md5_n8[7];
	ctxt->md5_buf[57] = ctxt->md5_n8[6];
	ctxt->md5_buf[58] = ctxt->md5_n8[5];
	ctxt->md5_buf[59] = ctxt->md5_n8[4];
	ctxt->md5_buf[60] = ctxt->md5_n8[3];
	ctxt->md5_buf[61] = ctxt->md5_n8[2];
	ctxt->md5_buf[62] = ctxt->md5_n8[1];
	ctxt->md5_buf[63] = ctxt->md5_n8[0];
#endif

	md5_calc(ctxt->md5_buf, ctxt);
}

void md5_result(BYTE *digest,md5_ctxt *ctxt)
{
	/* 4 byte words */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_st8[0], digest, 16);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2];
	digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0];
	digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6];
	digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4];
	digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10];
	digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8];
	digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14];
	digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12];
#endif
}

#if BYTE_ORDER == BIG_ENDIAN
DWORD X[16];
#endif

static void md5_calc(BYTE *b64,md5_ctxt *ctxt)
{
	DWORD A = ctxt->md5_sta;
	DWORD B = ctxt->md5_stb;
	DWORD C = ctxt->md5_stc;
	DWORD D = ctxt->md5_std;
#if BYTE_ORDER == LITTLE_ENDIAN
	DWORD *X = (DWORD *)b64;
#endif
#if BYTE_ORDER == BIG_ENDIAN
	/* 4 byte words */
	/* what a brute force but fast! */
	BYTE *y = (BYTE *)X;
	y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0];
	y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4];
	y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8];
	y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12];
	y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16];
	y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20];
	y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24];
	y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28];
	y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32];
	y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36];
	y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40];
	y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44];
	y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48];
	y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52];
	y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56];
	y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60];
#endif

	ROUND1(A, B, C, D,  0, Sa,  1); ROUND1(D, A, B, C,  1, Sb,  2);
	ROUND1(C, D, A, B,  2, Sc,  3); ROUND1(B, C, D, A,  3, Sd,  4);
	ROUND1(A, B, C, D,  4, Sa,  5); ROUND1(D, A, B, C,  5, Sb,  6);
	ROUND1(C, D, A, B,  6, Sc,  7); ROUND1(B, C, D, A,  7, Sd,  8);
	ROUND1(A, B, C, D,  8, Sa,  9); ROUND1(D, A, B, C,  9, Sb, 10);
	ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12);
	ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14);
	ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16);

	ROUND2(A, B, C, D,  1, Se, 17); ROUND2(D, A, B, C,  6, Sf, 18);
	ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A,  0, Sh, 20);
	ROUND2(A, B, C, D,  5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22);
	ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A,  4, Sh, 24);
	ROUND2(A, B, C, D,  9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26);
	ROUND2(C, D, A, B,  3, Sg, 27); ROUND2(B, C, D, A,  8, Sh, 28);
	ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C,  2, Sf, 30);
	ROUND2(C, D, A, B,  7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32);

	ROUND3(A, B, C, D,  5, Si, 33); ROUND3(D, A, B, C,  8, Sj, 34);
	ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36);
	ROUND3(A, B, C, D,  1, Si, 37); ROUND3(D, A, B, C,  4, Sj, 38);
	ROUND3(C, D, A, B,  7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40);
	ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C,  0, Sj, 42);
	ROUND3(C, D, A, B,  3, Sk, 43); ROUND3(B, C, D, A,  6, Sl, 44);
	ROUND3(A, B, C, D,  9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46);
	ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A,  2, Sl, 48);

	ROUND4(A, B, C, D,  0, Sm, 49); ROUND4(D, A, B, C,  7, Sn, 50);
	ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A,  5, Sp, 52);
	ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C,  3, Sn, 54);
	ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A,  1, Sp, 56);
	ROUND4(A, B, C, D,  8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58);
	ROUND4(C, D, A, B,  6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60);
	ROUND4(A, B, C, D,  4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62);
	ROUND4(C, D, A, B,  2, So, 63); ROUND4(B, C, D, A,  9, Sp, 64);

	ctxt->md5_sta += A;
	ctxt->md5_stb += B;
	ctxt->md5_stc += C;
	ctxt->md5_std += D;
}

NAMESPACE_END(util)


/* byte to bit */
	gap = MD5_BUFLEN - ctxt->md5_i;

/*	$FreeBSD: src/sys/crypto/md5.c,v 1.1.2.2 2001/07/03 11:01:27 ume Exp $	*/
/*	$KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $	*/

/*
 * All rights reserved.
 *
 */

#include <wtypes.h>
#include "stdlib.h"
#include "StdAfx.h"
#include "md5.h"

NAMESPACE_BEGIN(util)

#define LITTLE_ENDIAN 4321
#define BIG_ENDIAN 1234
#define BYTE_ORDER LITTLE_ENDIAN
#pragma intrinsic(_rotl)
#define SHIFT(X, s) _rotl(X, s)
#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))

#define ROUND1(a, b, c, d, k, s, i) { \
	(a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND2(a, b, c, d, k, s, i) { \
	(a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND3(a, b, c, d, k, s, i) { \
	(a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND4(a, b, c, d, k, s, i) { \
	(a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define Sa	 7
#define Sb	12
#define Sc	17
#define Sd	22

#define Se	 5
#define Sf	 9
#define Sg	14
#define Sh	20

#define Si	 4
#define Sj	11
#define Sk	16
#define Sl	23

#define Sm	 6
#define Sn	10
#define So	15
#define Sp	21

#define MD5_A0	0x67452301
#define MD5_B0	0xefcdab89
#define MD5_C0	0x98badcfe
#define MD5_D0	0x10325476

/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
static const DWORD T[65] = {
	0,
	0xd76aa478, 	0xe8c7b756,	0x242070db,	0xc1bdceee,
	0xf57c0faf,	0x4787c62a, 	0xa8304613,	0xfd469501,
	0x698098d8,	0x8b44f7af,	0xffff5bb1,	0x895cd7be,
	0x6b901122, 	0xfd987193, 	0xa679438e,	0x49b40821,

	0xf61e2562,	0xc040b340, 	0x265e5a51, 	0xe9b6c7aa,
	0xd62f105d,	0x2441453,	0xd8a1e681,	0xe7d3fbc8,
	0x21e1cde6,	0xc33707d6, 	0xf4d50d87, 	0x455a14ed,
	0xa9e3e905,	0xfcefa3f8, 	0x676f02d9, 	0x8d2a4c8a,

	0xfffa3942,	0x8771f681, 	0x6d9d6122, 	0xfde5380c,
	0xa4beea44, 	0x4bdecfa9, 	0xf6bb4b60, 	0xbebfbc70,
	0x289b7ec6, 	0xeaa127fa, 	0xd4ef3085,	0x4881d05,
	0xd9d4d039, 	0xe6db99e5, 	0x1fa27cf8, 	0xc4ac5665,

	0xf4292244, 	0x432aff97, 	0xab9423a7, 	0xfc93a039,
	0x655b59c3, 	0x8f0ccc92, 	0xffeff47d, 	0x85845dd1,
	0x6fa87e4f, 	0xfe2ce6e0, 	0xa3014314, 	0x4e0811a1,
	0xf7537e82, 	0xbd3af235, 	0x2ad7d2bb, 	0xeb86d391,
};

static const BYTE md5_paddat[MD5_BUFLEN] = {
	0x80,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
};

static void md5_calc (BYTE *, md5_ctxt *);

void md5_init(md5_ctxt *ctxt)
{
	ctxt->md5_n = 0;
	ctxt->md5_i = 0;
	ctxt->md5_sta = MD5_A0;
	ctxt->md5_stb = MD5_B0;
	ctxt->md5_stc = MD5_C0;
	ctxt->md5_std = MD5_D0;
	memset(ctxt->md5_buf, 0, sizeof(ctxt->md5_buf));
}
#define bcopy(src, dst, len) memcpy(dst, src, len)
void md5_loop(md5_ctxt *ctxt,BYTE *input,DWORD len) /* number of bytes */
{
	DWORD gap, i;

	ctxt->md5_n += len * 8;

	if (len >= gap) {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);

		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
			md5_calc((BYTE *)(input + i), ctxt);
		}

		ctxt->md5_i = len - i;
		bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
	} else {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			len);
		ctxt->md5_i += len;
	}
}

void md5_pad(md5_ctxt *ctxt)
{
	DWORD gap;

	/* Don't count up padding. Keep md5_n. */
	gap = MD5_BUFLEN - ctxt->md5_i;
	if (gap > 8) {
		bcopy((void *)md5_paddat,
		      (void *)(ctxt->md5_buf + ctxt->md5_i),
		      gap - sizeof(ctxt->md5_n));
	} else {
		/* including gap == 8 */
		bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);
		bcopy((void *)(md5_paddat + gap),
		      (void *)ctxt->md5_buf,
		      MD5_BUFLEN - sizeof(ctxt->md5_n));
	}

	/* 8 byte word */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	ctxt->md5_buf[56] = ctxt->md5_n8[7];
	ctxt->md5_buf[57] = ctxt->md5_n8[6];
	ctxt->md5_buf[58] = ctxt->md5_n8[5];
	ctxt->md5_buf[59] = ctxt->md5_n8[4];
	ctxt->md5_buf[60] = ctxt->md5_n8[3];
	ctxt->md5_buf[61] = ctxt->md5_n8[2];
	ctxt->md5_buf[62] = ctxt->md5_n8[1];
	ctxt->md5_buf[63] = ctxt->md5_n8[0];
#endif

	md5_calc(ctxt->md5_buf, ctxt);
}

void md5_result(BYTE *digest,md5_ctxt *ctxt)
{
	/* 4 byte words */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_st8[0], digest, 16);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2];
	digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0];
	digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6];
	digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4];
	digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10];
	digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8];
	digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14];
	digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12];
#endif
}

#if BYTE_ORDER == BIG_ENDIAN
DWORD X[16];
#endif

static void md5_calc(BYTE *b64,md5_ctxt *ctxt)
{
	DWORD A = ctxt->md5_sta;
	DWORD B = ctxt->md5_stb;
	DWORD C = ctxt->md5_stc;
	DWORD D = ctxt->md5_std;
#if BYTE_ORDER == LITTLE_ENDIAN
	DWORD *X = (DWORD *)b64;
#endif
#if BYTE_ORDER == BIG_ENDIAN
	/* 4 byte words */
	/* what a brute force but fast! */
	BYTE *y = (BYTE *)X;
	y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0];
	y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4];
	y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8];
	y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12];
	y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16];
	y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20];
	y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24];
	y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28];
	y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32];
	y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36];
	y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40];
	y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44];
	y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48];
	y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52];
	y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56];
	y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60];
#endif

	ROUND1(A, B, C, D,  0, Sa,  1); ROUND1(D, A, B, C,  1, Sb,  2);
	ROUND1(C, D, A, B,  2, Sc,  3); ROUND1(B, C, D, A,  3, Sd,  4);
	ROUND1(A, B, C, D,  4, Sa,  5); ROUND1(D, A, B, C,  5, Sb,  6);
	ROUND1(C, D, A, B,  6, Sc,  7); ROUND1(B, C, D, A,  7, Sd,  8);
	ROUND1(A, B, C, D,  8, Sa,  9); ROUND1(D, A, B, C,  9, Sb, 10);
	ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12);
	ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14);
	ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16);

	ROUND2(A, B, C, D,  1, Se, 17); ROUND2(D, A, B, C,  6, Sf, 18);
	ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A,  0, Sh, 20);
	ROUND2(A, B, C, D,  5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22);
	ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A,  4, Sh, 24);
	ROUND2(A, B, C, D,  9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26);
	ROUND2(C, D, A, B,  3, Sg, 27); ROUND2(B, C, D, A,  8, Sh, 28);
	ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C,  2, Sf, 30);
	ROUND2(C, D, A, B,  7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32);

	ROUND3(A, B, C, D,  5, Si, 33); ROUND3(D, A, B, C,  8, Sj, 34);
	ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36);
	ROUND3(A, B, C, D,  1, Si, 37); ROUND3(D, A, B, C,  4, Sj, 38);
	ROUND3(C, D, A, B,  7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40);
	ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C,  0, Sj, 42);
	ROUND3(C, D, A, B,  3, Sk, 43); ROUND3(B, C, D, A,  6, Sl, 44);
	ROUND3(A, B, C, D,  9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46);
	ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A,  2, Sl, 48);

	ROUND4(A, B, C, D,  0, Sm, 49); ROUND4(D, A, B, C,  7, Sn, 50);
	ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A,  5, Sp, 52);
	ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C,  3, Sn, 54);
	ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A,  1, Sp, 56);
	ROUND4(A, B, C, D,  8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58);
	ROUND4(C, D, A, B,  6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60);
	ROUND4(A, B, C, D,  4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62);
	ROUND4(C, D, A, B,  2, So, 63); ROUND4(B, C, D, A,  9, Sp, 64);

	ctxt->md5_sta += A;
	ctxt->md5_stb += B;
	ctxt->md5_stc += C;
	ctxt->md5_std += D;
}

NAMESPACE_END(util)


if (len >= gap) {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);

		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
			md5_calc((BYTE *)(input + i), ctxt);
		}

		ctxt->md5_i = len - i;
		bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
	} else {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			len);
		ctxt->md5_i += len;
	}
}

/*	$FreeBSD: src/sys/crypto/md5.c,v 1.1.2.2 2001/07/03 11:01:27 ume Exp $	*/
/*	$KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $	*/

/*
 * All rights reserved.
 *
 */

#include <wtypes.h>
#include "stdlib.h"
#include "StdAfx.h"
#include "md5.h"

NAMESPACE_BEGIN(util)

#define LITTLE_ENDIAN 4321
#define BIG_ENDIAN 1234
#define BYTE_ORDER LITTLE_ENDIAN
#pragma intrinsic(_rotl)
#define SHIFT(X, s) _rotl(X, s)
#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))

#define ROUND1(a, b, c, d, k, s, i) { \
	(a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND2(a, b, c, d, k, s, i) { \
	(a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND3(a, b, c, d, k, s, i) { \
	(a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND4(a, b, c, d, k, s, i) { \
	(a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define Sa	 7
#define Sb	12
#define Sc	17
#define Sd	22

#define Se	 5
#define Sf	 9
#define Sg	14
#define Sh	20

#define Si	 4
#define Sj	11
#define Sk	16
#define Sl	23

#define Sm	 6
#define Sn	10
#define So	15
#define Sp	21

#define MD5_A0	0x67452301
#define MD5_B0	0xefcdab89
#define MD5_C0	0x98badcfe
#define MD5_D0	0x10325476

/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
static const DWORD T[65] = {
	0,
	0xd76aa478, 	0xe8c7b756,	0x242070db,	0xc1bdceee,
	0xf57c0faf,	0x4787c62a, 	0xa8304613,	0xfd469501,
	0x698098d8,	0x8b44f7af,	0xffff5bb1,	0x895cd7be,
	0x6b901122, 	0xfd987193, 	0xa679438e,	0x49b40821,

	0xf61e2562,	0xc040b340, 	0x265e5a51, 	0xe9b6c7aa,
	0xd62f105d,	0x2441453,	0xd8a1e681,	0xe7d3fbc8,
	0x21e1cde6,	0xc33707d6, 	0xf4d50d87, 	0x455a14ed,
	0xa9e3e905,	0xfcefa3f8, 	0x676f02d9, 	0x8d2a4c8a,

	0xfffa3942,	0x8771f681, 	0x6d9d6122, 	0xfde5380c,
	0xa4beea44, 	0x4bdecfa9, 	0xf6bb4b60, 	0xbebfbc70,
	0x289b7ec6, 	0xeaa127fa, 	0xd4ef3085,	0x4881d05,
	0xd9d4d039, 	0xe6db99e5, 	0x1fa27cf8, 	0xc4ac5665,

	0xf4292244, 	0x432aff97, 	0xab9423a7, 	0xfc93a039,
	0x655b59c3, 	0x8f0ccc92, 	0xffeff47d, 	0x85845dd1,
	0x6fa87e4f, 	0xfe2ce6e0, 	0xa3014314, 	0x4e0811a1,
	0xf7537e82, 	0xbd3af235, 	0x2ad7d2bb, 	0xeb86d391,
};

static const BYTE md5_paddat[MD5_BUFLEN] = {
	0x80,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
};

static void md5_calc (BYTE *, md5_ctxt *);

void md5_init(md5_ctxt *ctxt)
{
	ctxt->md5_n = 0;
	ctxt->md5_i = 0;
	ctxt->md5_sta = MD5_A0;
	ctxt->md5_stb = MD5_B0;
	ctxt->md5_stc = MD5_C0;
	ctxt->md5_std = MD5_D0;
	memset(ctxt->md5_buf, 0, sizeof(ctxt->md5_buf));
}
#define bcopy(src, dst, len) memcpy(dst, src, len)
void md5_loop(md5_ctxt *ctxt,BYTE *input,DWORD len) /* number of bytes */
{
	DWORD gap, i;

	ctxt->md5_n += len * 8; /* byte to bit */
	gap = MD5_BUFLEN - ctxt->md5_i;

void md5_pad(md5_ctxt *ctxt)
{
	DWORD gap;

	/* Don't count up padding. Keep md5_n. */
	gap = MD5_BUFLEN - ctxt->md5_i;
	if (gap > 8) {
		bcopy((void *)md5_paddat,
		      (void *)(ctxt->md5_buf + ctxt->md5_i),
		      gap - sizeof(ctxt->md5_n));
	} else {
		/* including gap == 8 */
		bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);
		bcopy((void *)(md5_paddat + gap),
		      (void *)ctxt->md5_buf,
		      MD5_BUFLEN - sizeof(ctxt->md5_n));
	}

	/* 8 byte word */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	ctxt->md5_buf[56] = ctxt->md5_n8[7];
	ctxt->md5_buf[57] = ctxt->md5_n8[6];
	ctxt->md5_buf[58] = ctxt->md5_n8[5];
	ctxt->md5_buf[59] = ctxt->md5_n8[4];
	ctxt->md5_buf[60] = ctxt->md5_n8[3];
	ctxt->md5_buf[61] = ctxt->md5_n8[2];
	ctxt->md5_buf[62] = ctxt->md5_n8[1];
	ctxt->md5_buf[63] = ctxt->md5_n8[0];
#endif

	md5_calc(ctxt->md5_buf, ctxt);
}

void md5_result(BYTE *digest,md5_ctxt *ctxt)
{
	/* 4 byte words */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_st8[0], digest, 16);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2];
	digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0];
	digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6];
	digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4];
	digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10];
	digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8];
	digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14];
	digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12];
#endif
}

#if BYTE_ORDER == BIG_ENDIAN
DWORD X[16];
#endif

static void md5_calc(BYTE *b64,md5_ctxt *ctxt)
{
	DWORD A = ctxt->md5_sta;
	DWORD B = ctxt->md5_stb;
	DWORD C = ctxt->md5_stc;
	DWORD D = ctxt->md5_std;
#if BYTE_ORDER == LITTLE_ENDIAN
	DWORD *X = (DWORD *)b64;
#endif
#if BYTE_ORDER == BIG_ENDIAN
	/* 4 byte words */
	/* what a brute force but fast! */
	BYTE *y = (BYTE *)X;
	y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0];
	y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4];
	y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8];
	y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12];
	y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16];
	y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20];
	y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24];
	y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28];
	y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32];
	y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36];
	y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40];
	y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44];
	y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48];
	y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52];
	y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56];
	y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60];
#endif

	ROUND1(A, B, C, D,  0, Sa,  1); ROUND1(D, A, B, C,  1, Sb,  2);
	ROUND1(C, D, A, B,  2, Sc,  3); ROUND1(B, C, D, A,  3, Sd,  4);
	ROUND1(A, B, C, D,  4, Sa,  5); ROUND1(D, A, B, C,  5, Sb,  6);
	ROUND1(C, D, A, B,  6, Sc,  7); ROUND1(B, C, D, A,  7, Sd,  8);
	ROUND1(A, B, C, D,  8, Sa,  9); ROUND1(D, A, B, C,  9, Sb, 10);
	ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12);
	ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14);
	ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16);

	ROUND2(A, B, C, D,  1, Se, 17); ROUND2(D, A, B, C,  6, Sf, 18);
	ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A,  0, Sh, 20);
	ROUND2(A, B, C, D,  5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22);
	ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A,  4, Sh, 24);
	ROUND2(A, B, C, D,  9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26);
	ROUND2(C, D, A, B,  3, Sg, 27); ROUND2(B, C, D, A,  8, Sh, 28);
	ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C,  2, Sf, 30);
	ROUND2(C, D, A, B,  7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32);

	ROUND3(A, B, C, D,  5, Si, 33); ROUND3(D, A, B, C,  8, Sj, 34);
	ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36);
	ROUND3(A, B, C, D,  1, Si, 37); ROUND3(D, A, B, C,  4, Sj, 38);
	ROUND3(C, D, A, B,  7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40);
	ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C,  0, Sj, 42);
	ROUND3(C, D, A, B,  3, Sk, 43); ROUND3(B, C, D, A,  6, Sl, 44);
	ROUND3(A, B, C, D,  9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46);
	ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A,  2, Sl, 48);

	ROUND4(A, B, C, D,  0, Sm, 49); ROUND4(D, A, B, C,  7, Sn, 50);
	ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A,  5, Sp, 52);
	ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C,  3, Sn, 54);
	ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A,  1, Sp, 56);
	ROUND4(A, B, C, D,  8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58);
	ROUND4(C, D, A, B,  6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60);
	ROUND4(A, B, C, D,  4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62);
	ROUND4(C, D, A, B,  2, So, 63); ROUND4(B, C, D, A,  9, Sp, 64);

	ctxt->md5_sta += A;
	ctxt->md5_stb += B;
	ctxt->md5_stc += C;
	ctxt->md5_std += D;
}

NAMESPACE_END(util)


/*	$FreeBSD: src/sys/crypto/md5.c,v 1.1.2.2 2001/07/03 11:01:27 ume Exp $	*/
/*	$KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $	*/

/*
 * All rights reserved.
 *
 */

#include <wtypes.h>
#include "stdlib.h"
#include "StdAfx.h"
#include "md5.h"

NAMESPACE_BEGIN(util)

#define LITTLE_ENDIAN 4321
#define BIG_ENDIAN 1234
#define BYTE_ORDER LITTLE_ENDIAN
#pragma intrinsic(_rotl)
#define SHIFT(X, s) _rotl(X, s)
#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))

#define ROUND1(a, b, c, d, k, s, i) { \
	(a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND2(a, b, c, d, k, s, i) { \
	(a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND3(a, b, c, d, k, s, i) { \
	(a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND4(a, b, c, d, k, s, i) { \
	(a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define Sa	 7
#define Sb	12
#define Sc	17
#define Sd	22

#define Se	 5
#define Sf	 9
#define Sg	14
#define Sh	20

#define Si	 4
#define Sj	11
#define Sk	16
#define Sl	23

#define Sm	 6
#define Sn	10
#define So	15
#define Sp	21

#define MD5_A0	0x67452301
#define MD5_B0	0xefcdab89
#define MD5_C0	0x98badcfe
#define MD5_D0	0x10325476

/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
static const DWORD T[65] = {
	0,
	0xd76aa478, 	0xe8c7b756,	0x242070db,	0xc1bdceee,
	0xf57c0faf,	0x4787c62a, 	0xa8304613,	0xfd469501,
	0x698098d8,	0x8b44f7af,	0xffff5bb1,	0x895cd7be,
	0x6b901122, 	0xfd987193, 	0xa679438e,	0x49b40821,

	0xf61e2562,	0xc040b340, 	0x265e5a51, 	0xe9b6c7aa,
	0xd62f105d,	0x2441453,	0xd8a1e681,	0xe7d3fbc8,
	0x21e1cde6,	0xc33707d6, 	0xf4d50d87, 	0x455a14ed,
	0xa9e3e905,	0xfcefa3f8, 	0x676f02d9, 	0x8d2a4c8a,

	0xfffa3942,	0x8771f681, 	0x6d9d6122, 	0xfde5380c,
	0xa4beea44, 	0x4bdecfa9, 	0xf6bb4b60, 	0xbebfbc70,
	0x289b7ec6, 	0xeaa127fa, 	0xd4ef3085,	0x4881d05,
	0xd9d4d039, 	0xe6db99e5, 	0x1fa27cf8, 	0xc4ac5665,

	0xf4292244, 	0x432aff97, 	0xab9423a7, 	0xfc93a039,
	0x655b59c3, 	0x8f0ccc92, 	0xffeff47d, 	0x85845dd1,
	0x6fa87e4f, 	0xfe2ce6e0, 	0xa3014314, 	0x4e0811a1,
	0xf7537e82, 	0xbd3af235, 	0x2ad7d2bb, 	0xeb86d391,
};

static const BYTE md5_paddat[MD5_BUFLEN] = {
	0x80,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
};

static void md5_calc (BYTE *, md5_ctxt *);

void md5_init(md5_ctxt *ctxt)
{
	ctxt->md5_n = 0;
	ctxt->md5_i = 0;
	ctxt->md5_sta = MD5_A0;
	ctxt->md5_stb = MD5_B0;
	ctxt->md5_stc = MD5_C0;
	ctxt->md5_std = MD5_D0;
	memset(ctxt->md5_buf, 0, sizeof(ctxt->md5_buf));
}
#define bcopy(src, dst, len) memcpy(dst, src, len)
void md5_loop(md5_ctxt *ctxt,BYTE *input,DWORD len) /* number of bytes */
{
	DWORD gap, i;

	ctxt->md5_n += len * 8; /* byte to bit */
	gap = MD5_BUFLEN - ctxt->md5_i;

	if (len >= gap) {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);

		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
			md5_calc((BYTE *)(input + i), ctxt);
		}

		ctxt->md5_i = len - i;
		bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
	} else {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			len);
		ctxt->md5_i += len;
	}
}

void md5_pad(md5_ctxt *ctxt)
{
	DWORD gap;

	/* Don't count up padding. Keep md5_n. */
	gap = MD5_BUFLEN - ctxt->md5_i;
	if (gap > 8) {
		bcopy((void *)md5_paddat,
		      (void *)(ctxt->md5_buf + ctxt->md5_i),
		      gap - sizeof(ctxt->md5_n));
	} else {
		/* including gap == 8 */
		bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);
		bcopy((void *)(md5_paddat + gap),
		      (void *)ctxt->md5_buf,
		      MD5_BUFLEN - sizeof(ctxt->md5_n));
	}

	/* 8 byte word */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	ctxt->md5_buf[56] = ctxt->md5_n8[7];
	ctxt->md5_buf[57] = ctxt->md5_n8[6];
	ctxt->md5_buf[58] = ctxt->md5_n8[5];
	ctxt->md5_buf[59] = ctxt->md5_n8[4];
	ctxt->md5_buf[60] = ctxt->md5_n8[3];
	ctxt->md5_buf[61] = ctxt->md5_n8[2];
	ctxt->md5_buf[62] = ctxt->md5_n8[1];
	ctxt->md5_buf[63] = ctxt->md5_n8[0];
#endif

	md5_calc(ctxt->md5_buf, ctxt);
}

void md5_result(BYTE *digest,md5_ctxt *ctxt)
{
	/* 4 byte words */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_st8[0], digest, 16);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2];
	digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0];
	digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6];
	digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4];
	digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10];
	digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8];
	digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14];
	digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12];
#endif
}

#if BYTE_ORDER == BIG_ENDIAN
DWORD X[16];
#endif

static void md5_calc(BYTE *b64,md5_ctxt *ctxt)
{
	DWORD A = ctxt->md5_sta;
	DWORD B = ctxt->md5_stb;
	DWORD C = ctxt->md5_stc;
	DWORD D = ctxt->md5_std;
#if BYTE_ORDER == LITTLE_ENDIAN
	DWORD *X = (DWORD *)b64;
#endif
#if BYTE_ORDER == BIG_ENDIAN
	/* 4 byte words */
	/* what a brute force but fast! */
	BYTE *y = (BYTE *)X;
	y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0];
	y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4];
	y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8];
	y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12];
	y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16];
	y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20];
	y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24];
	y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28];
	y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32];
	y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36];
	y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40];
	y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44];
	y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48];
	y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52];
	y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56];
	y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60];
#endif

	ROUND1(A, B, C, D,  0, Sa,  1); ROUND1(D, A, B, C,  1, Sb,  2);
	ROUND1(C, D, A, B,  2, Sc,  3); ROUND1(B, C, D, A,  3, Sd,  4);
	ROUND1(A, B, C, D,  4, Sa,  5


if (gap > 8) {
		bcopy((void *)md5_paddat,
		      (void *)(ctxt->md5_buf + ctxt->md5_i),
		      gap - sizeof(ctxt->md5_n));
	} else {
		/* including gap == 8 */
		bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);
		bcopy((void *)(md5_paddat + gap),
		      (void *)ctxt->md5_buf,
		      MD5_BUFLEN - sizeof(ctxt->md5_n));
	}

/*	$FreeBSD: src/sys/crypto/md5.c,v 1.1.2.2 2001/07/03 11:01:27 ume Exp $	*/
/*	$KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $	*/

/*
 * All rights reserved.
 *
 */

#include <wtypes.h>
#include "stdlib.h"
#include "StdAfx.h"
#include "md5.h"

NAMESPACE_BEGIN(util)

#define LITTLE_ENDIAN 4321
#define BIG_ENDIAN 1234
#define BYTE_ORDER LITTLE_ENDIAN
#pragma intrinsic(_rotl)
#define SHIFT(X, s) _rotl(X, s)
#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))

#define ROUND1(a, b, c, d, k, s, i) { \
	(a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND2(a, b, c, d, k, s, i) { \
	(a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND3(a, b, c, d, k, s, i) { \
	(a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND4(a, b, c, d, k, s, i) { \
	(a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define Sa	 7
#define Sb	12
#define Sc	17
#define Sd	22

#define Se	 5
#define Sf	 9
#define Sg	14
#define Sh	20

#define Si	 4
#define Sj	11
#define Sk	16
#define Sl	23

#define Sm	 6
#define Sn	10
#define So	15
#define Sp	21

#define MD5_A0	0x67452301
#define MD5_B0	0xefcdab89
#define MD5_C0	0x98badcfe
#define MD5_D0	0x10325476

/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
static const DWORD T[65] = {
	0,
	0xd76aa478, 	0xe8c7b756,	0x242070db,	0xc1bdceee,
	0xf57c0faf,	0x4787c62a, 	0xa8304613,	0xfd469501,
	0x698098d8,	0x8b44f7af,	0xffff5bb1,	0x895cd7be,
	0x6b901122, 	0xfd987193, 	0xa679438e,	0x49b40821,

	0xf61e2562,	0xc040b340, 	0x265e5a51, 	0xe9b6c7aa,
	0xd62f105d,	0x2441453,	0xd8a1e681,	0xe7d3fbc8,
	0x21e1cde6,	0xc33707d6, 	0xf4d50d87, 	0x455a14ed,
	0xa9e3e905,	0xfcefa3f8, 	0x676f02d9, 	0x8d2a4c8a,

	0xfffa3942,	0x8771f681, 	0x6d9d6122, 	0xfde5380c,
	0xa4beea44, 	0x4bdecfa9, 	0xf6bb4b60, 	0xbebfbc70,
	0x289b7ec6, 	0xeaa127fa, 	0xd4ef3085,	0x4881d05,
	0xd9d4d039, 	0xe6db99e5, 	0x1fa27cf8, 	0xc4ac5665,

	0xf4292244, 	0x432aff97, 	0xab9423a7, 	0xfc93a039,
	0x655b59c3, 	0x8f0ccc92, 	0xffeff47d, 	0x85845dd1,
	0x6fa87e4f, 	0xfe2ce6e0, 	0xa3014314, 	0x4e0811a1,
	0xf7537e82, 	0xbd3af235, 	0x2ad7d2bb, 	0xeb86d391,
};

static const BYTE md5_paddat[MD5_BUFLEN] = {
	0x80,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
};

static void md5_calc (BYTE *, md5_ctxt *);

void md5_init(md5_ctxt *ctxt)
{
	ctxt->md5_n = 0;
	ctxt->md5_i = 0;
	ctxt->md5_sta = MD5_A0;
	ctxt->md5_stb = MD5_B0;
	ctxt->md5_stc = MD5_C0;
	ctxt->md5_std = MD5_D0;
	memset(ctxt->md5_buf, 0, sizeof(ctxt->md5_buf));
}
#define bcopy(src, dst, len) memcpy(dst, src, len)
void md5_loop(md5_ctxt *ctxt,BYTE *input,DWORD len) /* number of bytes */
{
	DWORD gap, i;

	ctxt->md5_n += len * 8; /* byte to bit */
	gap = MD5_BUFLEN - ctxt->md5_i;

	if (len >= gap) {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);

		for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
			md5_calc((BYTE *)(input + i), ctxt);
		}

		ctxt->md5_i = len - i;
		bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
	} else {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			len);
		ctxt->md5_i += len;
	}
}

void md5_pad(md5_ctxt *ctxt)
{
	DWORD gap;

	/* Don't count up padding. Keep md5_n. */
	gap = MD5_BUFLEN - ctxt->md5_i;

	/* 8 byte word */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	ctxt->md5_buf[56] = ctxt->md5_n8[7];
	ctxt->md5_buf[57] = ctxt->md5_n8[6];
	ctxt->md5_buf[58] = ctxt->md5_n8[5];
	ctxt->md5_buf[59] = ctxt->md5_n8[4];
	ctxt->md5_buf[60] = ctxt->md5_n8[3];
	ctxt->md5_buf[61] = ctxt->md5_n8[2];
	ctxt->md5_buf[62] = ctxt->md5_n8[1];
	ctxt->md5_buf[63] = ctxt->md5_n8[0];
#endif

	md5_calc(ctxt->md5_buf, ctxt);
}

void md5_result(BYTE *digest,md5_ctxt *ctxt)
{
	/* 4 byte words */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_st8[0], digest, 16);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2];
	digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0];
	digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6];
	digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4];
	digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10];
	digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8];
	digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14];
	digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12];
#endif
}

#if BYTE_ORDER == BIG_ENDIAN
DWORD X[16];
#endif

static void md5_calc(BYTE *b64,md5_ctxt *ctxt)
{
	DWORD A = ctxt->md5_sta;
	DWORD B = ctxt->md5_stb;
	DWORD C = ctxt->md5_stc;
	DWORD D = ctxt->md5_std;
#if BYTE_ORDER == LITTLE_ENDIAN
	DWORD *X = (DWORD *)b64;
#endif
#if BYTE_ORDER == BIG_ENDIAN
	/* 4 byte words */
	/* what a brute force but fast! */
	BYTE *y = (BYTE *)X;
	y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0];
	y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4];
	y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8];
	y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12];
	y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16];
	y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20];
	y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24];
	y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28];
	y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32];
	y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36];
	y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40];
	y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44];
	y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48];
	y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52];
	y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56];
	y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60];
#endif

	ROUND1(A, B, C, D,  0, Sa,  1); ROUND1(D, A, B, C,  1, Sb,  2);
	ROUND1(C, D, A, B,  2, Sc,  3); ROUND1(B, C, D, A,  3, Sd,  4);
	ROUND1(A, B, C, D,  4, Sa,  5); ROUND1(D, A, B, C,  5, Sb,  6);
	ROUND1(C, D, A, B,  6, Sc,  7); ROUND1(B, C, D, A,  7, Sd,  8);
	ROUND1(A, B, C, D,  8, Sa,  9); ROUND1(D, A, B, C,  9, Sb, 10);
	ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12);
	ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14);
	ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16);

	ROUND2(A, B, C, D,  1, Se, 17); ROUND2(D, A, B, C,  6, Sf, 18);
	ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A,  0, Sh, 20);
	ROUND2(A, B, C, D,  5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22);
	ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A,  4, Sh, 24);
	ROUND2(A, B, C, D,  9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26);
	ROUND2(C, D, A, B,  3, Sg, 27); ROUND2(B, C, D, A,  8, Sh, 28);
	ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C,  2, Sf, 30);
	ROUND2(C, D, A, B,  7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32);

	ROUND3(A, B, C, D,  5, Si, 33); ROUND3(D, A, B, C,  8, Sj, 34);
	ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36);
	ROUND3(A, B, C, D,  1, Si, 37); ROUND3(D, A, B, C,  4, Sj, 38);
	ROUND3(C, D, A, B,  7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40);
	ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C,  0, Sj, 42);
	ROUND3(C, D, A, B,  3, Sk, 43); ROUND3(B, C, D, A,  6, Sl, 44);
	ROUND3(A, B, C, D,  9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46);
	ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A,  2, Sl, 48);

	ROUND4(A, B, C, D,  0, Sm, 49); ROUND4(D, A, B, C,  7, Sn, 50);
	ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A,  5, Sp, 52);
	ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C,  3, Sn, 54);
	ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A,  1, Sp, 56);
	ROUND4(A, B, C, D,  8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58);
	ROUND4(C, D, A, B,  6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60);
	ROUND4(A, B, C, D,  4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62);
	ROUND4(C, D, A, B,  2, So, 63); ROUND4(B, C, D, A,  9, Sp, 64);

	ctxt->md5_sta += A;
	ctxt->md5_stb += B;
	ctxt->md5_stc += C;
	ctxt->md5_std += D;
}

NAMESPACE_END(util)


for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
			md5_calc((BYTE *)(input + i), ctxt);
		}

/*	$FreeBSD: src/sys/crypto/md5.c,v 1.1.2.2 2001/07/03 11:01:27 ume Exp $	*/
/*	$KAME: md5.c,v 1.5 2000/11/08 06:13:08 itojun Exp $	*/

/*
 * All rights reserved.
 *
 */

#include <wtypes.h>
#include "stdlib.h"
#include "StdAfx.h"
#include "md5.h"

NAMESPACE_BEGIN(util)

#define LITTLE_ENDIAN 4321
#define BIG_ENDIAN 1234
#define BYTE_ORDER LITTLE_ENDIAN
#pragma intrinsic(_rotl)
#define SHIFT(X, s) _rotl(X, s)
#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))

#define ROUND1(a, b, c, d, k, s, i) { \
	(a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND2(a, b, c, d, k, s, i) { \
	(a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND3(a, b, c, d, k, s, i) { \
	(a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define ROUND4(a, b, c, d, k, s, i) { \
	(a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
	(a) = SHIFT((a), (s)); \
	(a) = (b) + (a); \
}

#define Sa	 7
#define Sb	12
#define Sc	17
#define Sd	22

#define Se	 5
#define Sf	 9
#define Sg	14
#define Sh	20

#define Si	 4
#define Sj	11
#define Sk	16
#define Sl	23

#define Sm	 6
#define Sn	10
#define So	15
#define Sp	21

#define MD5_A0	0x67452301
#define MD5_B0	0xefcdab89
#define MD5_C0	0x98badcfe
#define MD5_D0	0x10325476

/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
static const DWORD T[65] = {
	0,
	0xd76aa478, 	0xe8c7b756,	0x242070db,	0xc1bdceee,
	0xf57c0faf,	0x4787c62a, 	0xa8304613,	0xfd469501,
	0x698098d8,	0x8b44f7af,	0xffff5bb1,	0x895cd7be,
	0x6b901122, 	0xfd987193, 	0xa679438e,	0x49b40821,

	0xf61e2562,	0xc040b340, 	0x265e5a51, 	0xe9b6c7aa,
	0xd62f105d,	0x2441453,	0xd8a1e681,	0xe7d3fbc8,
	0x21e1cde6,	0xc33707d6, 	0xf4d50d87, 	0x455a14ed,
	0xa9e3e905,	0xfcefa3f8, 	0x676f02d9, 	0x8d2a4c8a,

	0xfffa3942,	0x8771f681, 	0x6d9d6122, 	0xfde5380c,
	0xa4beea44, 	0x4bdecfa9, 	0xf6bb4b60, 	0xbebfbc70,
	0x289b7ec6, 	0xeaa127fa, 	0xd4ef3085,	0x4881d05,
	0xd9d4d039, 	0xe6db99e5, 	0x1fa27cf8, 	0xc4ac5665,

	0xf4292244, 	0x432aff97, 	0xab9423a7, 	0xfc93a039,
	0x655b59c3, 	0x8f0ccc92, 	0xffeff47d, 	0x85845dd1,
	0x6fa87e4f, 	0xfe2ce6e0, 	0xa3014314, 	0x4e0811a1,
	0xf7537e82, 	0xbd3af235, 	0x2ad7d2bb, 	0xeb86d391,
};

static const BYTE md5_paddat[MD5_BUFLEN] = {
	0x80,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
};

static void md5_calc (BYTE *, md5_ctxt *);

void md5_init(md5_ctxt *ctxt)
{
	ctxt->md5_n = 0;
	ctxt->md5_i = 0;
	ctxt->md5_sta = MD5_A0;
	ctxt->md5_stb = MD5_B0;
	ctxt->md5_stc = MD5_C0;
	ctxt->md5_std = MD5_D0;
	memset(ctxt->md5_buf, 0, sizeof(ctxt->md5_buf));
}
#define bcopy(src, dst, len) memcpy(dst, src, len)
void md5_loop(md5_ctxt *ctxt,BYTE *input,DWORD len) /* number of bytes */
{
	DWORD gap, i;

	ctxt->md5_n += len * 8; /* byte to bit */
	gap = MD5_BUFLEN - ctxt->md5_i;

	if (len >= gap) {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);

		ctxt->md5_i = len - i;
		bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
	} else {
		bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
			len);
		ctxt->md5_i += len;
	}
}

void md5_pad(md5_ctxt *ctxt)
{
	DWORD gap;

	/* Don't count up padding. Keep md5_n. */
	gap = MD5_BUFLEN - ctxt->md5_i;
	if (gap > 8) {
		bcopy((void *)md5_paddat,
		      (void *)(ctxt->md5_buf + ctxt->md5_i),
		      gap - sizeof(ctxt->md5_n));
	} else {
		/* including gap == 8 */
		bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
			gap);
		md5_calc(ctxt->md5_buf, ctxt);
		bcopy((void *)(md5_paddat + gap),
		      (void *)ctxt->md5_buf,
		      MD5_BUFLEN - sizeof(ctxt->md5_n));
	}

	/* 8 byte word */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	ctxt->md5_buf[56] = ctxt->md5_n8[7];
	ctxt->md5_buf[57] = ctxt->md5_n8[6];
	ctxt->md5_buf[58] = ctxt->md5_n8[5];
	ctxt->md5_buf[59] = ctxt->md5_n8[4];
	ctxt->md5_buf[60] = ctxt->md5_n8[3];
	ctxt->md5_buf[61] = ctxt->md5_n8[2];
	ctxt->md5_buf[62] = ctxt->md5_n8[1];
	ctxt->md5_buf[63] = ctxt->md5_n8[0];
#endif

	md5_calc(ctxt->md5_buf, ctxt);
}

void md5_result(BYTE *digest,md5_ctxt *ctxt)
{
	/* 4 byte words */
#if BYTE_ORDER == LITTLE_ENDIAN
	bcopy(&ctxt->md5_st8[0], digest, 16);
#endif
#if BYTE_ORDER == BIG_ENDIAN
	digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2];
	digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0];
	digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6];
	digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4];
	digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10];
	digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8];
	digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14];
	digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12];
#endif
}

#if BYTE_ORDER == BIG_ENDIAN
DWORD X[16];
#endif

static void md5_calc(BYTE *b64,md5_ctxt *ctxt)
{
	DWORD A = ctxt->md5_sta;
	DWORD B = ctxt->md5_stb;
	DWORD C = ctxt->md5_stc;
	DWORD D = ctxt->md5_std;
#if BYTE_ORDER == LITTLE_ENDIAN
	DWORD *X = (DWORD *)b64;
#endif
#if BYTE_ORDER == BIG_ENDIAN
	/* 4 byte words */
	/* what a brute force but fast! */
	BYTE *y = (BYTE *)X;
	y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0];
	y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4];
	y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8];
	y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12];
	y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16];
	y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20];
	y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24];
	y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28];
	y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32];
	y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36];
	y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40];
	y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44];
	y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48];
	y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52];
	y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56];
	y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60];
#endif

	ROUND1(A, B, C, D,  0, Sa,  1); ROUND1(D, A, B, C,  1, Sb,  2);
	ROUND1(C, D, A, B,  2, Sc,  3); ROUND1(B, C, D, A,  3, Sd,  4);
	ROUND1(A, B, C, D,  4, Sa,  5); ROUND1(D, A, B, C,  5, Sb,  6);
	ROUND1(C, D, A, B,  6, Sc,  7); ROUND1(B, C, D, A,  7, Sd,  8);
	ROUND1(A, B, C, D,  8, Sa,  9); ROUND1(D, A, B, C,  9, Sb, 10);
	ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12);
	ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14);
	ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16);

	ROUND2(A, B, C, D,  1, Se, 17); ROUND2(D, A, B, C,  6, Sf, 18);
	ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A,  0, Sh, 20);
	ROUND2(A, B, C, D,  5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22);
	ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A,  4, Sh, 24);
	ROUND2(A, B, C, D,  9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26);
	ROUND2(C, D, A, B,  3, Sg, 27); ROUND2(B, C, D, A,  8, Sh, 28);
	ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C,  2, Sf, 30);
	ROUND2(C, D, A, B,  7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32);

	ROUND3(A, B, C, D,  5, Si, 33); ROUND3(D, A, B, C,  8, Sj, 34);
	ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36);
	ROUND3(A, B, C, D,  1, Si, 37); ROUND3(D, A, B, C,  4, Sj, 38);
	ROUND3(C, D, A, B,  7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40);
	ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C,  0, Sj, 42);
	ROUND3(C, D, A, B,  3, Sk, 43); ROUND3(B, C, D, A,  6, Sl, 44);
	ROUND3(A, B, C, D,  9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46);
	ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A,  2, Sl, 48);

	ROUND4(A, B, C, D,  0, Sm, 49); ROUND4(D, A, B, C,  7, Sn, 50);
	ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A,  5, Sp, 52);
	ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C,  3, Sn, 54);
	ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A,  1, Sp, 56);
	ROUND4(A, B, C, D,  8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58);
	ROUND4(C, D, A, B,  6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60);
	ROUND4(A, B, C, D,  4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62);
	ROUND4(C, D, A, B,  2, So, 63); ROUND4(B, C, D, A,  9, Sp, 64);

	ctxt->md5_sta += A;
	ctxt->md5_stb += B;
	ctxt->md5_stc += C;
	ctxt->md5_std += D;
}

NAMESPACE_END(util)