<commit_before>/**
 * Copyright (c) 2014-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
#include <wdt/Wdt.h>
#include <wdt/Receiver.h>
#include <wdt/WdtResourceController.h>

#include <chrono>
#include <future>
#include <folly/String.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <iostream>
#include <fstream>
#include <signal.h>
#include <thread>

// Used in fbonly to add socket creator setup
#ifndef ADDITIONAL_SENDER_SETUP
#define ADDITIONAL_SENDER_SETUP
#endif

// This can be the fbonly (FbWdt) version (extended initialization, and options)
#ifndef WDTCLASS
#define WDTCLASS Wdt
#endif

// Flags not already in WdtOptions.h/WdtFlags.cpp.inc
DEFINE_bool(fork, false,
            "If true, forks the receiver, if false, no forking/stay in fg");

DEFINE_bool(run_as_daemon, false,
            "If true, run the receiver as never ending process");

DEFINE_string(directory, ".", "Source/Destination directory");
DEFINE_string(manifest, "",
              "If specified, then we will read a list of files and optional "
              "sizes from this file, use - for stdin");
DEFINE_string(
    destination, "",
    "empty is server (destination) mode, non empty is destination host");
DEFINE_bool(parse_transfer_log, false,
            "If true, transfer log is parsed and fixed");

DEFINE_string(transfer_id, "",
              "Transfer id. Receiver will generate one to be used (via URL) on"
              " the sender if not set explicitly");
DEFINE_int32(
    protocol_version, 0,
    "Protocol version to use, this is used to simulate protocol negotiation");

DEFINE_string(connection_url, "",
              "Provide the connection string to connect to receiver"
              " (incl. transfer_id and other parameters)."
              " Deprecated: use - arg instead for safe encryption key"
              " transmission");

DECLARE_bool(logtostderr);  // default of standard glog is off - let's set it on

DEFINE_int32(abort_after_seconds, 0,
             "Abort transfer after given seconds. 0 means don't abort.");

DEFINE_string(recovery_id, "", "Recovery-id to use for download resumption");

DEFINE_bool(treat_fewer_port_as_error, false,
            "If the receiver is unable to bind to all the ports, treat that as "
            "an error.");
DEFINE_bool(print_options, false,
            "If true, wdt prints the option values and exits. Option values "
            "printed take into account option type and other command line "
            "flags specified.");
DEFINE_bool(exit_on_bad_flags, true,
            "If true, wdt exits on bad/unknown flag. Otherwise, an unknown "
            "flags are ignored");
DEFINE_string(test_only_encryption_secret, "",
              "Test only encryption secret, to test url encoding/decoding");

DEFINE_string(app_name, "wdt", "Identifier used for reporting (scuba, at fb)");

using namespace facebook::wdt;

// TODO: move this to some util and/or delete
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::set<T> &v) {
  std::copy(v.begin(), v.end(), std::ostream_iterator<T>(os, " "));
  return os;
}

std::mutex abortMutex;
std::condition_variable abortCondVar;
bool isAbortCancelled = false;
std::shared_ptr<WdtAbortChecker> setupAbortChecker() {
  int abortSeconds = FLAGS_abort_after_seconds;
  if (abortSeconds <= 0) {
    return nullptr;
  }
  LOG(INFO) << "Setting up abort " << abortSeconds << " seconds.";
  static std::atomic<bool> abortTrigger{false};
  auto res = std::make_shared<WdtAbortChecker>(abortTrigger);
  auto lambda = [=] {
    LOG(INFO) << "Will abort in " << abortSeconds << " seconds.";
    std::unique_lock<std::mutex> lk(abortMutex);
    bool isNotAbort =
        abortCondVar.wait_for(lk, std::chrono::seconds(abortSeconds),
                              [&]() -> bool { return isAbortCancelled; });
    if (isNotAbort) {
      LOG(INFO) << "Already finished normally, no abort.";
    } else {
      LOG(INFO) << "Requesting abort.";
      abortTrigger.store(true);
    }
  };
  // Run this in a separate thread concurrently with sender/receiver
  static auto f = std::async(std::launch::async, lambda);
  return res;
}

void setAbortChecker(WdtBase &senderOrReceiver) {
  senderOrReceiver.setAbortChecker(setupAbortChecker());
}

void cancelAbort() {
  {
    std::unique_lock<std::mutex> lk(abortMutex);
    isAbortCancelled = true;
    abortCondVar.notify_one();
  }
  std::this_thread::yield();
}

void readManifest(std::istream &fin, WdtTransferRequest &req) {
  std::string line;
  while (std::getline(fin, line)) {
    std::vector<std::string> fields;
    folly::split('\t', line, fields, true);
    if (fields.empty() || fields.size() > 2) {
      LOG(FATAL) << "Invalid input manifest: " << line;
    }
    int64_t filesize = fields.size() > 1 ? folly::to<int64_t>(fields[1]) : -1;
    req.fileInfo.emplace_back(fields[0], filesize);
  }
}

namespace google {
extern GFLAGS_DLL_DECL void (*gflags_exitfunc)(int);
}

bool badGflagFound = false;

static std::string usage;
void printUsage() {
  std::cerr << usage << std::endl;
}

int main(int argc, char *argv[]) {
  FLAGS_logtostderr = true;
  // Ugliness in gflags' api; to be able to use program name
  google::SetArgv(argc, const_cast<const char **>(argv));
  google::SetVersionString(Protocol::getFullVersion());
  usage.assign("WDT Warp-speed Data Transfer. v ");
  usage.append(google::VersionString());
  usage.append(". Sample usage:\nTo transfer from srchost to desthost:\n\t");
  usage.append("ssh dsthost ");
  usage.append(google::ProgramInvocationShortName());
  usage.append(" -directory destdir | ssh srchost ");
  usage.append(google::ProgramInvocationShortName());
  usage.append(" -directory srcdir -");
  usage.append(
      "\nPassing - as the argument to wdt means start the sender and"
      " read the");
  usage.append(
      "\nconnection URL produced by the receiver, including encryption"
      " key, from stdin.");
  usage.append("\nUse --help to see all the options.");
  google::SetUsageMessage(usage);
  google::gflags_exitfunc = [](int code) {
    if (FLAGS_exit_on_bad_flags) {
      printUsage();
      exit(code);
    }
    badGflagFound = true;
  };
  google::ParseCommandLineFlags(&argc, &argv, true);
  google::InitGoogleLogging(argv[0]);
  if (badGflagFound) {
    LOG(ERROR) << "Continuing despite bad flags";
  }
  // Only non -flag argument allowed so far is "-" meaning
  // Read url from stdin and start a sender
  if (argc > 2 || (argc == 2 && (argv[1][0] != '-' || argv[1][1] != '\0'))) {
    printUsage();
    std::cerr << "Error: argument should be - (to read url from stdin) "
              << "or no arguments" << std::endl;
    exit(1);
  }
  signal(SIGPIPE, SIG_IGN);

  std::string connectUrl;
  if (argc == 2) {
    std::getline(std::cin, connectUrl);
    if (connectUrl.empty()) {
      LOG(ERROR) << "Sender unable to read connection url from stdin - exiting";
      return URI_PARSE_ERROR;
    }
  } else {
    connectUrl = FLAGS_connection_url;
  }

  // Might be a sub class (fbonly wdtCmdLine.cpp)
  Wdt &wdt = WDTCLASS::initializeWdt(FLAGS_app_name);
  if (FLAGS_print_options) {
    wdt.printWdtOptions(std::cout);
    return 0;
  }

  ErrorCode retCode = OK;

  // Odd ball case of log parsing
  if (FLAGS_parse_transfer_log) {
    // Log parsing mode
    WdtOptions::getMutable().enable_download_resumption = true;
    TransferLogManager transferLogManager;
    transferLogManager.setRootDir(FLAGS_directory);
    transferLogManager.openLog();
    bool success = transferLogManager.parseAndPrint();
    LOG_IF(ERROR, success) << "Transfer log parsing failed";
    transferLogManager.closeLog();
    return success ? OK : ERROR;
  }

  // General case : Sender or Receiver
  const auto &options = WdtOptions::get();
  std::unique_ptr<WdtTransferRequest> reqPtr;
  if (connectUrl.empty()) {
    reqPtr = folly::make_unique<WdtTransferRequest>(
        options.start_port, options.num_ports, FLAGS_directory);
    reqPtr->hostName = FLAGS_destination;
    reqPtr->transferId = FLAGS_transfer_id;
    if (!FLAGS_test_only_encryption_secret.empty()) {
      reqPtr->encryptionData =
          EncryptionParams(parseEncryptionType(options.encryption_type),
                           FLAGS_test_only_encryption_secret);
    }
  } else {
    reqPtr = folly::make_unique<WdtTransferRequest>(connectUrl);
    if (reqPtr->errorCode != OK) {
      LOG(ERROR) << "Invalid url \"" << connectUrl
                 << "\" : " << errorCodeToStr(reqPtr->errorCode);
      return ERROR;
    }
    reqPtr->directory = FLAGS_directory;
    LOG(INFO) << "Parsed url as " << reqPtr->getLogSafeString();
  }
  WdtTransferRequest &req = *reqPtr;
  if (FLAGS_protocol_version > 0) {
    req.protocolVersion = FLAGS_protocol_version;
  }

  if (FLAGS_destination.empty() && connectUrl.empty()) {
    Receiver receiver(req);
    if (!FLAGS_recovery_id.empty()) {
      WdtOptions::getMutable().enable_download_resumption = true;
      receiver.setRecoveryId(FLAGS_recovery_id);
    }
    WdtTransferRequest augmentedReq = receiver.init();
    retCode = augmentedReq.errorCode;
    if (retCode == FEWER_PORTS) {
      if (FLAGS_treat_fewer_port_as_error) {
        LOG(ERROR) << "Receiver could not bind to all the ports";
        return FEWER_PORTS;
      }
      retCode = OK;
    } else if (augmentedReq.errorCode != OK) {
      LOG(ERROR) << "Error setting up receiver " << errorCodeToStr(retCode);
      return retCode;
    }
    // In the log:
    LOG(INFO) << "Starting receiver with connection url "
              << augmentedReq.getLogSafeString();  // The url without secret
    // on stdout: the one with secret:
    std::cout << augmentedReq.genWdtUrlWithSecret() << std::endl;
    std::cout.flush();
    if (FLAGS_fork) {
      pid_t cpid = fork();
      if (cpid == -1) {
        perror("Failed to fork()");
        exit(1);
      }
      if (cpid > 0) {
        LOG(INFO) << "Detaching receiver";
        exit(0);
      }
      close(0);
      close(1);
    }
    setAbortChecker(receiver);
    if (!FLAGS_run_as_daemon) {
      retCode = receiver.transferAsync();
      if (retCode == OK) {
        std::unique_ptr<TransferReport> report = receiver.finish();
        retCode = report->getSummary().getErrorCode();
      }
    } else {
      retCode = receiver.runForever();
      // not reached
    }
  } else {
    // Sender mode
    if (!FLAGS_manifest.empty()) {
      // Each line should have the filename and optionally
      // the filesize separated by a single space
      if (FLAGS_manifest == "-") {
        readManifest(std::cin, req);
      } else {
        std::ifstream fin(FLAGS_manifest);
        readManifest(fin, req);
        fin.close();
      }
      LOG(INFO) << "Using files lists, number of files " << req.fileInfo.size();
    }
    LOG(INFO) << "Making Sender with encryption set = "
              << req.encryptionData.isSet();

    // TODO: find something more useful for namespace (userid ? directory?)
    // (shardid at fb)
    retCode = wdt.wdtSend(WdtResourceController::kGlobalNamespace, req,
                          setupAbortChecker());
  }
  cancelAbort();
  if (retCode == OK) {
    LOG(INFO) << "Returning with OK exit code";
  } else {
    LOG(ERROR) << "Returning with code " << retCode << " "
               << errorCodeToStr(retCode);
  }
  return retCode;
}
<commit_msg>fix --version and --help<commit_after>/**
 * Copyright (c) 2014-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
#include <wdt/Wdt.h>
#include <wdt/Receiver.h>
#include <wdt/WdtResourceController.h>

#include <chrono>
#include <future>
#include <folly/String.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <iostream>
#include <fstream>
#include <signal.h>
#include <thread>

// Used in fbonly to add socket creator setup
#ifndef ADDITIONAL_SENDER_SETUP
#define ADDITIONAL_SENDER_SETUP
#endif

// This can be the fbonly (FbWdt) version (extended initialization, and options)
#ifndef WDTCLASS
#define WDTCLASS Wdt
#endif

// Flags not already in WdtOptions.h/WdtFlags.cpp.inc
DEFINE_bool(fork, false,
            "If true, forks the receiver, if false, no forking/stay in fg");

DEFINE_bool(run_as_daemon, false,
            "If true, run the receiver as never ending process");

DEFINE_string(directory, ".", "Source/Destination directory");
DEFINE_string(manifest, "",
              "If specified, then we will read a list of files and optional "
              "sizes from this file, use - for stdin");
DEFINE_string(
    destination, "",
    "empty is server (destination) mode, non empty is destination host");
DEFINE_bool(parse_transfer_log, false,
            "If true, transfer log is parsed and fixed");

DEFINE_string(transfer_id, "",
              "Transfer id. Receiver will generate one to be used (via URL) on"
              " the sender if not set explicitly");
DEFINE_int32(
    protocol_version, 0,
    "Protocol version to use, this is used to simulate protocol negotiation");

DEFINE_string(connection_url, "",
              "Provide the connection string to connect to receiver"
              " (incl. transfer_id and other parameters)."
              " Deprecated: use - arg instead for safe encryption key"
              " transmission");

DECLARE_bool(logtostderr);  // default of standard glog is off - let's set it on

DEFINE_int32(abort_after_seconds, 0,
             "Abort transfer after given seconds. 0 means don't abort.");

DEFINE_string(recovery_id, "", "Recovery-id to use for download resumption");

DEFINE_bool(treat_fewer_port_as_error, false,
            "If the receiver is unable to bind to all the ports, treat that as "
            "an error.");
DEFINE_bool(print_options, false,
            "If true, wdt prints the option values and exits. Option values "
            "printed take into account option type and other command line "
            "flags specified.");
DEFINE_bool(exit_on_bad_flags, true,
            "If true, wdt exits on bad/unknown flag. Otherwise, an unknown "
            "flags are ignored");
DEFINE_string(test_only_encryption_secret, "",
              "Test only encryption secret, to test url encoding/decoding");

DEFINE_string(app_name, "wdt", "Identifier used for reporting (scuba, at fb)");

DECLARE_bool(help);

using namespace facebook::wdt;

// TODO: move this to some util and/or delete
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::set<T> &v) {
  std::copy(v.begin(), v.end(), std::ostream_iterator<T>(os, " "));
  return os;
}

std::mutex abortMutex;
std::condition_variable abortCondVar;
bool isAbortCancelled = false;
std::shared_ptr<WdtAbortChecker> setupAbortChecker() {
  int abortSeconds = FLAGS_abort_after_seconds;
  if (abortSeconds <= 0) {
    return nullptr;
  }
  LOG(INFO) << "Setting up abort " << abortSeconds << " seconds.";
  static std::atomic<bool> abortTrigger{false};
  auto res = std::make_shared<WdtAbortChecker>(abortTrigger);
  auto lambda = [=] {
    LOG(INFO) << "Will abort in " << abortSeconds << " seconds.";
    std::unique_lock<std::mutex> lk(abortMutex);
    bool isNotAbort =
        abortCondVar.wait_for(lk, std::chrono::seconds(abortSeconds),
                              [&]() -> bool { return isAbortCancelled; });
    if (isNotAbort) {
      LOG(INFO) << "Already finished normally, no abort.";
    } else {
      LOG(INFO) << "Requesting abort.";
      abortTrigger.store(true);
    }
  };
  // Run this in a separate thread concurrently with sender/receiver
  static auto f = std::async(std::launch::async, lambda);
  return res;
}

void setAbortChecker(WdtBase &senderOrReceiver) {
  senderOrReceiver.setAbortChecker(setupAbortChecker());
}

void cancelAbort() {
  {
    std::unique_lock<std::mutex> lk(abortMutex);
    isAbortCancelled = true;
    abortCondVar.notify_one();
  }
  std::this_thread::yield();
}

void readManifest(std::istream &fin, WdtTransferRequest &req) {
  std::string line;
  while (std::getline(fin, line)) {
    std::vector<std::string> fields;
    folly::split('\t', line, fields, true);
    if (fields.empty() || fields.size() > 2) {
      LOG(FATAL) << "Invalid input manifest: " << line;
    }
    int64_t filesize = fields.size() > 1 ? folly::to<int64_t>(fields[1]) : -1;
    req.fileInfo.emplace_back(fields[0], filesize);
  }
}

namespace google {
extern GFLAGS_DLL_DECL void (*gflags_exitfunc)(int);
}

bool badGflagFound = false;

static std::string usage;
void printUsage() {
  std::cerr << usage << std::endl;
}

int main(int argc, char *argv[]) {
  FLAGS_logtostderr = true;
  // Ugliness in gflags' api; to be able to use program name
  google::SetArgv(argc, const_cast<const char **>(argv));
  google::SetVersionString(Protocol::getFullVersion());
  usage.assign("WDT Warp-speed Data Transfer. v ");
  usage.append(google::VersionString());
  usage.append(". Sample usage:\nTo transfer from srchost to desthost:\n\t");
  usage.append("ssh dsthost ");
  usage.append(google::ProgramInvocationShortName());
  usage.append(" -directory destdir | ssh srchost ");
  usage.append(google::ProgramInvocationShortName());
  usage.append(" -directory srcdir -");
  usage.append(
      "\nPassing - as the argument to wdt means start the sender and"
      " read the");
  usage.append(
      "\nconnection URL produced by the receiver, including encryption"
      " key, from stdin.");
  usage.append("\nUse --help to see all the options.");
  google::SetUsageMessage(usage);
  google::gflags_exitfunc = [](int code) {
    if (code == 0 || FLAGS_help) {
      // By default gflags exit 1 with --help and 0 for --version (good)
      // let's also exit(0) for --help to be like most gnu command line
      exit(0);
    }
    // error cases:
    if (FLAGS_exit_on_bad_flags) {
      printUsage();
      exit(code);
    }
    badGflagFound = true;
  };
  google::ParseCommandLineFlags(&argc, &argv, true);
  google::InitGoogleLogging(argv[0]);
  if (badGflagFound) {
    LOG(ERROR) << "Continuing despite bad flags";
  }
  // Only non -flag argument allowed so far is "-" meaning
  // Read url from stdin and start a sender
  if (argc > 2 || (argc == 2 && (argv[1][0] != '-' || argv[1][1] != '\0'))) {
    printUsage();
    std::cerr << "Error: argument should be - (to read url from stdin) "
              << "or no arguments" << std::endl;
    exit(1);
  }
  signal(SIGPIPE, SIG_IGN);

  std::string connectUrl;
  if (argc == 2) {
    std::getline(std::cin, connectUrl);
    if (connectUrl.empty()) {
      LOG(ERROR) << "Sender unable to read connection url from stdin - exiting";
      return URI_PARSE_ERROR;
    }
  } else {
    connectUrl = FLAGS_connection_url;
  }

  // Might be a sub class (fbonly wdtCmdLine.cpp)
  Wdt &wdt = WDTCLASS::initializeWdt(FLAGS_app_name);
  if (FLAGS_print_options) {
    wdt.printWdtOptions(std::cout);
    return 0;
  }

  ErrorCode retCode = OK;

  // Odd ball case of log parsing
  if (FLAGS_parse_transfer_log) {
    // Log parsing mode
    WdtOptions::getMutable().enable_download_resumption = true;
    TransferLogManager transferLogManager;
    transferLogManager.setRootDir(FLAGS_directory);
    transferLogManager.openLog();
    bool success = transferLogManager.parseAndPrint();
    LOG_IF(ERROR, success) << "Transfer log parsing failed";
    transferLogManager.closeLog();
    return success ? OK : ERROR;
  }

  // General case : Sender or Receiver
  const auto &options = WdtOptions::get();
  std::unique_ptr<WdtTransferRequest> reqPtr;
  if (connectUrl.empty()) {
    reqPtr = folly::make_unique<WdtTransferRequest>(
        options.start_port, options.num_ports, FLAGS_directory);
    reqPtr->hostName = FLAGS_destination;
    reqPtr->transferId = FLAGS_transfer_id;
    if (!FLAGS_test_only_encryption_secret.empty()) {
      reqPtr->encryptionData =
          EncryptionParams(parseEncryptionType(options.encryption_type),
                           FLAGS_test_only_encryption_secret);
    }
  } else {
    reqPtr = folly::make_unique<WdtTransferRequest>(connectUrl);
    if (reqPtr->errorCode != OK) {
      LOG(ERROR) << "Invalid url \"" << connectUrl
                 << "\" : " << errorCodeToStr(reqPtr->errorCode);
      return ERROR;
    }
    reqPtr->directory = FLAGS_directory;
    LOG(INFO) << "Parsed url as " << reqPtr->getLogSafeString();
  }
  WdtTransferRequest &req = *reqPtr;
  if (FLAGS_protocol_version > 0) {
    req.protocolVersion = FLAGS_protocol_version;
  }

  if (FLAGS_destination.empty() && connectUrl.empty()) {
    Receiver receiver(req);
    if (!FLAGS_recovery_id.empty()) {
      WdtOptions::getMutable().enable_download_resumption = true;
      receiver.setRecoveryId(FLAGS_recovery_id);
    }
    WdtTransferRequest augmentedReq = receiver.init();
    retCode = augmentedReq.errorCode;
    if (retCode == FEWER_PORTS) {
      if (FLAGS_treat_fewer_port_as_error) {
        LOG(ERROR) << "Receiver could not bind to all the ports";
        return FEWER_PORTS;
      }
      retCode = OK;
    } else if (augmentedReq.errorCode != OK) {
      LOG(ERROR) << "Error setting up receiver " << errorCodeToStr(retCode);
      return retCode;
    }
    // In the log:
    LOG(INFO) << "Starting receiver with connection url "
              << augmentedReq.getLogSafeString();  // The url without secret
    // on stdout: the one with secret:
    std::cout << augmentedReq.genWdtUrlWithSecret() << std::endl;
    std::cout.flush();
    if (FLAGS_fork) {
      pid_t cpid = fork();
      if (cpid == -1) {
        perror("Failed to fork()");
        exit(1);
      }
      if (cpid > 0) {
        LOG(INFO) << "Detaching receiver";
        exit(0);
      }
      close(0);
      close(1);
    }
    setAbortChecker(receiver);
    if (!FLAGS_run_as_daemon) {
      retCode = receiver.transferAsync();
      if (retCode == OK) {
        std::unique_ptr<TransferReport> report = receiver.finish();
        retCode = report->getSummary().getErrorCode();
      }
    } else {
      retCode = receiver.runForever();
      // not reached
    }
  } else {
    // Sender mode
    if (!FLAGS_manifest.empty()) {
      // Each line should have the filename and optionally
      // the filesize separated by a single space
      if (FLAGS_manifest == "-") {
        readManifest(std::cin, req);
      } else {
        std::ifstream fin(FLAGS_manifest);
        readManifest(fin, req);
        fin.close();
      }
      LOG(INFO) << "Using files lists, number of files " << req.fileInfo.size();
    }
    LOG(INFO) << "Making Sender with encryption set = "
              << req.encryptionData.isSet();

    // TODO: find something more useful for namespace (userid ? directory?)
    // (shardid at fb)
    retCode = wdt.wdtSend(WdtResourceController::kGlobalNamespace, req,
                          setupAbortChecker());
  }
  cancelAbort();
  if (retCode == OK) {
    LOG(INFO) << "Returning with OK exit code";
  } else {
    LOG(ERROR) << "Returning with code " << retCode << " "
               << errorCodeToStr(retCode);
  }
  return retCode;
}
<|endoftext|>


<commit_before>/*
    This file is part of KAddressbook.
    Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qfile.h>

#include <kfiledialog.h>
#include <kio/netaccess.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <ktempfile.h>
#include <kurl.h>

#include "csvimportdialog.h"

#include "csv_xxport.h"

class CSVXXPortFactory : public XXPortFactory
{
  public:
    XXPortObject *xxportObject( KABC::AddressBook *ab, QWidget *parent, const char *name )
    {
      return new CSVXXPort( ab, parent, name );
    }
};

extern "C"
{
  void *init_libkaddrbk_csv_xxport()
  {
    return ( new CSVXXPortFactory() );
  }
}

CSVXXPort::CSVXXPort( KABC::AddressBook *ab, QWidget *parent, const char *name )
  : XXPortObject( ab, parent, name )
{
  createImportAction( i18n( "Import CSV List..." ) );
  createExportAction( i18n( "Export CSV List..." ) );
}

bool CSVXXPort::exportContacts( const KABC::AddresseeList &list, const QString& )
{
  KURL url = KFileDialog::getSaveURL( "addressbook.csv" );
  if ( url.isEmpty() )
      return true;

  if ( !url.isLocalFile() ) {
    KTempFile tmpFile;
    if ( tmpFile.status() != 0 ) {
      QString txt = i18n( "<qt>Unable to open file %1.%2.</qt>" );
      KMessageBox::error( parentWidget(), txt.arg( url.url() )
                          .arg( strerror( tmpFile.status() ) ) );
      return false;
    }

    doExport( tmpFile.file(), list );
    tmpFile.close();

    return KIO::NetAccess::upload( tmpFile.name(), url, parentWidget() );
  } else {
    QFile file( url.path() );
    if ( !file.open( IO_WriteOnly ) ) {
      QString txt = i18n( "<qt>Unable to open file %1.</qt>" );
      KMessageBox::error( parentWidget(), txt.arg( url.path() ) );
      return false;
    }

    doExport( &file, list );
    file.close();

    return true;
  }
}

KABC::AddresseeList CSVXXPort::importContacts( const QString& ) const
{
  CSVImportDialog dlg( addressBook(), parentWidget() );
  if ( dlg.exec() )
    return dlg.contacts();
  else
    return KABC::AddresseeList();
}

void CSVXXPort::doExport( QFile *fp, const KABC::AddresseeList &list )
{
  QTextStream t( fp );

  KABC::AddresseeList::ConstIterator iter;
  KABC::Field::List fields = addressBook()->fields();
  KABC::Field::List::Iterator fieldIter;
  bool first = true;

  // First output the column headings
  for ( fieldIter = fields.begin(); fieldIter != fields.end(); ++fieldIter ) {
    if ( !first )
      t << ",";

    t << "\"" << (*fieldIter)->label() << "\"";
    first = false;
  }
  t << "\n";

  // Then all the addressee objects
  KABC::Addressee addr;
  for ( iter = list.begin(); iter != list.end(); ++iter ) {
    addr = *iter;
    first = true;

    for ( fieldIter = fields.begin(); fieldIter != fields.end(); ++fieldIter ) {
      if ( !first )
        t << ",";

      t << "\"" << (*fieldIter)->value( addr ).replace( "\n", "\\n" ) << "\"";
      first = false;
    }

    t << "\n";
  }
}

#include "csv_xxport.moc"
<commit_msg>Export csv with QTextStream::Locale encoding.<commit_after>/*
    This file is part of KAddressbook.
    Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qfile.h>

#include <kfiledialog.h>
#include <kio/netaccess.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <ktempfile.h>
#include <kurl.h>

#include "csvimportdialog.h"

#include "csv_xxport.h"

class CSVXXPortFactory : public XXPortFactory
{
  public:
    XXPortObject *xxportObject( KABC::AddressBook *ab, QWidget *parent, const char *name )
    {
      return new CSVXXPort( ab, parent, name );
    }
};

extern "C"
{
  void *init_libkaddrbk_csv_xxport()
  {
    return ( new CSVXXPortFactory() );
  }
}

CSVXXPort::CSVXXPort( KABC::AddressBook *ab, QWidget *parent, const char *name )
  : XXPortObject( ab, parent, name )
{
  createImportAction( i18n( "Import CSV List..." ) );
  createExportAction( i18n( "Export CSV List..." ) );
}

bool CSVXXPort::exportContacts( const KABC::AddresseeList &list, const QString& )
{
  KURL url = KFileDialog::getSaveURL( "addressbook.csv" );
  if ( url.isEmpty() )
      return true;

  if ( !url.isLocalFile() ) {
    KTempFile tmpFile;
    if ( tmpFile.status() != 0 ) {
      QString txt = i18n( "<qt>Unable to open file %1.%2.</qt>" );
      KMessageBox::error( parentWidget(), txt.arg( url.url() )
                          .arg( strerror( tmpFile.status() ) ) );
      return false;
    }

    doExport( tmpFile.file(), list );
    tmpFile.close();

    return KIO::NetAccess::upload( tmpFile.name(), url, parentWidget() );
  } else {
    QFile file( url.path() );
    if ( !file.open( IO_WriteOnly ) ) {
      QString txt = i18n( "<qt>Unable to open file %1.</qt>" );
      KMessageBox::error( parentWidget(), txt.arg( url.path() ) );
      return false;
    }

    doExport( &file, list );
    file.close();

    return true;
  }
}

KABC::AddresseeList CSVXXPort::importContacts( const QString& ) const
{
  CSVImportDialog dlg( addressBook(), parentWidget() );
  if ( dlg.exec() )
    return dlg.contacts();
  else
    return KABC::AddresseeList();
}

void CSVXXPort::doExport( QFile *fp, const KABC::AddresseeList &list )
{
  QTextStream t( fp );
  t.setEncoding( QTextStream::Locale );

  KABC::AddresseeList::ConstIterator iter;
  KABC::Field::List fields = addressBook()->fields();
  KABC::Field::List::Iterator fieldIter;
  bool first = true;

  // First output the column headings
  for ( fieldIter = fields.begin(); fieldIter != fields.end(); ++fieldIter ) {
    if ( !first )
      t << ",";

    t << "\"" << (*fieldIter)->label() << "\"";
    first = false;
  }
  t << "\n";

  // Then all the addressee objects
  KABC::Addressee addr;
  for ( iter = list.begin(); iter != list.end(); ++iter ) {
    addr = *iter;
    first = true;

    for ( fieldIter = fields.begin(); fieldIter != fields.end(); ++fieldIter ) {
      if ( !first )
        t << ",";

      t << "\"" << (*fieldIter)->value( addr ).replace( "\n", "\\n" ) << "\"";
      first = false;
    }

    t << "\n";
  }
}

#include "csv_xxport.moc"
<|endoftext|>


<commit_before><commit_msg>[Backport] Aura: enable the touch events dispatch in DesktopRootWindowHostX11<commit_after><|endoftext|>


<commit_before><commit_msg>ATO-418-Updated test macro<commit_after><|endoftext|>


<commit_before>/*
 -----------------------------------------------------------------------------
 This source file is part of OGRE
 (Object-oriented Graphics Rendering Engine)
 For the latest info, see http://www.ogre3d.org/

 Copyright (c) 2000-2014 Torus Knot Software Ltd

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 -----------------------------------------------------------------------------
 */

#include <OgreZip.h>

#include "SamplePlugin.h"
#include "CharacterSample.h"

#include <emscripten/html5.h>
#include "Context.h"

Context::Context()
    :   OgreBites::SampleContext("OGRE Emscripten Sample", false), mBuffer(NULL), mNode(NULL)
{
}

bool Context::mouseWheelRolled(const OgreBites::MouseWheelEvent& evt) {
    OgreBites::MouseWheelEvent _evt = evt;
    // chrome reports values of 53 here
    _evt.y = std::min(3, std::max(-3, evt.y));
    return OgreBites::SampleContext::mouseWheelRolled(evt);
}

void Context::_mainLoop(void* target)
{
    Context* thizz = static_cast<Context*>(target);
    if (thizz->mRoot->endRenderingQueued())
	{
	    emscripten_cancel_main_loop();
	}
	else
    {
	    try
	    {
            //Pump messages in all registered RenderWindow windows
            Ogre::WindowEventUtilities::messagePump();

            if (!thizz->mRoot->renderOneFrame())
            {
                emscripten_cancel_main_loop();
            }
	    }
	    catch (Ogre::Exception& e)
	    {
            size_t length = emscripten_get_callstack(EM_LOG_C_STACK | EM_LOG_DEMANGLE | EM_LOG_NO_PATHS | EM_LOG_FUNC_PARAMS,0,0) + 50;
            char* buffer = new char[length];
            emscripten_get_callstack(EM_LOG_C_STACK | EM_LOG_DEMANGLE | EM_LOG_NO_PATHS | EM_LOG_FUNC_PARAMS, buffer, length);
            Ogre::LogManager::getSingleton().logMessage(buffer);
            delete[] buffer;

            emscripten_pause_main_loop();
	    }
    }
}

void Context::unloadResource(Ogre::ResourceManager* resMgr, const Ogre::String& resourceName)
{
    Ogre::ResourcePtr rPtr = resMgr->getResourceByName(resourceName, "General");
    if (!rPtr)
        return;

    rPtr->unload();
    resMgr->remove(resourceName, "General");
}

void Context::destroyMaterials( const Ogre::String& resourceGroupID )
{

    try
    {
        Ogre::MaterialManager* materialManager = Ogre::MaterialManager::getSingletonPtr();
        Ogre::ResourceManager::ResourceMapIterator resourceIterator = materialManager->getResourceIterator();

        std::vector< std::string > materialNamesToRemove;

        while( resourceIterator.hasMoreElements() )
        {
            Ogre::ResourcePtr material = resourceIterator.getNext();
            std::string matName = material->getName();

            if( resourceGroupID == material->getGroup())
            {
                mShaderGenerator->removeAllShaderBasedTechniques( matName, material->getGroup() );
                material->unload();
                material.reset();
                materialNamesToRemove.push_back( matName );
            }
        }

        for( size_t i = 0; i < materialNamesToRemove.size(); ++i )
        {
            materialManager->remove( materialNamesToRemove[i], resourceGroupID );
        }
        materialManager->removeUnreferencedResources();
    }
    catch( ... )
    {
        Ogre::LogManager::getSingleton().logMessage("An Error occurred trying to destroy Materials in " + resourceGroupID);
    }

}

void Context::destroyTextures( const Ogre::String& resourceGroupID )
{
    try
    {
        Ogre::TextureManager* textureManager = Ogre::TextureManager::getSingletonPtr();
        Ogre::ResourceManager::ResourceMapIterator resourceIterator = textureManager->getResourceIterator();

        std::vector< std::string > textureNamesToRemove;

        while( resourceIterator.hasMoreElements() )
        {
            Ogre::ResourcePtr texture = resourceIterator.getNext();
            Ogre::String resourceName = texture->getName();
            if( resourceGroupID == texture->getGroup())
            {
                texture->unload();
                texture.reset();
                textureNamesToRemove.push_back( resourceName );
            }
        }

        for( size_t i = 0; i < textureNamesToRemove.size(); ++i )
        {
            textureManager->remove( textureNamesToRemove[i], resourceGroupID );
        }
    }
    catch( ... )
    {
        Ogre::LogManager::getSingleton().logMessage("An Error occurred trying to destroy Textures in " + resourceGroupID);
    }

}

void Context::clearScene()
{
    if (mBuffer != NULL)
    {
        auto it = mNode->getAttachedObjectIterator();
        while (it.hasMoreElements())
        {
            //mSceneMgr->destroyMovableObject(it.getNext());
        }
        mNode->detachAllObjects();

        Ogre::MaterialManager* matMgr = Ogre::MaterialManager::getSingletonPtr();
        matMgr->removeUnreferencedResources();

        Ogre::MeshManager* meshMgr = Ogre::MeshManager::getSingletonPtr();
        meshMgr->unloadUnreferencedResources();

        Ogre::TextureManager* texMgr = Ogre::TextureManager::getSingletonPtr();
        texMgr->removeUnreferencedResources();

        if( Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("Download") && Ogre::ResourceGroupManager::getSingleton().isResourceGroupInitialised("Download") )
        {
            destroyMaterials( "Download" );
            destroyTextures( "Download" );

            Ogre::ResourceGroupManager::getSingleton().removeResourceLocation( "download.zip" );
            Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup( "Download" );
        }

        Ogre::EmbeddedZipArchiveFactory::removeEmbbeddedFile("download.zip");

        mShaderGenerator->removeAllShaderBasedTechniques();
        mShaderGenerator->flushShaderCache();

        //free(mBuffer);
        mBuffer = NULL;
    }
}

void Context::passAssetAsArrayBuffer(unsigned char* arr, int length) {

    try {

        clearScene();
        Ogre::ResourceGroupManager::getSingleton().createResourceGroup("Download");
        mBuffer = arr;

        Ogre::EmbeddedZipArchiveFactory::addEmbbeddedFile("download.zip", mBuffer, length, NULL);
        Ogre::ResourceGroupManager::getSingleton().addResourceLocation("download.zip","EmbeddedZip","Download");
        Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Download");

        Ogre::StringVectorPtr meshes = Ogre::ArchiveManager::getSingleton().load("download.zip","EmbeddedZip",true)->find("*.mesh");
        for (auto i : *meshes)
        {
            //mNode->attachObject(mSceneMgr->createEntity(i));
        }

    } catch (Ogre::Exception& ex) {
        Ogre::LogManager::getSingleton().logMessage(ex.what());

    }

}

void Context::setup() {
    OgreBites::ApplicationContext::setup();
    mCurrentSample = new Sample_Character();
    mCurrentSample->setShaderGenerator(mShaderGenerator);
    mCurrentSample->_setup(mWindow, mFSLayer, mOverlaySystem);
}
<commit_msg>Samples: Emscripten - update to new Bites API<commit_after>/*
 -----------------------------------------------------------------------------
 This source file is part of OGRE
 (Object-oriented Graphics Rendering Engine)
 For the latest info, see http://www.ogre3d.org/

 Copyright (c) 2000-2014 Torus Knot Software Ltd

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 -----------------------------------------------------------------------------
 */

#include <OgreZip.h>

#include "SamplePlugin.h"
#include "CharacterSample.h"

#include <emscripten/html5.h>
#include "Context.h"

Context::Context()
    :   OgreBites::SampleContext("OGRE Emscripten Sample", false), mBuffer(NULL), mNode(NULL)
{
}

bool Context::mouseWheelRolled(const OgreBites::MouseWheelEvent& evt) {
    OgreBites::MouseWheelEvent _evt = evt;
    // chrome reports values of 53 here
    _evt.y = std::min(3, std::max(-3, evt.y));
    return OgreBites::SampleContext::mouseWheelRolled(evt);
}

void Context::_mainLoop(void* target)
{
    Context* thizz = static_cast<Context*>(target);
    if (thizz->mRoot->endRenderingQueued())
	{
	    emscripten_cancel_main_loop();
	}
	else
    {
	    try
	    {
            //Pump messages in all registered RenderWindow windows
            Ogre::WindowEventUtilities::messagePump();

            if (!thizz->mRoot->renderOneFrame())
            {
                emscripten_cancel_main_loop();
            }
	    }
	    catch (Ogre::Exception& e)
	    {
            size_t length = emscripten_get_callstack(EM_LOG_C_STACK | EM_LOG_DEMANGLE | EM_LOG_NO_PATHS | EM_LOG_FUNC_PARAMS,0,0) + 50;
            char* buffer = new char[length];
            emscripten_get_callstack(EM_LOG_C_STACK | EM_LOG_DEMANGLE | EM_LOG_NO_PATHS | EM_LOG_FUNC_PARAMS, buffer, length);
            Ogre::LogManager::getSingleton().logMessage(buffer);
            delete[] buffer;

            emscripten_pause_main_loop();
	    }
    }
}

void Context::unloadResource(Ogre::ResourceManager* resMgr, const Ogre::String& resourceName)
{
    Ogre::ResourcePtr rPtr = resMgr->getResourceByName(resourceName, "General");
    if (!rPtr)
        return;

    rPtr->unload();
    resMgr->remove(resourceName, "General");
}

void Context::destroyMaterials( const Ogre::String& resourceGroupID )
{

    try
    {
        Ogre::MaterialManager* materialManager = Ogre::MaterialManager::getSingletonPtr();
        Ogre::ResourceManager::ResourceMapIterator resourceIterator = materialManager->getResourceIterator();

        std::vector< std::string > materialNamesToRemove;

        while( resourceIterator.hasMoreElements() )
        {
            Ogre::ResourcePtr material = resourceIterator.getNext();
            std::string matName = material->getName();

            if( resourceGroupID == material->getGroup())
            {
                mShaderGenerator->removeAllShaderBasedTechniques( matName, material->getGroup() );
                material->unload();
                material.reset();
                materialNamesToRemove.push_back( matName );
            }
        }

        for( size_t i = 0; i < materialNamesToRemove.size(); ++i )
        {
            materialManager->remove( materialNamesToRemove[i], resourceGroupID );
        }
        materialManager->removeUnreferencedResources();
    }
    catch( ... )
    {
        Ogre::LogManager::getSingleton().logMessage("An Error occurred trying to destroy Materials in " + resourceGroupID);
    }

}

void Context::destroyTextures( const Ogre::String& resourceGroupID )
{
    try
    {
        Ogre::TextureManager* textureManager = Ogre::TextureManager::getSingletonPtr();
        Ogre::ResourceManager::ResourceMapIterator resourceIterator = textureManager->getResourceIterator();

        std::vector< std::string > textureNamesToRemove;

        while( resourceIterator.hasMoreElements() )
        {
            Ogre::ResourcePtr texture = resourceIterator.getNext();
            Ogre::String resourceName = texture->getName();
            if( resourceGroupID == texture->getGroup())
            {
                texture->unload();
                texture.reset();
                textureNamesToRemove.push_back( resourceName );
            }
        }

        for( size_t i = 0; i < textureNamesToRemove.size(); ++i )
        {
            textureManager->remove( textureNamesToRemove[i], resourceGroupID );
        }
    }
    catch( ... )
    {
        Ogre::LogManager::getSingleton().logMessage("An Error occurred trying to destroy Textures in " + resourceGroupID);
    }

}

void Context::clearScene()
{
    if (mBuffer != NULL)
    {
        auto it = mNode->getAttachedObjectIterator();
        while (it.hasMoreElements())
        {
            //mSceneMgr->destroyMovableObject(it.getNext());
        }
        mNode->detachAllObjects();

        Ogre::MaterialManager* matMgr = Ogre::MaterialManager::getSingletonPtr();
        matMgr->removeUnreferencedResources();

        Ogre::MeshManager* meshMgr = Ogre::MeshManager::getSingletonPtr();
        meshMgr->unloadUnreferencedResources();

        Ogre::TextureManager* texMgr = Ogre::TextureManager::getSingletonPtr();
        texMgr->removeUnreferencedResources();

        if( Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("Download") && Ogre::ResourceGroupManager::getSingleton().isResourceGroupInitialised("Download") )
        {
            destroyMaterials( "Download" );
            destroyTextures( "Download" );

            Ogre::ResourceGroupManager::getSingleton().removeResourceLocation( "download.zip" );
            Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup( "Download" );
        }

        Ogre::EmbeddedZipArchiveFactory::removeEmbbeddedFile("download.zip");

        mShaderGenerator->removeAllShaderBasedTechniques();
        mShaderGenerator->flushShaderCache();

        //free(mBuffer);
        mBuffer = NULL;
    }
}

void Context::passAssetAsArrayBuffer(unsigned char* arr, int length) {

    try {

        clearScene();
        Ogre::ResourceGroupManager::getSingleton().createResourceGroup("Download");
        mBuffer = arr;

        Ogre::EmbeddedZipArchiveFactory::addEmbbeddedFile("download.zip", mBuffer, length, NULL);
        Ogre::ResourceGroupManager::getSingleton().addResourceLocation("download.zip","EmbeddedZip","Download");
        Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Download");

        Ogre::StringVectorPtr meshes = Ogre::ArchiveManager::getSingleton().load("download.zip","EmbeddedZip",true)->find("*.mesh");
        for (auto i : *meshes)
        {
            //mNode->attachObject(mSceneMgr->createEntity(i));
        }

    } catch (Ogre::Exception& ex) {
        Ogre::LogManager::getSingleton().logMessage(ex.what());

    }

}

void Context::setup() {
    OgreBites::ApplicationContext::setup();
    mWindow = getRenderWindow();
    addInputListener(this);

    mCurrentSample = new Sample_Character();
    mCurrentSample->setShaderGenerator(mShaderGenerator);
    mCurrentSample->_setup(mWindow, mFSLayer, mOverlaySystem);
}
<|endoftext|>


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

#include <grpc/support/port_platform.h>

#include "src/core/lib/security/security_connector/local/local_security_connector.h"

#include <stdbool.h>
#include <string.h>

#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>

#include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/socket_utils.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/security/credentials/local/local_credentials.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/tsi/local_transport_security.h"

#define GRPC_UDS_URI_PATTERN "unix:"
#define GRPC_LOCAL_TRANSPORT_SECURITY_TYPE "local"

namespace {

grpc_core::RefCountedPtr<grpc_auth_context> local_auth_context_create(
    const tsi_peer* peer) {
  /* Create auth context. */
  grpc_core::RefCountedPtr<grpc_auth_context> ctx =
      grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
  grpc_auth_context_add_cstring_property(
      ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
      GRPC_LOCAL_TRANSPORT_SECURITY_TYPE);
  GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
                 ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1);
  GPR_ASSERT(peer->property_count == 1);
  const tsi_peer_property* prop = &peer->properties[0];
  GPR_ASSERT(prop != nullptr);
  GPR_ASSERT(strcmp(prop->name, TSI_SECURITY_LEVEL_PEER_PROPERTY) == 0);
  grpc_auth_context_add_property(ctx.get(),
                                 GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
                                 prop->value.data, prop->value.length);
  return ctx;
}

void local_check_peer(grpc_security_connector* sc, tsi_peer peer,
                      grpc_endpoint* ep,
                      grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                      grpc_closure* on_peer_checked,
                      grpc_local_connect_type type) {
  int fd = grpc_endpoint_get_fd(ep);
  grpc_resolved_address resolved_addr;
  memset(&resolved_addr, 0, sizeof(resolved_addr));
  resolved_addr.len = GRPC_MAX_SOCKADDR_SIZE;
  bool is_endpoint_local = false;
  if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(resolved_addr.addr),
                  &resolved_addr.len) == 0) {
    grpc_resolved_address addr_normalized;
    grpc_resolved_address* addr =
        grpc_sockaddr_is_v4mapped(&resolved_addr, &addr_normalized)
            ? &addr_normalized
            : &resolved_addr;
    grpc_sockaddr* sock_addr = reinterpret_cast<grpc_sockaddr*>(&addr->addr);
    // UDS
    if (type == UDS && grpc_is_unix_socket(addr)) {
      is_endpoint_local = true;
      // IPV4
    } else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET) {
      const grpc_sockaddr_in* addr4 =
          reinterpret_cast<const grpc_sockaddr_in*>(sock_addr);
      if (grpc_htonl(addr4->sin_addr.s_addr) == INADDR_LOOPBACK) {
        is_endpoint_local = true;
      }
      // IPv6
    } else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET6) {
      const grpc_sockaddr_in6* addr6 =
          reinterpret_cast<const grpc_sockaddr_in6*>(addr);
      if (memcmp(&addr6->sin6_addr, &in6addr_loopback,
                 sizeof(in6addr_loopback)) == 0) {
        is_endpoint_local = true;
      }
    }
  }
  grpc_error* error = GRPC_ERROR_NONE;
  if (!is_endpoint_local) {
    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
        "Endpoint is neither UDS or TCP loopback address.");
    grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
    return;
  }
  // Add TSI_SECURITY_LEVEL_PEER_PROPERTY type peer property.
  size_t new_property_count = peer.property_count + 1;
  tsi_peer_property* new_properties = static_cast<tsi_peer_property*>(
      gpr_zalloc(sizeof(*new_properties) * new_property_count));
  for (size_t i = 0; i < peer.property_count; i++) {
    new_properties[i] = peer.properties[i];
  }
  if (peer.properties != nullptr) gpr_free(peer.properties);
  peer.properties = new_properties;
  // TODO(yihuazhang): Set security level of local TCP to TSI_SECURITY_NONE.
  const char* security_level =
      tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY);
  tsi_result result = tsi_construct_string_peer_property_from_cstring(
      TSI_SECURITY_LEVEL_PEER_PROPERTY, security_level,
      &peer.properties[peer.property_count]);
  if (result != TSI_OK) return;
  peer.property_count++;
  /* Create an auth context which is necessary to pass the santiy check in
   * {client, server}_auth_filter that verifies if the peer's auth context is
   * obtained during handshakes. The auth context is only checked for its
   * existence and not actually used.
   */
  *auth_context = local_auth_context_create(&peer);
  tsi_peer_destruct(&peer);
  error = *auth_context != nullptr ? GRPC_ERROR_NONE
                                   : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                                         "Could not create local auth context");
  grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
}

class grpc_local_channel_security_connector final
    : public grpc_channel_security_connector {
 public:
  grpc_local_channel_security_connector(
      grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
      grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
      const char* target_name)
      : grpc_channel_security_connector(nullptr, std::move(channel_creds),
                                        std::move(request_metadata_creds)),
        target_name_(gpr_strdup(target_name)) {}

  ~grpc_local_channel_security_connector() override { gpr_free(target_name_); }

  void add_handshakers(
      const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
      grpc_core::HandshakeManager* handshake_manager) override {
    tsi_handshaker* handshaker = nullptr;
    GPR_ASSERT(local_tsi_handshaker_create(true /* is_client */, &handshaker) ==
               TSI_OK);
    handshake_manager->Add(
        grpc_core::SecurityHandshakerCreate(handshaker, this, args));
  }

  int cmp(const grpc_security_connector* other_sc) const override {
    auto* other =
        reinterpret_cast<const grpc_local_channel_security_connector*>(
            other_sc);
    int c = channel_security_connector_cmp(other);
    if (c != 0) return c;
    return strcmp(target_name_, other->target_name_);
  }

  void check_peer(tsi_peer peer, grpc_endpoint* ep,
                  grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                  grpc_closure* on_peer_checked) override {
    grpc_local_credentials* creds =
        reinterpret_cast<grpc_local_credentials*>(mutable_channel_creds());
    local_check_peer(this, peer, ep, auth_context, on_peer_checked,
                     creds->connect_type());
  }

  bool check_call_host(grpc_core::StringView host,
                       grpc_auth_context* /*auth_context*/,
                       grpc_closure* /*on_call_host_checked*/,
                       grpc_error** error) override {
    if (host.empty() || host != target_name_) {
      *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
          "local call host does not match target name");
    }
    return true;
  }

  void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
                              grpc_error* error) override {
    GRPC_ERROR_UNREF(error);
  }

  const char* target_name() const { return target_name_; }

 private:
  char* target_name_;
};

class grpc_local_server_security_connector final
    : public grpc_server_security_connector {
 public:
  grpc_local_server_security_connector(
      grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
      : grpc_server_security_connector(nullptr, std::move(server_creds)) {}
  ~grpc_local_server_security_connector() override = default;

  void add_handshakers(
      const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
      grpc_core::HandshakeManager* handshake_manager) override {
    tsi_handshaker* handshaker = nullptr;
    GPR_ASSERT(local_tsi_handshaker_create(false /* is_client */,
                                           &handshaker) == TSI_OK);
    handshake_manager->Add(
        grpc_core::SecurityHandshakerCreate(handshaker, this, args));
  }

  void check_peer(tsi_peer peer, grpc_endpoint* ep,
                  grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                  grpc_closure* on_peer_checked) override {
    grpc_local_server_credentials* creds =
        static_cast<grpc_local_server_credentials*>(mutable_server_creds());
    local_check_peer(this, peer, ep, auth_context, on_peer_checked,
                     creds->connect_type());
  }

  int cmp(const grpc_security_connector* other) const override {
    return server_security_connector_cmp(
        static_cast<const grpc_server_security_connector*>(other));
  }
};
}  // namespace

grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_local_channel_security_connector_create(
    grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
    grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
    const grpc_channel_args* args, const char* target_name) {
  if (channel_creds == nullptr || target_name == nullptr) {
    gpr_log(
        GPR_ERROR,
        "Invalid arguments to grpc_local_channel_security_connector_create()");
    return nullptr;
  }
  // Perform sanity check on UDS address. For TCP local connection, the check
  // will be done during check_peer procedure.
  grpc_local_credentials* creds =
      static_cast<grpc_local_credentials*>(channel_creds.get());
  const grpc_arg* server_uri_arg =
      grpc_channel_args_find(args, GRPC_ARG_SERVER_URI);
  const char* server_uri_str = grpc_channel_arg_get_string(server_uri_arg);
  if (creds->connect_type() == UDS &&
      strncmp(GRPC_UDS_URI_PATTERN, server_uri_str,
              strlen(GRPC_UDS_URI_PATTERN)) != 0) {
    gpr_log(GPR_ERROR,
            "Invalid UDS target name to "
            "grpc_local_channel_security_connector_create()");
    return nullptr;
  }
  return grpc_core::MakeRefCounted<grpc_local_channel_security_connector>(
      channel_creds, request_metadata_creds, target_name);
}

grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_local_server_security_connector_create(
    grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
  if (server_creds == nullptr) {
    gpr_log(
        GPR_ERROR,
        "Invalid arguments to grpc_local_server_security_connector_create()");
    return nullptr;
  }
  return grpc_core::MakeRefCounted<grpc_local_server_security_connector>(
      std::move(server_creds));
}
<commit_msg>update local tcp security level<commit_after>/*
 *
 * Copyright 2018 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <grpc/support/port_platform.h>

#include "src/core/lib/security/security_connector/local/local_security_connector.h"

#include <stdbool.h>
#include <string.h>

#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>

#include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/socket_utils.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/security/credentials/local/local_credentials.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/tsi/local_transport_security.h"

#define GRPC_UDS_URI_PATTERN "unix:"
#define GRPC_LOCAL_TRANSPORT_SECURITY_TYPE "local"

namespace {

grpc_core::RefCountedPtr<grpc_auth_context> local_auth_context_create(
    const tsi_peer* peer) {
  /* Create auth context. */
  grpc_core::RefCountedPtr<grpc_auth_context> ctx =
      grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
  grpc_auth_context_add_cstring_property(
      ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
      GRPC_LOCAL_TRANSPORT_SECURITY_TYPE);
  GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
                 ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1);
  GPR_ASSERT(peer->property_count == 1);
  const tsi_peer_property* prop = &peer->properties[0];
  GPR_ASSERT(prop != nullptr);
  GPR_ASSERT(strcmp(prop->name, TSI_SECURITY_LEVEL_PEER_PROPERTY) == 0);
  grpc_auth_context_add_property(ctx.get(),
                                 GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
                                 prop->value.data, prop->value.length);
  return ctx;
}

void local_check_peer(grpc_security_connector* sc, tsi_peer peer,
                      grpc_endpoint* ep,
                      grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                      grpc_closure* on_peer_checked,
                      grpc_local_connect_type type) {
  int fd = grpc_endpoint_get_fd(ep);
  grpc_resolved_address resolved_addr;
  memset(&resolved_addr, 0, sizeof(resolved_addr));
  resolved_addr.len = GRPC_MAX_SOCKADDR_SIZE;
  bool is_endpoint_local = false;
  if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(resolved_addr.addr),
                  &resolved_addr.len) == 0) {
    grpc_resolved_address addr_normalized;
    grpc_resolved_address* addr =
        grpc_sockaddr_is_v4mapped(&resolved_addr, &addr_normalized)
            ? &addr_normalized
            : &resolved_addr;
    grpc_sockaddr* sock_addr = reinterpret_cast<grpc_sockaddr*>(&addr->addr);
    // UDS
    if (type == UDS && grpc_is_unix_socket(addr)) {
      is_endpoint_local = true;
      // IPV4
    } else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET) {
      const grpc_sockaddr_in* addr4 =
          reinterpret_cast<const grpc_sockaddr_in*>(sock_addr);
      if (grpc_htonl(addr4->sin_addr.s_addr) == INADDR_LOOPBACK) {
        is_endpoint_local = true;
      }
      // IPv6
    } else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET6) {
      const grpc_sockaddr_in6* addr6 =
          reinterpret_cast<const grpc_sockaddr_in6*>(addr);
      if (memcmp(&addr6->sin6_addr, &in6addr_loopback,
                 sizeof(in6addr_loopback)) == 0) {
        is_endpoint_local = true;
      }
    }
  }
  grpc_error* error = GRPC_ERROR_NONE;
  if (!is_endpoint_local) {
    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
        "Endpoint is neither UDS or TCP loopback address.");
    grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
    return;
  }
  // Add TSI_SECURITY_LEVEL_PEER_PROPERTY type peer property.
  size_t new_property_count = peer.property_count + 1;
  tsi_peer_property* new_properties = static_cast<tsi_peer_property*>(
      gpr_zalloc(sizeof(*new_properties) * new_property_count));
  for (size_t i = 0; i < peer.property_count; i++) {
    new_properties[i] = peer.properties[i];
  }
  if (peer.properties != nullptr) gpr_free(peer.properties);
  peer.properties = new_properties;
  const char* security_level =
      type == LOCAL_TCP
          ? tsi_security_level_to_string(TSI_SECURITY_NONE)
          : tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY);
  tsi_result result = tsi_construct_string_peer_property_from_cstring(
      TSI_SECURITY_LEVEL_PEER_PROPERTY, security_level,
      &peer.properties[peer.property_count]);
  if (result != TSI_OK) return;
  peer.property_count++;
  /* Create an auth context which is necessary to pass the santiy check in
   * {client, server}_auth_filter that verifies if the peer's auth context is
   * obtained during handshakes. The auth context is only checked for its
   * existence and not actually used.
   */
  *auth_context = local_auth_context_create(&peer);
  tsi_peer_destruct(&peer);
  error = *auth_context != nullptr ? GRPC_ERROR_NONE
                                   : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
                                         "Could not create local auth context");
  grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
}

class grpc_local_channel_security_connector final
    : public grpc_channel_security_connector {
 public:
  grpc_local_channel_security_connector(
      grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
      grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
      const char* target_name)
      : grpc_channel_security_connector(nullptr, std::move(channel_creds),
                                        std::move(request_metadata_creds)),
        target_name_(gpr_strdup(target_name)) {}

  ~grpc_local_channel_security_connector() override { gpr_free(target_name_); }

  void add_handshakers(
      const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
      grpc_core::HandshakeManager* handshake_manager) override {
    tsi_handshaker* handshaker = nullptr;
    GPR_ASSERT(local_tsi_handshaker_create(true /* is_client */, &handshaker) ==
               TSI_OK);
    handshake_manager->Add(
        grpc_core::SecurityHandshakerCreate(handshaker, this, args));
  }

  int cmp(const grpc_security_connector* other_sc) const override {
    auto* other =
        reinterpret_cast<const grpc_local_channel_security_connector*>(
            other_sc);
    int c = channel_security_connector_cmp(other);
    if (c != 0) return c;
    return strcmp(target_name_, other->target_name_);
  }

  void check_peer(tsi_peer peer, grpc_endpoint* ep,
                  grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                  grpc_closure* on_peer_checked) override {
    grpc_local_credentials* creds =
        reinterpret_cast<grpc_local_credentials*>(mutable_channel_creds());
    local_check_peer(this, peer, ep, auth_context, on_peer_checked,
                     creds->connect_type());
  }

  bool check_call_host(grpc_core::StringView host,
                       grpc_auth_context* /*auth_context*/,
                       grpc_closure* /*on_call_host_checked*/,
                       grpc_error** error) override {
    if (host.empty() || host != target_name_) {
      *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
          "local call host does not match target name");
    }
    return true;
  }

  void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
                              grpc_error* error) override {
    GRPC_ERROR_UNREF(error);
  }

  const char* target_name() const { return target_name_; }

 private:
  char* target_name_;
};

class grpc_local_server_security_connector final
    : public grpc_server_security_connector {
 public:
  grpc_local_server_security_connector(
      grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
      : grpc_server_security_connector(nullptr, std::move(server_creds)) {}
  ~grpc_local_server_security_connector() override = default;

  void add_handshakers(
      const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
      grpc_core::HandshakeManager* handshake_manager) override {
    tsi_handshaker* handshaker = nullptr;
    GPR_ASSERT(local_tsi_handshaker_create(false /* is_client */,
                                           &handshaker) == TSI_OK);
    handshake_manager->Add(
        grpc_core::SecurityHandshakerCreate(handshaker, this, args));
  }

  void check_peer(tsi_peer peer, grpc_endpoint* ep,
                  grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
                  grpc_closure* on_peer_checked) override {
    grpc_local_server_credentials* creds =
        static_cast<grpc_local_server_credentials*>(mutable_server_creds());
    local_check_peer(this, peer, ep, auth_context, on_peer_checked,
                     creds->connect_type());
  }

  int cmp(const grpc_security_connector* other) const override {
    return server_security_connector_cmp(
        static_cast<const grpc_server_security_connector*>(other));
  }
};
}  // namespace

grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_local_channel_security_connector_create(
    grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
    grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
    const grpc_channel_args* args, const char* target_name) {
  if (channel_creds == nullptr || target_name == nullptr) {
    gpr_log(
        GPR_ERROR,
        "Invalid arguments to grpc_local_channel_security_connector_create()");
    return nullptr;
  }
  // Perform sanity check on UDS address. For TCP local connection, the check
  // will be done during check_peer procedure.
  grpc_local_credentials* creds =
      static_cast<grpc_local_credentials*>(channel_creds.get());
  const grpc_arg* server_uri_arg =
      grpc_channel_args_find(args, GRPC_ARG_SERVER_URI);
  const char* server_uri_str = grpc_channel_arg_get_string(server_uri_arg);
  if (creds->connect_type() == UDS &&
      strncmp(GRPC_UDS_URI_PATTERN, server_uri_str,
              strlen(GRPC_UDS_URI_PATTERN)) != 0) {
    gpr_log(GPR_ERROR,
            "Invalid UDS target name to "
            "grpc_local_channel_security_connector_create()");
    return nullptr;
  }
  return grpc_core::MakeRefCounted<grpc_local_channel_security_connector>(
      channel_creds, request_metadata_creds, target_name);
}

grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_local_server_security_connector_create(
    grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
  if (server_creds == nullptr) {
    gpr_log(
        GPR_ERROR,
        "Invalid arguments to grpc_local_server_security_connector_create()");
    return nullptr;
  }
  return grpc_core::MakeRefCounted<grpc_local_server_security_connector>(
      std::move(server_creds));
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Authors: Mark Young <marky@lunarg.com>
//          Nat Brown <natb@valvesoftware.com>
//

#include <cstring>
#include "xr_dependencies.h"

#if defined DISABLE_STD_FILESYSTEM
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0

#else
// If the C++ macro is set to the version containing C++17, it must support
// the final C++17 package
#if __cplusplus >= 201703L
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1

#elif defined(_MSC_VER) && _MSC_VER >= 1900

#if defined(_HAS_CXX17) && _HAS_CXX17
// When MSC supports c++17 use <filesystem> package.
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#else
// MSC before c++17 need to use <experimental/filesystem> package.
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
#endif  // !_HAS_CXX17

// Right now, GCC still only supports the experimental filesystem items starting in GCC 6
#elif (__GNUC__ >= 6)
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0

// If Clang, check for feature support
#elif defined(__clang__) && (__cpp_lib_filesystem || __cpp_lib_experimental_filesystem)
#if __cpp_lib_filesystem
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#else
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
#endif

// If all above fails, fall back to standard C++ and OS-specific items
#else
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0
#endif
#endif

#if USE_FINAL_FS == 1
#include <filesystem>
#define FS_PREFIX std::filesystem
#elif USE_EXPERIMENTAL_FS == 1
#if (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
#error "Windows universal application doesn't support system::experimental::filesystem"
#endif
#include <experimental/filesystem>
#define FS_PREFIX std::experimental::filesystem
#elif defined(XR_USE_PLATFORM_WIN32)
// Windows fallback includes
#include <stdint.h>
#include <direct.h>
#include <shlwapi.h>
#else
// Linux/Apple fallback includes
#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <dirent.h>
#endif

#include "filesystem_utils.hpp"

#if defined(XR_USE_PLATFORM_WIN32)
#define PATH_SEPARATOR ';'
#define DIRECTORY_SYMBOL '\\'
#else
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
#endif

#if (USE_FINAL_FS == 1) || (USE_EXPERIMENTAL_FS == 1)
// We can use one of the C++ filesystem packages

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        return FS_PREFIX::is_regular_file(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        return FS_PREFIX::is_directory(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return FS_PREFIX::exists(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        FS_PREFIX::path file_path(path);
        return file_path.is_absolute();
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        FS_PREFIX::path cur_path = FS_PREFIX::current_path();
        path = cur_path.string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        FS_PREFIX::path path_var(file_path);
        parent_path = path_var.parent_path().string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        absolute = FS_PREFIX::absolute(path).string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        FS_PREFIX::path parent_path(parent);
        FS_PREFIX::path child_path(child);
        FS_PREFIX::path full_path = parent_path / child_path;
        combined = full_path.string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        for (auto& dir_iter : FS_PREFIX::directory_iterator(path)) {
            files.push_back(dir_iter.path().filename().string());
        }
        return true;
    } catch (...) {
    }
    return false;
}

#elif defined(XR_OS_WINDOWS)

// Workaround for MS VS 2010/2013 don't support the experimental filesystem

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        return (1 != PathIsDirectoryA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        return (1 == PathIsDirectoryA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return (1 == PathFileExistsA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        if ((path[0] == '\\') || (path[1] == ':' && (path[2] == '\\' || path[2] == '/'))) {
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        char tmp_path[MAX_PATH];
        if (nullptr != _getcwd(tmp_path, MAX_PATH - 1)) {
            path = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        std::string full_path;
        if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
            std::string::size_type lastSeperator = full_path.find_last_of(DIRECTORY_SYMBOL);
            parent_path = (lastSeperator == 0) ? full_path : full_path.substr(0, lastSeperator - 1);
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        char tmp_path[MAX_PATH];
        if (0 != GetFullPathNameA(path.c_str(), MAX_PATH, tmp_path, NULL)) {
            absolute = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        std::string::size_type parent_len = parent.length();
        if (0 == parent_len || "." == parent || ".\\" == parent || "./" == parent) {
            combined = child;
            return true;
        }
        char last_char = parent[parent_len - 1];
        if (last_char == DIRECTORY_SYMBOL) {
            parent_len--;
        }
        combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        WIN32_FIND_DATA file_data;
        HANDLE file_handle = FindFirstFileA(path.c_str(), &file_data);
        if (file_handle != INVALID_HANDLE_VALUE) {
            do {
                if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
                    files.push_back(file_data.cFileName);
                }
            } while (FindNextFile(file_handle, &file_data));
            return true;
        }
    } catch (...) {
    }
    return false;
}

#else  // XR_OS_LINUX/XR_OS_APPLE fallback

#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>

// simple POSIX-compatible implementation of the <filesystem> pieces used by OpenXR

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        struct stat path_stat;
        stat(path.c_str(), &path_stat);
        return S_ISREG(path_stat.st_mode);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        struct stat path_stat;
        stat(path.c_str(), &path_stat);
        return S_ISDIR(path_stat.st_mode);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return (access(path.c_str(), F_OK) != -1);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        return (path[0] == DIRECTORY_SYMBOL);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        char tmp_path[PATH_MAX];
        if (nullptr != getcwd(tmp_path, PATH_MAX - 1)) {
            path = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        std::string full_path;
        if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
            std::string::size_type lastSeperator = full_path.find_last_of(DIRECTORY_SYMBOL);
            parent_path = (lastSeperator == 0) ? full_path : full_path.substr(0, lastSeperator - 1);
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        char buf[PATH_MAX];
        if (nullptr != realpath(path.c_str(), buf)) {
            absolute = buf;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        std::string::size_type parent_len = parent.length();
        if (0 == parent_len || "." == parent || "./" == parent) {
            combined = child;
            return true;
        }
        char last_char = parent[parent_len - 1];
        if (last_char == DIRECTORY_SYMBOL) {
            parent_len--;
        }
        combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        DIR* dir;
        struct dirent* entry;
        dir = opendir(path.c_str());
        while (dir && (entry = readdir(dir))) {
            files.push_back(entry->d_name);
        }
        closedir(dir);
        return true;
    } catch (...) {
    }
    return false;
}

#endif
<commit_msg>make filesystem_util unicode compatible when USE_EXPERIMENTAL_FS=0 and USE_FINAL_FS=0<commit_after>// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Authors: Mark Young <marky@lunarg.com>
//          Nat Brown <natb@valvesoftware.com>
//

#include <cstring>
#include "xr_dependencies.h"

#if defined DISABLE_STD_FILESYSTEM
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0

#else
// If the C++ macro is set to the version containing C++17, it must support
// the final C++17 package
#if __cplusplus >= 201703L
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1

#elif defined(_MSC_VER) && _MSC_VER >= 1900

#if defined(_HAS_CXX17) && _HAS_CXX17
// When MSC supports c++17 use <filesystem> package.
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#else
// MSC before c++17 need to use <experimental/filesystem> package.
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
#endif  // !_HAS_CXX17

// Right now, GCC still only supports the experimental filesystem items starting in GCC 6
#elif (__GNUC__ >= 6)
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0

// If Clang, check for feature support
#elif defined(__clang__) && (__cpp_lib_filesystem || __cpp_lib_experimental_filesystem)
#if __cpp_lib_filesystem
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#else
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
#endif

// If all above fails, fall back to standard C++ and OS-specific items
#else
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0
#endif
#endif

#if USE_FINAL_FS == 1
#include <filesystem>
#define FS_PREFIX std::filesystem
#elif USE_EXPERIMENTAL_FS == 1
#if (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
#error "Windows universal application doesn't support system::experimental::filesystem"
#endif
#include <experimental/filesystem>
#define FS_PREFIX std::experimental::filesystem
#elif defined(XR_USE_PLATFORM_WIN32)
// Windows fallback includes
#include <stdint.h>
#include <direct.h>
#include <shlwapi.h>
#else
// Linux/Apple fallback includes
#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <dirent.h>
#endif

#include "filesystem_utils.hpp"

#if defined(XR_USE_PLATFORM_WIN32)
#define PATH_SEPARATOR ';'
#define DIRECTORY_SYMBOL '\\'
#else
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
#endif

#if (USE_FINAL_FS == 1) || (USE_EXPERIMENTAL_FS == 1)
// We can use one of the C++ filesystem packages

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        return FS_PREFIX::is_regular_file(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        return FS_PREFIX::is_directory(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return FS_PREFIX::exists(path);
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        FS_PREFIX::path file_path(path);
        return file_path.is_absolute();
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        FS_PREFIX::path cur_path = FS_PREFIX::current_path();
        path = cur_path.string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        FS_PREFIX::path path_var(file_path);
        parent_path = path_var.parent_path().string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        absolute = FS_PREFIX::absolute(path).string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        FS_PREFIX::path parent_path(parent);
        FS_PREFIX::path child_path(child);
        FS_PREFIX::path full_path = parent_path / child_path;
        combined = full_path.string();
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        for (auto& dir_iter : FS_PREFIX::directory_iterator(path)) {
            files.push_back(dir_iter.path().filename().string());
        }
        return true;
    } catch (...) {
    }
    return false;
}

#elif defined(XR_OS_WINDOWS)

// Workaround for MS VS 2010/2013 don't support the experimental filesystem

std::vector<wchar_t> MultibyteToWChar(std::string str) {
    const char* mbstr = str.c_str();
    std::mbstate_t state = std::mbstate_t();
    std::size_t len = 1 + std::mbsrtowcs(NULL, &mbstr, 0, &state);
    std::vector<wchar_t> wstr(len);
    std::mbsrtowcs(&wstr[0], &mbstr, wstr.size(), &state);
    return wstr;
}

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        return (1 != PathIsDirectoryA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        return (1 == PathIsDirectoryA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return (1 == PathFileExistsA(path.c_str()));
    } catch (...) {
        return false;
    }
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        if ((path[0] == '\\') || (path[1] == ':' && (path[2] == '\\' || path[2] == '/'))) {
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        char tmp_path[MAX_PATH];
        if (nullptr != _getcwd(tmp_path, MAX_PATH - 1)) {
            path = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        std::string full_path;
        if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
            std::string::size_type lastSeperator = full_path.find_last_of(DIRECTORY_SYMBOL);
            parent_path = (lastSeperator == 0) ? full_path : full_path.substr(0, lastSeperator - 1);
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        char tmp_path[MAX_PATH];
        if (0 != GetFullPathNameA(path.c_str(), MAX_PATH, tmp_path, NULL)) {
            absolute = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        std::string::size_type parent_len = parent.length();
        if (0 == parent_len || "." == parent || ".\\" == parent || "./" == parent) {
            combined = child;
            return true;
        }
        char last_char = parent[parent_len - 1];
        if (last_char == DIRECTORY_SYMBOL) {
            parent_len--;
        }
        combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        WIN32_FIND_DATA file_data;
        HANDLE file_handle = FindFirstFileA(path.c_str(), &file_data);
        if (file_handle != INVALID_HANDLE_VALUE) {
            do {
                if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
                    const wchar_t* wstr = file_data.cFileName;
                    std::mbstate_t state = std::mbstate_t();
                    std::size_t len = 1 + std::wcsrtombs(nullptr, &wstr, 0, &state);
                    std::vector<char> mbstr(len);
                    std::wcsrtombs(&mbstr[0], &wstr, mbstr.size(), &state);
                    files.push_back(mbstr.data());
                }
            } while (FindNextFile(file_handle, &file_data));
            return true;
        }
    } catch (...) {
    }
    return false;
}

#else  // XR_OS_LINUX/XR_OS_APPLE fallback

#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>

// simple POSIX-compatible implementation of the <filesystem> pieces used by OpenXR

bool FileSysUtilsIsRegularFile(const std::string& path) {
    try {
        struct stat path_stat;
        stat(path.c_str(), &path_stat);
        return S_ISREG(path_stat.st_mode);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsIsDirectory(const std::string& path) {
    try {
        struct stat path_stat;
        stat(path.c_str(), &path_stat);
        return S_ISDIR(path_stat.st_mode);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsPathExists(const std::string& path) {
    try {
        return (access(path.c_str(), F_OK) != -1);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsIsAbsolutePath(const std::string& path) {
    try {
        return (path[0] == DIRECTORY_SYMBOL);
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetCurrentPath(std::string& path) {
    try {
        char tmp_path[PATH_MAX];
        if (nullptr != getcwd(tmp_path, PATH_MAX - 1)) {
            path = tmp_path;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
    try {
        std::string full_path;
        if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
            std::string::size_type lastSeperator = full_path.find_last_of(DIRECTORY_SYMBOL);
            parent_path = (lastSeperator == 0) ? full_path : full_path.substr(0, lastSeperator - 1);
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
    try {
        char buf[PATH_MAX];
        if (nullptr != realpath(path.c_str(), buf)) {
            absolute = buf;
            return true;
        }
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
    try {
        std::string::size_type parent_len = parent.length();
        if (0 == parent_len || "." == parent || "./" == parent) {
            combined = child;
            return true;
        }
        char last_char = parent[parent_len - 1];
        if (last_char == DIRECTORY_SYMBOL) {
            parent_len--;
        }
        combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
    try {
        std::string::size_type start = 0;
        std::string::size_type location = path_list.find(PATH_SEPARATOR);
        while (location != std::string::npos) {
            paths.push_back(path_list.substr(start, location));
            start = location + 1;
            location = path_list.find(PATH_SEPARATOR, start);
        }
        paths.push_back(path_list.substr(start, location));
        return true;
    } catch (...) {
    }
    return false;
}

bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
    try {
        DIR* dir;
        struct dirent* entry;
        dir = opendir(path.c_str());
        while (dir && (entry = readdir(dir))) {
            files.push_back(entry->d_name);
        }
        closedir(dir);
        return true;
    } catch (...) {
    }
    return false;
}

#endif
<|endoftext|>