<commit_before>/*
  Copyright Kitware, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "Detect.h"
#include "Options.h"
#include "RunClang.h"
#include "Utils.h"

#include "llvm/Config/llvm-config.h"

#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"

#include <iostream>
#include <set>
#include <sstream>
#include <string.h>
#include <system_error>
#include <vector>

#if LLVM_VERSION_MAJOR > 3 ||                                                 \
  LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
#include "llvm/Support/StringSaver.h"
#else
class StringSaver : public llvm::cl::StringSaver
{
  std::set<std::string> Strings;

public:
  const char* SaveString(const char* s)
  {
    return this->Strings.insert(s).first->c_str();
  }
};
#endif

int main(int argc_in, const char** argv_in)
{
  suppressInteractiveErrors();

  llvm::InitializeAllTargets();
  llvm::InitializeAllTargetMCs();
  llvm::InitializeAllAsmPrinters();
  llvm::InitializeAllAsmParsers();

  llvm::SmallVector<const char*, 64> argv;
  llvm::SpecificBumpPtrAllocator<char> argAlloc;
  if (std::error_code e = llvm::sys::Process::GetArgumentVector(
        argv, llvm::ArrayRef<const char*>(argv_in, argc_in), argAlloc)) {
    llvm::errs() << "error: could not get arguments: " << e.message() << "\n";
    return 1;
  } else if (argv.empty()) {
    llvm::errs() << "error: no argv[0]?!\n";
    return 1;
  }

#if LLVM_VERSION_MAJOR > 3 ||                                                 \
  LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 8
  llvm::BumpPtrAllocator argSaverAlloc;
  llvm::StringSaver argSaver(argSaverAlloc);
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 7
  llvm::BumpPtrAllocator argSaverAlloc;
  llvm::BumpPtrStringSaver argSaver(argSaverAlloc);
#else
  StringSaver argSaver;
#endif
  llvm::cl::ExpandResponseFiles(argSaver, llvm::cl::TokenizeGNUCommandLine,
                                argv);

  size_t const argc = argv.size();

  if (!findResourceDir(argv[0], std::cerr)) {
    return 1;
  }

  /* clang-format off */
  const char* usage =
    "Usage: castxml ( <castxml-opt> | <clang-opt> | <src> )...\n"
    "\n"
    "  Options interpreted by castxml are listed below.\n"
    "  Remaining options are given to the internal Clang compiler.\n"
    "\n"
    "Options:\n"
    "\n"
    "  --castxml-cc-<id> <cc>\n"
    "  --castxml-cc-<id> \"(\" <cc> <cc-opt>... \")\"\n"
    "    Configure the internal Clang preprocessor and target\n"
    "    platform to match that of the given compiler command.\n"
    "    The <id> must be \"gnu\", \"msvc\", \"gnu-c\", or \"msvc-c\".\n"
    "    <cc> names a compiler (e.g. \"gcc\") and <cc-opt>... specifies\n"
    "    options that may affect its target (e.g. \"-m32\").\n"
    "\n"
    "  --castxml-output=<v>\n"
    "    Write castxml-format output to <src>.xml or file named by '-o'\n"
    "    The <v> specifies the \"epic\" format version number to generate,\n"
    "    and must be '1'.\n"
    "\n"
    "  --castxml-gccxml\n"
    "    Write gccxml-format output to <src>.xml or file named by '-o'\n"
    "    Use this option if you need an output similar to the one generated\n"
    "    by the legacy gccxml tool.\n"
    "\n"
    "  --castxml-start <name>[,<name>]...\n"
    "    Start AST traversal at declaration(s) with the given (qualified)\n"
    "    name(s).  Multiple names may be specified as a comma-separated\n"
    "    list or by repeating the option.\n"
    "\n"
    "  -help, --help\n"
    "    Print castxml and internal Clang compiler usage information\n"
    "\n"
    "  -o <file>\n"
    "    Write output to <file>\n"
    "\n"
    "  --version\n"
    "    Print castxml and internal Clang compiler version information\n"
    "\n"
    ;
  /* clang-format on */

  Options opts;
  llvm::SmallVector<const char*, 16> clang_args;
  llvm::SmallVector<const char*, 16> cc_args;
  const char* cc_id = 0;

  for (size_t i = 1; i < argc; ++i) {
    if (strcmp(argv[i], "--castxml-gccxml") == 0) {
      if (!opts.GccXml) {
        opts.GccXml = true;
      } else {
        /* clang-format off */
        std::cerr <<
          "error: '--castxml-gccxml' may be given at most once!\n"
          "\n" <<
          usage
          ;
        /* clang-format on */
        return 1;
      }
    } else if (strncmp(argv[i], "--castxml-output=", 17) == 0) {
      if (!opts.CastXml) {
        opts.CastXml = true;
        opts.CastXmlEpicFormatVersion = atoi(argv[i] + 17);
        if (opts.CastXmlEpicFormatVersion != 1) {
          /* clang-format off */
            std::cerr <<
              "error: '--castxml-output=<v>' accepts only '1' as '<v>'!\n"
              "\n" <<
              usage
              ;
          /* clang-format on */
        }
      } else {
        /* clang-format off */
        std::cerr <<
          "error: '--castxml-output=<v>' may be given at most once!\n"
          "\n" <<
          usage
          ;
        /* clang-format on */
        return 1;
      }
    } else if (strcmp(argv[i], "--castxml-start") == 0) {
      if ((i + 1) < argc) {
        std::string item;
        std::stringstream stream(argv[++i]);
        while (std::getline(stream, item, ',')) {
          opts.StartNames.push_back(item);
        }
      } else {
        /* clang-format off */
        std::cerr <<
          "error: argument to '--castxml-start' is missing "
          "(expected 1 value)\n"
          "\n" <<
          usage
          ;
        /* clang-format on */
        return 1;
      }
    } else if (strncmp(argv[i], "--castxml-cc-", 13) == 0) {
      if (!cc_id) {
        cc_id = argv[i] + 13;
        if ((i + 1) >= argc) {
          continue;
        }
        ++i;
        if (strncmp(argv[i], "-", 1) == 0) {
          /* clang-format off */
          std::cerr <<
            "error: argument to '--castxml-cc-" << cc_id <<
            "' may not start with '-'\n"
            "\n" <<
            usage
            ;
          /* clang-format on */
          return 1;
        }
        if (strcmp(argv[i], "(") == 0) {
          unsigned int depth = 1;
          for (++i; i < argc && depth > 0; ++i) {
            if (strncmp(argv[i], "--castxml-", 10) == 0) {
              /* clang-format off */
              std::cerr <<
                "error: arguments to '--castxml-cc-" << cc_id <<
                "' may not start with '--castxml-'\n"
                "\n" <<
                usage
                ;
              /* clang-format on */
              return 1;
            } else if (strcmp(argv[i], "(") == 0) {
              ++depth;
              cc_args.push_back(argv[i]);
            } else if (strcmp(argv[i], ")") == 0) {
              if (--depth) {
                cc_args.push_back(argv[i]);
              }
            } else {
              cc_args.push_back(argv[i]);
            }
          }
          if (depth) {
            /* clang-format off */
            std::cerr <<
              "error: unbalanced parentheses after '--castxml-cc-" <<
              cc_id << "'\n"
              "\n" <<
              usage
              ;
            /* clang-format on */
            return 1;
          }
          --i;
        } else {
          cc_args.push_back(argv[i]);
        }
      } else {
        /* clang-format off */
        std::cerr <<
          "error: '--castxml-cc-<id>' may be given at most once!\n"
          "\n" <<
          usage
          ;
        /* clang-format on */
        return 1;
      }
    } else if (strcmp(argv[i], "-E") == 0) {
      opts.PPOnly = true;
    } else if (strcmp(argv[i], "-o") == 0) {
      if ((i + 1) < argc) {
        opts.OutputFile = argv[++i];
      } else {
        /* clang-format off */
        std::cerr <<
          "error: argument to '-o' is missing (expected 1 value)\n"
          "\n" <<
          usage
          ;
        /* clang-format on */
        return 1;
      }
    } else if (strcmp(argv[i], "-help") == 0 ||
               strcmp(argv[i], "--help") == 0) {
      /* clang-format off */
      std::cout <<
        usage <<
        "\n"
        "Help for the internal Clang compiler appears below.\n"
        "\n"
        "---------------------------------------------------------------"
        "\n" <<
        std::endl;
      /* clang-format on */
      // Also print Clang help.
      clang_args.push_back(argv[i]);
    } else if (strcmp(argv[i], "--version") == 0) {
      /* clang-format off */
      std::cout <<
        "castxml version " << getVersionString() << "\n"
        "\n"
        "CastXML project maintained and supported by Kitware "
        "(kitware.com).\n" <<
        std::endl;
      /* clang-format on */
      // Also print Clang version.
      clang_args.push_back(argv[i]);
    } else {
      clang_args.push_back(argv[i]);
      if (strcmp(argv[i], "-target") == 0 ||
          strcmp(argv[i], "--target") == 0 ||
          strncmp(argv[i], "-target=", 8) == 0 ||
          strncmp(argv[i], "--target=", 9) == 0) {
        opts.HaveTarget = true;
      } else if (strncmp(argv[i], "-std=", 5) == 0) {
        opts.HaveStd = true;
      }
    }
  }

  if (cc_id) {
    opts.HaveCC = true;
    if (cc_args.empty()) {
      /* clang-format off */
      std::cerr <<
        "error: '--castxml-cc-" << cc_id <<
        "' must be followed by a compiler command!\n"
        "\n" <<
        usage
        ;
      /* clang-format on */
      return 1;
    }
    if (!detectCC(cc_id, cc_args.data(), cc_args.data() + cc_args.size(),
                  opts)) {
      return 1;
    }
  }

  if (opts.GccXml && opts.CastXml) {
    /* clang-format off */
    std::cerr <<
      "error: '--castxml-gccxml' and '--castxml-output=<v>'"
      " may not be not be used together!\n"
      "\n" <<
      usage
      ;
    /* clang-format on */
    return 1;
  }

  if (clang_args.empty()) {
    return 0;
  }

  return runClang(clang_args.data(), clang_args.data() + clang_args.size(),
                  opts);
}
<commit_msg>castxml: Process arguments before initializing LLVM targets<commit_after>/*
  Copyright Kitware, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "Detect.h"
#include "Options.h"
#include "RunClang.h"
#include "Utils.h"

#include "llvm/Config/llvm-config.h"

#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"

#include <iostream>
#include <set>
#include <sstream>
#include <string.h>
#include <system_error>
#include <vector>

#if LLVM_VERSION_MAJOR > 3 ||                                                 \
  LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
#include "llvm/Support/StringSaver.h"
#else
class StringSaver : public llvm::cl::StringSaver
{
  std::set<std::string> Strings;

public:
  const char* SaveString(const char* s)
  {
    return this->Strings.insert(s).first->c_str();
  }
};
#endif

int main(int argc_in, const char** argv_in)
{
  suppressInteractiveErrors();

  llvm::SmallVector<const char*, 64> argv;
  llvm::SpecificBumpPtrAllocator<char> argAlloc;
  if (std::error_code e = llvm::sys::Process::GetArgumentVector(
        argv, llvm::ArrayRef<const char*>(argv_in, argc_in), argAlloc)) {
    llvm::errs() << "error: could not get arguments: " << e.message() << "\n";
    return 1;
  } else if (argv.empty()) {
    llvm::errs() << "error: no argv[0]?!\n";
    return 1;
  }

  llvm::InitializeAllTargets();
  llvm::InitializeAllTargetMCs();
  llvm::InitializeAllAsmPrinters();
  llvm::InitializeAllAsmParsers();

#if LLVM_VERSION_MAJOR > 3 ||                                                 \
  LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 8
  llvm::BumpPtrAllocator argSaverAlloc;
  llvm::StringSaver argSaver(argSaverAlloc);
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 7
  llvm::BumpPtrAllocator argSaverAlloc;
  llvm::BumpPtrStringSaver argSaver(argSaverAlloc);
#else
  StringSaver argSaver;
#endif
  llvm::cl::ExpandResponseFiles(argSaver, llvm::cl::TokenizeGNUCommandLine,
                                argv);

  size_t const argc = argv.size();

  if (!findResourceDir(argv[0], std::cerr)) {
    return 1;
  }

  /* clang-format off */
  const char* usage =
    "Usage: castxml ( <castxml-opt> | <clang-opt> | <src> )...\n"
    "\n"
    "  Options interpreted by castxml are listed below.\n"
    "  Remaining options are given to the internal Clang compiler.\n"
    "\n"
    "Options:\n"
    "\n"
    "  --castxml-cc-<id> <cc>\n"
    "  --castxml-cc-<id> \"(\" <cc> <cc-opt>... \")\"\n"
    "    Configure the internal Clang preprocessor and target\n"
    "    platform to match that of the given compiler command.\n"
    "    The <id> must be \"gnu\", \"msvc\", \"gnu-c\", or \"msvc-c\".\n"
    "    <cc> names a compiler (e.g. \"gcc\") and <cc-opt>... specifies\n"
    "    options that may affect its target (e.g. \"-m32\").\n"
    "\n"
    "  --castxml-output=<v>\n"
    "    Write castxml-format output to <src>.xml or file named by '-o'\n"
    "    The <v> specifies the \"epic\" format version number to generate,\n"
    "    and must be '1'.\n"
    "\n"
    "  --castxml-gccxml\n"
    "    Write gccxml-format output to <src>.xml or file named by '-o'\n"
    "    Use this option if you need an output similar to the one generated\n"
    "    by the legacy gccxml tool.\n"
    "\n"
    "  --castxml-start <name>[,<name>]...\n"
    "    Start AST traversal at declaration(s) with the given (qualified)\n"
    "    name(s).  Multiple names may be specified as a comma-separated\n"
    "    list or by repeating the option.\n"
    "\n"
    "  -help, --help\n"
    "    Print castxml and internal Clang compiler usage information\n"
    "\n"
    "  -o <file>\n"
    "    Write output to <file>\n"
    "\n"
    "  --version\n"
    "    Print castxml and internal Clang compiler version information\n"
    "\n"
    ;
  /* clang-format on */

  Options opts;
  llvm::SmallVector<const char*, 16> clang_args;
  llvm::SmallVector<const char*, 16> cc_args;
  const char* cc_id = 0;

  for (size_t i = 1; i < argc; ++i) {
    if (strcmp(argv[i], "--castxml-gccxml") == 0) {
      if (!opts.GccXml) {
        opts.GccXml = true;
      } else {
        /* clang-format off */
        std::cerr <<
          "error: '--castxml-gccxml' may be given at most once!\n"
          "\n" <<
          usage
          ;
        /* clang-format on */
        return 1;
      }
    } else if (strncmp(argv[i], "--castxml-output=", 17) == 0) {
      if (!opts.CastXml) {
        opts.CastXml = true;
        opts.CastXmlEpicFormatVersion = atoi(argv[i] + 17);
        if (opts.CastXmlEpicFormatVersion != 1) {
          /* clang-format off */
            std::cerr <<
              "error: '--castxml-output=<v>' accepts only '1' as '<v>'!\n"
              "\n" <<
              usage
              ;
          /* clang-format on */
        }
      } else {
        /* clang-format off */
        std::cerr <<
          "error: '--castxml-output=<v>' may be given at most once!\n"
          "\n" <<
          usage
          ;
        /* clang-format on */
        return 1;
      }
    } else if (strcmp(argv[i], "--castxml-start") == 0) {
      if ((i + 1) < argc) {
        std::string item;
        std::stringstream stream(argv[++i]);
        while (std::getline(stream, item, ',')) {
          opts.StartNames.push_back(item);
        }
      } else {
        /* clang-format off */
        std::cerr <<
          "error: argument to '--castxml-start' is missing "
          "(expected 1 value)\n"
          "\n" <<
          usage
          ;
        /* clang-format on */
        return 1;
      }
    } else if (strncmp(argv[i], "--castxml-cc-", 13) == 0) {
      if (!cc_id) {
        cc_id = argv[i] + 13;
        if ((i + 1) >= argc) {
          continue;
        }
        ++i;
        if (strncmp(argv[i], "-", 1) == 0) {
          /* clang-format off */
          std::cerr <<
            "error: argument to '--castxml-cc-" << cc_id <<
            "' may not start with '-'\n"
            "\n" <<
            usage
            ;
          /* clang-format on */
          return 1;
        }
        if (strcmp(argv[i], "(") == 0) {
          unsigned int depth = 1;
          for (++i; i < argc && depth > 0; ++i) {
            if (strncmp(argv[i], "--castxml-", 10) == 0) {
              /* clang-format off */
              std::cerr <<
                "error: arguments to '--castxml-cc-" << cc_id <<
                "' may not start with '--castxml-'\n"
                "\n" <<
                usage
                ;
              /* clang-format on */
              return 1;
            } else if (strcmp(argv[i], "(") == 0) {
              ++depth;
              cc_args.push_back(argv[i]);
            } else if (strcmp(argv[i], ")") == 0) {
              if (--depth) {
                cc_args.push_back(argv[i]);
              }
            } else {
              cc_args.push_back(argv[i]);
            }
          }
          if (depth) {
            /* clang-format off */
            std::cerr <<
              "error: unbalanced parentheses after '--castxml-cc-" <<
              cc_id << "'\n"
              "\n" <<
              usage
              ;
            /* clang-format on */
            return 1;
          }
          --i;
        } else {
          cc_args.push_back(argv[i]);
        }
      } else {
        /* clang-format off */
        std::cerr <<
          "error: '--castxml-cc-<id>' may be given at most once!\n"
          "\n" <<
          usage
          ;
        /* clang-format on */
        return 1;
      }
    } else if (strcmp(argv[i], "-E") == 0) {
      opts.PPOnly = true;
    } else if (strcmp(argv[i], "-o") == 0) {
      if ((i + 1) < argc) {
        opts.OutputFile = argv[++i];
      } else {
        /* clang-format off */
        std::cerr <<
          "error: argument to '-o' is missing (expected 1 value)\n"
          "\n" <<
          usage
          ;
        /* clang-format on */
        return 1;
      }
    } else if (strcmp(argv[i], "-help") == 0 ||
               strcmp(argv[i], "--help") == 0) {
      /* clang-format off */
      std::cout <<
        usage <<
        "\n"
        "Help for the internal Clang compiler appears below.\n"
        "\n"
        "---------------------------------------------------------------"
        "\n" <<
        std::endl;
      /* clang-format on */
      // Also print Clang help.
      clang_args.push_back(argv[i]);
    } else if (strcmp(argv[i], "--version") == 0) {
      /* clang-format off */
      std::cout <<
        "castxml version " << getVersionString() << "\n"
        "\n"
        "CastXML project maintained and supported by Kitware "
        "(kitware.com).\n" <<
        std::endl;
      /* clang-format on */
      // Also print Clang version.
      clang_args.push_back(argv[i]);
    } else {
      clang_args.push_back(argv[i]);
      if (strcmp(argv[i], "-target") == 0 ||
          strcmp(argv[i], "--target") == 0 ||
          strncmp(argv[i], "-target=", 8) == 0 ||
          strncmp(argv[i], "--target=", 9) == 0) {
        opts.HaveTarget = true;
      } else if (strncmp(argv[i], "-std=", 5) == 0) {
        opts.HaveStd = true;
      }
    }
  }

  if (cc_id) {
    opts.HaveCC = true;
    if (cc_args.empty()) {
      /* clang-format off */
      std::cerr <<
        "error: '--castxml-cc-" << cc_id <<
        "' must be followed by a compiler command!\n"
        "\n" <<
        usage
        ;
      /* clang-format on */
      return 1;
    }
    if (!detectCC(cc_id, cc_args.data(), cc_args.data() + cc_args.size(),
                  opts)) {
      return 1;
    }
  }

  if (opts.GccXml && opts.CastXml) {
    /* clang-format off */
    std::cerr <<
      "error: '--castxml-gccxml' and '--castxml-output=<v>'"
      " may not be not be used together!\n"
      "\n" <<
      usage
      ;
    /* clang-format on */
    return 1;
  }

  if (clang_args.empty()) {
    return 0;
  }

  return runClang(clang_args.data(), clang_args.data() + clang_args.size(),
                  opts);
}
<|endoftext|>


<commit_before>/*!
  \copyright (c) RDO-Team, 2011
  \file      document.cpp
  \author    Урусов Андрей (rdo@rk9.bmstu.ru)
  \date      01.11.2010
  \brief
  \indent    4T
*/

// ---------------------------------------------------------------------------- PCH
#include "converter/smr2rdox/pch.h"
// ----------------------------------------------------------------------- INCLUDES
#include <boost/filesystem.hpp>
// ----------------------------------------------------------------------- SYNOPSIS
#include "converter/smr2rdox/update/document.h"
// --------------------------------------------------------------------------------

OPEN_RDO_CONVERTER_SMR2RDOX_NAMESPACE

//#define DUMP_DOCUMENT

// --------------------------------------------------------------------------------
// -------------------- Document
// --------------------------------------------------------------------------------
Document::Document()
{}

Document::~Document()
{
	close();
}

void Document::create(CREF(tstring) filePath, CREF(tstring) modelName)
{
	m_filePath  = filePath;
	m_modelName = modelName;
}

void Document::init(rdo::converter::smr2rdox::RDOFileTypeIn type, REF(std::ifstream) stream)
{
	Type typeOut;
	switch (type)
	{
	case rdo::converter::smr2rdox::PAT_IN: typeOut = PAT; break;
	case rdo::converter::smr2rdox::RTP_IN: typeOut = RTP; break;
	case rdo::converter::smr2rdox::RSS_IN: typeOut = RSS; break;
	case rdo::converter::smr2rdox::OPR_IN: typeOut = OPR; break;
	case rdo::converter::smr2rdox::FRM_IN: typeOut = FRM; break;
	case rdo::converter::smr2rdox::FUN_IN: typeOut = FUN; break;
	case rdo::converter::smr2rdox::DPT_IN: typeOut = DPT; break;
	case rdo::converter::smr2rdox::SMR_IN: typeOut = SMR; break;
	case rdo::converter::smr2rdox::PMD_IN: typeOut = PMD; break;
	case rdo::converter::smr2rdox::PMV_IN: typeOut = PMV; break;
	default                              : typeOut = UNDEFINED; NEVER_REACH_HERE; break;
	}
	LPMemoryStream streamOut = getMemoryStream(typeOut);
	streamOut->init(stream);
}

void Document::insertUpdate(CREF(LPDocUpdate) pUpdate)
{
	ASSERT(pUpdate);

	m_updateContainer.push_back(Update(pUpdate, false));
}

void Document::convert()
{
	LPIDocument pDocument = LPDocument(this).interface_cast<IDocument>();

#ifdef DUMP_DOCUMENT
	{
		STL_FOR_ALL_CONST(m_updateContainer, it)
		{
			LPDocUpdate pUpdate = it->first;
			ASSERT(pUpdate);
			pUpdate->dump(pDocument);
		}
	}
#endif

	STL_FOR_ALL(m_updateContainer, it)
	{
		it->second = true;
		LPDocUpdate pUpdate = it->first;
		ASSERT(pUpdate);
		pUpdate->apply(pDocument);

#ifdef DUMP_DOCUMENT
		{
			TRACE("=================\n");
			STL_FOR_ALL_CONST(m_updateContainer, it)
			{
				if (!it->second)
				{
					LPDocUpdate pUpdate = it->first;
					ASSERT(pUpdate);
					pUpdate->dump(pDocument);
				}
			}
		}
#endif
	}
}

Document::TypeOut Document::typeToOut(CREF(Type) typeIn) const
{
	switch (typeIn)
	{
	case PAT: return rdo::converter::smr2rdox::PAT_OUT;
	case RTP: return rdo::converter::smr2rdox::RTP_OUT;
	case RSS: return rdo::converter::smr2rdox::RSS_OUT;
	case FRM: return rdo::converter::smr2rdox::FRM_OUT;
	case FUN: return rdo::converter::smr2rdox::FUN_OUT;
	case DPT: return rdo::converter::smr2rdox::DPT_OUT;
	case SMR: return rdo::converter::smr2rdox::SMR_OUT;
	case PMD: return rdo::converter::smr2rdox::PMD_OUT;
	case PMV: return rdo::converter::smr2rdox::PMV_OUT;
	case TRC: return rdo::converter::smr2rdox::TRC_OUT;
	case EVN: return rdo::converter::smr2rdox::EVN_OUT;
	case PRC: return rdo::converter::smr2rdox::PRC_OUT;
	default : break;
	}
	return rdo::converter::smr2rdox::UNDEFINED_OUT;
}

void Document::close()
{
	STL_FOR_ALL_CONST(m_memoryFileList, memoryIt)
	{
		TypeOut typeOut = typeToOut(memoryIt->first);
		if (typeOut != rdo::converter::smr2rdox::UNDEFINED_OUT)
		{
			LPFileStream pFileStream = getFileStream(typeOut);
			ASSERT(pFileStream);
			memoryIt->second->get(*pFileStream.get());
		}
	}
	m_memoryFileList.clear();

	STL_FOR_ALL_CONST(m_streamFileList, fileIt)
	{
		fileIt->second->close();
	}
	m_streamFileList.clear();
}

tstring Document::getName(TypeOut typeOut) const
{
	tstring extention;
	switch (typeOut)
	{
	case rdo::converter::smr2rdox::PAT_OUT: extention = "pat"; break;
	case rdo::converter::smr2rdox::RTP_OUT: extention = "rtp"; break;
	case rdo::converter::smr2rdox::RSS_OUT: extention = "rss"; break;
	case rdo::converter::smr2rdox::FRM_OUT: extention = "frm"; break;
	case rdo::converter::smr2rdox::FUN_OUT: extention = "fun"; break;
	case rdo::converter::smr2rdox::DPT_OUT: extention = "dpt"; break;
	case rdo::converter::smr2rdox::SMR_OUT: extention = "smr"; break;
	case rdo::converter::smr2rdox::PMD_OUT: extention = "pmd"; break;
	case rdo::converter::smr2rdox::PMV_OUT: extention = "pmv"; break;
	case rdo::converter::smr2rdox::TRC_OUT: extention = "trc"; break;
	case rdo::converter::smr2rdox::EVN_OUT: extention = "evn"; break;
	case rdo::converter::smr2rdox::PRC_OUT: extention = "prc"; break;
	default: NEVER_REACH_HERE;
	}

	boost::filesystem::path fileName(boost::filesystem::path(m_filePath) / m_modelName);
	fileName.replace_extension(rdo::format(".%s", extention.c_str()));
	return fileName.string();
}

Document::LPMemoryStream Document::getMemoryStream(Type type)
{
	BOOST_AUTO(it, m_memoryFileList.find(type));
	if (it == m_memoryFileList.end())
	{
		LPMemoryStream pMemoryStream = LPMemoryStream(new MemoryStream());
		std::pair<MemoryFileList::iterator, rbool> result = m_memoryFileList.insert(MemoryFileList::value_type(type, pMemoryStream));
		ASSERT(result.second);
		it = result.first;
	}
	return it->second;
}

Document::LPFileStream Document::getFileStream(TypeOut type)
{
	BOOST_AUTO(it, m_streamFileList.find(type));
	if (it == m_streamFileList.end())
	{
		LPFileStream pFileStream = LPFileStream(new std::ofstream(getName(type).c_str(), std::ios::trunc | std::ios::binary));
		std::pair<StreamFileList::iterator, rbool> result = m_streamFileList.insert(StreamFileList::value_type(type, pFileStream));
		ASSERT(result.second);
		it = result.first;
	}
	return it->second;
}

void Document::insert(Type type, ruint to, CREF(tstring) value)
{
	LPMemoryStream streamOut = getMemoryStream(type);
	streamOut->insert(to, value);

	STL_FOR_ALL(m_updateContainer, it)
	{
		if (!it->second)
		{
			LPDocUpdate pUpdate = it->first;
			ASSERT(pUpdate);
			pUpdate->insert(type, to, value.length());
		}
	}
}

void Document::remove(Type type, ruint from, ruint to)
{
	LPMemoryStream streamOut = getMemoryStream(type);
	streamOut->remove(from, to);

	STL_FOR_ALL(m_updateContainer, it)
	{
		if (!it->second)
		{
			LPDocUpdate pUpdate = it->first;
			ASSERT(pUpdate);
			pUpdate->remove(type, from, to);
		}
	}
}

tstring Document::get(Type type, ruint from, ruint to)
{
	return getMemoryStream(type)->get(from, to);
}

// --------------------------------------------------------------------------------
// -------------------- MemoryStream
// --------------------------------------------------------------------------------
void Document::MemoryStream::init(REF(std::ifstream) stream)
{
	if (!m_buffer.empty())
	{
		return;
	}

	for (;;)
	{
		char byte;
		stream.get(byte);
		if (stream.eof())
		{
			break;
		}
		m_buffer.push_back(byte);
	}
}

void Document::MemoryStream::get(REF(std::ofstream) stream) const
{
	stream.write(&m_buffer[0], m_buffer.size());
}

void Document::MemoryStream::insert(ruint to, CREF(tstring) value)
{
	Buffer::iterator itTo;
	switch (to)
	{
	case IDocUpdate::Position::POSITION_BEGIN: itTo = m_buffer.begin();      break;
	case IDocUpdate::Position::POSITION_END  : itTo = m_buffer.end();        break;
	default                                  : itTo = m_buffer.begin() + to; break;
	}

	for (ruint i = 0; i < value.length(); ++i)
	{
		itTo = m_buffer.insert(itTo, value[i]);
		++itTo;
	}
}

void Document::MemoryStream::remove(ruint from, ruint to)
{
	Buffer::iterator itFrom;
	switch (from)
	{
	case IDocUpdate::Position::POSITION_BEGIN: itFrom = m_buffer.begin();        break;
	case IDocUpdate::Position::POSITION_END  : itFrom = m_buffer.end();          break;
	default                                  : itFrom = m_buffer.begin() + from; break;
	}

	Buffer::iterator itTo;
	switch (to)
	{
	case IDocUpdate::Position::POSITION_BEGIN: itTo = m_buffer.begin();      break;
	case IDocUpdate::Position::POSITION_END  : itTo = m_buffer.end();        break;
	default                                  : itTo = m_buffer.begin() + to; break;
	}

	m_buffer.erase(itFrom, itTo);
}

tstring Document::MemoryStream::get(ruint from, ruint to)
{
	Buffer::iterator itFrom = m_buffer.begin() + from;
	Buffer::iterator itTo   = m_buffer.begin() + to;
	tstring result;
	result.resize(to - from);
	std::copy(itFrom, itTo, result.begin());
	return result;
}

CLOSE_RDO_CONVERTER_SMR2RDOX_NAMESPACE
<commit_msg> - конвертор преобразует результат в юникод<commit_after>/*!
  \copyright (c) RDO-Team, 2011
  \file      document.cpp
  \author    Урусов Андрей (rdo@rk9.bmstu.ru)
  \date      01.11.2010
  \brief
  \indent    4T
*/

// ---------------------------------------------------------------------------- PCH
#include "converter/smr2rdox/pch.h"
// ----------------------------------------------------------------------- INCLUDES
#include <boost/filesystem.hpp>
// ----------------------------------------------------------------------- SYNOPSIS
#include "converter/smr2rdox/update/document.h"
#include "utils/rdolocale.h"
// --------------------------------------------------------------------------------

OPEN_RDO_CONVERTER_SMR2RDOX_NAMESPACE

//#define DUMP_DOCUMENT

// --------------------------------------------------------------------------------
// -------------------- Document
// --------------------------------------------------------------------------------
Document::Document()
{}

Document::~Document()
{
	close();
}

void Document::create(CREF(tstring) filePath, CREF(tstring) modelName)
{
	m_filePath  = filePath;
	m_modelName = modelName;
}

void Document::init(rdo::converter::smr2rdox::RDOFileTypeIn type, REF(std::ifstream) stream)
{
	Type typeOut;
	switch (type)
	{
	case rdo::converter::smr2rdox::PAT_IN: typeOut = PAT; break;
	case rdo::converter::smr2rdox::RTP_IN: typeOut = RTP; break;
	case rdo::converter::smr2rdox::RSS_IN: typeOut = RSS; break;
	case rdo::converter::smr2rdox::OPR_IN: typeOut = OPR; break;
	case rdo::converter::smr2rdox::FRM_IN: typeOut = FRM; break;
	case rdo::converter::smr2rdox::FUN_IN: typeOut = FUN; break;
	case rdo::converter::smr2rdox::DPT_IN: typeOut = DPT; break;
	case rdo::converter::smr2rdox::SMR_IN: typeOut = SMR; break;
	case rdo::converter::smr2rdox::PMD_IN: typeOut = PMD; break;
	case rdo::converter::smr2rdox::PMV_IN: typeOut = PMV; break;
	default                              : typeOut = UNDEFINED; NEVER_REACH_HERE; break;
	}
	LPMemoryStream streamOut = getMemoryStream(typeOut);
	streamOut->init(stream);
}

void Document::insertUpdate(CREF(LPDocUpdate) pUpdate)
{
	ASSERT(pUpdate);

	m_updateContainer.push_back(Update(pUpdate, false));
}

void Document::convert()
{
	LPIDocument pDocument = LPDocument(this).interface_cast<IDocument>();

#ifdef DUMP_DOCUMENT
	{
		STL_FOR_ALL_CONST(m_updateContainer, it)
		{
			LPDocUpdate pUpdate = it->first;
			ASSERT(pUpdate);
			pUpdate->dump(pDocument);
		}
	}
#endif

	STL_FOR_ALL(m_updateContainer, it)
	{
		it->second = true;
		LPDocUpdate pUpdate = it->first;
		ASSERT(pUpdate);
		pUpdate->apply(pDocument);

#ifdef DUMP_DOCUMENT
		{
			TRACE("=================\n");
			STL_FOR_ALL_CONST(m_updateContainer, it)
			{
				if (!it->second)
				{
					LPDocUpdate pUpdate = it->first;
					ASSERT(pUpdate);
					pUpdate->dump(pDocument);
				}
			}
		}
#endif
	}
}

Document::TypeOut Document::typeToOut(CREF(Type) typeIn) const
{
	switch (typeIn)
	{
	case PAT: return rdo::converter::smr2rdox::PAT_OUT;
	case RTP: return rdo::converter::smr2rdox::RTP_OUT;
	case RSS: return rdo::converter::smr2rdox::RSS_OUT;
	case FRM: return rdo::converter::smr2rdox::FRM_OUT;
	case FUN: return rdo::converter::smr2rdox::FUN_OUT;
	case DPT: return rdo::converter::smr2rdox::DPT_OUT;
	case SMR: return rdo::converter::smr2rdox::SMR_OUT;
	case PMD: return rdo::converter::smr2rdox::PMD_OUT;
	case PMV: return rdo::converter::smr2rdox::PMV_OUT;
	case TRC: return rdo::converter::smr2rdox::TRC_OUT;
	case EVN: return rdo::converter::smr2rdox::EVN_OUT;
	case PRC: return rdo::converter::smr2rdox::PRC_OUT;
	default : break;
	}
	return rdo::converter::smr2rdox::UNDEFINED_OUT;
}

void Document::close()
{
	STL_FOR_ALL_CONST(m_memoryFileList, memoryIt)
	{
		TypeOut typeOut = typeToOut(memoryIt->first);
		if (typeOut != rdo::converter::smr2rdox::UNDEFINED_OUT)
		{
			LPFileStream pFileStream = getFileStream(typeOut);
			ASSERT(pFileStream);
			memoryIt->second->get(*pFileStream.get());
		}
	}
	m_memoryFileList.clear();

	STL_FOR_ALL_CONST(m_streamFileList, fileIt)
	{
		fileIt->second->close();
	}
	m_streamFileList.clear();
}

tstring Document::getName(TypeOut typeOut) const
{
	tstring extention;
	switch (typeOut)
	{
	case rdo::converter::smr2rdox::PAT_OUT: extention = "pat"; break;
	case rdo::converter::smr2rdox::RTP_OUT: extention = "rtp"; break;
	case rdo::converter::smr2rdox::RSS_OUT: extention = "rss"; break;
	case rdo::converter::smr2rdox::FRM_OUT: extention = "frm"; break;
	case rdo::converter::smr2rdox::FUN_OUT: extention = "fun"; break;
	case rdo::converter::smr2rdox::DPT_OUT: extention = "dpt"; break;
	case rdo::converter::smr2rdox::SMR_OUT: extention = "smr"; break;
	case rdo::converter::smr2rdox::PMD_OUT: extention = "pmd"; break;
	case rdo::converter::smr2rdox::PMV_OUT: extention = "pmv"; break;
	case rdo::converter::smr2rdox::TRC_OUT: extention = "trc"; break;
	case rdo::converter::smr2rdox::EVN_OUT: extention = "evn"; break;
	case rdo::converter::smr2rdox::PRC_OUT: extention = "prc"; break;
	default: NEVER_REACH_HERE;
	}

	boost::filesystem::path fileName(boost::filesystem::path(m_filePath) / m_modelName);
	fileName.replace_extension(rdo::format(".%s", extention.c_str()));
	return fileName.string();
}

Document::LPMemoryStream Document::getMemoryStream(Type type)
{
	BOOST_AUTO(it, m_memoryFileList.find(type));
	if (it == m_memoryFileList.end())
	{
		LPMemoryStream pMemoryStream = LPMemoryStream(new MemoryStream());
		std::pair<MemoryFileList::iterator, rbool> result = m_memoryFileList.insert(MemoryFileList::value_type(type, pMemoryStream));
		ASSERT(result.second);
		it = result.first;
	}
	return it->second;
}

Document::LPFileStream Document::getFileStream(TypeOut type)
{
	BOOST_AUTO(it, m_streamFileList.find(type));
	if (it == m_streamFileList.end())
	{
		LPFileStream pFileStream = LPFileStream(new std::ofstream(getName(type).c_str(), std::ios::trunc | std::ios::binary));
		std::pair<StreamFileList::iterator, rbool> result = m_streamFileList.insert(StreamFileList::value_type(type, pFileStream));
		ASSERT(result.second);
		it = result.first;
	}
	return it->second;
}

void Document::insert(Type type, ruint to, CREF(tstring) value)
{
	LPMemoryStream streamOut = getMemoryStream(type);
	streamOut->insert(to, value);

	STL_FOR_ALL(m_updateContainer, it)
	{
		if (!it->second)
		{
			LPDocUpdate pUpdate = it->first;
			ASSERT(pUpdate);
			pUpdate->insert(type, to, value.length());
		}
	}
}

void Document::remove(Type type, ruint from, ruint to)
{
	LPMemoryStream streamOut = getMemoryStream(type);
	streamOut->remove(from, to);

	STL_FOR_ALL(m_updateContainer, it)
	{
		if (!it->second)
		{
			LPDocUpdate pUpdate = it->first;
			ASSERT(pUpdate);
			pUpdate->remove(type, from, to);
		}
	}
}

tstring Document::get(Type type, ruint from, ruint to)
{
	return getMemoryStream(type)->get(from, to);
}

// --------------------------------------------------------------------------------
// -------------------- MemoryStream
// --------------------------------------------------------------------------------
void Document::MemoryStream::init(REF(std::ifstream) stream)
{
	if (!m_buffer.empty())
	{
		return;
	}

	for (;;)
	{
		char byte;
		stream.get(byte);
		if (stream.eof())
		{
			break;
		}
		m_buffer.push_back(byte);
	}
}

void Document::MemoryStream::get(REF(std::ofstream) stream) const
{
	std::string result = rdo::locale::convertFromCLocale(std::string(&m_buffer[0], m_buffer.size()));
	stream << result;
}

void Document::MemoryStream::insert(ruint to, CREF(tstring) value)
{
	Buffer::iterator itTo;
	switch (to)
	{
	case IDocUpdate::Position::POSITION_BEGIN: itTo = m_buffer.begin();      break;
	case IDocUpdate::Position::POSITION_END  : itTo = m_buffer.end();        break;
	default                                  : itTo = m_buffer.begin() + to; break;
	}

	for (ruint i = 0; i < value.length(); ++i)
	{
		itTo = m_buffer.insert(itTo, value[i]);
		++itTo;
	}
}

void Document::MemoryStream::remove(ruint from, ruint to)
{
	Buffer::iterator itFrom;
	switch (from)
	{
	case IDocUpdate::Position::POSITION_BEGIN: itFrom = m_buffer.begin();        break;
	case IDocUpdate::Position::POSITION_END  : itFrom = m_buffer.end();          break;
	default                                  : itFrom = m_buffer.begin() + from; break;
	}

	Buffer::iterator itTo;
	switch (to)
	{
	case IDocUpdate::Position::POSITION_BEGIN: itTo = m_buffer.begin();      break;
	case IDocUpdate::Position::POSITION_END  : itTo = m_buffer.end();        break;
	default                                  : itTo = m_buffer.begin() + to; break;
	}

	m_buffer.erase(itFrom, itTo);
}

tstring Document::MemoryStream::get(ruint from, ruint to)
{
	Buffer::iterator itFrom = m_buffer.begin() + from;
	Buffer::iterator itTo   = m_buffer.begin() + to;
	tstring result;
	result.resize(to - from);
	std::copy(itFrom, itTo, result.begin());
	return result;
}

CLOSE_RDO_CONVERTER_SMR2RDOX_NAMESPACE
<|endoftext|>


<commit_before>//
// Copyright (c) 2018 Rokas Kupstys
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include <cppast/cpp_template.hpp>
#include <fmt/format.h>
#include "GeneratorContext.h"
#include "Urho3DTypeMaps.h"

namespace Urho3D
{

bool Urho3DTypeMaps::Visit(MetaEntity* entity, cppast::visitor_info info)
{
    if (entity->ast_ == nullptr)
        return true;

    if (entity->kind_ == cppast::cpp_entity_kind::member_variable_t)
        HandleType(entity->Ast<cppast::cpp_member_variable>().type());
    else if (entity->kind_ == cppast::cpp_entity_kind::variable_t)
        HandleType(entity->Ast<cppast::cpp_variable>().type());
    else if (entity->kind_ == cppast::cpp_entity_kind::member_function_t)
    {
        HandleType(entity->Ast<cppast::cpp_member_function>().return_type());
        for (const auto& param : entity->children_)
            HandleType(param->Ast<cppast::cpp_function_parameter>().type());
    }
    else if (entity->kind_ == cppast::cpp_entity_kind::function_t)
    {
        HandleType(entity->Ast<cppast::cpp_function>().return_type());
        for (const auto& param : entity->children_)
            HandleType(param->Ast<cppast::cpp_function_parameter>().type());
    }
    else if (entity->kind_ == cppast::cpp_entity_kind::constructor_t)
    {
        for (const auto& param : entity->children_)
            HandleType(param->Ast<cppast::cpp_function_parameter>().type());
    }
    return true;
}

void Urho3DTypeMaps::HandleType(const cppast::cpp_type& type)
{
    const auto& realType = GetBaseType(type);
    if (realType.kind() != cppast::cpp_type_kind::template_instantiation_t)
        return;

    auto typeName = cppast::to_string(realType);

    // Typemap already generated
    if (generator->GetTypeMap(typeName) != nullptr)
        return;

    std::string csType;
    std::string pInvokeType = "IntPtr";
    std::string cppType;
    std::string vectorKind;
    const TypeMap* typeMap = nullptr;

    if (str::starts_with(typeName, "PODVector<"))
        vectorKind = "PODVector";
    else if (str::starts_with(typeName, "Vector<SharedPtr<") || str::starts_with(typeName, "Vector<WeakPtr<"))
        vectorKind = "Vector";
    else if (str::starts_with(typeName, "Vector<") && str::ends_with(typeName, " *>"))
        vectorKind = "Vector";
    else if (str::starts_with(typeName, "SharedPtr<") || str::starts_with(typeName, "WeakPtr<"))
    {
        // Wrap smart pointers
        spdlog::get("console")->info("Auto-typemap: {}", typeName);
        TypeMap map;
        map.cppType_ = typeName;
        if (str::starts_with(typeName, "SharedPtr<"))
        {
            // Get T from SharedPtr<T>
            map.csType_ = typeName.substr(10, typeName.length() - 11);
            map.cToCppTemplate_ = fmt::format("SharedPtr<{}>({{value}})", map.csType_);
        }
        else
        {
            // Get T from WeakPtr<T>
            map.csType_ = typeName.substr(8, typeName.length() - 9);
            map.cToCppTemplate_ = fmt::format("WeakPtr<{}>({{value}})", map.csType_);
        }
        map.cType_ = map.csType_ + "*";
        str::replace_str(map.csType_, "::", ".");
        map.cppToCTemplate_ = "{value}.Get()";
        map.pInvokeToCSTemplate_ = fmt::format("{}.GetManagedInstance({{value}}, false)", map.csType_);
        map.csToPInvokeTemplate_ = fmt::format("{}.GetNativeInstance({{value}})", map.csType_);
        generator->typeMaps_[typeName] = map;
        return;
    }

    if (!vectorKind.empty())
    {
        // Wrap vectors
        const auto& tpl = dynamic_cast<const cppast::cpp_template_instantiation_type&>(realType);
        // cppast has no info for us. Make a best guess about the type in question.
        cppType = tpl.unexposed_arguments();
        auto primitiveType = PrimitiveToCppType(cppType);
        if (primitiveType == cppast::cpp_builtin_type_kind::cpp_void)
        {
            // Class pointer array
            if (str::starts_with(cppType, "SharedPtr<"))                    // starts with
            {
                // Get T from SharedPtr<T>
                csType = cppType.substr(10, cppType.length() - 11);
            }
            else if (str::starts_with(cppType, "WeakPtr<"))
            {
                // Get T from SharedPtr<T>
                csType = cppType.substr(8, cppType.length() - 9);
            }
            else if (str::ends_with(cppType, " *"))
            {
                // Get pointer type
                csType = cppType.substr(0, cppType.length() - 2);
                if (csType.find("const ") == 0)
                    csType = csType.substr(6);
            }
            else
                csType = cppType;

            if (!container::contains(generator->symbols_, csType))
                // Undefined type, required because unknown types pass is yet to run
                return;

            str::replace_str(csType, "::", ".");
        }
        else
        {
            // Builtin type
            csType = pInvokeType = PrimitiveToPInvokeType(primitiveType);
        }

        if (!csType.empty())
        {
            if (csType == "string")
            {
                spdlog::get("console")->info("TODO: Implement StrArrayMarshaller");
                // Size of string is not constant therefore they must be handled differently.
                throw std::exception();
            }

            spdlog::get("console")->info("Auto-typemap: {}", typeName);
            TypeMap map;
            map.cppType_ = typeName;

            map.csType_ = map.pInvokeType_ = fmt::format("{csType}[]", FMT_CAPTURE(csType));
            map.cType_ = "void*";
            map.cppToCTemplate_ = fmt::format("CSharpConverter<Urho3D::{vectorKind}<{cppType}>>::ToCSharp({{value}})",
                                              FMT_CAPTURE(cppType), FMT_CAPTURE(vectorKind));
            map.cToCppTemplate_ = fmt::format("CSharpConverter<Urho3D::{vectorKind}<{cppType}>>::FromCSharp({{value}})",
                                              FMT_CAPTURE(cppType), FMT_CAPTURE(vectorKind));
            if (IsBuiltinPInvokeType(csType) || (typeMap != nullptr && typeMap->isValueType_))
                map.customMarshaller_ = fmt::format("PodArrayMarshaller<{}>", csType);
            else
                map.customMarshaller_ = fmt::format("ObjArrayMarshaller<{}>", csType);
            map.isValueType_ = true;
            map.isArray_ = true;
            generator->typeMaps_[typeName] = map;
            return;
        }
    }

    // spdlog::get("console")->debug(">>>>>> {}", typeName);
}

}
<commit_msg>CSharp: Fix typemapping SharedPtr<T>.<commit_after>//
// Copyright (c) 2018 Rokas Kupstys
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include <cppast/cpp_template.hpp>
#include <fmt/format.h>
#include "GeneratorContext.h"
#include "Urho3DTypeMaps.h"

namespace Urho3D
{

bool Urho3DTypeMaps::Visit(MetaEntity* entity, cppast::visitor_info info)
{
    if (entity->ast_ == nullptr)
        return true;

    if (entity->kind_ == cppast::cpp_entity_kind::member_variable_t)
        HandleType(entity->Ast<cppast::cpp_member_variable>().type());
    else if (entity->kind_ == cppast::cpp_entity_kind::variable_t)
        HandleType(entity->Ast<cppast::cpp_variable>().type());
    else if (entity->kind_ == cppast::cpp_entity_kind::member_function_t)
    {
        HandleType(entity->Ast<cppast::cpp_member_function>().return_type());
        for (const auto& param : entity->children_)
            HandleType(param->Ast<cppast::cpp_function_parameter>().type());
    }
    else if (entity->kind_ == cppast::cpp_entity_kind::function_t)
    {
        HandleType(entity->Ast<cppast::cpp_function>().return_type());
        for (const auto& param : entity->children_)
            HandleType(param->Ast<cppast::cpp_function_parameter>().type());
    }
    else if (entity->kind_ == cppast::cpp_entity_kind::constructor_t)
    {
        for (const auto& param : entity->children_)
            HandleType(param->Ast<cppast::cpp_function_parameter>().type());
    }
    return true;
}

void Urho3DTypeMaps::HandleType(const cppast::cpp_type& type)
{
    const auto& realType = GetBaseType(type);
    if (realType.kind() != cppast::cpp_type_kind::template_instantiation_t)
        return;

    auto typeName = cppast::to_string(realType);

    // Typemap already generated
    if (generator->GetTypeMap(typeName) != nullptr)
        return;

    std::string csType;
    std::string pInvokeType = "IntPtr";
    std::string cppType;
    std::string vectorKind;
    const TypeMap* typeMap = nullptr;

    if (str::starts_with(typeName, "PODVector<"))
        vectorKind = "PODVector";
    else if (str::starts_with(typeName, "Vector<SharedPtr<") || str::starts_with(typeName, "Vector<WeakPtr<"))
        vectorKind = "Vector";
    else if (str::starts_with(typeName, "Vector<") && str::ends_with(typeName, " *>"))
        vectorKind = "Vector";
    else if (str::starts_with(typeName, "SharedPtr<") || str::starts_with(typeName, "WeakPtr<"))
    {
        // Wrap smart pointers
        spdlog::get("console")->info("Auto-typemap: {}", typeName);
        TypeMap map;
        map.cppType_ = typeName;
        if (str::starts_with(typeName, "SharedPtr<"))
        {
            // Get T from SharedPtr<T>
            map.csType_ = typeName.substr(10, typeName.length() - 11);
            map.cToCppTemplate_ = fmt::format("SharedPtr<{}>({{value}})", map.csType_);
            map.cppToCTemplate_ = "{value}.Detach()";
        }
        else
        {
            // Get T from WeakPtr<T>
            map.csType_ = typeName.substr(8, typeName.length() - 9);
            map.cToCppTemplate_ = fmt::format("WeakPtr<{}>({{value}})", map.csType_);
            map.cppToCTemplate_ = "{value}.Get()";
        }
        map.cType_ = map.csType_ + "*";
        str::replace_str(map.csType_, "::", ".");
        map.pInvokeToCSTemplate_ = fmt::format("{}.GetManagedInstance({{value}}, false)", map.csType_);
        map.csToPInvokeTemplate_ = fmt::format("{}.GetNativeInstance({{value}})", map.csType_);
        generator->typeMaps_[typeName] = map;
        return;
    }

    if (!vectorKind.empty())
    {
        // Wrap vectors
        const auto& tpl = dynamic_cast<const cppast::cpp_template_instantiation_type&>(realType);
        // cppast has no info for us. Make a best guess about the type in question.
        cppType = tpl.unexposed_arguments();
        auto primitiveType = PrimitiveToCppType(cppType);
        if (primitiveType == cppast::cpp_builtin_type_kind::cpp_void)
        {
            // Class pointer array
            if (str::starts_with(cppType, "SharedPtr<"))                    // starts with
            {
                // Get T from SharedPtr<T>
                csType = cppType.substr(10, cppType.length() - 11);
            }
            else if (str::starts_with(cppType, "WeakPtr<"))
            {
                // Get T from SharedPtr<T>
                csType = cppType.substr(8, cppType.length() - 9);
            }
            else if (str::ends_with(cppType, " *"))
            {
                // Get pointer type
                csType = cppType.substr(0, cppType.length() - 2);
                if (csType.find("const ") == 0)
                    csType = csType.substr(6);
            }
            else
                csType = cppType;

            if (!container::contains(generator->symbols_, csType))
                // Undefined type, required because unknown types pass is yet to run
                return;

            str::replace_str(csType, "::", ".");
        }
        else
        {
            // Builtin type
            csType = pInvokeType = PrimitiveToPInvokeType(primitiveType);
        }

        if (!csType.empty())
        {
            if (csType == "string")
            {
                spdlog::get("console")->info("TODO: Implement StrArrayMarshaller");
                // Size of string is not constant therefore they must be handled differently.
                throw std::exception();
            }

            spdlog::get("console")->info("Auto-typemap: {}", typeName);
            TypeMap map;
            map.cppType_ = typeName;

            map.csType_ = map.pInvokeType_ = fmt::format("{csType}[]", FMT_CAPTURE(csType));
            map.cType_ = "void*";
            map.cppToCTemplate_ = fmt::format("CSharpConverter<Urho3D::{vectorKind}<{cppType}>>::ToCSharp({{value}})",
                                              FMT_CAPTURE(cppType), FMT_CAPTURE(vectorKind));
            map.cToCppTemplate_ = fmt::format("CSharpConverter<Urho3D::{vectorKind}<{cppType}>>::FromCSharp({{value}})",
                                              FMT_CAPTURE(cppType), FMT_CAPTURE(vectorKind));
            if (IsBuiltinPInvokeType(csType) || (typeMap != nullptr && typeMap->isValueType_))
                map.customMarshaller_ = fmt::format("PodArrayMarshaller<{}>", csType);
            else
                map.customMarshaller_ = fmt::format("ObjArrayMarshaller<{}>", csType);
            map.isValueType_ = true;
            map.isArray_ = true;
            generator->typeMaps_[typeName] = map;
            return;
        }
    }

    // spdlog::get("console")->debug(">>>>>> {}", typeName);
}

}
<|endoftext|>


<commit_before>/*
    This file is part of libkcal.
    Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>

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

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

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qdatetime.h>
#include <qstring.h>
#include <qptrlist.h>
#include <qregexp.h>
#include <qclipboard.h>
#include <qfile.h>
#include <qtextstream.h>

#include <kdebug.h>
#include <klocale.h>

extern "C" {
  #include <ical.h>
  #include <icalss.h>
  #include <icalparser.h>
  #include <icalrestriction.h>
}

#include "calendar.h"
#include "journal.h"

#include "icalformat.h"
#include "icalformatimpl.h"

#define _ICAL_VERSION "2.0"

using namespace KCal;

ICalFormat::ICalFormat()
{
  mImpl = new ICalFormatImpl( this );

  mTimeZoneId = "UTC";
  mUtc = true;
}

ICalFormat::~ICalFormat()
{
  delete mImpl;
}

bool ICalFormat::load( Calendar *calendar, const QString &fileName)
{
  kdDebug(5800) << "ICalFormat::load() " << fileName << endl;

  clearException();

  QFile file( fileName );
  if (!file.open( IO_ReadOnly ) ) {
    kdDebug(5800) << "ICalFormat::load() load error" << endl;
    setException(new ErrorFormat(ErrorFormat::LoadError));
    return false;
  }
  QTextStream ts( &file );
  QString text = ts.read();
  file.close();

  return fromString( calendar, text );
}

bool ICalFormat::save( Calendar *calendar, const QString &fileName )
{
  kdDebug(5800) << "ICalFormat::save(): " << fileName << endl;

  clearException();

  QString text = toString( calendar );

  if ( text.isNull() ) return false;

  // TODO: write backup file

  QFile file( fileName );
  if (!file.open( IO_WriteOnly ) ) {
    setException(new ErrorFormat(ErrorFormat::SaveError,
                 i18n("Could not open file '%1'").arg(fileName)));
    return false;
  }
  QTextStream ts( &file );
  ts << text;
  file.close();

  return true;
}

bool ICalFormat::fromString( Calendar *cal, const QString &text )
{
  setTimeZone( cal->timeZoneId(), !cal->isLocalTime() );

  // Get first VCALENDAR component.
  // TODO: Handle more than one VCALENDAR or non-VCALENDAR top components
  icalcomponent *calendar;

  calendar = icalcomponent_new_from_string( text.local8Bit().data());
  //  kdDebug(5800) << "Error: " << icalerror_perror() << endl;
  if (!calendar) {
    kdDebug(5800) << "ICalFormat::load() parse error" << endl;
    setException(new ErrorFormat(ErrorFormat::ParseErrorIcal));
    return false;
  }

  bool success = true;

  if (icalcomponent_isa(calendar) != ICAL_VCALENDAR_COMPONENT) {
    kdDebug(5800) << "ICalFormat::load(): No VCALENDAR component found" << endl;
    setException(new ErrorFormat(ErrorFormat::NoCalendar));
    success = false;
  } else {
    // put all objects into their proper places
    if ( !mImpl->populate( cal, calendar ) ) {
      kdDebug(5800) << "ICalFormat::load(): Could not populate calendar" << endl;
      if ( !exception() ) {
        setException(new ErrorFormat(ErrorFormat::ParseErrorKcal));
      }
      success = false;
    } else
      mLoadedProductId = mImpl->loadedProductId();
  }

  icalcomponent_free( calendar );

  return success;
}

QString ICalFormat::toString( Calendar *cal )
{
  setTimeZone( cal->timeZoneId(), !cal->isLocalTime() );

  icalcomponent *calendar = mImpl->createCalendarComponent(cal);

  icalcomponent *component;

  // todos
  QPtrList<Todo> todoList = cal->rawTodos();
  QPtrListIterator<Todo> qlt(todoList);
  for (; qlt.current(); ++qlt) {
    component = mImpl->writeTodo(qlt.current());
    icalcomponent_add_component(calendar,component);
  }

  // events
  QPtrList<Event> events = cal->rawEvents();
  Event *ev;
  for(ev=events.first();ev;ev=events.next()) {
    component = mImpl->writeEvent(ev);
    icalcomponent_add_component(calendar,component);
  }

  // journals
  QPtrList<Journal> journals = cal->journals();
  Journal *j;
  for(j=journals.first();j;j=journals.next()) {
    component = mImpl->writeJournal(j);
    icalcomponent_add_component(calendar,component);
  }

  const char *text = icalcomponent_as_ical_string( calendar );

  icalcomponent_free( calendar );

  if (!text) {
    setException(new ErrorFormat(ErrorFormat::SaveError,
                 i18n("libical error")));
    return QString::null;
  }

  return QString::fromLocal8Bit( text );
}

QString ICalFormat::toString( Incidence *incidence )
{
  icalcomponent *component;

  component = mImpl->writeIncidence( incidence );

  const char *text = icalcomponent_as_ical_string( component );

  icalcomponent_free( component );

  return QString::fromLocal8Bit( text );
}

QString ICalFormat::toString( Recurrence *recurrence )
{
  icalproperty *property;
  property = mImpl->writeRecurrenceRule( recurrence );
  const char *text = icalproperty_as_ical_string( property );
  icalproperty_free( property );
  return QString::fromLocal8Bit( text );
}

bool ICalFormat::fromString( Recurrence * recurrence, const QString& rrule )
{
  bool success = true;
  icalerror_clear_errno();
  struct icalrecurrencetype recur = icalrecurrencetype_from_string( rrule );
  if ( icalerrno != ICAL_NO_ERROR ) {
    kdDebug() << "Recurrence parsing error: " << icalerror_strerror( icalerrno ) << endl;
    success = false;
  }

  if ( success ) {
    mImpl->readRecurrence( recur, recurrence );
  }

  return success;
}

QString ICalFormat::createScheduleMessage(IncidenceBase *incidence,
                                          Scheduler::Method method)
{
  icalcomponent *message = mImpl->createScheduleComponent(incidence,method);

  QString messageText = icalcomponent_as_ical_string(message);

#if 0
  kdDebug(5800) << "ICalFormat::createScheduleMessage: message START\n"
            << messageText
            << "ICalFormat::createScheduleMessage: message END" << endl;
#endif

  return messageText;
}

ScheduleMessage *ICalFormat::parseScheduleMessage( Calendar *cal,
                                                   const QString &messageText )
{
  clearException();

  if (messageText.isEmpty()) return 0;

  icalcomponent *message;
  message = icalparser_parse_string(messageText.local8Bit());

  if (!message) return 0;

  icalproperty *m = icalcomponent_get_first_property(message,
                                                     ICAL_METHOD_PROPERTY);

  if (!m) return 0;

  icalcomponent *c;

  IncidenceBase *incidence = 0;
  c = icalcomponent_get_first_component(message,ICAL_VEVENT_COMPONENT);
  if (c) {
    incidence = mImpl->readEvent(c);
  }

  c = icalcomponent_get_first_component(message,ICAL_VTODO_COMPONENT);
  if (c) {
    incidence = mImpl->readTodo(c);
  }

  c = icalcomponent_get_first_component(message,ICAL_VFREEBUSY_COMPONENT);
  if (c) {
    incidence = mImpl->readFreeBusy(c);
  }

  if (!incidence) {
    kdDebug() << "ICalFormat:parseScheduleMessage: object is not a freebusy, event or todo" << endl;
    return 0;
  }

  kdDebug(5800) << "ICalFormat::parseScheduleMessage() getting method..." << endl;

  icalproperty_method icalmethod = icalproperty_get_method(m);
  Scheduler::Method method;

  switch (icalmethod) {
    case ICAL_METHOD_PUBLISH:
      method = Scheduler::Publish;
      break;
    case ICAL_METHOD_REQUEST:
      method = Scheduler::Request;
      break;
    case ICAL_METHOD_REFRESH:
      method = Scheduler::Refresh;
      break;
    case ICAL_METHOD_CANCEL:
      method = Scheduler::Cancel;
      break;
    case ICAL_METHOD_ADD:
      method = Scheduler::Add;
      break;
    case ICAL_METHOD_REPLY:
      method = Scheduler::Reply;
      break;
    case ICAL_METHOD_COUNTER:
      method = Scheduler::Counter;
      break;
    case ICAL_METHOD_DECLINECOUNTER:
      method = Scheduler::Declinecounter;
      break;
    default:
      method = Scheduler::NoMethod;
      kdDebug(5800) << "ICalFormat::parseScheduleMessage(): Unknow method" << endl;
      break;
  }

  kdDebug(5800) << "ICalFormat::parseScheduleMessage() restriction..." << endl;

  if (!icalrestriction_check(message)) {
    setException(new ErrorFormat(ErrorFormat::Restriction,
                                   Scheduler::methodName(method) + ": " +
                                   mImpl->extractErrorProperty(c)));
    return 0;
  }

  icalcomponent *calendarComponent = mImpl->createCalendarComponent(cal);

  Incidence *existingIncidence = cal->event(incidence->uid());
  if (existingIncidence) {
    // TODO: check, if cast is required, or if it can be done by virtual funcs.
    if (existingIncidence->type() == "Todo") {
      Todo *todo = static_cast<Todo *>(existingIncidence);
      icalcomponent_add_component(calendarComponent,
                                  mImpl->writeTodo(todo));
    }
    if (existingIncidence->type() == "Event") {
      Event *event = static_cast<Event *>(existingIncidence);
      icalcomponent_add_component(calendarComponent,
                                  mImpl->writeEvent(event));
    }
  } else {
    calendarComponent = 0;
  }

  kdDebug(5800) << "ICalFormat::parseScheduleMessage() classify..." << endl;

  icalclass result = icalclassify(message,calendarComponent,(char *)"");

  kdDebug(5800) << "ICalFormat::parseScheduleMessage() returning..." << endl;

  ScheduleMessage::Status status;

  switch (result) {
    case ICAL_PUBLISH_NEW_CLASS:
      status = ScheduleMessage::PublishNew;
      break;
    case ICAL_OBSOLETE_CLASS:
      status = ScheduleMessage::Obsolete;
      break;
    case ICAL_REQUEST_NEW_CLASS:
      status = ScheduleMessage::RequestNew;
      break;
    case ICAL_REQUEST_UPDATE_CLASS:
      status = ScheduleMessage::RequestUpdate;
      break;
    case ICAL_UNKNOWN_CLASS:
    default:
      status = ScheduleMessage::Unknown;
      break;
  }

  return new ScheduleMessage(incidence,method,status);
}

void ICalFormat::setTimeZone( const QString &id, bool utc )
{
  mTimeZoneId = id;
  mUtc = utc;
}

QString ICalFormat::timeZoneId() const
{
  return mTimeZoneId;
}

bool ICalFormat::utc() const
{
  return mUtc;
}
<commit_msg>The variable c is used later for error message so don't overwrite it when incidence has been set<commit_after>/*
    This file is part of libkcal.
    Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>

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

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

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qdatetime.h>
#include <qstring.h>
#include <qptrlist.h>
#include <qregexp.h>
#include <qclipboard.h>
#include <qfile.h>
#include <qtextstream.h>

#include <kdebug.h>
#include <klocale.h>

extern "C" {
  #include <ical.h>
  #include <icalss.h>
  #include <icalparser.h>
  #include <icalrestriction.h>
}

#include "calendar.h"
#include "journal.h"

#include "icalformat.h"
#include "icalformatimpl.h"

#define _ICAL_VERSION "2.0"

using namespace KCal;

ICalFormat::ICalFormat()
{
  mImpl = new ICalFormatImpl( this );

  mTimeZoneId = "UTC";
  mUtc = true;
}

ICalFormat::~ICalFormat()
{
  delete mImpl;
}

bool ICalFormat::load( Calendar *calendar, const QString &fileName)
{
  kdDebug(5800) << "ICalFormat::load() " << fileName << endl;

  clearException();

  QFile file( fileName );
  if (!file.open( IO_ReadOnly ) ) {
    kdDebug(5800) << "ICalFormat::load() load error" << endl;
    setException(new ErrorFormat(ErrorFormat::LoadError));
    return false;
  }
  QTextStream ts( &file );
  QString text = ts.read();
  file.close();

  return fromString( calendar, text );
}

bool ICalFormat::save( Calendar *calendar, const QString &fileName )
{
  kdDebug(5800) << "ICalFormat::save(): " << fileName << endl;

  clearException();

  QString text = toString( calendar );

  if ( text.isNull() ) return false;

  // TODO: write backup file

  QFile file( fileName );
  if (!file.open( IO_WriteOnly ) ) {
    setException(new ErrorFormat(ErrorFormat::SaveError,
                 i18n("Could not open file '%1'").arg(fileName)));
    return false;
  }
  QTextStream ts( &file );
  ts << text;
  file.close();

  return true;
}

bool ICalFormat::fromString( Calendar *cal, const QString &text )
{
  setTimeZone( cal->timeZoneId(), !cal->isLocalTime() );

  // Get first VCALENDAR component.
  // TODO: Handle more than one VCALENDAR or non-VCALENDAR top components
  icalcomponent *calendar;

  calendar = icalcomponent_new_from_string( text.local8Bit().data());
  //  kdDebug(5800) << "Error: " << icalerror_perror() << endl;
  if (!calendar) {
    kdDebug(5800) << "ICalFormat::load() parse error" << endl;
    setException(new ErrorFormat(ErrorFormat::ParseErrorIcal));
    return false;
  }

  bool success = true;

  if (icalcomponent_isa(calendar) != ICAL_VCALENDAR_COMPONENT) {
    kdDebug(5800) << "ICalFormat::load(): No VCALENDAR component found" << endl;
    setException(new ErrorFormat(ErrorFormat::NoCalendar));
    success = false;
  } else {
    // put all objects into their proper places
    if ( !mImpl->populate( cal, calendar ) ) {
      kdDebug(5800) << "ICalFormat::load(): Could not populate calendar" << endl;
      if ( !exception() ) {
        setException(new ErrorFormat(ErrorFormat::ParseErrorKcal));
      }
      success = false;
    } else
      mLoadedProductId = mImpl->loadedProductId();
  }

  icalcomponent_free( calendar );

  return success;
}

QString ICalFormat::toString( Calendar *cal )
{
  setTimeZone( cal->timeZoneId(), !cal->isLocalTime() );

  icalcomponent *calendar = mImpl->createCalendarComponent(cal);

  icalcomponent *component;

  // todos
  QPtrList<Todo> todoList = cal->rawTodos();
  QPtrListIterator<Todo> qlt(todoList);
  for (; qlt.current(); ++qlt) {
    component = mImpl->writeTodo(qlt.current());
    icalcomponent_add_component(calendar,component);
  }

  // events
  QPtrList<Event> events = cal->rawEvents();
  Event *ev;
  for(ev=events.first();ev;ev=events.next()) {
    component = mImpl->writeEvent(ev);
    icalcomponent_add_component(calendar,component);
  }

  // journals
  QPtrList<Journal> journals = cal->journals();
  Journal *j;
  for(j=journals.first();j;j=journals.next()) {
    component = mImpl->writeJournal(j);
    icalcomponent_add_component(calendar,component);
  }

  const char *text = icalcomponent_as_ical_string( calendar );

  icalcomponent_free( calendar );

  if (!text) {
    setException(new ErrorFormat(ErrorFormat::SaveError,
                 i18n("libical error")));
    return QString::null;
  }

  return QString::fromLocal8Bit( text );
}

QString ICalFormat::toString( Incidence *incidence )
{
  icalcomponent *component;

  component = mImpl->writeIncidence( incidence );

  const char *text = icalcomponent_as_ical_string( component );

  icalcomponent_free( component );

  return QString::fromLocal8Bit( text );
}

QString ICalFormat::toString( Recurrence *recurrence )
{
  icalproperty *property;
  property = mImpl->writeRecurrenceRule( recurrence );
  const char *text = icalproperty_as_ical_string( property );
  icalproperty_free( property );
  return QString::fromLocal8Bit( text );
}

bool ICalFormat::fromString( Recurrence * recurrence, const QString& rrule )
{
  bool success = true;
  icalerror_clear_errno();
  struct icalrecurrencetype recur = icalrecurrencetype_from_string( rrule );
  if ( icalerrno != ICAL_NO_ERROR ) {
    kdDebug() << "Recurrence parsing error: " << icalerror_strerror( icalerrno ) << endl;
    success = false;
  }

  if ( success ) {
    mImpl->readRecurrence( recur, recurrence );
  }

  return success;
}

QString ICalFormat::createScheduleMessage(IncidenceBase *incidence,
                                          Scheduler::Method method)
{
  icalcomponent *message = mImpl->createScheduleComponent(incidence,method);

  QString messageText = icalcomponent_as_ical_string(message);

#if 0
  kdDebug(5800) << "ICalFormat::createScheduleMessage: message START\n"
            << messageText
            << "ICalFormat::createScheduleMessage: message END" << endl;
#endif

  return messageText;
}

ScheduleMessage *ICalFormat::parseScheduleMessage( Calendar *cal,
                                                   const QString &messageText )
{
  clearException();

  if (messageText.isEmpty()) return 0;

  icalcomponent *message;
  message = icalparser_parse_string(messageText.local8Bit());

  if (!message) return 0;

  icalproperty *m = icalcomponent_get_first_property(message,
                                                     ICAL_METHOD_PROPERTY);

  if (!m) return 0;

  icalcomponent *c;

  IncidenceBase *incidence = 0;
  c = icalcomponent_get_first_component(message,ICAL_VEVENT_COMPONENT);
  if (c) {
    incidence = mImpl->readEvent(c);
  }

  if (!incidence) {
    c = icalcomponent_get_first_component(message,ICAL_VTODO_COMPONENT);
    if (c) {
      incidence = mImpl->readTodo(c);
    }
  }

  if (!incidence) {
    c = icalcomponent_get_first_component(message,ICAL_VFREEBUSY_COMPONENT);
    if (c) {
      incidence = mImpl->readFreeBusy(c);
    }
  }

  if (!incidence) {
    kdDebug() << "ICalFormat:parseScheduleMessage: object is not a freebusy, event or todo" << endl;
    return 0;
  }

  kdDebug(5800) << "ICalFormat::parseScheduleMessage() getting method..." << endl;

  icalproperty_method icalmethod = icalproperty_get_method(m);
  Scheduler::Method method;

  switch (icalmethod) {
    case ICAL_METHOD_PUBLISH:
      method = Scheduler::Publish;
      break;
    case ICAL_METHOD_REQUEST:
      method = Scheduler::Request;
      break;
    case ICAL_METHOD_REFRESH:
      method = Scheduler::Refresh;
      break;
    case ICAL_METHOD_CANCEL:
      method = Scheduler::Cancel;
      break;
    case ICAL_METHOD_ADD:
      method = Scheduler::Add;
      break;
    case ICAL_METHOD_REPLY:
      method = Scheduler::Reply;
      break;
    case ICAL_METHOD_COUNTER:
      method = Scheduler::Counter;
      break;
    case ICAL_METHOD_DECLINECOUNTER:
      method = Scheduler::Declinecounter;
      break;
    default:
      method = Scheduler::NoMethod;
      kdDebug(5800) << "ICalFormat::parseScheduleMessage(): Unknow method" << endl;
      break;
  }

  kdDebug(5800) << "ICalFormat::parseScheduleMessage() restriction..." << endl;

  if (!icalrestriction_check(message)) {
    setException(new ErrorFormat(ErrorFormat::Restriction,
                                   Scheduler::methodName(method) + ": " +
                                   mImpl->extractErrorProperty(c)));
    return 0;
  }

  icalcomponent *calendarComponent = mImpl->createCalendarComponent(cal);

  Incidence *existingIncidence = cal->event(incidence->uid());
  if (existingIncidence) {
    // TODO: check, if cast is required, or if it can be done by virtual funcs.
    if (existingIncidence->type() == "Todo") {
      Todo *todo = static_cast<Todo *>(existingIncidence);
      icalcomponent_add_component(calendarComponent,
                                  mImpl->writeTodo(todo));
    }
    if (existingIncidence->type() == "Event") {
      Event *event = static_cast<Event *>(existingIncidence);
      icalcomponent_add_component(calendarComponent,
                                  mImpl->writeEvent(event));
    }
  } else {
    calendarComponent = 0;
  }

  kdDebug(5800) << "ICalFormat::parseScheduleMessage() classify..." << endl;

  icalclass result = icalclassify(message,calendarComponent,(char *)"");

  kdDebug(5800) << "ICalFormat::parseScheduleMessage() returning..." << endl;

  ScheduleMessage::Status status;

  switch (result) {
    case ICAL_PUBLISH_NEW_CLASS:
      status = ScheduleMessage::PublishNew;
      break;
    case ICAL_OBSOLETE_CLASS:
      status = ScheduleMessage::Obsolete;
      break;
    case ICAL_REQUEST_NEW_CLASS:
      status = ScheduleMessage::RequestNew;
      break;
    case ICAL_REQUEST_UPDATE_CLASS:
      status = ScheduleMessage::RequestUpdate;
      break;
    case ICAL_UNKNOWN_CLASS:
    default:
      status = ScheduleMessage::Unknown;
      break;
  }

  return new ScheduleMessage(incidence,method,status);
}

void ICalFormat::setTimeZone( const QString &id, bool utc )
{
  mTimeZoneId = id;
  mUtc = utc;
}

QString ICalFormat::timeZoneId() const
{
  return mTimeZoneId;
}

bool ICalFormat::utc() const
{
  return mUtc;
}
<|endoftext|>


<commit_before>#include "search_engine.hpp"
#include "result.hpp"
#include "search_query.hpp"

#include "../storage/country_info.hpp"

#include "../indexer/categories_holder.hpp"
#include "../indexer/search_string_utils.hpp"
#include "../indexer/mercator.hpp"
#include "../indexer/scales.hpp"

#include "../platform/platform.hpp"

#include "../geometry/distance_on_sphere.hpp"

#include "../base/logging.hpp"
#include "../base/stl_add.hpp"

#include "../std/map.hpp"
#include "../std/vector.hpp"
#include "../std/bind.hpp"

namespace search
{

typedef vector<Query::SuggestT> SuggestsContainerT;

class EngineData
{
public:
  EngineData(Reader * pCategoriesR, ModelReaderPtr polyR, ModelReaderPtr countryR)
    : m_categories(pCategoriesR), m_infoGetter(polyR, countryR)
  {
  }

  CategoriesHolder m_categories;
  SuggestsContainerT m_stringsToSuggest;
  storage::CountryInfoGetter m_infoGetter;
};

namespace
{

class InitSuggestions
{
  // Key - is a string with language.
  typedef map<pair<strings::UniString, int8_t>, uint8_t> SuggestMapT;
  SuggestMapT m_suggests;

public:
  void operator() (CategoriesHolder::Category::Name const & name)
  {
    if (name.m_prefixLengthToSuggest != CategoriesHolder::Category::EMPTY_PREFIX_LENGTH)
    {
      strings::UniString const uniName = NormalizeAndSimplifyString(name.m_name);

      uint8_t & score = m_suggests[make_pair(uniName, name.m_lang)];
      if (score == 0 || score > name.m_prefixLengthToSuggest)
        score = name.m_prefixLengthToSuggest;
    }
  }

  void GetSuggests(SuggestsContainerT & cont) const
  {
    cont.reserve(m_suggests.size());
    for (SuggestMapT::const_iterator i = m_suggests.begin(); i != m_suggests.end(); ++i)
      cont.push_back(Query::SuggestT(i->first.first, i->second, i->first.second));
  }
};

}

Engine::Engine(IndexType const * pIndex, Reader * pCategoriesR,
               ModelReaderPtr polyR, ModelReaderPtr countryR,
               string const & lang)
  : m_readyThread(false),
    m_pIndex(pIndex),
    m_pData(new EngineData(pCategoriesR, polyR, countryR))
{
  InitSuggestions doInit;
  m_pData->m_categories.ForEachName(bind<void>(ref(doInit), _1));
  doInit.GetSuggests(m_pData->m_stringsToSuggest);

  m_pQuery.reset(new Query(pIndex,
                           &m_pData->m_categories,
                           &m_pData->m_stringsToSuggest,
                           &m_pData->m_infoGetter,
                           RESULTS_COUNT));
  m_pQuery->SetPreferredLanguage(lang);
}

Engine::~Engine()
{
}

namespace
{
  m2::PointD GetViewportXY(double lat, double lon)
  {
    return m2::PointD(MercatorBounds::LonToX(lon), MercatorBounds::LatToY(lat));
  }
  m2::RectD GetViewportRect(double lat, double lon, double radius = 20000)
  {
    return MercatorBounds::MetresToXY(lon, lat, radius);
  }

  enum { VIEWPORT_RECT = 0, NEARME_RECT = 1 };

  // X metres in mercator (lon, lat) units.
  double const epsEqualRects = 100.0 * MercatorBounds::degreeInMetres;
  double const epsEqualPoints = 500.0 * MercatorBounds::degreeInMetres;

  /// Check rects for optimal search (avoid duplicating).
  void AnalyzeRects(m2::RectD arrRects[2])
  {
    if (arrRects[NEARME_RECT].IsRectInside(arrRects[VIEWPORT_RECT]) &&
        arrRects[NEARME_RECT].Center().EqualDxDy(arrRects[VIEWPORT_RECT].Center(), epsEqualRects))
    {
      arrRects[VIEWPORT_RECT].MakeEmpty();
    }
    else
    {
      if (arrRects[VIEWPORT_RECT].IsRectInside(arrRects[NEARME_RECT]) &&
          (scales::GetScaleLevel(arrRects[VIEWPORT_RECT]) + Query::SCALE_SEARCH_DEPTH >= scales::GetUpperScale()))
      {
        arrRects[NEARME_RECT].MakeEmpty();
      }
    }
  }
}

void Engine::PrepareSearch(m2::RectD const & viewport,
                           bool hasPt, double lat, double lon)
{
  m2::RectD const nearby = (hasPt ? GetViewportRect(lat, lon) : m2::RectD());

  // bind does copy of all rects
  GetPlatform().RunAsync(bind(&Engine::SetViewportAsync, this, viewport, nearby));
}

bool Engine::Search(SearchParams const & params, m2::RectD const & viewport)
{
  // Check for equal query.
  if (!params.IsResetMode() &&
      m_params.IsEqualCommon(params) &&
      m2::IsEqual(m_viewport, viewport, epsEqualRects, epsEqualRects))
  {
    if (!m_params.m_validPos)
      return false;

    m2::PointD const p1 = GetViewportXY(m_params.m_lat, m_params.m_lon);
    m2::PointD const p2 = GetViewportXY(params.m_lat, params.m_lon);

    if (p1.EqualDxDy(p2, epsEqualPoints))
      return false;
  }

  {
    // Assign new search params.
    threads::MutexGuard guard(m_updateMutex);
    m_params = params;
    m_viewport = viewport;
  }

  // Run task.
  GetPlatform().RunAsync(bind(&Engine::SearchAsync, this));

  return true;
}

void Engine::SetViewportAsync(m2::RectD const & viewport, m2::RectD const & nearby)
{
  // First of all - cancel previous query.
  m_pQuery->DoCancel();

  // Enter to run new search.
  threads::MutexGuard searchGuard(m_searchMutex);

  m2::RectD arrRects[] = { viewport, nearby };
  AnalyzeRects(arrRects);

  m_pQuery->SetViewport(arrRects, ARRAY_SIZE(arrRects));
}

void Engine::SearchAsync()
{
  {
    // Avoid many threads waiting in search mutex. One is enough.
    threads::MutexGuard readyGuard(m_readyMutex);
    if (m_readyThread)
      return;
    m_readyThread = true;
  }

  // First of all - cancel previous query.
  m_pQuery->DoCancel();

  // Enter to run new search.
  threads::MutexGuard searchGuard(m_searchMutex);

  {
    threads::MutexGuard readyGuard(m_readyMutex);
    m_readyThread = false;
  }

  // Get current search params.
  SearchParams params;
  m2::RectD arrRects[2];

  {
    threads::MutexGuard updateGuard(m_updateMutex);
    params = m_params;
    arrRects[VIEWPORT_RECT] = m_viewport;
  }

  // Initialize query.
  bool worldSearch = true;
  if (params.m_validPos)
  {
    m_pQuery->SetPosition(GetViewportXY(params.m_lat, params.m_lon));

    arrRects[NEARME_RECT] = GetViewportRect(params.m_lat, params.m_lon);

    // Do not search in viewport for "NearMe" mode.
    if (params.IsNearMeMode())
    {
      worldSearch = false;
      arrRects[VIEWPORT_RECT].MakeEmpty();
    }
    else
      AnalyzeRects(arrRects);
  }
  else
    m_pQuery->NullPosition();

  m_pQuery->SetViewport(arrRects, 2);
  m_pQuery->SetSearchInWorld(worldSearch);
  if (params.IsLanguageValid())
    m_pQuery->SetInputLanguage(params.m_inputLanguageCode);

  Results res;

  try
  {
    if (params.m_query.empty())
    {
      // Search for empty query only around viewport.
      if (params.m_validPos)
      {
        double arrR[] = { 500, 1000, 2000 };
        for (size_t i = 0; i < ARRAY_SIZE(arrR); ++i)
        {
          res.Clear();
          m_pQuery->SearchAllInViewport(GetViewportRect(params.m_lat, params.m_lon, arrR[i]), res, 3*RESULTS_COUNT);

          if (m_pQuery->IsCanceled() || res.GetCount() >= 2*RESULTS_COUNT)
            break;
        }
      }
    }
    else
      m_pQuery->Search(params.m_query, res);
  }
  catch (Query::CancelException const &)
  {
  }

  // Emit results even if search was canceled and we have something.
  size_t const count = res.GetCount();
  if (!m_pQuery->IsCanceled() || count > 0)
    params.m_callback(res);

  // Make additional search in whole mwm when not enough results (only for non-empty query).
  if (!params.m_query.empty() && !m_pQuery->IsCanceled() && count < RESULTS_COUNT)
  {
    try
    {
      m_pQuery->SearchAdditional(res);
    }
    catch (Query::CancelException const &)
    {
    }

    // Emit if we have more results.
    if (res.GetCount() > count)
      params.m_callback(res);
  }
}

string Engine::GetCountryFile(m2::PointD const & pt)
{
  threads::MutexGuard searchGuard(m_searchMutex);

  return m_pData->m_infoGetter.GetRegionFile(pt);
}

string Engine::GetCountryCode(m2::PointD const & pt)
{
  threads::MutexGuard searchGuard(m_searchMutex);

  storage::CountryInfo info;
  m_pData->m_infoGetter.GetRegionInfo(pt, info);
  return info.m_flag;
}

template <class T> string Engine::GetCountryNameT(T const & t)
{
  threads::MutexGuard searchGuard(m_searchMutex);

  storage::CountryInfo info;
  m_pData->m_infoGetter.GetRegionInfo(t, info);
  return info.m_name;
}

string Engine::GetCountryName(m2::PointD const & pt)
{
  return GetCountryNameT(pt);
}

string Engine::GetCountryName(string const & id)
{
  return GetCountryNameT(id);
}

bool Engine::GetNameByType(uint32_t type, int8_t lang, string & name) const
{
  return m_pData->m_categories.GetNameByType(type, lang, name);
}

m2::RectD Engine::GetCountryBounds(string const & file) const
{
  return m_pData->m_infoGetter.CalcLimitRect(file);
}

int8_t Engine::GetCurrentLanguage() const
{
  return m_pQuery->GetPrefferedLanguage();
}

void Engine::ClearViewportsCache()
{
  threads::MutexGuard guard(m_searchMutex);

  m_pQuery->ClearCaches();
}

void Engine::ClearAllCaches()
{
  threads::MutexGuard guard(m_searchMutex);

  m_pQuery->ClearCaches();
  m_pData->m_infoGetter.ClearCaches();
}

}  // namespace search
<commit_msg>Fix concurrent issue in read/write of search params.<commit_after>#include "search_engine.hpp"
#include "result.hpp"
#include "search_query.hpp"

#include "../storage/country_info.hpp"

#include "../indexer/categories_holder.hpp"
#include "../indexer/search_string_utils.hpp"
#include "../indexer/mercator.hpp"
#include "../indexer/scales.hpp"

#include "../platform/platform.hpp"

#include "../geometry/distance_on_sphere.hpp"

#include "../base/logging.hpp"
#include "../base/stl_add.hpp"

#include "../std/map.hpp"
#include "../std/vector.hpp"
#include "../std/bind.hpp"

namespace search
{

typedef vector<Query::SuggestT> SuggestsContainerT;

class EngineData
{
public:
  EngineData(Reader * pCategoriesR, ModelReaderPtr polyR, ModelReaderPtr countryR)
    : m_categories(pCategoriesR), m_infoGetter(polyR, countryR)
  {
  }

  CategoriesHolder m_categories;
  SuggestsContainerT m_stringsToSuggest;
  storage::CountryInfoGetter m_infoGetter;
};

namespace
{

class InitSuggestions
{
  // Key - is a string with language.
  typedef map<pair<strings::UniString, int8_t>, uint8_t> SuggestMapT;
  SuggestMapT m_suggests;

public:
  void operator() (CategoriesHolder::Category::Name const & name)
  {
    if (name.m_prefixLengthToSuggest != CategoriesHolder::Category::EMPTY_PREFIX_LENGTH)
    {
      strings::UniString const uniName = NormalizeAndSimplifyString(name.m_name);

      uint8_t & score = m_suggests[make_pair(uniName, name.m_lang)];
      if (score == 0 || score > name.m_prefixLengthToSuggest)
        score = name.m_prefixLengthToSuggest;
    }
  }

  void GetSuggests(SuggestsContainerT & cont) const
  {
    cont.reserve(m_suggests.size());
    for (SuggestMapT::const_iterator i = m_suggests.begin(); i != m_suggests.end(); ++i)
      cont.push_back(Query::SuggestT(i->first.first, i->second, i->first.second));
  }
};

}

Engine::Engine(IndexType const * pIndex, Reader * pCategoriesR,
               ModelReaderPtr polyR, ModelReaderPtr countryR,
               string const & lang)
  : m_readyThread(false),
    m_pIndex(pIndex),
    m_pData(new EngineData(pCategoriesR, polyR, countryR))
{
  InitSuggestions doInit;
  m_pData->m_categories.ForEachName(bind<void>(ref(doInit), _1));
  doInit.GetSuggests(m_pData->m_stringsToSuggest);

  m_pQuery.reset(new Query(pIndex,
                           &m_pData->m_categories,
                           &m_pData->m_stringsToSuggest,
                           &m_pData->m_infoGetter,
                           RESULTS_COUNT));
  m_pQuery->SetPreferredLanguage(lang);
}

Engine::~Engine()
{
}

namespace
{
  m2::PointD GetViewportXY(double lat, double lon)
  {
    return m2::PointD(MercatorBounds::LonToX(lon), MercatorBounds::LatToY(lat));
  }
  m2::RectD GetViewportRect(double lat, double lon, double radius = 20000)
  {
    return MercatorBounds::MetresToXY(lon, lat, radius);
  }

  enum { VIEWPORT_RECT = 0, NEARME_RECT = 1 };

  // X metres in mercator (lon, lat) units.
  double const epsEqualRects = 100.0 * MercatorBounds::degreeInMetres;
  double const epsEqualPoints = 500.0 * MercatorBounds::degreeInMetres;

  /// Check rects for optimal search (avoid duplicating).
  void AnalyzeRects(m2::RectD arrRects[2])
  {
    if (arrRects[NEARME_RECT].IsRectInside(arrRects[VIEWPORT_RECT]) &&
        arrRects[NEARME_RECT].Center().EqualDxDy(arrRects[VIEWPORT_RECT].Center(), epsEqualRects))
    {
      arrRects[VIEWPORT_RECT].MakeEmpty();
    }
    else
    {
      if (arrRects[VIEWPORT_RECT].IsRectInside(arrRects[NEARME_RECT]) &&
          (scales::GetScaleLevel(arrRects[VIEWPORT_RECT]) + Query::SCALE_SEARCH_DEPTH >= scales::GetUpperScale()))
      {
        arrRects[NEARME_RECT].MakeEmpty();
      }
    }
  }
}

void Engine::PrepareSearch(m2::RectD const & viewport,
                           bool hasPt, double lat, double lon)
{
  m2::RectD const nearby = (hasPt ? GetViewportRect(lat, lon) : m2::RectD());

  // bind does copy of all rects
  GetPlatform().RunAsync(bind(&Engine::SetViewportAsync, this, viewport, nearby));
}

bool Engine::Search(SearchParams const & params, m2::RectD const & viewport)
{
  {
    threads::MutexGuard guard(m_updateMutex);

    // Check for equal query.
    if (!params.IsResetMode() &&
        m_params.IsEqualCommon(params) &&
        m2::IsEqual(m_viewport, viewport, epsEqualRects, epsEqualRects))
    {
      if (!m_params.m_validPos)
        return false;

      m2::PointD const p1 = GetViewportXY(m_params.m_lat, m_params.m_lon);
      m2::PointD const p2 = GetViewportXY(params.m_lat, params.m_lon);

      if (p1.EqualDxDy(p2, epsEqualPoints))
        return false;
    }

    // Assign new search params.
    m_params = params;
    m_viewport = viewport;
  }

  // Run task.
  GetPlatform().RunAsync(bind(&Engine::SearchAsync, this));

  return true;
}

void Engine::SetViewportAsync(m2::RectD const & viewport, m2::RectD const & nearby)
{
  // First of all - cancel previous query.
  m_pQuery->DoCancel();

  // Enter to run new search.
  threads::MutexGuard searchGuard(m_searchMutex);

  m2::RectD arrRects[] = { viewport, nearby };
  AnalyzeRects(arrRects);

  m_pQuery->SetViewport(arrRects, ARRAY_SIZE(arrRects));
}

void Engine::SearchAsync()
{
  {
    // Avoid many threads waiting in search mutex. One is enough.
    threads::MutexGuard readyGuard(m_readyMutex);
    if (m_readyThread)
      return;
    m_readyThread = true;
  }

  // First of all - cancel previous query.
  m_pQuery->DoCancel();

  // Enter to run new search.
  threads::MutexGuard searchGuard(m_searchMutex);

  {
    threads::MutexGuard readyGuard(m_readyMutex);
    m_readyThread = false;
  }

  // Get current search params.
  SearchParams params;
  m2::RectD arrRects[2];

  {
    threads::MutexGuard updateGuard(m_updateMutex);
    params = m_params;
    arrRects[VIEWPORT_RECT] = m_viewport;
  }

  // Initialize query.
  bool worldSearch = true;
  if (params.m_validPos)
  {
    m_pQuery->SetPosition(GetViewportXY(params.m_lat, params.m_lon));

    arrRects[NEARME_RECT] = GetViewportRect(params.m_lat, params.m_lon);

    // Do not search in viewport for "NearMe" mode.
    if (params.IsNearMeMode())
    {
      worldSearch = false;
      arrRects[VIEWPORT_RECT].MakeEmpty();
    }
    else
      AnalyzeRects(arrRects);
  }
  else
    m_pQuery->NullPosition();

  m_pQuery->SetViewport(arrRects, 2);
  m_pQuery->SetSearchInWorld(worldSearch);
  if (params.IsLanguageValid())
    m_pQuery->SetInputLanguage(params.m_inputLanguageCode);

  Results res;

  try
  {
    if (params.m_query.empty())
    {
      // Search for empty query only around viewport.
      if (params.m_validPos)
      {
        double arrR[] = { 500, 1000, 2000 };
        for (size_t i = 0; i < ARRAY_SIZE(arrR); ++i)
        {
          res.Clear();
          m_pQuery->SearchAllInViewport(GetViewportRect(params.m_lat, params.m_lon, arrR[i]), res, 3*RESULTS_COUNT);

          if (m_pQuery->IsCanceled() || res.GetCount() >= 2*RESULTS_COUNT)
            break;
        }
      }
    }
    else
      m_pQuery->Search(params.m_query, res);
  }
  catch (Query::CancelException const &)
  {
  }

  // Emit results even if search was canceled and we have something.
  size_t const count = res.GetCount();
  if (!m_pQuery->IsCanceled() || count > 0)
    params.m_callback(res);

  // Make additional search in whole mwm when not enough results (only for non-empty query).
  if (!params.m_query.empty() && !m_pQuery->IsCanceled() && count < RESULTS_COUNT)
  {
    try
    {
      m_pQuery->SearchAdditional(res);
    }
    catch (Query::CancelException const &)
    {
    }

    // Emit if we have more results.
    if (res.GetCount() > count)
      params.m_callback(res);
  }
}

string Engine::GetCountryFile(m2::PointD const & pt)
{
  threads::MutexGuard searchGuard(m_searchMutex);

  return m_pData->m_infoGetter.GetRegionFile(pt);
}

string Engine::GetCountryCode(m2::PointD const & pt)
{
  threads::MutexGuard searchGuard(m_searchMutex);

  storage::CountryInfo info;
  m_pData->m_infoGetter.GetRegionInfo(pt, info);
  return info.m_flag;
}

template <class T> string Engine::GetCountryNameT(T const & t)
{
  threads::MutexGuard searchGuard(m_searchMutex);

  storage::CountryInfo info;
  m_pData->m_infoGetter.GetRegionInfo(t, info);
  return info.m_name;
}

string Engine::GetCountryName(m2::PointD const & pt)
{
  return GetCountryNameT(pt);
}

string Engine::GetCountryName(string const & id)
{
  return GetCountryNameT(id);
}

bool Engine::GetNameByType(uint32_t type, int8_t lang, string & name) const
{
  return m_pData->m_categories.GetNameByType(type, lang, name);
}

m2::RectD Engine::GetCountryBounds(string const & file) const
{
  return m_pData->m_infoGetter.CalcLimitRect(file);
}

int8_t Engine::GetCurrentLanguage() const
{
  return m_pQuery->GetPrefferedLanguage();
}

void Engine::ClearViewportsCache()
{
  threads::MutexGuard guard(m_searchMutex);

  m_pQuery->ClearCaches();
}

void Engine::ClearAllCaches()
{
  threads::MutexGuard guard(m_searchMutex);

  m_pQuery->ClearCaches();
  m_pData->m_infoGetter.ClearCaches();
}

}  // namespace search
<|endoftext|>