<commit_before>// Filename: loader.cxx
// Created by:  mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "loader.h"
#include "loaderFileType.h"
#include "loaderFileTypeRegistry.h"
#include "config_pgraph.h"

#include "config_express.h"
#include "config_util.h"
#include "virtualFileSystem.h"
#include "event.h"
#include "pt_Event.h"
#include "throw_event.h"
#include "eventParameter.h"
#include "circBuffer.h"
#include "filename.h"
#include "load_dso.h"
#include "string_utils.h"
#include "plist.h"
#include "pvector.h"

#include <algorithm>

bool Loader::_file_types_loaded = false;

////////////////////////////////////////////////////////////////////
//      Struct : LoaderToken
// Description : Holds a request for the loader (load or delete), as
//               well as the return information after the request has
//               completed.
////////////////////////////////////////////////////////////////////
class LoaderToken : public ReferenceCount {
public:
  INLINE LoaderToken(uint id, const string &event_name, const Filename &path,
                     bool search, PandaNode *node=NULL) :
    _id(id),
    _event_name(event_name),
    _path(path),
    _search(search),
    _node(node)
  { }
  uint _id;
  string _event_name;
  Filename _path;
  bool _search;
  PT(PandaNode) _node;
};

////////////////////////////////////////////////////////////////////
//     Function: Loader::Constructor
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
Loader::
Loader() : AsyncUtility() {
  _token_board = new LoaderTokenBoard;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::Destructor
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
Loader::
~Loader() {
  destroy_thread();
  delete _token_board;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::find_all_files
//       Access: Published
//  Description: Searches along the given search path for the given
//               file name, and fills up the results list with all
//               possible matches and their associated types, in
//               order.
////////////////////////////////////////////////////////////////////
int Loader::
find_all_files(const Filename &filename, const DSearchPath &search_path,
               Loader::Results &results) const {
  if (!_file_types_loaded) {
    load_file_types();
  }
  string extension = filename.get_extension();
  string extra_ext;
  bool pz_file = false;

#ifdef HAVE_ZLIB
  if (extension == "pz") {
    // The extension ".pz" is special.  This is an explicitly-named
    // compressed file.  We'll decompress it on the fly, if possible.
    // (This relies on the auto_unwrap parameter to vfs->read_file(),
    // which is different from the implicitly-named compressed file
    // action that you might get if vfs-implicit-pz is enabled.)
    extra_ext = extension;
    extension = Filename(filename.get_basename_wo_extension()).get_extension();
    pz_file = true;
  }
#endif  // HAVE_ZLIB

  int num_added = 0;

  if (!extension.empty()) {
    // If the extension is not empty, it specifies a single file type.
    LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr();
    LoaderFileType *requested_type =
      reg->get_type_from_extension(extension);

    if (requested_type != (LoaderFileType *)NULL &&
        (!pz_file || requested_type->supports_compressed())) {
      if (!filename.is_local()) {
        // Global filename, take it as it is.
        results.add_file(filename, requested_type);
        num_added++;

      } else {
        // Local filename, search along the path.
        DSearchPath::Results files;
        VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
        num_added = vfs->find_all_files(filename, search_path, files);

        for (int i = 0; i < num_added; ++i) {
          results.add_file(files.get_file(i), requested_type);
        }
      }
    }
  } else {
    // If the extension *is* empty, we have to search for all possible
    // file types.
    LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr();
    int num_types = reg->get_num_types();

    if (!filename.is_local()) {
      // Global filename, take it as it is.
      for (int t = 0; t < num_types; ++t) {
        LoaderFileType *type = reg->get_type(t);
        Filename file(filename);
        file.set_extension(type->get_extension());
        file = file.get_fullpath() + extra_ext;

        VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
        if (vfs->exists(file)) {
          results.add_file(file, type);
          ++num_added;
        }
      }
    } else {
      // Local filename, look it up on the model path.
      int num_dirs = search_path.get_num_directories();
      for (int i = 0; i < num_dirs; ++i) {
        const Filename &directory = search_path.get_directory(i);

        for (int t = 0; t < num_types; ++t) {
          LoaderFileType *type = reg->get_type(t);
          Filename file(directory, filename);
          file.set_extension(type->get_extension());
          file = file.get_fullpath() + extra_ext;

          VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
          if (vfs->exists(file)) {
            results.add_file(file, type);
            ++num_added;
          }
        }
      }
    }
  }

  return num_added;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::request_load
//       Access: Published
//  Description: Requests an asynchronous load of a file.  The request
//               will be queued and served by the asynchronous thread.
//               If event_name is nonempty, it is the name of the
//               event that will be thrown (with the uint id as its
//               single parameter) when the loading is completed later.
//
//               The return value is an integer which can be used to
//               identify this particular request later to
//               fetch_load(), or 0 if there has been an error.
//
//               If search is true, the file is searched for along the
//               model path; otherwise, only the exact filename is
//               loaded.
////////////////////////////////////////////////////////////////////
uint Loader::
request_load(const string &event_name, const Filename &filename, bool search) {
  if (!_file_types_loaded) {
    load_file_types();
  }

  PT(LoaderToken) tok;
  if (asynchronous_loads) {

    // Make sure we actually are threaded
    if (!_threaded) {
      loader_cat.info()
        << "Loader::request_load() - create_thread() was "
        << "never called!  Calling it now..." << endl;
      create_thread();
    }

    // We need to grab the lock in order to signal the condition variable
#ifdef OLD_HAVE_IPC
    _lock.lock();
#endif

      if (_token_board->_waiting.full()) {
        loader_cat.error()
          << "Loader::request_load() - Too many pending requests\n";
        return 0;
      }

      if (loader_cat.is_debug()) {
        loader_cat.debug()
          << "Load requested for file: " << filename << "\n";
      }

      tok = new LoaderToken(_next_token++, event_name, filename, search);
      _token_board->_waiting.push_back(tok);

#ifdef OLD_HAVE_IPC
      _request_cond->signal();
    _lock.unlock();
#endif

  } else {
    // If we're not running asynchronously, process the load request
    // directly now.
    if (_token_board->_waiting.full()) {
      loader_cat.error()
        << "Loader::request_load() - Too many pending requests\n";
      return 0;
    }

    if (loader_cat.is_debug()) {
      loader_cat.debug()
        << "Load requested for file: " << filename << "\n";
    }

    tok = new LoaderToken(_next_token++, event_name, filename, search);
    _token_board->_waiting.push_back(tok);
    process_request();
  }

  return tok->_id;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::check_load
//       Access: Published
//  Description: Returns true if the indicated load-request has
//               completed and not yet been fetched, false otherwise.
////////////////////////////////////////////////////////////////////
bool Loader::
check_load(uint id) {
  return _token_board->is_done_token(id);
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::fetch_load
//       Access: Published
//  Description: Returns the Node associated with the indicated id
//               number (returned by a previous call to request_load),
//               or NULL if the request has not yet completed.
////////////////////////////////////////////////////////////////////
PT(PandaNode) Loader::
fetch_load(uint id) {
  PT(LoaderToken) tok = _token_board->get_done_token(id);
  if (tok.is_null()) {
    loader_cat.debug()
      << "Request to fetch id " << id << " which has not yet completed.\n";
    return NULL;
  }
  PT(PandaNode) node = tok->_node;
  return node;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::load_file_types
//       Access: Private, Static
//  Description: Loads up all of the dynamic libraries named in a
//               load-file-type Configure variable.  Presumably this
//               will make the various file types available for
//               runtime loading.
////////////////////////////////////////////////////////////////////
void Loader::
load_file_types() {
  if (!_file_types_loaded) {
    int num_unique_values = load_file_type.get_num_unique_values();

    for (int i = 0; i < num_unique_values; i++) {
      string param = load_file_type.get_unique_value(i);

      vector_string words;
      extract_words(param, words);

      if (words.size() == 1) {
        // Exactly one word: load the named library immediately.
        string name = words[0];
        Filename dlname = Filename::dso_filename("lib" + name + ".so");
        loader_cat.info()
          << "loading file type module: " << name << endl;
        void *tmp = load_dso(dlname);
        if (tmp == (void *)NULL) {
          loader_cat.warning()
            << "Unable to load " << dlname.to_os_specific()
            << ": " << load_dso_error() << endl;
        }

      } else if (words.size() > 1) {
        // Multiple words: the first n words are filename extensions,
        // and the last word is the name of the library to load should
        // any of those filename extensions be encountered.
        LoaderFileTypeRegistry *registry = LoaderFileTypeRegistry::get_global_ptr();
        size_t num_extensions = words.size() - 1;
        string library_name = words[num_extensions];

        for (size_t i = 0; i < num_extensions; i++) {
          string extension = words[i];
          if (extension[0] == '.') {
            extension = extension.substr(1);
          }

          registry->register_deferred_type(extension, library_name);
        }
      }
    }

    _file_types_loaded = true;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::process_request
//       Access: Private
//  Description: Serves any requests on the token board, moving them
//               to the done queue.
////////////////////////////////////////////////////////////////////
bool Loader::
process_request() {
  if (_shutdown) {
    if (loader_cat.is_debug())
      loader_cat.debug()
          << "Loader shutting down...\n";
    return false;
  }

  // If there is actually a request token - process it
  while (!_token_board->_waiting.empty()) {
    PT(LoaderToken) tok = _token_board->_waiting.front();
    _token_board->_waiting.pop_front();
    tok->_node = load_file(tok->_path, tok->_search);
    if (tok->_node == (PandaNode *)NULL) {
      loader_cat.error()
        << "Loader::callback() - couldn't find file: "
        << tok->_path << "\n";
    } else {
      _token_board->_done.push_back(tok);

      // Throw a "done" event now.
      if (!tok->_event_name.empty()) {
        PT_Event done = new Event(tok->_event_name);
        done->add_parameter(EventParameter((int)tok->_id));
        throw_event(done);
      }
    }

    if (loader_cat.is_debug()) {
      loader_cat.debug()
        << "loading complete for " << tok->_path << "\n";
    }
  }

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::load_file
//       Access: Private
//  Description: Loads a single scene graph file, if possible.
//               Returns the Node that is the root of the file, or
//               NULL if the file cannot be loaded.
//
//               If search is true, the file is searched for along the
//               model path; otherwise, only the exact filename is
//               loaded.
////////////////////////////////////////////////////////////////////
PT(PandaNode) Loader::
load_file(const Filename &filename, const LoaderOptions &options) const {
  Results results;
  int num_files;

  bool search = (options.get_flags() & LoaderOptions::LF_search) != 0;

  if (search) {
    // Look for the file along the model path.
    num_files = find_all_files(filename, get_model_path(), results);
  } else {
    // Look for the file only where it is.
    num_files = find_all_files(filename, DSearchPath(Filename(".")), results);
  }

  if (num_files == 0) {
    // Couldn't find the file.  Either it doesn't exist, or it's an
    // unknown file type.  Report a useful message either way.
    string extension = filename.get_extension();
#ifdef HAVE_ZLIB
    if (extension == "pz") {
      extension = Filename(filename.get_basename_wo_extension()).get_extension();
    }
#endif  // HAVE_ZLIB
    if (!extension.empty()) {
      LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr();
      LoaderFileType *requested_type =
        reg->get_type_from_extension(extension);
      if (requested_type == (LoaderFileType *)NULL) {
        loader_cat.error()
          << "Extension of file " << filename
          << " is unrecognized; cannot load.\n";
        loader_cat.error(false)
          << "Currently known scene file types are:\n";
        reg->write(loader_cat.error(false), 2);
        return NULL;
      }
    }

    if (search) {
      loader_cat.error()
        << "Couldn't load file " << filename << ": not found on model path "
        << "(which is currently: \"" << get_model_path() << "\")\n";
    } else {
      loader_cat.error()
        << "Couldn't load file ./" << filename << ": does not exist.\n";
    }
    return NULL;
  }

  for (int i = 0; i < num_files; ++i) {
    const Filename &path = results.get_file(i);
    LoaderFileType *type = results.get_file_type(i);
    PT(PandaNode) result = type->load_file(path, options);
    if (result != (PandaNode *)NULL) {
      return result;
    }
  }

  // None of the matching files could be loaded.  Oh well.
  if (search) {
    loader_cat.error()
      << "Couldn't load file " << filename
      << ": all matching files on model path invalid "
      << "(the model path is currently: \"" << get_model_path() << "\")\n";
  } else {
    loader_cat.error()
      << "Couldn't load file " << filename
      << ": invalid.\n";
  }
  return NULL;
}

<commit_msg>better diagnostic<commit_after>// Filename: loader.cxx
// Created by:  mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "loader.h"
#include "loaderFileType.h"
#include "loaderFileTypeRegistry.h"
#include "config_pgraph.h"

#include "config_express.h"
#include "config_util.h"
#include "virtualFileSystem.h"
#include "event.h"
#include "pt_Event.h"
#include "throw_event.h"
#include "eventParameter.h"
#include "circBuffer.h"
#include "filename.h"
#include "load_dso.h"
#include "string_utils.h"
#include "plist.h"
#include "pvector.h"

#include <algorithm>

bool Loader::_file_types_loaded = false;

////////////////////////////////////////////////////////////////////
//      Struct : LoaderToken
// Description : Holds a request for the loader (load or delete), as
//               well as the return information after the request has
//               completed.
////////////////////////////////////////////////////////////////////
class LoaderToken : public ReferenceCount {
public:
  INLINE LoaderToken(uint id, const string &event_name, const Filename &path,
                     bool search, PandaNode *node=NULL) :
    _id(id),
    _event_name(event_name),
    _path(path),
    _search(search),
    _node(node)
  { }
  uint _id;
  string _event_name;
  Filename _path;
  bool _search;
  PT(PandaNode) _node;
};

////////////////////////////////////////////////////////////////////
//     Function: Loader::Constructor
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
Loader::
Loader() : AsyncUtility() {
  _token_board = new LoaderTokenBoard;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::Destructor
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
Loader::
~Loader() {
  destroy_thread();
  delete _token_board;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::find_all_files
//       Access: Published
//  Description: Searches along the given search path for the given
//               file name, and fills up the results list with all
//               possible matches and their associated types, in
//               order.
////////////////////////////////////////////////////////////////////
int Loader::
find_all_files(const Filename &filename, const DSearchPath &search_path,
               Loader::Results &results) const {
  if (!_file_types_loaded) {
    load_file_types();
  }
  string extension = filename.get_extension();
  string extra_ext;
  bool pz_file = false;

#ifdef HAVE_ZLIB
  if (extension == "pz") {
    // The extension ".pz" is special.  This is an explicitly-named
    // compressed file.  We'll decompress it on the fly, if possible.
    // (This relies on the auto_unwrap parameter to vfs->read_file(),
    // which is different from the implicitly-named compressed file
    // action that you might get if vfs-implicit-pz is enabled.)
    extra_ext = extension;
    extension = Filename(filename.get_basename_wo_extension()).get_extension();
    pz_file = true;
  }
#endif  // HAVE_ZLIB

  int num_added = 0;

  if (!extension.empty()) {
    // If the extension is not empty, it specifies a single file type.
    LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr();
    LoaderFileType *requested_type =
      reg->get_type_from_extension(extension);

    if (requested_type != (LoaderFileType *)NULL &&
        (!pz_file || requested_type->supports_compressed())) {
      if (!filename.is_local()) {
        // Global filename, take it as it is.
        results.add_file(filename, requested_type);
        num_added++;

      } else {
        // Local filename, search along the path.
        DSearchPath::Results files;
        VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
        num_added = vfs->find_all_files(filename, search_path, files);

        for (int i = 0; i < num_added; ++i) {
          results.add_file(files.get_file(i), requested_type);
        }
      }
    }
  } else {
    // If the extension *is* empty, we have to search for all possible
    // file types.
    LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr();
    int num_types = reg->get_num_types();

    if (!filename.is_local()) {
      // Global filename, take it as it is.
      for (int t = 0; t < num_types; ++t) {
        LoaderFileType *type = reg->get_type(t);
        Filename file(filename);
        file.set_extension(type->get_extension());
        file = file.get_fullpath() + extra_ext;

        VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
        if (vfs->exists(file)) {
          results.add_file(file, type);
          ++num_added;
        }
      }
    } else {
      // Local filename, look it up on the model path.
      int num_dirs = search_path.get_num_directories();
      for (int i = 0; i < num_dirs; ++i) {
        const Filename &directory = search_path.get_directory(i);

        for (int t = 0; t < num_types; ++t) {
          LoaderFileType *type = reg->get_type(t);
          Filename file(directory, filename);
          file.set_extension(type->get_extension());
          file = file.get_fullpath() + extra_ext;

          VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
          if (vfs->exists(file)) {
            results.add_file(file, type);
            ++num_added;
          }
        }
      }
    }
  }

  return num_added;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::request_load
//       Access: Published
//  Description: Requests an asynchronous load of a file.  The request
//               will be queued and served by the asynchronous thread.
//               If event_name is nonempty, it is the name of the
//               event that will be thrown (with the uint id as its
//               single parameter) when the loading is completed later.
//
//               The return value is an integer which can be used to
//               identify this particular request later to
//               fetch_load(), or 0 if there has been an error.
//
//               If search is true, the file is searched for along the
//               model path; otherwise, only the exact filename is
//               loaded.
////////////////////////////////////////////////////////////////////
uint Loader::
request_load(const string &event_name, const Filename &filename, bool search) {
  if (!_file_types_loaded) {
    load_file_types();
  }

  PT(LoaderToken) tok;
  if (asynchronous_loads) {

    // Make sure we actually are threaded
    if (!_threaded) {
      loader_cat.info()
        << "Loader::request_load() - create_thread() was "
        << "never called!  Calling it now..." << endl;
      create_thread();
    }

    // We need to grab the lock in order to signal the condition variable
#ifdef OLD_HAVE_IPC
    _lock.lock();
#endif

      if (_token_board->_waiting.full()) {
        loader_cat.error()
          << "Loader::request_load() - Too many pending requests\n";
        return 0;
      }

      if (loader_cat.is_debug()) {
        loader_cat.debug()
          << "Load requested for file: " << filename << "\n";
      }

      tok = new LoaderToken(_next_token++, event_name, filename, search);
      _token_board->_waiting.push_back(tok);

#ifdef OLD_HAVE_IPC
      _request_cond->signal();
    _lock.unlock();
#endif

  } else {
    // If we're not running asynchronously, process the load request
    // directly now.
    if (_token_board->_waiting.full()) {
      loader_cat.error()
        << "Loader::request_load() - Too many pending requests\n";
      return 0;
    }

    if (loader_cat.is_debug()) {
      loader_cat.debug()
        << "Load requested for file: " << filename << "\n";
    }

    tok = new LoaderToken(_next_token++, event_name, filename, search);
    _token_board->_waiting.push_back(tok);
    process_request();
  }

  return tok->_id;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::check_load
//       Access: Published
//  Description: Returns true if the indicated load-request has
//               completed and not yet been fetched, false otherwise.
////////////////////////////////////////////////////////////////////
bool Loader::
check_load(uint id) {
  return _token_board->is_done_token(id);
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::fetch_load
//       Access: Published
//  Description: Returns the Node associated with the indicated id
//               number (returned by a previous call to request_load),
//               or NULL if the request has not yet completed.
////////////////////////////////////////////////////////////////////
PT(PandaNode) Loader::
fetch_load(uint id) {
  PT(LoaderToken) tok = _token_board->get_done_token(id);
  if (tok.is_null()) {
    loader_cat.debug()
      << "Request to fetch id " << id << " which has not yet completed.\n";
    return NULL;
  }
  PT(PandaNode) node = tok->_node;
  return node;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::load_file_types
//       Access: Private, Static
//  Description: Loads up all of the dynamic libraries named in a
//               load-file-type Configure variable.  Presumably this
//               will make the various file types available for
//               runtime loading.
////////////////////////////////////////////////////////////////////
void Loader::
load_file_types() {
  if (!_file_types_loaded) {
    int num_unique_values = load_file_type.get_num_unique_values();

    for (int i = 0; i < num_unique_values; i++) {
      string param = load_file_type.get_unique_value(i);

      vector_string words;
      extract_words(param, words);

      if (words.size() == 1) {
        // Exactly one word: load the named library immediately.
        string name = words[0];
        Filename dlname = Filename::dso_filename("lib" + name + ".so");
        loader_cat.info()
          << "loading file type module: " << name << endl;
        void *tmp = load_dso(dlname);
        if (tmp == (void *)NULL) {
          loader_cat.warning()
            << "Unable to load " << dlname.to_os_specific()
            << ": " << load_dso_error() << endl;
        }

      } else if (words.size() > 1) {
        // Multiple words: the first n words are filename extensions,
        // and the last word is the name of the library to load should
        // any of those filename extensions be encountered.
        LoaderFileTypeRegistry *registry = LoaderFileTypeRegistry::get_global_ptr();
        size_t num_extensions = words.size() - 1;
        string library_name = words[num_extensions];

        for (size_t i = 0; i < num_extensions; i++) {
          string extension = words[i];
          if (extension[0] == '.') {
            extension = extension.substr(1);
          }

          registry->register_deferred_type(extension, library_name);
        }
      }
    }

    _file_types_loaded = true;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::process_request
//       Access: Private
//  Description: Serves any requests on the token board, moving them
//               to the done queue.
////////////////////////////////////////////////////////////////////
bool Loader::
process_request() {
  if (_shutdown) {
    if (loader_cat.is_debug())
      loader_cat.debug()
          << "Loader shutting down...\n";
    return false;
  }

  // If there is actually a request token - process it
  while (!_token_board->_waiting.empty()) {
    PT(LoaderToken) tok = _token_board->_waiting.front();
    _token_board->_waiting.pop_front();
    tok->_node = load_file(tok->_path, tok->_search);
    if (tok->_node == (PandaNode *)NULL) {
      loader_cat.error()
        << "Loader::callback() - couldn't find file: "
        << tok->_path << "\n";
    } else {
      _token_board->_done.push_back(tok);

      // Throw a "done" event now.
      if (!tok->_event_name.empty()) {
        PT_Event done = new Event(tok->_event_name);
        done->add_parameter(EventParameter((int)tok->_id));
        throw_event(done);
      }
    }

    if (loader_cat.is_debug()) {
      loader_cat.debug()
        << "loading complete for " << tok->_path << "\n";
    }
  }

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: Loader::load_file
//       Access: Private
//  Description: Loads a single scene graph file, if possible.
//               Returns the Node that is the root of the file, or
//               NULL if the file cannot be loaded.
//
//               If search is true, the file is searched for along the
//               model path; otherwise, only the exact filename is
//               loaded.
////////////////////////////////////////////////////////////////////
PT(PandaNode) Loader::
load_file(const Filename &filename, const LoaderOptions &options) const {
  Results results;
  int num_files;

  bool search = (options.get_flags() & LoaderOptions::LF_search) != 0;

  if (search) {
    // Look for the file along the model path.
    num_files = find_all_files(filename, get_model_path(), results);
  } else {
    // Look for the file only where it is.
    num_files = find_all_files(filename, DSearchPath(Filename(".")), results);
  }

  if (num_files == 0) {
    // Couldn't find the file.  Either it doesn't exist, or it's an
    // unknown file type.  Report a useful message either way.
    string extension = filename.get_extension();
    bool pz_file = false;
#ifdef HAVE_ZLIB
    if (extension == "pz") {
      pz_file = true;
      extension = Filename(filename.get_basename_wo_extension()).get_extension();
    }
#endif  // HAVE_ZLIB
    if (!extension.empty()) {
      LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr();
      LoaderFileType *requested_type =
        reg->get_type_from_extension(extension);
      if (requested_type == (LoaderFileType *)NULL) {
        loader_cat.error()
          << "Extension of file " << filename
          << " is unrecognized; cannot load.\n";
        loader_cat.error(false)
          << "Currently known scene file types are:\n";
        reg->write(loader_cat.error(false), 2);
        return NULL;
      } else if (pz_file && !requested_type->supports_compressed()) {
        loader_cat.error()
          << requested_type->get_name() << " file type (."
          << extension << ") does not support in-line compression.\n";
        return NULL;
      }
    }

    if (search) {
      loader_cat.error()
        << "Couldn't load file " << filename << ": not found on model path "
        << "(which is currently: \"" << get_model_path() << "\")\n";
    } else {
      loader_cat.error()
        << "Couldn't load file ./" << filename << ": does not exist.\n";
    }
    return NULL;
  }

  for (int i = 0; i < num_files; ++i) {
    const Filename &path = results.get_file(i);
    LoaderFileType *type = results.get_file_type(i);
    PT(PandaNode) result = type->load_file(path, options);
    if (result != (PandaNode *)NULL) {
      return result;
    }
  }

  // None of the matching files could be loaded.  Oh well.
  if (search) {
    loader_cat.error()
      << "Couldn't load file " << filename
      << ": all matching files on model path invalid "
      << "(the model path is currently: \"" << get_model_path() << "\")\n";
  } else {
    loader_cat.error()
      << "Couldn't load file " << filename
      << ": invalid.\n";
  }
  return NULL;
}

<|endoftext|>


<commit_before>#ifndef _WIN32
#include "WindowsContainer.h"
int WINAPI WinMain(
	HINSTANCE	hInstance,
	HINSTANCE	hPrevInstance,
	LPSTR		lpCmdLine,
	int			nCmdShow)
{
	WindowsContainer win;
	win.main(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
	return 0;
}

#else

#include "vld.h" //insert debug-flag here
#include "LinuxContainer.h"
int main(int argc, char** argv)
{
	LinuxContainer* linuxContainer = new LinuxContainer();
	linuxContainer->mainContainer(argc, argv);
	DELETE_NULL(linuxContainer);

	return 0;
}
#endif //_WIN32
<commit_msg>Changed to windows in main.cpp<commit_after>#ifdef _WIN32
#include "WindowsContainer.h"
int WINAPI WinMain(
	HINSTANCE	hInstance,
	HINSTANCE	hPrevInstance,
	LPSTR		lpCmdLine,
	int			nCmdShow)
{
	WindowsContainer win;
	win.main(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
	return 0;
}

#else

#include "vld.h" //insert debug-flag here
#include "LinuxContainer.h"
int main(int argc, char** argv)
{
	LinuxContainer* linuxContainer = new LinuxContainer();
	linuxContainer->mainContainer(argc, argv);
	DELETE_NULL(linuxContainer);

	return 0;
}
#endif //_WIN32
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "maemorunfactories.h"

#include "maemoapplicationrunnerhelperactions.h"
#include "maemoconstants.h"
#include "maemoglobal.h"
#include "maemoremotemountsmodel.h"
#include "maemorunconfiguration.h"

#include <debugger/debuggerconstants.h>
#include <debugger/debuggerstartparameters.h>
#include <debugger/debuggerplugin.h>
#include <debugger/debuggerrunner.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/target.h>
#include <qt4projectmanager/qt4nodes.h>
#include <qt4projectmanager/qt4project.h>
#include <qtsupport/customexecutablerunconfiguration.h>
#include <remotelinux/remotelinuxdebugsupport.h>
#include <remotelinux/remotelinuxruncontrol.h>

using namespace Debugger;
using namespace ProjectExplorer;
using namespace Qt4ProjectManager;
using namespace RemoteLinux;

namespace Madde {
namespace Internal {

namespace {

QString pathFromId(Core::Id id)
{
    QString idStr = id.toString();
    const QString prefix = QLatin1String(MAEMO_RC_ID_PREFIX);
    if (!idStr.startsWith(prefix))
        return QString();
    return idStr.mid(prefix.size());
}

template<class Receiver> void setHelperActions(Receiver *receiver, MaemoRunConfiguration *runConfig,
        RunControl *runControl)
{
    const Kit * const k = runConfig->target()->kit();
    MaemoPreRunAction * const preRunAction = new MaemoPreRunAction(
            DeviceKitInformation::device(k), MaemoGlobal::maddeRoot(k),
            runConfig->remoteMounts()->mountSpecs(), runControl);
    MaemoPostRunAction * const postRunAction
            = new MaemoPostRunAction(preRunAction->mounter(), runControl);
    receiver->setApplicationRunnerPreRunAction(preRunAction);
    receiver->setApplicationRunnerPostRunAction(postRunAction);
}

} // namespace

MaemoRunConfigurationFactory::MaemoRunConfigurationFactory(QObject *parent)
    : QmakeRunConfigurationFactory(parent)
{ setObjectName(QLatin1String("MaemoRunConfigurationFactory")); }

MaemoRunConfigurationFactory::~MaemoRunConfigurationFactory()
{
}

bool MaemoRunConfigurationFactory::canCreate(Target *parent, const Core::Id id) const
{
    if (!canHandle(parent))
        return false;
    return static_cast<Qt4Project *>(parent->project())->hasApplicationProFile(pathFromId(id));
}

bool MaemoRunConfigurationFactory::canRestore(Target *parent,
    const QVariantMap &map) const
{
    return canHandle(parent)
        && ProjectExplorer::idFromMap(map).toString().startsWith(QLatin1String(MAEMO_RC_ID_PREFIX));
}

bool MaemoRunConfigurationFactory::canClone(Target *parent,
    RunConfiguration *source) const
{
    if (!canHandle(parent))
        return false;
    const RemoteLinuxRunConfiguration * const rlrc
            = qobject_cast<RemoteLinuxRunConfiguration *>(source);
    QString idStr = QString::fromLatin1(source->id().name()) + QLatin1Char('.')
            + rlrc->projectFilePath();
    return rlrc && canCreate(parent, Core::Id(idStr));
}

QList<Core::Id> MaemoRunConfigurationFactory::availableCreationIds(Target *parent) const
{
    QList<Core::Id> result;
    if (!canHandle(parent))
        return result;
    QStringList proFiles = static_cast<Qt4Project *>(parent->project())->applicationProFilePathes(QLatin1String(MAEMO_RC_ID_PREFIX));
    foreach (const QString &pf, proFiles)
        result << Core::Id(pf);
    return result;
}

QString MaemoRunConfigurationFactory::displayNameForId(const Core::Id id) const
{
    return QFileInfo(pathFromId(id)).completeBaseName()
        + QLatin1String(" (on remote Maemo device)");
}

RunConfiguration *MaemoRunConfigurationFactory::create(Target *parent, const Core::Id id)
{
    if (!canCreate(parent, id))
        return 0;
    return new MaemoRunConfiguration(parent, id, pathFromId(id));
}

RunConfiguration *MaemoRunConfigurationFactory::restore(Target *parent,
    const QVariantMap &map)
{
    if (!canRestore(parent, map))
        return 0;

    Core::Id id = ProjectExplorer::idFromMap(map);
    MaemoRunConfiguration *rc
        = new MaemoRunConfiguration(parent, id, pathFromId(id));
    if (rc->fromMap(map))
        return rc;

    delete rc;
    return 0;
}

RunConfiguration *MaemoRunConfigurationFactory::clone(Target *parent, RunConfiguration *source)
{
    if (!canClone(parent, source))
        return 0;

    MaemoRunConfiguration *old = static_cast<MaemoRunConfiguration *>(source);
    return new MaemoRunConfiguration(parent, old);
}

bool MaemoRunConfigurationFactory::canHandle(Target *t) const
{
    if (!t->project()->supportsKit(t->kit()))
        return false;
    if (!qobject_cast<Qt4Project *>(t->project()))
        return false;
    Core::Id devType = DeviceTypeKitInformation::deviceTypeId(t->kit());
    return devType == Maemo5OsType || devType == HarmattanOsType;
}

QList<RunConfiguration *> MaemoRunConfigurationFactory::runConfigurationsForNode(Target *t, Node *n)
{
    QList<ProjectExplorer::RunConfiguration *> result;
    foreach (ProjectExplorer::RunConfiguration *rc, t->runConfigurations())
        if (MaemoRunConfiguration *mrc = qobject_cast<MaemoRunConfiguration *>(rc))
            if (mrc->projectFilePath() == n->path())
                result << rc;
    return result;
}

MaemoRunControlFactory::MaemoRunControlFactory(QObject *parent)
    : IRunControlFactory(parent)
{
}

MaemoRunControlFactory::~MaemoRunControlFactory()
{
}

bool MaemoRunControlFactory::canRun(RunConfiguration *runConfiguration, RunMode mode) const
{
    const MaemoRunConfiguration * const maemoRunConfig
        = qobject_cast<MaemoRunConfiguration *>(runConfiguration);
    if (!maemoRunConfig || !maemoRunConfig->isEnabled())
        return false;
    return maemoRunConfig->hasEnoughFreePorts(mode);
}

RunControl* MaemoRunControlFactory::create(RunConfiguration *runConfig, RunMode mode, QString *errorMessage)
{
    Q_ASSERT(canRun(runConfig, mode));

    MaemoRunConfiguration *rc = qobject_cast<MaemoRunConfiguration *>(runConfig);
    Q_ASSERT(rc);

    if (mode == NormalRunMode) {
        RemoteLinuxRunControl * const runControl = new RemoteLinuxRunControl(rc);
        setHelperActions(runControl, rc, runControl);
        return runControl;
    }

    const DebuggerStartParameters params = LinuxDeviceDebugSupport::startParameters(rc);
    DebuggerRunControl * const runControl = DebuggerPlugin::createDebugger(params, rc, errorMessage);
    if (!runControl)
        return 0;
    LinuxDeviceDebugSupport * const debugSupport
            = new LinuxDeviceDebugSupport(rc, runControl->engine());
    setHelperActions(debugSupport, rc, runControl);
    connect(runControl, SIGNAL(finished()), debugSupport, SLOT(handleDebuggingFinished()));
    return runControl;
}

QString MaemoRunControlFactory::displayName() const
{
    return tr("Run on device");
}

    } // namespace Internal
} // namespace Madde
<commit_msg>Maemo: Remove use of deprecated Core::Id(QString)<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "maemorunfactories.h"

#include "maemoapplicationrunnerhelperactions.h"
#include "maemoconstants.h"
#include "maemoglobal.h"
#include "maemoremotemountsmodel.h"
#include "maemorunconfiguration.h"

#include <debugger/debuggerconstants.h>
#include <debugger/debuggerstartparameters.h>
#include <debugger/debuggerplugin.h>
#include <debugger/debuggerrunner.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/target.h>
#include <qt4projectmanager/qt4nodes.h>
#include <qt4projectmanager/qt4project.h>
#include <qtsupport/customexecutablerunconfiguration.h>
#include <remotelinux/remotelinuxdebugsupport.h>
#include <remotelinux/remotelinuxruncontrol.h>

using namespace Debugger;
using namespace ProjectExplorer;
using namespace Qt4ProjectManager;
using namespace RemoteLinux;

namespace Madde {
namespace Internal {

namespace {

QString pathFromId(Core::Id id)
{
    QString idStr = id.toString();
    const QString prefix = QLatin1String(MAEMO_RC_ID_PREFIX);
    if (!idStr.startsWith(prefix))
        return QString();
    return idStr.mid(prefix.size());
}

template<class Receiver> void setHelperActions(Receiver *receiver, MaemoRunConfiguration *runConfig,
        RunControl *runControl)
{
    const Kit * const k = runConfig->target()->kit();
    MaemoPreRunAction * const preRunAction = new MaemoPreRunAction(
            DeviceKitInformation::device(k), MaemoGlobal::maddeRoot(k),
            runConfig->remoteMounts()->mountSpecs(), runControl);
    MaemoPostRunAction * const postRunAction
            = new MaemoPostRunAction(preRunAction->mounter(), runControl);
    receiver->setApplicationRunnerPreRunAction(preRunAction);
    receiver->setApplicationRunnerPostRunAction(postRunAction);
}

} // namespace

MaemoRunConfigurationFactory::MaemoRunConfigurationFactory(QObject *parent)
    : QmakeRunConfigurationFactory(parent)
{ setObjectName(QLatin1String("MaemoRunConfigurationFactory")); }

MaemoRunConfigurationFactory::~MaemoRunConfigurationFactory()
{
}

bool MaemoRunConfigurationFactory::canCreate(Target *parent, const Core::Id id) const
{
    if (!canHandle(parent))
        return false;
    return static_cast<Qt4Project *>(parent->project())->hasApplicationProFile(pathFromId(id));
}

bool MaemoRunConfigurationFactory::canRestore(Target *parent,
    const QVariantMap &map) const
{
    return canHandle(parent)
        && ProjectExplorer::idFromMap(map).toString().startsWith(QLatin1String(MAEMO_RC_ID_PREFIX));
}

bool MaemoRunConfigurationFactory::canClone(Target *parent,
    RunConfiguration *source) const
{
    if (!canHandle(parent))
        return false;
    const RemoteLinuxRunConfiguration * const rlrc
            = qobject_cast<RemoteLinuxRunConfiguration *>(source);
    Core::Id id = source->id().withSuffix(QLatin1Char('.') + rlrc->projectFilePath());
    return rlrc && canCreate(parent, id);
}

QList<Core::Id> MaemoRunConfigurationFactory::availableCreationIds(Target *parent) const
{
    QList<Core::Id> result;
    if (!canHandle(parent))
        return result;
    QStringList proFiles = static_cast<Qt4Project *>(parent->project())->applicationProFilePathes(QLatin1String(MAEMO_RC_ID_PREFIX));
    foreach (const QString &pf, proFiles)
        result << Core::Id::fromString(pf);
    return result;
}

QString MaemoRunConfigurationFactory::displayNameForId(const Core::Id id) const
{
    return QFileInfo(pathFromId(id)).completeBaseName()
        + QLatin1String(" (on remote Maemo device)");
}

RunConfiguration *MaemoRunConfigurationFactory::create(Target *parent, const Core::Id id)
{
    if (!canCreate(parent, id))
        return 0;
    return new MaemoRunConfiguration(parent, id, pathFromId(id));
}

RunConfiguration *MaemoRunConfigurationFactory::restore(Target *parent,
    const QVariantMap &map)
{
    if (!canRestore(parent, map))
        return 0;

    Core::Id id = ProjectExplorer::idFromMap(map);
    MaemoRunConfiguration *rc
        = new MaemoRunConfiguration(parent, id, pathFromId(id));
    if (rc->fromMap(map))
        return rc;

    delete rc;
    return 0;
}

RunConfiguration *MaemoRunConfigurationFactory::clone(Target *parent, RunConfiguration *source)
{
    if (!canClone(parent, source))
        return 0;

    MaemoRunConfiguration *old = static_cast<MaemoRunConfiguration *>(source);
    return new MaemoRunConfiguration(parent, old);
}

bool MaemoRunConfigurationFactory::canHandle(Target *t) const
{
    if (!t->project()->supportsKit(t->kit()))
        return false;
    if (!qobject_cast<Qt4Project *>(t->project()))
        return false;
    Core::Id devType = DeviceTypeKitInformation::deviceTypeId(t->kit());
    return devType == Maemo5OsType || devType == HarmattanOsType;
}

QList<RunConfiguration *> MaemoRunConfigurationFactory::runConfigurationsForNode(Target *t, Node *n)
{
    QList<ProjectExplorer::RunConfiguration *> result;
    foreach (ProjectExplorer::RunConfiguration *rc, t->runConfigurations())
        if (MaemoRunConfiguration *mrc = qobject_cast<MaemoRunConfiguration *>(rc))
            if (mrc->projectFilePath() == n->path())
                result << rc;
    return result;
}

MaemoRunControlFactory::MaemoRunControlFactory(QObject *parent)
    : IRunControlFactory(parent)
{
}

MaemoRunControlFactory::~MaemoRunControlFactory()
{
}

bool MaemoRunControlFactory::canRun(RunConfiguration *runConfiguration, RunMode mode) const
{
    const MaemoRunConfiguration * const maemoRunConfig
        = qobject_cast<MaemoRunConfiguration *>(runConfiguration);
    if (!maemoRunConfig || !maemoRunConfig->isEnabled())
        return false;
    return maemoRunConfig->hasEnoughFreePorts(mode);
}

RunControl* MaemoRunControlFactory::create(RunConfiguration *runConfig, RunMode mode, QString *errorMessage)
{
    Q_ASSERT(canRun(runConfig, mode));

    MaemoRunConfiguration *rc = qobject_cast<MaemoRunConfiguration *>(runConfig);
    Q_ASSERT(rc);

    if (mode == NormalRunMode) {
        RemoteLinuxRunControl * const runControl = new RemoteLinuxRunControl(rc);
        setHelperActions(runControl, rc, runControl);
        return runControl;
    }

    const DebuggerStartParameters params = LinuxDeviceDebugSupport::startParameters(rc);
    DebuggerRunControl * const runControl = DebuggerPlugin::createDebugger(params, rc, errorMessage);
    if (!runControl)
        return 0;
    LinuxDeviceDebugSupport * const debugSupport
            = new LinuxDeviceDebugSupport(rc, runControl->engine());
    setHelperActions(debugSupport, rc, runControl);
    connect(runControl, SIGNAL(finished()), debugSupport, SLOT(handleDebuggingFinished()));
    return runControl;
}

QString MaemoRunControlFactory::displayName() const
{
    return tr("Run on device");
}

    } // namespace Internal
} // namespace Madde
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 - 2013 Jolla Ltd.
** Contact: http://jolla.com/
**
** This file is part of Qt Creator.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Digia.
**
****************************************************************************/

#include "mertargetsxmlparser.h"

#include <utils/fileutils.h>

#include <QAbstractMessageHandler>
#include <QAbstractXmlReceiver>
#include <QXmlSchema>
#include <QXmlSchemaValidator>
#include <QXmlQuery>
#include <QXmlStreamWriter>
#include <QStack>
#include <QFileInfo>

const char TARGET[] = "target";
const char TARGETS[] = "targets";
const char OUTPUT[] = "output";
const char NAME[] = "name";
const char VERSION[] = "version";
const char GCCDUMPMACHINE[] = "GccDumpMachine";
const char QMAKEQUERY[] = "QmakeQuery";

namespace Mer {

namespace {

class MessageHandler : public QAbstractMessageHandler
{
public:
    QString errorString() const
    {
        return QObject::tr("Error %1:%2:%3 %4").arg(m_identifier.toString())
                .arg(m_sourceLocation.line())
                .arg(m_sourceLocation.column())
                .arg(m_description);
    }

protected:
    virtual void handleMessage(QtMsgType /*type*/, const QString &description,
                               const QUrl &identifier, const QSourceLocation &sourceLocation)
    {
        m_description = description;
        m_identifier = identifier;
        m_sourceLocation = sourceLocation;
    }

private:
    QString m_description;
    QSourceLocation m_sourceLocation;
    QUrl m_identifier;
};

class XmlReceiver : public QAbstractXmlReceiver
{
public:
    XmlReceiver(const QXmlNamePool &namePool) : m_namePool(namePool), m_version(-1) {}

    int version() const
    {
        return m_version;
    }

    QList<MerTargetData> targetData() const
    {
        return m_targets;
    }

protected:
    virtual void startElement(const QXmlName &name)
    {
        const QString element = name.localName(m_namePool);
        if (element == QLatin1String(TARGET))
            m_currentTarget.clear();
        m_currentElementStack.push(element);
    }

    virtual void endElement()
    {
        if (m_currentElementStack.pop() == QLatin1String(TARGET))
            m_targets.append(m_currentTarget);
    }

    virtual void attribute(const QXmlName &name,
                           const QStringRef &value)
    {
        const QString attributeName = name.localName(m_namePool);
        const QString attributeValue = value.toString();
        const QString element = m_currentElementStack.top();
        if (element == QLatin1String(TARGETS) && attributeName == QLatin1String(VERSION))
            m_version = attributeValue.toInt();
        else if (element == QLatin1String(TARGET) && attributeName == QLatin1String(NAME))
            m_currentTarget.name = attributeValue;
        else if (element == QLatin1String(OUTPUT) && attributeName == QLatin1String(NAME))
            m_attributeValue = attributeValue;
        else
            m_attributeValue.clear();
    }

    virtual void characters(const QStringRef &value)
    {
        if (m_currentElementStack.top() == QLatin1String(OUTPUT)) {
            if (m_attributeValue == QLatin1String(GCCDUMPMACHINE))
                m_currentTarget.gccDumpMachine = value.toString();
            else if (m_attributeValue == QLatin1String(QMAKEQUERY))
                m_currentTarget.qmakeQuery = value.toString();
        }
    }

    virtual void comment(const QString &/*value*/)
    {
    }

    virtual void startDocument()
    {
    }

    virtual void endDocument()
    {
    }

    virtual void processingInstruction(const QXmlName &/*target*/, const QString &/*value*/)
    {
    }

    virtual void atomicValue(const QVariant &/*value*/)
    {
    }
    virtual void namespaceBinding(const QXmlName &/*name*/)
    {
    }
    virtual void startOfSequence()
    {
    }
    virtual void endOfSequence()
    {
    }

private:
    QXmlNamePool m_namePool;
    QStack<QString> m_currentElementStack;
    QList<MerTargetData> m_targets;
    MerTargetData m_currentTarget;
    QString m_attributeValue;
    int m_version;
};

#ifdef Q_OS_MAC
#  define SHARE_PATH "/../Resources"
#else
#  define SHARE_PATH "/../share/qtcreator"
#endif

static QString applicationDirPath()
{
    return QCoreApplication::applicationDirPath();
}

static inline QString sharedDirPath()
{
    QString appPath = applicationDirPath();

    return QFileInfo(appPath + QLatin1String(SHARE_PATH)).absoluteFilePath();
}

} // Anonymous

class MerTargetsXmlReaderPrivate
{
public:
    MerTargetsXmlReaderPrivate()
        : receiver(new XmlReceiver(query.namePool())),
          error(false)
    {}

    ~MerTargetsXmlReaderPrivate()
    {
        delete receiver;
    }

    QXmlQuery query;
    XmlReceiver *receiver;
    MessageHandler messageHandler;
    bool error;
    QString errorString;
};

MerTargetsXmlReader::MerTargetsXmlReader(const QString &fileName, QObject *parent)
    : QObject(parent),
      d(new MerTargetsXmlReaderPrivate)
{
    Utils::FileReader reader;
    d->error = !reader.fetch(fileName, QIODevice::ReadOnly);
    if (d->error) {
        d->errorString = reader.errorString();
        return;
    }

    QXmlSchema schema;
    schema.setMessageHandler(&d->messageHandler);

    Utils::FileReader schemeReader;
    d->error = !schemeReader.fetch(QString::fromLatin1("%1/mer/targets.xsd").arg(sharedDirPath()),
            QIODevice::ReadOnly);
    if (d->error) {
        d->errorString = schemeReader.errorString();
        return;
    }
    schema.load(schemeReader.data());
    d->error = !schema.isValid();
    if (d->error) {
        d->errorString = d->messageHandler.errorString();
        return;
    }

    QXmlSchemaValidator validator(schema);
    validator.setMessageHandler(&d->messageHandler);
    d->error = !validator.validate(reader.data());
    if (d->error) {
        d->errorString = d->messageHandler.errorString();
        return;
    }

    d->query.setQuery(QString::fromLatin1("doc('%1')").arg(fileName));
    d->query.setMessageHandler(&d->messageHandler);
    d->error = !d->query.isValid();
    if (d->error) {
        d->errorString = d->messageHandler.errorString();
        return;
    }

    d->error = !d->query.evaluateTo(d->receiver);
    if (d->error)
        d->errorString = d->messageHandler.errorString();
}

MerTargetsXmlReader::~MerTargetsXmlReader()
{
    delete d;
}

bool MerTargetsXmlReader::hasError() const
{
    return d->error;
}

QString MerTargetsXmlReader::errorString() const
{
    return d->errorString;
}

QList<MerTargetData> MerTargetsXmlReader::targetData() const
{
    return d->receiver->targetData();
}

int MerTargetsXmlReader::version() const
{
    return d->receiver->version();
}

void MerTargetData::clear()
{
    name.clear();
    gccDumpMachine.clear();
    qmakeQuery.clear();
}

class MerTargetsXmlWriterPrivate
{
public:
    MerTargetsXmlWriterPrivate(const QString &fileName) : fileSaver(fileName, QIODevice::WriteOnly) {}

    Utils::FileSaver fileSaver;
};

MerTargetsXmlWriter::MerTargetsXmlWriter(const QString &fileName, int version,
                                         const QList<MerTargetData> &targetData, QObject *parent)
    : QObject(parent),
      d(new MerTargetsXmlWriterPrivate(fileName))
{
    QByteArray data;
    QXmlStreamWriter writer(&data);
    writer.setAutoFormatting(true);
    writer.writeStartDocument();
    writer.writeStartElement(QLatin1String(TARGETS));
    writer.writeAttribute(QLatin1String(VERSION), QString::number(version));
    foreach (const MerTargetData &d, targetData) {
        writer.writeStartElement(QLatin1String(TARGET));
        writer.writeAttribute(QLatin1String(NAME), d.name);
        writer.writeStartElement(QLatin1String(OUTPUT));
        writer.writeAttribute(QLatin1String(NAME), QLatin1String(GCCDUMPMACHINE));
        writer.writeCharacters(d.gccDumpMachine);
        writer.writeEndElement(); // output
        writer.writeStartElement(QLatin1String(OUTPUT));
        writer.writeAttribute(QLatin1String(NAME), QLatin1String(QMAKEQUERY));
        writer.writeCharacters(d.qmakeQuery);
        writer.writeEndElement(); // output
        writer.writeEndElement(); // target
    }
    writer.writeEndElement(); // targets
    writer.writeEndDocument();
    d->fileSaver.write(data);
    d->fileSaver.finalize();
}

MerTargetsXmlWriter::~MerTargetsXmlWriter()
{
    delete d;
}

bool MerTargetsXmlWriter::hasError() const
{
    return d->fileSaver.hasError();
}

QString MerTargetsXmlWriter::errorString() const
{
    return d->fileSaver.errorString();
}

} // Mer
<commit_msg>Mer: Fix reading targets.xml file in Windows.<commit_after>/****************************************************************************
**
** Copyright (C) 2012 - 2013 Jolla Ltd.
** Contact: http://jolla.com/
**
** This file is part of Qt Creator.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Digia.
**
****************************************************************************/

#include "mertargetsxmlparser.h"

#include <utils/fileutils.h>

#include <QAbstractMessageHandler>
#include <QAbstractXmlReceiver>
#include <QXmlSchema>
#include <QXmlSchemaValidator>
#include <QXmlQuery>
#include <QXmlStreamWriter>
#include <QStack>
#include <QFileInfo>

const char TARGET[] = "target";
const char TARGETS[] = "targets";
const char OUTPUT[] = "output";
const char NAME[] = "name";
const char VERSION[] = "version";
const char GCCDUMPMACHINE[] = "GccDumpMachine";
const char QMAKEQUERY[] = "QmakeQuery";

namespace Mer {

namespace {

class MessageHandler : public QAbstractMessageHandler
{
public:
    QString errorString() const
    {
        return QObject::tr("Error %1:%2:%3 %4").arg(m_identifier.toString())
                .arg(m_sourceLocation.line())
                .arg(m_sourceLocation.column())
                .arg(m_description);
    }

protected:
    virtual void handleMessage(QtMsgType /*type*/, const QString &description,
                               const QUrl &identifier, const QSourceLocation &sourceLocation)
    {
        m_description = description;
        m_identifier = identifier;
        m_sourceLocation = sourceLocation;
    }

private:
    QString m_description;
    QSourceLocation m_sourceLocation;
    QUrl m_identifier;
};

class XmlReceiver : public QAbstractXmlReceiver
{
public:
    XmlReceiver(const QXmlNamePool &namePool) : m_namePool(namePool), m_version(-1) {}

    int version() const
    {
        return m_version;
    }

    QList<MerTargetData> targetData() const
    {
        return m_targets;
    }

protected:
    virtual void startElement(const QXmlName &name)
    {
        const QString element = name.localName(m_namePool);
        if (element == QLatin1String(TARGET))
            m_currentTarget.clear();
        m_currentElementStack.push(element);
    }

    virtual void endElement()
    {
        if (m_currentElementStack.pop() == QLatin1String(TARGET))
            m_targets.append(m_currentTarget);
    }

    virtual void attribute(const QXmlName &name,
                           const QStringRef &value)
    {
        const QString attributeName = name.localName(m_namePool);
        const QString attributeValue = value.toString();
        const QString element = m_currentElementStack.top();
        if (element == QLatin1String(TARGETS) && attributeName == QLatin1String(VERSION))
            m_version = attributeValue.toInt();
        else if (element == QLatin1String(TARGET) && attributeName == QLatin1String(NAME))
            m_currentTarget.name = attributeValue;
        else if (element == QLatin1String(OUTPUT) && attributeName == QLatin1String(NAME))
            m_attributeValue = attributeValue;
        else
            m_attributeValue.clear();
    }

    virtual void characters(const QStringRef &value)
    {
        if (m_currentElementStack.top() == QLatin1String(OUTPUT)) {
            if (m_attributeValue == QLatin1String(GCCDUMPMACHINE))
                m_currentTarget.gccDumpMachine = value.toString();
            else if (m_attributeValue == QLatin1String(QMAKEQUERY))
                m_currentTarget.qmakeQuery = value.toString();
        }
    }

    virtual void comment(const QString &/*value*/)
    {
    }

    virtual void startDocument()
    {
    }

    virtual void endDocument()
    {
    }

    virtual void processingInstruction(const QXmlName &/*target*/, const QString &/*value*/)
    {
    }

    virtual void atomicValue(const QVariant &/*value*/)
    {
    }
    virtual void namespaceBinding(const QXmlName &/*name*/)
    {
    }
    virtual void startOfSequence()
    {
    }
    virtual void endOfSequence()
    {
    }

private:
    QXmlNamePool m_namePool;
    QStack<QString> m_currentElementStack;
    QList<MerTargetData> m_targets;
    MerTargetData m_currentTarget;
    QString m_attributeValue;
    int m_version;
};

#ifdef Q_OS_MAC
#  define SHARE_PATH "/../Resources"
#else
#  define SHARE_PATH "/../share/qtcreator"
#endif

static QString applicationDirPath()
{
    return QCoreApplication::applicationDirPath();
}

static inline QString sharedDirPath()
{
    QString appPath = applicationDirPath();

    return QFileInfo(appPath + QLatin1String(SHARE_PATH)).absoluteFilePath();
}

} // Anonymous

class MerTargetsXmlReaderPrivate
{
public:
    MerTargetsXmlReaderPrivate()
        : receiver(new XmlReceiver(query.namePool())),
          error(false)
    {}

    ~MerTargetsXmlReaderPrivate()
    {
        delete receiver;
    }

    QXmlQuery query;
    XmlReceiver *receiver;
    MessageHandler messageHandler;
    bool error;
    QString errorString;
};

MerTargetsXmlReader::MerTargetsXmlReader(const QString &fileName, QObject *parent)
    : QObject(parent),
      d(new MerTargetsXmlReaderPrivate)
{
    Utils::FileReader reader;
    d->error = !reader.fetch(fileName, QIODevice::ReadOnly);
    if (d->error) {
        d->errorString = reader.errorString();
        return;
    }

    QXmlSchema schema;
    schema.setMessageHandler(&d->messageHandler);

    Utils::FileReader schemeReader;
    d->error = !schemeReader.fetch(QString::fromLatin1("%1/mer/targets.xsd").arg(sharedDirPath()),
            QIODevice::ReadOnly);
    if (d->error) {
        d->errorString = schemeReader.errorString();
        return;
    }
    schema.load(schemeReader.data());
    d->error = !schema.isValid();
    if (d->error) {
        d->errorString = d->messageHandler.errorString();
        return;
    }

    QXmlSchemaValidator validator(schema);
    validator.setMessageHandler(&d->messageHandler);
    d->error = !validator.validate(reader.data());
    if (d->error) {
        d->errorString = d->messageHandler.errorString();
        return;
    }

    QUrl docfile = QUrl::fromLocalFile(fileName);
    d->query.setQuery(QString::fromLatin1("doc('%1')").arg(docfile.toString()));
    d->query.setMessageHandler(&d->messageHandler);
    d->error = !d->query.isValid();
    if (d->error) {
        d->errorString = d->messageHandler.errorString();
        return;
    }

    d->error = !d->query.evaluateTo(d->receiver);
    if (d->error)
        d->errorString = d->messageHandler.errorString();
}

MerTargetsXmlReader::~MerTargetsXmlReader()
{
    delete d;
}

bool MerTargetsXmlReader::hasError() const
{
    return d->error;
}

QString MerTargetsXmlReader::errorString() const
{
    return d->errorString;
}

QList<MerTargetData> MerTargetsXmlReader::targetData() const
{
    return d->receiver->targetData();
}

int MerTargetsXmlReader::version() const
{
    return d->receiver->version();
}

void MerTargetData::clear()
{
    name.clear();
    gccDumpMachine.clear();
    qmakeQuery.clear();
}

class MerTargetsXmlWriterPrivate
{
public:
    MerTargetsXmlWriterPrivate(const QString &fileName) : fileSaver(fileName, QIODevice::WriteOnly) {}

    Utils::FileSaver fileSaver;
};

MerTargetsXmlWriter::MerTargetsXmlWriter(const QString &fileName, int version,
                                         const QList<MerTargetData> &targetData, QObject *parent)
    : QObject(parent),
      d(new MerTargetsXmlWriterPrivate(fileName))
{
    QByteArray data;
    QXmlStreamWriter writer(&data);
    writer.setAutoFormatting(true);
    writer.writeStartDocument();
    writer.writeStartElement(QLatin1String(TARGETS));
    writer.writeAttribute(QLatin1String(VERSION), QString::number(version));
    foreach (const MerTargetData &d, targetData) {
        writer.writeStartElement(QLatin1String(TARGET));
        writer.writeAttribute(QLatin1String(NAME), d.name);
        writer.writeStartElement(QLatin1String(OUTPUT));
        writer.writeAttribute(QLatin1String(NAME), QLatin1String(GCCDUMPMACHINE));
        writer.writeCharacters(d.gccDumpMachine);
        writer.writeEndElement(); // output
        writer.writeStartElement(QLatin1String(OUTPUT));
        writer.writeAttribute(QLatin1String(NAME), QLatin1String(QMAKEQUERY));
        writer.writeCharacters(d.qmakeQuery);
        writer.writeEndElement(); // output
        writer.writeEndElement(); // target
    }
    writer.writeEndElement(); // targets
    writer.writeEndDocument();
    d->fileSaver.write(data);
    d->fileSaver.finalize();
}

MerTargetsXmlWriter::~MerTargetsXmlWriter()
{
    delete d;
}

bool MerTargetsXmlWriter::hasError() const
{
    return d->fileSaver.hasError();
}

QString MerTargetsXmlWriter::errorString() const
{
    return d->fileSaver.errorString();
}

} // Mer
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015, Nagoya University

 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 this
 *    list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 *  * Neither the name of Autoware nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 LIABILITY,
 *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "waypoint_loader_core.h"

namespace waypoint_maker {
// Constructor
WaypointLoaderNode::WaypointLoaderNode() : private_nh_("~") { initPubSub(); }

// Destructor
WaypointLoaderNode::~WaypointLoaderNode() {}

void WaypointLoaderNode::initPubSub() {
  // setup publisher
  if (disable_decision_maker_) {
    lane_pub_ = nh_.advertise<autoware_msgs::LaneArray>("/lane_waypoints_array",
                                                        10, true);
  } else {
    lane_pub_ = nh_.advertise<autoware_msgs::LaneArray>(
        "/based/lane_waypoints_array", 10, true);
  }
  config_sub_ = nh_.subscribe("/config/waypoint_loader", 1,
                              &WaypointLoaderNode::configCallback, this);
  output_cmd_sub_ =
      nh_.subscribe("/config/waypoint_loader_output", 1,
                    &WaypointLoaderNode::outputCommandCallback, this);
}

void WaypointLoaderNode::initParameter(
    const autoware_msgs::ConfigWaypointLoader::ConstPtr &conf) {
  // parameter settings
  disable_decision_maker_ = conf->disable_decision_maker;
  filtering_mode_ = conf->filtering_mode;
  multi_lane_csv_ = conf->multi_lane_csv;
}

void WaypointLoaderNode::configCallback(
    const autoware_msgs::ConfigWaypointLoader::ConstPtr &conf) {
  filter_.initParameter(conf);
  initParameter(conf);

  parseColumns(multi_lane_csv_, &multi_file_path_);
  autoware_msgs::LaneArray lane_array;
  createLaneArray(multi_file_path_, &lane_array);
  lane_pub_.publish(lane_array);
  output_lane_array_ = lane_array;
}

void WaypointLoaderNode::outputCommandCallback(
    const std_msgs::Bool::ConstPtr &output_cmd) {
  std::vector<std::string> dst_multi_file_path = multi_file_path_;
  for (auto &el : dst_multi_file_path)
    el = addFileSuffix(el, "_filtered");
  saveLaneArray(dst_multi_file_path, output_lane_array_);
}

const std::string addFileSuffix(std::string file_path, std::string suffix) {
  std::string output_file_path, tmp;
  std::string directory_path, filename, extension;

  tmp = file_path;
  const std::string::size_type idx_slash = tmp.find_last_of("/");
  if (idx_slash != std::string::npos)
    tmp.erase(0, idx_slash);
  const std::string::size_type idx_dot = tmp.find_last_of(".");
  const std::string::size_type idx_dot_allpath = file_path.find_last_of(".");
  if (idx_dot != std::string::npos && idx_dot != tmp.size() - 1)
    file_path.erase(idx_dot_allpath, file_path.size() - 1);
  file_path += suffix + ".csv";
  return file_path;
}

void WaypointLoaderNode::createLaneArray(const std::vector<std::string> &paths,
                                         autoware_msgs::LaneArray *lane_array) {
  for (const auto &el : paths) {
    autoware_msgs::lane lane;
    createLaneWaypoint(el, &lane);
    if (filtering_mode_)
      filter_.filterLaneWaypoint(&lane);
    lane_array->lanes.push_back(lane);
  }
}

void WaypointLoaderNode::saveLaneArray(
    const std::vector<std::string> &paths,
    const autoware_msgs::LaneArray &lane_array) {
  unsigned long idx = 0;
  for (const auto &file_path : paths) {
    std::ofstream ofs(file_path.c_str());
    ofs << "x,y,z,yaw,velocity,change_flag,steering_flag,accel_flag,stop_flag,"
           "event_flag"
        << std::endl;
    for (const auto &el : lane_array.lanes[idx].waypoints) {
      ofs << std::fixed << std::setprecision(4) << el.pose.pose.position.x
          << "," << el.pose.pose.position.y << "," << el.pose.pose.position.z
          << "," << tf::getYaw(el.pose.pose.orientation) << ","
          << mps2kmph(el.twist.twist.linear.x) << "," << (int)el.change_flag
          << "," << (int)el.wpstate.steering_state << ","
          << (int)el.wpstate.accel_state << ","
          << (int)el.wpstate.stopline_state << ","
          << (int)el.wpstate.event_state << std::endl;
    }
    idx++;
  }
}

void WaypointLoaderNode::createLaneWaypoint(const std::string &file_path,
                                            autoware_msgs::lane *lane) {
  if (!verifyFileConsistency(file_path.c_str())) {
    ROS_ERROR("lane data is something wrong...");
    return;
  }

  ROS_INFO("lane data is valid. publishing...");
  FileFormat format = checkFileFormat(file_path.c_str());
  std::vector<autoware_msgs::waypoint> wps;
  if (format == FileFormat::ver1)
    loadWaypointsForVer1(file_path.c_str(), &wps);
  else if (format == FileFormat::ver2)
    loadWaypointsForVer2(file_path.c_str(), &wps);
  else
    loadWaypointsForVer3(file_path.c_str(), &wps);
  lane->header.frame_id = "/map";
  lane->header.stamp = ros::Time(0);
  lane->waypoints = wps;
}

void WaypointLoaderNode::loadWaypointsForVer1(
    const char *filename, std::vector<autoware_msgs::waypoint> *wps) {
  std::ifstream ifs(filename);

  if (!ifs)
    return;

  std::string line;
  std::getline(ifs, line); // Remove first line

  while (std::getline(ifs, line)) {
    autoware_msgs::waypoint wp;
    parseWaypointForVer1(line, &wp);
    wps->push_back(wp);
  }

  size_t last = wps->size() - 1;
  for (size_t i = 0; i < wps->size(); ++i) {
    if (i != last) {
      double yaw = atan2(wps->at(i + 1).pose.pose.position.y -
                             wps->at(i).pose.pose.position.y,
                         wps->at(i + 1).pose.pose.position.x -
                             wps->at(i).pose.pose.position.x);
      wps->at(i).pose.pose.orientation = tf::createQuaternionMsgFromYaw(yaw);
    } else {
      wps->at(i).pose.pose.orientation = wps->at(i - 1).pose.pose.orientation;
    }
  }
}

void WaypointLoaderNode::parseWaypointForVer1(const std::string &line,
                                              autoware_msgs::waypoint *wp) {
  std::vector<std::string> columns;
  parseColumns(line, &columns);

  wp->pose.pose.position.x = std::stod(columns[0]);
  wp->pose.pose.position.y = std::stod(columns[1]);
  wp->pose.pose.position.z = std::stod(columns[2]);
  wp->twist.twist.linear.x = kmph2mps(std::stod(columns[3]));
}

void WaypointLoaderNode::loadWaypointsForVer2(
    const char *filename, std::vector<autoware_msgs::waypoint> *wps) {
  std::ifstream ifs(filename);

  if (!ifs)
    return;

  std::string line;
  std::getline(ifs, line); // Remove first line

  while (std::getline(ifs, line)) {
    autoware_msgs::waypoint wp;
    parseWaypointForVer2(line, &wp);
    wps->push_back(wp);
  }
}

void WaypointLoaderNode::parseWaypointForVer2(const std::string &line,
                                              autoware_msgs::waypoint *wp) {
  std::vector<std::string> columns;
  parseColumns(line, &columns);

  wp->pose.pose.position.x = std::stod(columns[0]);
  wp->pose.pose.position.y = std::stod(columns[1]);
  wp->pose.pose.position.z = std::stod(columns[2]);
  wp->pose.pose.orientation =
      tf::createQuaternionMsgFromYaw(std::stod(columns[3]));
  wp->twist.twist.linear.x = kmph2mps(std::stod(columns[4]));
}

void WaypointLoaderNode::loadWaypointsForVer3(
    const char *filename, std::vector<autoware_msgs::waypoint> *wps) {
  std::ifstream ifs(filename);

  if (!ifs)
    return;

  std::string line;
  std::getline(ifs, line); // get first line
  std::vector<std::string> contents;
  parseColumns(line, &contents);

  // std::getline(ifs, line);  // remove second line
  while (std::getline(ifs, line)) {
    autoware_msgs::waypoint wp;
    parseWaypointForVer3(line, contents, &wp);
    wps->push_back(wp);
  }
}

void WaypointLoaderNode::parseWaypointForVer3(
    const std::string &line, const std::vector<std::string> &contents,
    autoware_msgs::waypoint *wp) {
  std::vector<std::string> columns;
  parseColumns(line, &columns);
  std::unordered_map<std::string, std::string> map;
  for (size_t i = 0; i < contents.size(); i++) {
    map[contents.at(i)] = columns.at(i);
  }

  wp->pose.pose.position.x = std::stod(map["x"]);
  wp->pose.pose.position.y = std::stod(map["y"]);
  wp->pose.pose.position.z = std::stod(map["z"]);
  wp->pose.pose.orientation =
      tf::createQuaternionMsgFromYaw(std::stod(map["yaw"]));
  wp->twist.twist.linear.x = kmph2mps(std::stod(map["velocity"]));
  wp->change_flag = std::stoi(map["change_flag"]);
  wp->wpstate.steering_state = (map.find("steering_flag") != map.end())
                                   ? std::stoi(map["steering_flag"])
                                   : 0;
  wp->wpstate.accel_state =
      (map.find("accel_flag") != map.end()) ? std::stoi(map["accel_flag"]) : 0;
  wp->wpstate.stopline_state =
      (map.find("stop_flag") != map.end()) ? std::stoi(map["stop_flag"]) : 0;
  wp->wpstate.event_state =
      (map.find("event_flag") != map.end()) ? std::stoi(map["event_flag"]) : 0;
}

FileFormat WaypointLoaderNode::checkFileFormat(const char *filename) {
  std::ifstream ifs(filename);

  if (!ifs) {
    return FileFormat::unknown;
  }

  // get first line
  std::string line;
  std::getline(ifs, line);

  // parse first line
  std::vector<std::string> parsed_columns;
  parseColumns(line, &parsed_columns);

  // check if first element in the first column does not include digit
  if (!std::any_of(parsed_columns.at(0).cbegin(), parsed_columns.at(0).cend(),
                   isdigit)) {
    return FileFormat::ver3;
  }

  // if element consists only digit
  int num_of_columns = countColumns(line);
  ROS_INFO("columns size: %d", num_of_columns);

  return (num_of_columns == 3
              ? FileFormat::ver1 // if data consists "x y z (velocity)"
              : num_of_columns == 4
                    ? FileFormat::ver2 // if data consists "x y z yaw (velocity)
                    : FileFormat::unknown);
}

bool WaypointLoaderNode::verifyFileConsistency(const char *filename) {
  ROS_INFO("verify...");
  std::ifstream ifs(filename);

  if (!ifs)
    return false;

  FileFormat format = checkFileFormat(filename);
  ROS_INFO("format: %d", static_cast<FileFormat>(format));
  if (format == FileFormat::unknown) {
    ROS_ERROR("unknown file format");
    return false;
  }

  std::string line;
  std::getline(ifs, line); // remove first line

  size_t ncol = format == FileFormat::ver1
                    ? 4                              // x,y,z,velocity
                    : format == FileFormat::ver2 ? 5 // x,y,z,yaw,velocity
                                                 : countColumns(line);

  while (std::getline(ifs, line)) // search from second line
  {
    if (countColumns(line) != ncol)
      return false;
  }
  return true;
}

void parseColumns(const std::string &line, std::vector<std::string> *columns) {
  std::istringstream ss(line);
  std::string column;
  while (std::getline(ss, column, ',')) {
    columns->push_back(column);
  }
}

size_t countColumns(const std::string &line) {
  std::istringstream ss(line);
  size_t ncol = 0;

  std::string column;
  while (std::getline(ss, column, ',')) {
    ++ncol;
  }

  return ncol;
}

} // waypoint_maker
<commit_msg>Ignore space character of waypoints.csv<commit_after>/*
 *  Copyright (c) 2015, Nagoya University

 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 this
 *    list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 *  * Neither the name of Autoware nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 LIABILITY,
 *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "waypoint_loader_core.h"

namespace waypoint_maker {
// Constructor
WaypointLoaderNode::WaypointLoaderNode() : private_nh_("~") { initPubSub(); }

// Destructor
WaypointLoaderNode::~WaypointLoaderNode() {}

void WaypointLoaderNode::initPubSub() {
  // setup publisher
  if (disable_decision_maker_) {
    lane_pub_ = nh_.advertise<autoware_msgs::LaneArray>("/lane_waypoints_array",
                                                        10, true);
  } else {
    lane_pub_ = nh_.advertise<autoware_msgs::LaneArray>(
        "/based/lane_waypoints_array", 10, true);
  }
  config_sub_ = nh_.subscribe("/config/waypoint_loader", 1,
                              &WaypointLoaderNode::configCallback, this);
  output_cmd_sub_ =
      nh_.subscribe("/config/waypoint_loader_output", 1,
                    &WaypointLoaderNode::outputCommandCallback, this);
}

void WaypointLoaderNode::initParameter(
    const autoware_msgs::ConfigWaypointLoader::ConstPtr &conf) {
  // parameter settings
  disable_decision_maker_ = conf->disable_decision_maker;
  filtering_mode_ = conf->filtering_mode;
  multi_lane_csv_ = conf->multi_lane_csv;
}

void WaypointLoaderNode::configCallback(
    const autoware_msgs::ConfigWaypointLoader::ConstPtr &conf) {
  filter_.initParameter(conf);
  initParameter(conf);

  parseColumns(multi_lane_csv_, &multi_file_path_);
  autoware_msgs::LaneArray lane_array;
  createLaneArray(multi_file_path_, &lane_array);
  lane_pub_.publish(lane_array);
  output_lane_array_ = lane_array;
}

void WaypointLoaderNode::outputCommandCallback(
    const std_msgs::Bool::ConstPtr &output_cmd) {
  std::vector<std::string> dst_multi_file_path = multi_file_path_;
  for (auto &el : dst_multi_file_path)
    el = addFileSuffix(el, "_filtered");
  saveLaneArray(dst_multi_file_path, output_lane_array_);
}

const std::string addFileSuffix(std::string file_path, std::string suffix) {
  std::string output_file_path, tmp;
  std::string directory_path, filename, extension;

  tmp = file_path;
  const std::string::size_type idx_slash = tmp.find_last_of("/");
  if (idx_slash != std::string::npos)
    tmp.erase(0, idx_slash);
  const std::string::size_type idx_dot = tmp.find_last_of(".");
  const std::string::size_type idx_dot_allpath = file_path.find_last_of(".");
  if (idx_dot != std::string::npos && idx_dot != tmp.size() - 1)
    file_path.erase(idx_dot_allpath, file_path.size() - 1);
  file_path += suffix + ".csv";
  return file_path;
}

void WaypointLoaderNode::createLaneArray(const std::vector<std::string> &paths,
                                         autoware_msgs::LaneArray *lane_array) {
  for (const auto &el : paths) {
    autoware_msgs::lane lane;
    createLaneWaypoint(el, &lane);
    if (filtering_mode_)
      filter_.filterLaneWaypoint(&lane);
    lane_array->lanes.push_back(lane);
  }
}

void WaypointLoaderNode::saveLaneArray(
    const std::vector<std::string> &paths,
    const autoware_msgs::LaneArray &lane_array) {
  unsigned long idx = 0;
  for (const auto &file_path : paths) {
    std::ofstream ofs(file_path.c_str());
    ofs << "x,y,z,yaw,velocity,change_flag,steering_flag,accel_flag,stop_flag,"
           "event_flag"
        << std::endl;
    for (const auto &el : lane_array.lanes[idx].waypoints) {
      ofs << std::fixed << std::setprecision(4) << el.pose.pose.position.x
          << "," << el.pose.pose.position.y << "," << el.pose.pose.position.z
          << "," << tf::getYaw(el.pose.pose.orientation) << ","
          << mps2kmph(el.twist.twist.linear.x) << "," << (int)el.change_flag
          << "," << (int)el.wpstate.steering_state << ","
          << (int)el.wpstate.accel_state << ","
          << (int)el.wpstate.stopline_state << ","
          << (int)el.wpstate.event_state << std::endl;
    }
    idx++;
  }
}

void WaypointLoaderNode::createLaneWaypoint(const std::string &file_path,
                                            autoware_msgs::lane *lane) {
  if (!verifyFileConsistency(file_path.c_str())) {
    ROS_ERROR("lane data is something wrong...");
    return;
  }

  ROS_INFO("lane data is valid. publishing...");
  FileFormat format = checkFileFormat(file_path.c_str());
  std::vector<autoware_msgs::waypoint> wps;
  if (format == FileFormat::ver1)
    loadWaypointsForVer1(file_path.c_str(), &wps);
  else if (format == FileFormat::ver2)
    loadWaypointsForVer2(file_path.c_str(), &wps);
  else
    loadWaypointsForVer3(file_path.c_str(), &wps);
  lane->header.frame_id = "/map";
  lane->header.stamp = ros::Time(0);
  lane->waypoints = wps;
}

void WaypointLoaderNode::loadWaypointsForVer1(
    const char *filename, std::vector<autoware_msgs::waypoint> *wps) {
  std::ifstream ifs(filename);

  if (!ifs)
    return;

  std::string line;
  std::getline(ifs, line); // Remove first line

  while (std::getline(ifs, line)) {
    autoware_msgs::waypoint wp;
    parseWaypointForVer1(line, &wp);
    wps->push_back(wp);
  }

  size_t last = wps->size() - 1;
  for (size_t i = 0; i < wps->size(); ++i) {
    if (i != last) {
      double yaw = atan2(wps->at(i + 1).pose.pose.position.y -
                             wps->at(i).pose.pose.position.y,
                         wps->at(i + 1).pose.pose.position.x -
                             wps->at(i).pose.pose.position.x);
      wps->at(i).pose.pose.orientation = tf::createQuaternionMsgFromYaw(yaw);
    } else {
      wps->at(i).pose.pose.orientation = wps->at(i - 1).pose.pose.orientation;
    }
  }
}

void WaypointLoaderNode::parseWaypointForVer1(const std::string &line,
                                              autoware_msgs::waypoint *wp) {
  std::vector<std::string> columns;
  parseColumns(line, &columns);

  wp->pose.pose.position.x = std::stod(columns[0]);
  wp->pose.pose.position.y = std::stod(columns[1]);
  wp->pose.pose.position.z = std::stod(columns[2]);
  wp->twist.twist.linear.x = kmph2mps(std::stod(columns[3]));
}

void WaypointLoaderNode::loadWaypointsForVer2(
    const char *filename, std::vector<autoware_msgs::waypoint> *wps) {
  std::ifstream ifs(filename);

  if (!ifs)
    return;

  std::string line;
  std::getline(ifs, line); // Remove first line

  while (std::getline(ifs, line)) {
    autoware_msgs::waypoint wp;
    parseWaypointForVer2(line, &wp);
    wps->push_back(wp);
  }
}

void WaypointLoaderNode::parseWaypointForVer2(const std::string &line,
                                              autoware_msgs::waypoint *wp) {
  std::vector<std::string> columns;
  parseColumns(line, &columns);

  wp->pose.pose.position.x = std::stod(columns[0]);
  wp->pose.pose.position.y = std::stod(columns[1]);
  wp->pose.pose.position.z = std::stod(columns[2]);
  wp->pose.pose.orientation =
      tf::createQuaternionMsgFromYaw(std::stod(columns[3]));
  wp->twist.twist.linear.x = kmph2mps(std::stod(columns[4]));
}

void WaypointLoaderNode::loadWaypointsForVer3(
    const char *filename, std::vector<autoware_msgs::waypoint> *wps) {
  std::ifstream ifs(filename);

  if (!ifs)
    return;

  std::string line;
  std::getline(ifs, line); // get first line
  std::vector<std::string> contents;
  parseColumns(line, &contents);

  // std::getline(ifs, line);  // remove second line
  while (std::getline(ifs, line)) {
    autoware_msgs::waypoint wp;
    parseWaypointForVer3(line, contents, &wp);
    wps->push_back(wp);
  }
}

void WaypointLoaderNode::parseWaypointForVer3(
    const std::string &line, const std::vector<std::string> &contents,
    autoware_msgs::waypoint *wp) {
  std::vector<std::string> columns;
  parseColumns(line, &columns);
  std::unordered_map<std::string, std::string> map;
  for (size_t i = 0; i < contents.size(); i++) {
    map[contents.at(i)] = columns.at(i);
  }

  wp->pose.pose.position.x = std::stod(map["x"]);
  wp->pose.pose.position.y = std::stod(map["y"]);
  wp->pose.pose.position.z = std::stod(map["z"]);
  wp->pose.pose.orientation =
      tf::createQuaternionMsgFromYaw(std::stod(map["yaw"]));
  wp->twist.twist.linear.x = kmph2mps(std::stod(map["velocity"]));
  wp->change_flag = std::stoi(map["change_flag"]);
  wp->wpstate.steering_state = (map.find("steering_flag") != map.end())
                                   ? std::stoi(map["steering_flag"])
                                   : 0;
  wp->wpstate.accel_state =
      (map.find("accel_flag") != map.end()) ? std::stoi(map["accel_flag"]) : 0;
  wp->wpstate.stopline_state =
      (map.find("stop_flag") != map.end()) ? std::stoi(map["stop_flag"]) : 0;
  wp->wpstate.event_state =
      (map.find("event_flag") != map.end()) ? std::stoi(map["event_flag"]) : 0;
}

FileFormat WaypointLoaderNode::checkFileFormat(const char *filename) {
  std::ifstream ifs(filename);

  if (!ifs) {
    return FileFormat::unknown;
  }

  // get first line
  std::string line;
  std::getline(ifs, line);

  // parse first line
  std::vector<std::string> parsed_columns;
  parseColumns(line, &parsed_columns);

  // check if first element in the first column does not include digit
  if (!std::any_of(parsed_columns.at(0).cbegin(), parsed_columns.at(0).cend(),
                   isdigit)) {
    return FileFormat::ver3;
  }

  // if element consists only digit
  int num_of_columns = countColumns(line);
  ROS_INFO("columns size: %d", num_of_columns);

  return (num_of_columns == 3
              ? FileFormat::ver1 // if data consists "x y z (velocity)"
              : num_of_columns == 4
                    ? FileFormat::ver2 // if data consists "x y z yaw (velocity)
                    : FileFormat::unknown);
}

bool WaypointLoaderNode::verifyFileConsistency(const char *filename) {
  ROS_INFO("verify...");
  std::ifstream ifs(filename);

  if (!ifs)
    return false;

  FileFormat format = checkFileFormat(filename);
  ROS_INFO("format: %d", static_cast<FileFormat>(format));
  if (format == FileFormat::unknown) {
    ROS_ERROR("unknown file format");
    return false;
  }

  std::string line;
  std::getline(ifs, line); // remove first line

  size_t ncol = format == FileFormat::ver1
                    ? 4                              // x,y,z,velocity
                    : format == FileFormat::ver2 ? 5 // x,y,z,yaw,velocity
                                                 : countColumns(line);

  while (std::getline(ifs, line)) // search from second line
  {
    if (countColumns(line) != ncol)
      return false;
  }
  return true;
}

void parseColumns(const std::string &line, std::vector<std::string> *columns) {
  std::istringstream ss(line);
  std::string column;
  while (std::getline(ss, column, ',')) {
    while (1) {
      auto res = std::find(column.begin(), column.end(), ' ');
      if (res == column.end())
        break;
      column.erase(res);
    }
    if (!column.empty())
      columns->push_back(column);
  }
}

size_t countColumns(const std::string &line) {
  std::istringstream ss(line);
  size_t ncol = 0;

  std::string column;
  while (std::getline(ss, column, ',')) {
    ++ncol;
  }

  return ncol;
}

} // waypoint_maker
<|endoftext|>