<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2014 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <mapnik/json/topojson_grammar.hpp>

namespace mapnik { namespace topojson {

namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
namespace fusion = boost::fusion;

template <typename Iterator, typename ErrorHandler>
topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
    : topojson_grammar::base_type(topology, "topojson")
{
    qi::lit_type lit;
    qi::double_type double_;
    qi::int_type int_;
    qi::omit_type omit;
    qi::_val_type _val;
    qi::_1_type _1;
    qi::_2_type _2;
    qi::_3_type _3;
    qi::_4_type _4;
    qi::_r1_type _r1;
    using qi::fail;
    using qi::on_error;
    using phoenix::push_back;
    using phoenix::construct;
    // generic json types
    json_.value = json_.object | json_.array | json_.string_ | json_.number
        ;

    json_.pairs = json_.key_value % lit(',')
        ;

    json_.key_value = (json_.string_ >> lit(':') >> json_.value)
        ;

    json_.object = lit('{') >> *json_.pairs >> lit('}')
        ;

    json_.array = lit('[')
        >> json_.value >> *(lit(',') >> json_.value)
        >> lit(']')
        ;

    json_.number = json_.strict_double[_val = json_.double_converter(_1)]
        | json_.int__[_val = json_.integer_converter(_1)]
        | lit("true")[_val = true]
        | lit("false")[_val = false]
        | lit("null")[_val = construct<value_null>()]
        ;

    // topo json
    topology = lit('{') >> lit("\"type\"") >> lit(':') >> lit("\"Topology\"")
                        >> ( (lit(',') >> objects) ^ ( lit(',') >> arcs) ^ (lit(',') >> transform) ^ (lit(',') >> bbox))
                        >> lit('}')
        ;

    transform = lit("\"transform\"") >> lit(':') >> lit('{')
                                     >> lit("\"scale\"") >> lit(':')
                                     >> lit('[')
                                     >> double_ >> lit(',')
                                     >> double_ >> lit(']') >> lit(',')
                                     >> lit("\"translate\"") >> lit(':')
                                     >> lit('[') >> double_ >> lit(',') >> double_ >> lit(']')
                                     >> lit('}')
        ;

    bbox = lit("\"bbox\"") >> lit(':')
                           >> lit('[') >> double_ >> lit(',') >> double_
                           >> lit(',') >> double_ >> lit(',') >> double_
                           >> lit(']')
        ;

    objects = lit("\"objects\"")
        >> lit(':')
        >> lit('{')
        >> -((omit[json_.string_]
              >> lit(':')
              >>  (geometry_collection(_val) | geometry)) % lit(','))
        >> lit('}')
        ;

    geometry =
        point |
        linestring |
        polygon |
        multi_point |
        multi_linestring |
        multi_polygon |
        omit[json_.object]
        ;

    geometry_collection =  lit('{')
               >> lit("\"type\"") >> lit(':') >> lit("\"GeometryCollection\"") >> lit(',')
               >> lit("\"geometries\"") >> lit(':') >> lit('[') >> -(geometry[push_back(_r1, _1)] % lit(','))
               >> lit(']')
               >> lit('}')
        ;
    point = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"Point\"")
        >> ((lit(',') >> lit("\"coordinates\"") >> lit(':') >> coordinate)
            ^ (lit(',') >> properties) /*^ (lit(',') >> omit[id])*/)
        >> lit('}')
        ;

    multi_point = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"MultiPoint\"")
        >> ((lit(',') >> lit("\"coordinates\"") >> lit(':')
             >> lit('[') >> -(coordinate % lit(',')) >> lit(']'))
            ^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
        >> lit('}')
        ;

    linestring = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"LineString\"")
        >> ((lit(',') >> lit("\"arcs\"") >> lit(':') >> lit('[') >> int_ >> lit(']'))
            ^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
        >> lit('}')
        ;

    multi_linestring = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"MultiLineString\"")
        >> ((lit(',') >> lit("\"arcs\"") >> lit(':') >> lit('[')
             >> -((lit('[') >> int_ >> lit(']')) % lit(',')) >> lit(']'))
            ^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
        >> lit('}')
        ;

    polygon = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"Polygon\"")
        >> ((lit(',') >> lit("\"arcs\"") >> lit(':')
             >> lit('[') >> -(ring % lit(',')) >> lit(']'))
            ^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
        >> lit('}')
        ;

    multi_polygon = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"MultiPolygon\"")
        >> ((lit(',') >> lit("\"arcs\"") >> lit(':')
             >> lit('[')
             >> -((lit('[') >> -(ring % lit(',')) >> lit(']')) % lit(','))
             >> lit(']')) ^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
        >> lit('}')
        ;

    id = lit("\"id\"") >> lit(':') >> omit[json_.value]
        ;

    ring = lit('[') >> -(int_ % lit(',')) >> lit(']')
        ;

    properties = lit("\"properties\"")
        >> lit(':')
        >> (( lit('{') >> attributes >> lit('}')) | json_.object)
        ;

    attributes = (json_.string_ >> lit(':') >> attribute_value) % lit(',')
        ;

    attribute_value %= json_.number | json_.string_  ;

    arcs = lit("\"arcs\"") >> lit(':')
                           >> lit('[') >> -( arc % lit(',')) >> lit(']') ;

    arc = lit('[') >> -(coordinate % lit(',')) >> lit(']') ;

    coordinate = lit('[') >> double_ >> lit(',') >> double_ >> lit(']');

    topology.name("topology");
    transform.name("transform");
    objects.name("objects");
    arc.name("arc");
    arcs.name("arcs");
    json_.value.name("value");
    coordinate.name("coordinate");

    point.name("point");
    multi_point.name("multi_point");
    linestring.name("linestring");
    polygon.name("polygon");
    multi_polygon.name("multi_polygon");
    geometry_collection.name("geometry_collection");
    // error handler
    on_error<fail>(topology, error_handler(_1, _2, _3, _4));
}

}}
<commit_msg>topojson grammar - add optional bbox element which is omitted<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2014 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <mapnik/json/topojson_grammar.hpp>

namespace mapnik { namespace topojson {

namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
namespace fusion = boost::fusion;

template <typename Iterator, typename ErrorHandler>
topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
    : topojson_grammar::base_type(topology, "topojson")
{
    qi::lit_type lit;
    qi::double_type double_;
    qi::int_type int_;
    qi::omit_type omit;
    qi::_val_type _val;
    qi::_1_type _1;
    qi::_2_type _2;
    qi::_3_type _3;
    qi::_4_type _4;
    qi::_r1_type _r1;
    using qi::fail;
    using qi::on_error;
    using phoenix::push_back;
    using phoenix::construct;
    // generic json types
    json_.value = json_.object | json_.array | json_.string_ | json_.number
        ;

    json_.pairs = json_.key_value % lit(',')
        ;

    json_.key_value = (json_.string_ >> lit(':') >> json_.value)
        ;

    json_.object = lit('{') >> *json_.pairs >> lit('}')
        ;

    json_.array = lit('[')
        >> json_.value >> *(lit(',') >> json_.value)
        >> lit(']')
        ;

    json_.number = json_.strict_double[_val = json_.double_converter(_1)]
        | json_.int__[_val = json_.integer_converter(_1)]
        | lit("true")[_val = true]
        | lit("false")[_val = false]
        | lit("null")[_val = construct<value_null>()]
        ;

    // topo json
    topology = lit('{') >> lit("\"type\"") >> lit(':') >> lit("\"Topology\"")
                        >> ( (lit(',') >> objects) ^ ( lit(',') >> arcs) ^ (lit(',') >> transform) ^ (lit(',') >> bbox))
                        >> lit('}')
        ;

    transform = lit("\"transform\"") >> lit(':') >> lit('{')
                                     >> lit("\"scale\"") >> lit(':')
                                     >> lit('[')
                                     >> double_ >> lit(',')
                                     >> double_ >> lit(']') >> lit(',')
                                     >> lit("\"translate\"") >> lit(':')
                                     >> lit('[') >> double_ >> lit(',') >> double_ >> lit(']')
                                     >> lit('}')
        ;

    bbox = lit("\"bbox\"") >> lit(':')
                           >> lit('[') >> double_ >> lit(',') >> double_
                           >> lit(',') >> double_ >> lit(',') >> double_
                           >> lit(']')
        ;

    objects = lit("\"objects\"")
        >> lit(':')
        >> lit('{')
        >> -((omit[json_.string_]
              >> lit(':')
              >>  (geometry_collection(_val) | geometry)) % lit(','))
        >> lit('}')
        ;

    geometry =
        point |
        linestring |
        polygon |
        multi_point |
        multi_linestring |
        multi_polygon |
        omit[json_.object]
        ;

    geometry_collection =  lit('{')
               >> lit("\"type\"") >> lit(':') >> lit("\"GeometryCollection\"")
               >> -(lit(',') >> omit[bbox])
               >> lit(',') >> lit("\"geometries\"") >> lit(':') >> lit('[') >> -(geometry[push_back(_r1, _1)] % lit(','))
               >> lit(']')
               >> lit('}')
        ;
    point = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"Point\"")
        >> -(lit(',') >> omit[bbox])
        >> ((lit(',') >> lit("\"coordinates\"") >> lit(':') >> coordinate)
            ^ (lit(',') >> properties) /*^ (lit(',') >> omit[id])*/)
        >> lit('}')
        ;

    multi_point = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"MultiPoint\"")
        >> -(lit(',') >> omit[bbox])
        >> ((lit(',') >> lit("\"coordinates\"") >> lit(':')
             >> lit('[') >> -(coordinate % lit(',')) >> lit(']'))
            ^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
        >> lit('}')
        ;

    linestring = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"LineString\"")
        >> ((lit(',') >> lit("\"arcs\"") >> lit(':') >> lit('[') >> int_ >> lit(']'))
            ^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
        >> lit('}')
        ;

    multi_linestring = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"MultiLineString\"")
        >> -(lit(',') >> omit[bbox])
        >> ((lit(',') >> lit("\"arcs\"") >> lit(':') >> lit('[')
             >> -((lit('[') >> int_ >> lit(']')) % lit(',')) >> lit(']'))
            ^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
        >> lit('}')
        ;

    polygon = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"Polygon\"")
        >> -(lit(',') >> omit[bbox])
        >> ((lit(',') >> lit("\"arcs\"") >> lit(':')
             >> lit('[') >> -(ring % lit(',')) >> lit(']'))
            ^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
        >> lit('}')
        ;

    multi_polygon = lit('{')
        >> lit("\"type\"") >> lit(':') >> lit("\"MultiPolygon\"")
        >> -(lit(',') >> omit[bbox])
        >> ((lit(',') >> lit("\"arcs\"") >> lit(':')
             >> lit('[')
             >> -((lit('[') >> -(ring % lit(',')) >> lit(']')) % lit(','))
             >> lit(']')) ^ (lit(',') >> properties) ^ (lit(',') >> omit[id]))
        >> lit('}')
        ;

    id = lit("\"id\"") >> lit(':') >> omit[json_.value]
        ;

    ring = lit('[') >> -(int_ % lit(',')) >> lit(']')
        ;

    properties = lit("\"properties\"")
        >> lit(':')
        >> (( lit('{') >> attributes >> lit('}')) | json_.object)
        ;

    attributes = (json_.string_ >> lit(':') >> attribute_value) % lit(',')
        ;

    attribute_value %= json_.number | json_.string_  ;

    arcs = lit("\"arcs\"") >> lit(':')
                           >> lit('[') >> -( arc % lit(',')) >> lit(']') ;

    arc = lit('[') >> -(coordinate % lit(',')) >> lit(']') ;

    coordinate = lit('[') >> double_ >> lit(',') >> double_ >> lit(']');

    topology.name("topology");
    transform.name("transform");
    objects.name("objects");
    arc.name("arc");
    arcs.name("arcs");
    json_.value.name("value");
    coordinate.name("coordinate");

    point.name("point");
    multi_point.name("multi_point");
    linestring.name("linestring");
    polygon.name("polygon");
    multi_polygon.name("multi_polygon");
    geometry_collection.name("geometry_collection");
    // error handler
    on_error<fail>(topology, error_handler(_1, _2, _3, _4));
}

}}
<|endoftext|>


<commit_before>// Copyright (C) 2010-2015 Joshua Boyce
// See the file COPYING for copying permission.

#pragma once

#include <fstream>
#include <memory>
#include <string>
#include <vector>

#include <windows.h>
#include <shlwapi.h>

#include <hadesmem/config.hpp>
#include <hadesmem/error.hpp>
#include <hadesmem/detail/self_path.hpp>
#include <hadesmem/detail/smart_handle.hpp>
#include <hadesmem/detail/str_conv.hpp>

#define HADESMEM_PATHCCH_ALLOW_LONG_PATHS 0x00000001

namespace hadesmem
{
namespace detail
{
template <typename CharT>
inline std::unique_ptr<std::basic_fstream<CharT>>
  OpenFile(std::wstring const& path, std::ios_base::openmode mode)
{
  return std::unique_ptr<std::basic_fstream<CharT>>{
    new std::basic_fstream<CharT>{path, mode}};
}

inline bool DoesFileExist(std::wstring const& path)
{
  return ::GetFileAttributesW(path.c_str()) != INVALID_FILE_ATTRIBUTES;
}

inline bool DoesDirectoryExist(std::wstring const& path)
{
  auto const attrs = ::GetFileAttributesW(path.c_str());
  return attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY);
}

inline bool IsPathRelative(std::wstring const& path)
{
  // Relative paths are always limited to a total of MAX_PATH characters
  return (path.size() >= MAX_PATH) ? false : !!::PathIsRelativeW(path.c_str());
}

inline std::wstring CombinePath(std::wstring const& base,
                                std::wstring const& append)
{
  // Use newer and better PathCchCombineEx if it's available.
  detail::SmartModuleHandle const path_mod{
    LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll")};
  if (path_mod.IsValid())
  {
    using PathCchCombineExFn = HRESULT(WINAPI*)(PWSTR pszPathOut,
                                                size_t cchPathOut,
                                                PCWSTR pszPathIn,
                                                PCWSTR pszMore,
                                                unsigned long dwFlags);
    auto const path_cch_combine_ex = reinterpret_cast<PathCchCombineExFn>(
      GetProcAddress(path_mod.GetHandle(), "PathCchCombineEx"));
    if (path_cch_combine_ex)
    {
      std::vector<wchar_t> buffer(HADESMEM_DETAIL_MAX_PATH_UNICODE);
      HRESULT const hr = path_cch_combine_ex(buffer.data(),
                                             buffer.size(),
                                             base.c_str(),
                                             append.c_str(),
                                             HADESMEM_PATHCCH_ALLOW_LONG_PATHS);
      if (!SUCCEEDED(hr))
      {
        HADESMEM_DETAIL_THROW_EXCEPTION(
          Error{} << ErrorString{"PathCchCombineEx failed."}
                  << ErrorCodeWinHr{hr});
      }

      return buffer.data();
    }
  }

  // Fall back to older API with MAX_PATH limit.
  std::vector<wchar_t> buffer(MAX_PATH);
  if (!::PathCombineW(buffer.data(), base.c_str(), append.c_str()))
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"PathCombineW failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  return buffer.data();
}

inline SmartFileHandle OpenFileForMetadata(std::wstring const& path)
{
  HANDLE const file =
    ::CreateFileW(path.c_str(),
                  GENERIC_READ,
                  FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
                  nullptr,
                  OPEN_EXISTING,
                  FILE_FLAG_BACKUP_SEMANTICS,
                  nullptr);
  if (file == INVALID_HANDLE_VALUE)
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{} << ErrorString{"CreateFile failed."}
                                            << ErrorCodeWinLast{last_error});
  }

  return SmartFileHandle(file);
}

inline BY_HANDLE_FILE_INFORMATION GetFileInformationByHandle(HANDLE file)
{
  BY_HANDLE_FILE_INFORMATION file_info{};
  if (!::GetFileInformationByHandle(file, &file_info))
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error{} << ErrorString{"GetFileInformationByHandle failed."}
              << ErrorCodeWinLast{last_error});
  }

  return file_info;
}

inline bool ArePathsEquivalent(std::wstring const& left,
                               std::wstring const& right)
{
  SmartFileHandle const left_file{OpenFileForMetadata(left)};
  SmartFileHandle const right_file{OpenFileForMetadata(right)};
  BY_HANDLE_FILE_INFORMATION left_file_info =
    GetFileInformationByHandle(left_file.GetHandle());
  BY_HANDLE_FILE_INFORMATION right_file_info =
    GetFileInformationByHandle(right_file.GetHandle());
  return left_file_info.dwVolumeSerialNumber ==
           right_file_info.dwVolumeSerialNumber &&
         left_file_info.nFileIndexHigh == right_file_info.nFileIndexHigh &&
         left_file_info.nFileIndexLow == right_file_info.nFileIndexLow &&
         left_file_info.nFileSizeHigh == right_file_info.nFileSizeHigh &&
         left_file_info.nFileSizeLow == right_file_info.nFileSizeLow &&
         left_file_info.ftLastWriteTime.dwLowDateTime ==
           right_file_info.ftLastWriteTime.dwLowDateTime &&
         left_file_info.ftLastWriteTime.dwHighDateTime ==
           right_file_info.ftLastWriteTime.dwHighDateTime;
}

inline std::wstring GetRootPath(std::wstring const& path)
{
  int const drive_num = ::PathGetDriveNumberW(path.c_str());
  if (drive_num == -1)
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"PathGetDriveNumber failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  std::vector<wchar_t> drive_path(4);
  ::PathBuildRootW(drive_path.data(), drive_num);
  if (drive_path[0] == L'\0' || drive_path[1] == L'\0' ||
      drive_path[2] == L'\0')
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"PathBuildRoot failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  return drive_path.data();
}

inline DWORD GetFileAttributesWrapper(std::wstring const& path)
{
  DWORD const attributes = ::GetFileAttributesW(path.c_str());
  if (attributes == INVALID_FILE_ATTRIBUTES)
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"GetFileAttributes failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  return attributes;
}

inline void CreateDirectoryWrapper(std::wstring const& path)
{
  if (!CreateDirectoryW(path.c_str(), nullptr))
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"CreateDirectory failed."}
                                    << ErrorCodeWinLast{last_error});
  }
}

inline void CopyFileWrapper(std::wstring const& existing_path,
                            std::wstring const& new_path,
                            bool fail_if_exists)
{
  if (!CopyFileW(existing_path.c_str(), new_path.c_str(), fail_if_exists))
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{} << ErrorString{"CopyFile failed."}
                                            << ErrorCodeWinLast{last_error});
  }
}

inline bool IsDirectory(std::wstring const& path)
{
  DWORD const attributes =
    ::hadesmem::detail::GetFileAttributesWrapper(path.c_str());
  return !!(attributes & FILE_ATTRIBUTE_DIRECTORY);
}

inline bool IsSymlink(std::wstring const& path)
{
  DWORD const attributes =
    ::hadesmem::detail::GetFileAttributesWrapper(path.c_str());
  return !!(attributes & FILE_ATTRIBUTE_REPARSE_POINT);
}

inline std::wstring GetFullPathNameWrapper(std::wstring const& path)
{
  std::vector<wchar_t> full_path(HADESMEM_DETAIL_MAX_PATH_UNICODE);
  DWORD len = GetFullPathNameW(path.c_str(),
                               static_cast<DWORD>(full_path.size()),
                               full_path.data(),
                               nullptr);
  if (!len || full_path.size() < len)
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error{} << ErrorString{"GetFullPathNameW failed."}
              << ErrorCodeWinLast{last_error} << ErrorCodeWinOther{len});
  }

  return full_path.data();
}

inline std::wstring GetPathBaseName(std::wstring const& path)
{
  return std::wstring(std::find_if(path.rbegin(),
                                   path.rend(),
                                   [](wchar_t c)
                                   {
                                     return c == '\\' || c == '/';
                                   }).base(),
                      path.end());
}

inline std::wstring PathFindFileNameWrapper(std::wstring const& path)
{
  std::vector<wchar_t> file_name(MAX_PATH);
  auto const p = PathFindFileNameW(path.c_str());
  if (p == path.c_str())
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"PathFindFileNameW failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  return file_name.data();
}

inline std::wstring MakeExtendedPath(std::wstring path)
{
  // Use newer and better PathCchCanonicalizeEx if it's available, then fall
  // through to the custom implementation to ensure we always get an extended
  // path back out, rather than just when it's longer than MAX_PATH.
  detail::SmartModuleHandle const path_mod{
    LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll")};
  if (path_mod.IsValid())
  {
    using PathCchCanonicalizeExFn = HRESULT(WINAPI*)(PWSTR pszPathOut,
                                                     size_t cchPathOut,
                                                     PCWSTR pszPathIn,
                                                     unsigned long dwFlags);
    auto const path_cch_combine_ex = reinterpret_cast<PathCchCanonicalizeExFn>(
      GetProcAddress(path_mod.GetHandle(), "PathCchCanonicalizeEx"));
    if (path_cch_combine_ex)
    {
      std::vector<wchar_t> buffer(HADESMEM_DETAIL_MAX_PATH_UNICODE);
      HRESULT const hr = path_cch_combine_ex(buffer.data(),
                                             buffer.size(),
                                             path.c_str(),
                                             HADESMEM_PATHCCH_ALLOW_LONG_PATHS);
      if (!SUCCEEDED(hr))
      {
        HADESMEM_DETAIL_THROW_EXCEPTION(
          Error{} << ErrorString{"PathCchCanonicalizeEx failed."}
                  << ErrorCodeWinHr{hr});
      }

      path = buffer.data();
    }
  }

  // Modified code from http://bit.ly/1int3Iv.
  if (path.compare(0, 2, L"\\\\"))
  {
    if (hadesmem::detail::IsPathRelative(path))
    {
      // ..\foo\bar
      return MakeExtendedPath(hadesmem::detail::CombinePath(
        hadesmem::detail::GetSelfDirPath(), path));
    }
    else
    {
      if (path.compare(0, 1, L"\\"))
      {
        // c:\foo\bar
        return L"\\\\?\\" + path;
      }
      else
      {
        // \foo\bar
        return MakeExtendedPath(hadesmem::detail::GetFullPathNameWrapper(path));
      }
    }
  }
  else
  {
    if (path.compare(0, 3, L"\\\\?"))
    {
      // \\server\share\folder
      return L"\\\\?\\UNC\\" + path.substr(2);
    }
    else
    {
      // \\?\c:\foo\bar
      return path;
    }
  }
}

inline void BufferToFile(std::wstring const& path,
                         void const* buffer,
                         std::streamsize len)
{
  auto const file = OpenFile<char>(path, std::ios::out | std::ios::binary);
  if (!*file)
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"Failed to create file."});
  }

  if (!file->write(static_cast<char const*>(buffer), len))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"Failed to write file."});
  }
}

inline std::vector<char> FileToBuffer(std::wstring const& path)
{
  auto const file =
    OpenFile<char>(path, std::ios::in | std::ios::binary | std::ios::ate);
  if (!*file)
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"Failed to create file."});
  }

  std::streampos const size = file->tellg();
  if (size <= 0)
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error() << hadesmem::ErrorString("Empty or invalid file."));
  }

  if (!file->seekg(0, std::ios::beg))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(hadesmem::Error() << hadesmem::ErrorString(
                                      "Seeking to beginning of file failed."));
  }

  std::vector<char> buffer(static_cast<std::size_t>(size));
  if (!file->read(buffer.data(), static_cast<std::streamsize>(size)))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"Failed to write file."});
  }

  return buffer;
}
}
}
<commit_msg>[Filesystem] Support not throwing when the directory already exists.<commit_after>// Copyright (C) 2010-2015 Joshua Boyce
// See the file COPYING for copying permission.

#pragma once

#include <fstream>
#include <memory>
#include <string>
#include <vector>

#include <windows.h>
#include <shlwapi.h>

#include <hadesmem/config.hpp>
#include <hadesmem/error.hpp>
#include <hadesmem/detail/self_path.hpp>
#include <hadesmem/detail/smart_handle.hpp>
#include <hadesmem/detail/str_conv.hpp>

#define HADESMEM_PATHCCH_ALLOW_LONG_PATHS 0x00000001

namespace hadesmem
{
namespace detail
{
template <typename CharT>
inline std::unique_ptr<std::basic_fstream<CharT>>
  OpenFile(std::wstring const& path, std::ios_base::openmode mode)
{
  return std::unique_ptr<std::basic_fstream<CharT>>{
    new std::basic_fstream<CharT>{path, mode}};
}

inline bool DoesFileExist(std::wstring const& path)
{
  return ::GetFileAttributesW(path.c_str()) != INVALID_FILE_ATTRIBUTES;
}

inline bool DoesDirectoryExist(std::wstring const& path)
{
  auto const attrs = ::GetFileAttributesW(path.c_str());
  return attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY);
}

inline bool IsPathRelative(std::wstring const& path)
{
  // Relative paths are always limited to a total of MAX_PATH characters
  return (path.size() >= MAX_PATH) ? false : !!::PathIsRelativeW(path.c_str());
}

inline std::wstring CombinePath(std::wstring const& base,
                                std::wstring const& append)
{
  // Use newer and better PathCchCombineEx if it's available.
  detail::SmartModuleHandle const path_mod{
    LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll")};
  if (path_mod.IsValid())
  {
    using PathCchCombineExFn = HRESULT(WINAPI*)(PWSTR pszPathOut,
                                                size_t cchPathOut,
                                                PCWSTR pszPathIn,
                                                PCWSTR pszMore,
                                                unsigned long dwFlags);
    auto const path_cch_combine_ex = reinterpret_cast<PathCchCombineExFn>(
      GetProcAddress(path_mod.GetHandle(), "PathCchCombineEx"));
    if (path_cch_combine_ex)
    {
      std::vector<wchar_t> buffer(HADESMEM_DETAIL_MAX_PATH_UNICODE);
      HRESULT const hr = path_cch_combine_ex(buffer.data(),
                                             buffer.size(),
                                             base.c_str(),
                                             append.c_str(),
                                             HADESMEM_PATHCCH_ALLOW_LONG_PATHS);
      if (!SUCCEEDED(hr))
      {
        HADESMEM_DETAIL_THROW_EXCEPTION(
          Error{} << ErrorString{"PathCchCombineEx failed."}
                  << ErrorCodeWinHr{hr});
      }

      return buffer.data();
    }
  }

  // Fall back to older API with MAX_PATH limit.
  std::vector<wchar_t> buffer(MAX_PATH);
  if (!::PathCombineW(buffer.data(), base.c_str(), append.c_str()))
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"PathCombineW failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  return buffer.data();
}

inline SmartFileHandle OpenFileForMetadata(std::wstring const& path)
{
  HANDLE const file =
    ::CreateFileW(path.c_str(),
                  GENERIC_READ,
                  FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
                  nullptr,
                  OPEN_EXISTING,
                  FILE_FLAG_BACKUP_SEMANTICS,
                  nullptr);
  if (file == INVALID_HANDLE_VALUE)
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{} << ErrorString{"CreateFile failed."}
                                            << ErrorCodeWinLast{last_error});
  }

  return SmartFileHandle(file);
}

inline BY_HANDLE_FILE_INFORMATION GetFileInformationByHandle(HANDLE file)
{
  BY_HANDLE_FILE_INFORMATION file_info{};
  if (!::GetFileInformationByHandle(file, &file_info))
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error{} << ErrorString{"GetFileInformationByHandle failed."}
              << ErrorCodeWinLast{last_error});
  }

  return file_info;
}

inline bool ArePathsEquivalent(std::wstring const& left,
                               std::wstring const& right)
{
  SmartFileHandle const left_file{OpenFileForMetadata(left)};
  SmartFileHandle const right_file{OpenFileForMetadata(right)};
  BY_HANDLE_FILE_INFORMATION left_file_info =
    GetFileInformationByHandle(left_file.GetHandle());
  BY_HANDLE_FILE_INFORMATION right_file_info =
    GetFileInformationByHandle(right_file.GetHandle());
  return left_file_info.dwVolumeSerialNumber ==
           right_file_info.dwVolumeSerialNumber &&
         left_file_info.nFileIndexHigh == right_file_info.nFileIndexHigh &&
         left_file_info.nFileIndexLow == right_file_info.nFileIndexLow &&
         left_file_info.nFileSizeHigh == right_file_info.nFileSizeHigh &&
         left_file_info.nFileSizeLow == right_file_info.nFileSizeLow &&
         left_file_info.ftLastWriteTime.dwLowDateTime ==
           right_file_info.ftLastWriteTime.dwLowDateTime &&
         left_file_info.ftLastWriteTime.dwHighDateTime ==
           right_file_info.ftLastWriteTime.dwHighDateTime;
}

inline std::wstring GetRootPath(std::wstring const& path)
{
  int const drive_num = ::PathGetDriveNumberW(path.c_str());
  if (drive_num == -1)
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"PathGetDriveNumber failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  std::vector<wchar_t> drive_path(4);
  ::PathBuildRootW(drive_path.data(), drive_num);
  if (drive_path[0] == L'\0' || drive_path[1] == L'\0' ||
      drive_path[2] == L'\0')
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"PathBuildRoot failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  return drive_path.data();
}

inline DWORD GetFileAttributesWrapper(std::wstring const& path)
{
  DWORD const attributes = ::GetFileAttributesW(path.c_str());
  if (attributes == INVALID_FILE_ATTRIBUTES)
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"GetFileAttributes failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  return attributes;
}

inline void CreateDirectoryWrapper(std::wstring const& path,
                                   bool fail_if_already_exists = true)
{
  if (!CreateDirectoryW(path.c_str(), nullptr))
  {
    DWORD const last_error = ::GetLastError();
    if (!fail_if_already_exists && last_error == ERROR_ALREADY_EXISTS)
    {
      return;
    }
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"CreateDirectory failed."}
                                    << ErrorCodeWinLast{last_error});
  }
}

inline void CopyFileWrapper(std::wstring const& existing_path,
                            std::wstring const& new_path,
                            bool fail_if_exists)
{
  if (!CopyFileW(existing_path.c_str(), new_path.c_str(), fail_if_exists))
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{} << ErrorString{"CopyFile failed."}
                                            << ErrorCodeWinLast{last_error});
  }
}

inline bool IsDirectory(std::wstring const& path)
{
  DWORD const attributes =
    ::hadesmem::detail::GetFileAttributesWrapper(path.c_str());
  return !!(attributes & FILE_ATTRIBUTE_DIRECTORY);
}

inline bool IsSymlink(std::wstring const& path)
{
  DWORD const attributes =
    ::hadesmem::detail::GetFileAttributesWrapper(path.c_str());
  return !!(attributes & FILE_ATTRIBUTE_REPARSE_POINT);
}

inline std::wstring GetFullPathNameWrapper(std::wstring const& path)
{
  std::vector<wchar_t> full_path(HADESMEM_DETAIL_MAX_PATH_UNICODE);
  DWORD len = GetFullPathNameW(path.c_str(),
                               static_cast<DWORD>(full_path.size()),
                               full_path.data(),
                               nullptr);
  if (!len || full_path.size() < len)
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error{} << ErrorString{"GetFullPathNameW failed."}
              << ErrorCodeWinLast{last_error} << ErrorCodeWinOther{len});
  }

  return full_path.data();
}

inline std::wstring GetPathBaseName(std::wstring const& path)
{
  return std::wstring(std::find_if(path.rbegin(),
                                   path.rend(),
                                   [](wchar_t c)
                                   {
                                     return c == '\\' || c == '/';
                                   }).base(),
                      path.end());
}

inline std::wstring PathFindFileNameWrapper(std::wstring const& path)
{
  std::vector<wchar_t> file_name(MAX_PATH);
  auto const p = PathFindFileNameW(path.c_str());
  if (p == path.c_str())
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"PathFindFileNameW failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  return file_name.data();
}

inline std::wstring MakeExtendedPath(std::wstring path)
{
  // Use newer and better PathCchCanonicalizeEx if it's available, then fall
  // through to the custom implementation to ensure we always get an extended
  // path back out, rather than just when it's longer than MAX_PATH.
  detail::SmartModuleHandle const path_mod{
    LoadLibraryW(L"api-ms-win-core-path-l1-1-0.dll")};
  if (path_mod.IsValid())
  {
    using PathCchCanonicalizeExFn = HRESULT(WINAPI*)(PWSTR pszPathOut,
                                                     size_t cchPathOut,
                                                     PCWSTR pszPathIn,
                                                     unsigned long dwFlags);
    auto const path_cch_combine_ex = reinterpret_cast<PathCchCanonicalizeExFn>(
      GetProcAddress(path_mod.GetHandle(), "PathCchCanonicalizeEx"));
    if (path_cch_combine_ex)
    {
      std::vector<wchar_t> buffer(HADESMEM_DETAIL_MAX_PATH_UNICODE);
      HRESULT const hr = path_cch_combine_ex(buffer.data(),
                                             buffer.size(),
                                             path.c_str(),
                                             HADESMEM_PATHCCH_ALLOW_LONG_PATHS);
      if (!SUCCEEDED(hr))
      {
        HADESMEM_DETAIL_THROW_EXCEPTION(
          Error{} << ErrorString{"PathCchCanonicalizeEx failed."}
                  << ErrorCodeWinHr{hr});
      }

      path = buffer.data();
    }
  }

  // Modified code from http://bit.ly/1int3Iv.
  if (path.compare(0, 2, L"\\\\"))
  {
    if (hadesmem::detail::IsPathRelative(path))
    {
      // ..\foo\bar
      return MakeExtendedPath(hadesmem::detail::CombinePath(
        hadesmem::detail::GetSelfDirPath(), path));
    }
    else
    {
      if (path.compare(0, 1, L"\\"))
      {
        // c:\foo\bar
        return L"\\\\?\\" + path;
      }
      else
      {
        // \foo\bar
        return MakeExtendedPath(hadesmem::detail::GetFullPathNameWrapper(path));
      }
    }
  }
  else
  {
    if (path.compare(0, 3, L"\\\\?"))
    {
      // \\server\share\folder
      return L"\\\\?\\UNC\\" + path.substr(2);
    }
    else
    {
      // \\?\c:\foo\bar
      return path;
    }
  }
}

inline void BufferToFile(std::wstring const& path,
                         void const* buffer,
                         std::streamsize len)
{
  auto const file = OpenFile<char>(path, std::ios::out | std::ios::binary);
  if (!*file)
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"Failed to create file."});
  }

  if (!file->write(static_cast<char const*>(buffer), len))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"Failed to write file."});
  }
}

inline std::vector<char> FileToBuffer(std::wstring const& path)
{
  auto const file =
    OpenFile<char>(path, std::ios::in | std::ios::binary | std::ios::ate);
  if (!*file)
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"Failed to create file."});
  }

  std::streampos const size = file->tellg();
  if (size <= 0)
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error() << hadesmem::ErrorString("Empty or invalid file."));
  }

  if (!file->seekg(0, std::ios::beg))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(hadesmem::Error() << hadesmem::ErrorString(
                                      "Seeking to beginning of file failed."));
  }

  std::vector<char> buffer(static_cast<std::size_t>(size));
  if (!file->read(buffer.data(), static_cast<std::streamsize>(size)))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"Failed to write file."});
  }

  return buffer;
}
}
}
<|endoftext|>


<commit_before>// uatraits is a simple tool for user agent detection
// Copyright (C) 2011 Yandex <highpower@yandex-team.ru>

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

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

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifndef UATRAITS_DETAILS_REGEX_DEFINITION_HPP_INCLUDED
#define UATRAITS_DETAILS_REGEX_DEFINITION_HPP_INCLUDED

#include <list>
#include <string>
#include <cstdlib>
#include <iostream>

#include "uatraits/config.hpp"
#include "uatraits/details/definition.hpp"
#include "uatraits/details/pcre_utils.hpp"
#include "uatraits/details/regex_utils.hpp"

namespace uatraits { namespace details {

template <typename Traits>
class regex_definition : public definition<Traits> {

public:
	regex_definition(char const *name, char const *xpath, char const *pattern, char const *result);
	virtual ~regex_definition();

	virtual void dump(std::ostream &out) const;
	virtual bool detect(char const *begin, char const *end, Traits &traits) const;

private:
	regex_definition(regex_definition const &);
	regex_definition& operator = (regex_definition const &);

	using definition<Traits>::name;
	using definition<Traits>::xpath;

private:
	std::string replace_pattern_;
	std::list<regex_data> replaces_;
	std::pair<pcre*, pcre_extra*> regex_;
};

template <typename Traits> inline
regex_definition<Traits>::regex_definition(char const *name, char const *xpath, char const *pattern, char const *replace_pattern) :
	definition<Traits>(name, xpath), replace_pattern_(replace_pattern), regex_(0, 0)
{
	int max = -1;
	regex_ = pcre_compile_regex(pattern);
	int res = pcre_fullinfo(regex_.first, regex_.second, PCRE_INFO_CAPTURECOUNT, &max);
	if (0 != res || -1 == max) {
		throw error("can not get capture count from %s: %d", pattern, res);
	}
	find_replaces(replace_pattern_, replaces_);
	std::size_t replace_count = replaces_.size();
	if (replace_count > static_cast<std::size_t>(max)) {
	 	throw error("definition intended to replace more items (%llu) than it could capture in %s (%llu)",
	 	    static_cast<unsigned long long>(replace_count), pattern, static_cast<unsigned long long>(max));
	}
}

template <typename Traits> inline
regex_definition<Traits>::~regex_definition() {
    pcre_free_regex(regex_);
}

template <typename Traits> inline void
regex_definition<Traits>::dump(std::ostream &out) const {
    out << "regex definition at [" << xpath() << "] triggered: setting " << name() << "=" << replace_pattern_ << " being substituted during detection" << std::endl;
}

template <typename Traits> inline bool
regex_definition<Traits>::detect(char const *begin, char const *end, Traits &traits) const {

	std::vector<int> match((replaces_.size() + 1) * 3, 0);
	int result = pcre_exec(regex_.first, regex_.second, begin, end - begin, 0, 0, &match[0], match.size());
	if (PCRE_ERROR_NOMATCH == result) {
		return false;
	}
	else if (result < 0) {
		throw error("error while regex matching: %d", result);
	}
	if (static_cast<std::size_t>(result) != replaces_.size() + 1) {
	    throw error("error while regex matching: captured %d while desired %d", result - 1, replaces_.size());
	}
	std::string temp(replace_pattern_);
	for (std::list<regex_data>::const_reverse_iterator ri = replaces_.rbegin(), rend = replaces_.rend(); ri != rend; ++ri) {
    	temp.replace(temp.begin() + ri->begin, temp.begin() + ri->end, begin + match[2 * ri->index], begin + match[2 * ri->index + 1]);
	}
	traits[name()] = temp;
	return true;
}

}} // namespaces

#endif // UATRAITS_DETAILS_REGEX_DEFINITION_HPP_INCLUDED

<commit_msg>fixed wrong include directives again<commit_after>// uatraits is a simple tool for user agent detection
// Copyright (C) 2011 Yandex <highpower@yandex-team.ru>

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

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

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifndef UATRAITS_DETAILS_REGEX_DEFINITION_HPP_INCLUDED
#define UATRAITS_DETAILS_REGEX_DEFINITION_HPP_INCLUDED

#include <list>
#include <string>
#include <vector>
#include <cstdlib>
#include <iostream>

#include "uatraits/config.hpp"
#include "uatraits/details/definition.hpp"
#include "uatraits/details/pcre_utils.hpp"
#include "uatraits/details/regex_utils.hpp"

namespace uatraits { namespace details {

template <typename Traits>
class regex_definition : public definition<Traits> {

public:
	regex_definition(char const *name, char const *xpath, char const *pattern, char const *result);
	virtual ~regex_definition();

	virtual void dump(std::ostream &out) const;
	virtual bool detect(char const *begin, char const *end, Traits &traits) const;

private:
	regex_definition(regex_definition const &);
	regex_definition& operator = (regex_definition const &);

	using definition<Traits>::name;
	using definition<Traits>::xpath;

private:
	std::string replace_pattern_;
	std::list<regex_data> replaces_;
	std::pair<pcre*, pcre_extra*> regex_;
};

template <typename Traits> inline
regex_definition<Traits>::regex_definition(char const *name, char const *xpath, char const *pattern, char const *replace_pattern) :
	definition<Traits>(name, xpath), replace_pattern_(replace_pattern), regex_(0, 0)
{
	int max = -1;
	regex_ = pcre_compile_regex(pattern);
	int res = pcre_fullinfo(regex_.first, regex_.second, PCRE_INFO_CAPTURECOUNT, &max);
	if (0 != res || -1 == max) {
		throw error("can not get capture count from %s: %d", pattern, res);
	}
	find_replaces(replace_pattern_, replaces_);
	std::size_t replace_count = replaces_.size();
	if (replace_count > static_cast<std::size_t>(max)) {
	 	throw error("definition intended to replace more items (%llu) than it could capture in %s (%llu)",
	 	    static_cast<unsigned long long>(replace_count), pattern, static_cast<unsigned long long>(max));
	}
}

template <typename Traits> inline
regex_definition<Traits>::~regex_definition() {
    pcre_free_regex(regex_);
}

template <typename Traits> inline void
regex_definition<Traits>::dump(std::ostream &out) const {
    out << "regex definition at [" << xpath() << "] triggered: setting " << name() << "=" << replace_pattern_ << " being substituted during detection" << std::endl;
}

template <typename Traits> inline bool
regex_definition<Traits>::detect(char const *begin, char const *end, Traits &traits) const {

	std::vector<int> match((replaces_.size() + 1) * 3, 0);
	int result = pcre_exec(regex_.first, regex_.second, begin, end - begin, 0, 0, &match[0], match.size());
	if (PCRE_ERROR_NOMATCH == result) {
		return false;
	}
	else if (result < 0) {
		throw error("error while regex matching: %d", result);
	}
	if (static_cast<std::size_t>(result) != replaces_.size() + 1) {
	    throw error("error while regex matching: captured %d while desired %d", result - 1, replaces_.size());
	}
	std::string temp(replace_pattern_);
	for (std::list<regex_data>::const_reverse_iterator ri = replaces_.rbegin(), rend = replaces_.rend(); ri != rend; ++ri) {
    	temp.replace(temp.begin() + ri->begin, temp.begin() + ri->end, begin + match[2 * ri->index], begin + match[2 * ri->index + 1]);
	}
	traits[name()] = temp;
	return true;
}

}} // namespaces

#endif // UATRAITS_DETAILS_REGEX_DEFINITION_HPP_INCLUDED

<|endoftext|>


<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/XKBlib.h>
#include <GL/glx.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include "SkWindow.h"

#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkColor.h"
#include "SkEvent.h"
#include "SkKey.h"
#include "SkWindow.h"
#include "XkeysToSkKeys.h"
extern "C" {
    #include "keysym2ucs.h"
}

const int WIDTH = 500;
const int HEIGHT = 500;

// Determine which events to listen for.
const long EVENT_MASK = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask
        |ExposureMask|PointerMotionMask|KeyPressMask|KeyReleaseMask;

SkOSWindow::SkOSWindow(void* unused)
    : fVi(NULL)
    , fMSAASampleCount(0) {
    fUnixWindow.fDisplay = NULL;
    fUnixWindow.fGLContext = NULL;
    this->initWindow(0);
    this->resize(WIDTH, HEIGHT);
}

SkOSWindow::~SkOSWindow() {
    this->closeWindow();
}

void SkOSWindow::closeWindow() {
    if (NULL != fUnixWindow.fDisplay) {
        this->detach();
        SkASSERT(NULL != fUnixWindow.fGc);
        XFreeGC(fUnixWindow.fDisplay, fUnixWindow.fGc);
        fUnixWindow.fGc = NULL;
        XDestroyWindow(fUnixWindow.fDisplay, fUnixWindow.fWin);
        fVi = NULL;
        XCloseDisplay(fUnixWindow.fDisplay);
        fUnixWindow.fDisplay = NULL;
        fMSAASampleCount = 0;
    }
}

void SkOSWindow::initWindow(int requestedMSAASampleCount) {
    if (fMSAASampleCount != requestedMSAASampleCount) {
        this->closeWindow();
    }
    // presence of fDisplay means we already have a window
    if (NULL != fUnixWindow.fDisplay) {
        return;
    }
    fUnixWindow.fDisplay = XOpenDisplay(NULL);
    Display* dsp = fUnixWindow.fDisplay;
    if (NULL == dsp) {
        SkDebugf("Could not open an X Display");
        return;
    }
    // Attempt to create a window that supports GL
    GLint att[] = {
        GLX_RGBA,
        GLX_DEPTH_SIZE, 24,
        GLX_DOUBLEBUFFER,
        GLX_STENCIL_SIZE, 8,
        None
    };
    SkASSERT(NULL == fVi);
    if (requestedMSAASampleCount > 0) {
        static const GLint kAttCount = SK_ARRAY_COUNT(att);
        GLint msaaAtt[kAttCount + 4];
        memcpy(msaaAtt, att, sizeof(att));
        SkASSERT(None == msaaAtt[kAttCount - 1]);
        msaaAtt[kAttCount - 1] = GLX_SAMPLE_BUFFERS_ARB;
        msaaAtt[kAttCount + 0] = 1;
        msaaAtt[kAttCount + 1] = GLX_SAMPLES_ARB;
        msaaAtt[kAttCount + 2] = requestedMSAASampleCount;
        msaaAtt[kAttCount + 3] = None;
        fVi = glXChooseVisual(dsp, DefaultScreen(dsp), msaaAtt);
        fMSAASampleCount = requestedMSAASampleCount;
    }
    if (NULL == fVi) {
        fVi = glXChooseVisual(dsp, DefaultScreen(dsp), att);
        fMSAASampleCount = 0;
    }

    if (fVi) {
        Colormap colorMap = XCreateColormap(dsp,
                                            RootWindow(dsp, fVi->screen),
                                            fVi->visual,
                                             AllocNone);
        XSetWindowAttributes swa;
        swa.colormap = colorMap;
        swa.event_mask = EVENT_MASK;
        fUnixWindow.fWin = XCreateWindow(dsp,
                                         RootWindow(dsp, fVi->screen),
                                         0, 0, // x, y
                                         WIDTH, HEIGHT,
                                         0, // border width
                                         fVi->depth,
                                         InputOutput,
                                         fVi->visual,
                                         CWEventMask | CWColormap,
                                         &swa);
    } else {
        // Create a simple window instead.  We will not be able to show GL
        fUnixWindow.fWin = XCreateSimpleWindow(dsp,
                                               DefaultRootWindow(dsp),
                                               0, 0,  // x, y
                                               WIDTH, HEIGHT,
                                               0,     // border width
                                               0,     // border value
                                               0);    // background value
    }
    this->mapWindowAndWait();
    fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL);
}

void SkOSWindow::post_linuxevent() {
    // Put an event in the X queue to fire an SkEvent.
    if (NULL == fUnixWindow.fDisplay) {
        return;
    }
    long event_mask = NoEventMask;
    XClientMessageEvent event;
    event.type = ClientMessage;
    Atom myAtom(0);
    event.message_type = myAtom;
    event.format = 32;
    event.data.l[0] = 0;
    XSendEvent(fUnixWindow.fDisplay, fUnixWindow.fWin, false, 0,
               (XEvent*) &event);
    XFlush(fUnixWindow.fDisplay);
}

static unsigned getModifierKeys(const XEvent& evt) {
//    unsigned xmod = evt.xkey.state;
    return 0;   // TODO
}

void SkOSWindow::loop() {
    Display* dsp = fUnixWindow.fDisplay;
    if (NULL == dsp) {
        return;
    }
    XSelectInput(dsp, fUnixWindow.fWin, EVENT_MASK);

    bool loop = true;
    XEvent evt;
    while (loop) {
        XNextEvent(dsp, &evt);
        switch (evt.type) {
            case Expose:
                if (evt.xexpose.count == 0)
                    this->inval(NULL);
                break;
            case ConfigureNotify:
                this->resize(evt.xconfigure.width, evt.xconfigure.height);
                break;
            case ButtonPress:
                if (evt.xbutton.button == Button1)
                    this->handleClick(evt.xbutton.x, evt.xbutton.y,
                              SkView::Click::kDown_State, getModifierKeys(evt));
                break;
            case ButtonRelease:
                if (evt.xbutton.button == Button1)
                    this->handleClick(evt.xbutton.x, evt.xbutton.y,
                                  SkView::Click::kUp_State, getModifierKeys(evt));
                break;
            case MotionNotify:
                this->handleClick(evt.xmotion.x, evt.xmotion.y,
                              SkView::Click::kMoved_State, getModifierKeys(evt));
                break;
            case KeyPress: {
                KeySym keysym = XkbKeycodeToKeysym(dsp, evt.xkey.keycode, 0, 0);
                //SkDebugf("pressed key %i!\n\tKeySym:%i\n", evt.xkey.keycode, XKeycodeToKeysym(dsp, evt.xkey.keycode, 0));
                if (keysym == XK_Escape) {
                    loop = false;
                    break;
                }
                this->handleKey(XKeyToSkKey(keysym));
                long uni = keysym2ucs(keysym);
                if (uni != -1) {
                    this->handleChar((SkUnichar) uni);
                }
                break;
            }
            case KeyRelease:
                //SkDebugf("released key %i\n", evt.xkey.keycode);
                this->handleKeyUp(XKeyToSkKey(XkbKeycodeToKeysym(dsp, evt.xkey.keycode, 0, 0)));
                break;
            case ClientMessage:
                if (SkEvent::ProcessEvent()) {
                    this->post_linuxevent();
                }
                break;
            default:
                // Do nothing for other events
                break;
        }
    }
}

void SkOSWindow::mapWindowAndWait() {
    SkASSERT(NULL != fUnixWindow.fDisplay);
    Display* dsp = fUnixWindow.fDisplay;
    Window win = fUnixWindow.fWin;
    XMapWindow(dsp, win);

    long eventMask = StructureNotifyMask;
    XSelectInput(dsp, win, eventMask);

    // Wait until screen is ready.
    XEvent evt;
    do {
        XNextEvent(dsp, &evt);
    } while(evt.type != MapNotify);

}

bool SkOSWindow::attach(SkBackEndTypes /* attachType */, int msaaSampleCount) {
    this->initWindow(msaaSampleCount);
    if (NULL == fUnixWindow.fDisplay) {
        return false;
    }
    if (NULL == fUnixWindow.fGLContext) {
        SkASSERT(NULL != fVi);

        fUnixWindow.fGLContext = glXCreateContext(fUnixWindow.fDisplay,
                                                  fVi,
                                                  NULL,
                                                  GL_TRUE);
        if (NULL == fUnixWindow.fGLContext) {
            return false;
        }
    }
    glXMakeCurrent(fUnixWindow.fDisplay,
                   fUnixWindow.fWin,
                   fUnixWindow.fGLContext);
    glViewport(0, 0,
               SkScalarRound(this->width()), SkScalarRound(this->height()));
    glClearColor(0, 0, 0, 0);
    glClearStencil(0);
    glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    return true;
}

void SkOSWindow::detach() {
    if (NULL == fUnixWindow.fDisplay || NULL == fUnixWindow.fGLContext) {
        return;
    }
    glXMakeCurrent(fUnixWindow.fDisplay, None, NULL);
    glXDestroyContext(fUnixWindow.fDisplay, fUnixWindow.fGLContext);
    fUnixWindow.fGLContext = NULL;
}

void SkOSWindow::present() {
    if (NULL != fUnixWindow.fDisplay && NULL != fUnixWindow.fGLContext) {
        glXSwapBuffers(fUnixWindow.fDisplay, fUnixWindow.fWin);
    }
}

void SkOSWindow::onSetTitle(const char title[]) {
    if (NULL == fUnixWindow.fDisplay) {
        return;
    }
    XTextProperty textProp;
    textProp.value = (unsigned char*)title;
    textProp.format = 8;
    textProp.nitems = strlen((char*)textProp.value);
    textProp.encoding = XA_STRING;
    XSetWMName(fUnixWindow.fDisplay, fUnixWindow.fWin, &textProp);
}

void SkOSWindow::onHandleInval(const SkIRect&) {
    (new SkEvent("inval-imageview", this->getSinkID()))->post();
}

bool SkOSWindow::onEvent(const SkEvent& evt) {
    if (evt.isType("inval-imageview")) {
        update(NULL);
        if (NULL == fUnixWindow.fGLContext)
            this->doPaint();
        return true;
    }
    return INHERITED::onEvent(evt);
}

static bool convertBitmapToXImage(XImage& image, const SkBitmap& bitmap) {
    sk_bzero(&image, sizeof(image));

    int bitsPerPixel = bitmap.bytesPerPixel() * 8;
    image.width = bitmap.width();
    image.height = bitmap.height();
    image.format = ZPixmap;
    image.data = (char*) bitmap.getPixels();
    image.byte_order = LSBFirst;
    image.bitmap_unit = bitsPerPixel;
    image.bitmap_bit_order = LSBFirst;
    image.bitmap_pad = bitsPerPixel;
    image.depth = 24;
    image.bytes_per_line = bitmap.rowBytes() - bitmap.width() * bitmap.bytesPerPixel();
    image.bits_per_pixel = bitsPerPixel;
    return XInitImage(&image);
}

void SkOSWindow::doPaint() {
    if (NULL == fUnixWindow.fDisplay) {
        return;
    }
    // Draw the bitmap to the screen.
    const SkBitmap& bitmap = getBitmap();
    int width = bitmap.width();
    int height = bitmap.height();

    XImage image;
    if (!convertBitmapToXImage(image, bitmap)) {
        return;
    }

    XPutImage(fUnixWindow.fDisplay,
              fUnixWindow.fWin,
              fUnixWindow.fGc,
              &image,
              0, 0,     // src x,y
              0, 0,     // dst x,y
              width, height);
}

bool SkOSWindow::onHandleChar(SkUnichar) {
    return false;
}

bool SkOSWindow::onHandleKey(SkKey key) {
    return false;
}

bool SkOSWindow::onHandleKeyUp(SkKey key) {
    return false;
}
<commit_msg>fix linux build<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/XKBlib.h>
#include <GL/glx.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include "SkWindow.h"

#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkColor.h"
#include "SkEvent.h"
#include "SkKey.h"
#include "SkWindow.h"
#include "XkeysToSkKeys.h"
extern "C" {
    #include "keysym2ucs.h"
}

const int WIDTH = 500;
const int HEIGHT = 500;

// Determine which events to listen for.
const long EVENT_MASK = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask
        |ExposureMask|PointerMotionMask|KeyPressMask|KeyReleaseMask;

SkOSWindow::SkOSWindow(void* unused)
    : fVi(NULL)
    , fMSAASampleCount(0) {
    fUnixWindow.fDisplay = NULL;
    fUnixWindow.fGLContext = NULL;
    this->initWindow(0);
    this->resize(WIDTH, HEIGHT);
}

SkOSWindow::~SkOSWindow() {
    this->closeWindow();
}

void SkOSWindow::closeWindow() {
    if (NULL != fUnixWindow.fDisplay) {
        this->detach();
        SkASSERT(NULL != fUnixWindow.fGc);
        XFreeGC(fUnixWindow.fDisplay, fUnixWindow.fGc);
        fUnixWindow.fGc = NULL;
        XDestroyWindow(fUnixWindow.fDisplay, fUnixWindow.fWin);
        fVi = NULL;
        XCloseDisplay(fUnixWindow.fDisplay);
        fUnixWindow.fDisplay = NULL;
        fMSAASampleCount = 0;
    }
}

void SkOSWindow::initWindow(int requestedMSAASampleCount) {
    if (fMSAASampleCount != requestedMSAASampleCount) {
        this->closeWindow();
    }
    // presence of fDisplay means we already have a window
    if (NULL != fUnixWindow.fDisplay) {
        return;
    }
    fUnixWindow.fDisplay = XOpenDisplay(NULL);
    Display* dsp = fUnixWindow.fDisplay;
    if (NULL == dsp) {
        SkDebugf("Could not open an X Display");
        return;
    }
    // Attempt to create a window that supports GL
    GLint att[] = {
        GLX_RGBA,
        GLX_DEPTH_SIZE, 24,
        GLX_DOUBLEBUFFER,
        GLX_STENCIL_SIZE, 8,
        None
    };
    SkASSERT(NULL == fVi);
    if (requestedMSAASampleCount > 0) {
        static const GLint kAttCount = SK_ARRAY_COUNT(att);
        GLint msaaAtt[kAttCount + 4];
        memcpy(msaaAtt, att, sizeof(att));
        SkASSERT(None == msaaAtt[kAttCount - 1]);
        msaaAtt[kAttCount - 1] = GLX_SAMPLE_BUFFERS_ARB;
        msaaAtt[kAttCount + 0] = 1;
        msaaAtt[kAttCount + 1] = GLX_SAMPLES_ARB;
        msaaAtt[kAttCount + 2] = requestedMSAASampleCount;
        msaaAtt[kAttCount + 3] = None;
        fVi = glXChooseVisual(dsp, DefaultScreen(dsp), msaaAtt);
        fMSAASampleCount = requestedMSAASampleCount;
    }
    if (NULL == fVi) {
        fVi = glXChooseVisual(dsp, DefaultScreen(dsp), att);
        fMSAASampleCount = 0;
    }

    if (fVi) {
        Colormap colorMap = XCreateColormap(dsp,
                                            RootWindow(dsp, fVi->screen),
                                            fVi->visual,
                                             AllocNone);
        XSetWindowAttributes swa;
        swa.colormap = colorMap;
        swa.event_mask = EVENT_MASK;
        fUnixWindow.fWin = XCreateWindow(dsp,
                                         RootWindow(dsp, fVi->screen),
                                         0, 0, // x, y
                                         WIDTH, HEIGHT,
                                         0, // border width
                                         fVi->depth,
                                         InputOutput,
                                         fVi->visual,
                                         CWEventMask | CWColormap,
                                         &swa);
    } else {
        // Create a simple window instead.  We will not be able to show GL
        fUnixWindow.fWin = XCreateSimpleWindow(dsp,
                                               DefaultRootWindow(dsp),
                                               0, 0,  // x, y
                                               WIDTH, HEIGHT,
                                               0,     // border width
                                               0,     // border value
                                               0);    // background value
    }
    this->mapWindowAndWait();
    fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL);
}

void SkOSWindow::post_linuxevent() {
    // Put an event in the X queue to fire an SkEvent.
    if (NULL == fUnixWindow.fDisplay) {
        return;
    }
    long event_mask = NoEventMask;
    XClientMessageEvent event;
    event.type = ClientMessage;
    Atom myAtom(0);
    event.message_type = myAtom;
    event.format = 32;
    event.data.l[0] = 0;
    XSendEvent(fUnixWindow.fDisplay, fUnixWindow.fWin, false, 0,
               (XEvent*) &event);
    XFlush(fUnixWindow.fDisplay);
}

static unsigned getModi(const XEvent& evt) {
//    unsigned xmod = evt.xkey.state;
    return 0;   // TODO
}

void SkOSWindow::loop() {
    Display* dsp = fUnixWindow.fDisplay;
    if (NULL == dsp) {
        return;
    }
    XSelectInput(dsp, fUnixWindow.fWin, EVENT_MASK);

    bool loop = true;
    XEvent evt;
    while (loop) {
        XNextEvent(dsp, &evt);
        switch (evt.type) {
            case Expose:
                if (evt.xexpose.count == 0)
                    this->inval(NULL);
                break;
            case ConfigureNotify:
                this->resize(evt.xconfigure.width, evt.xconfigure.height);
                break;
            case ButtonPress:
                if (evt.xbutton.button == Button1)
                    this->handleClick(evt.xbutton.x, evt.xbutton.y,
                                SkView::Click::kDown_State, NULL, getModi(evt));
                break;
            case ButtonRelease:
                if (evt.xbutton.button == Button1)
                    this->handleClick(evt.xbutton.x, evt.xbutton.y,
                                  SkView::Click::kUp_State, NULL, getModi(evt));
                break;
            case MotionNotify:
                this->handleClick(evt.xmotion.x, evt.xmotion.y,
                               SkView::Click::kMoved_State, NULL, getModi(evt));
                break;
            case KeyPress: {
                KeySym keysym = XkbKeycodeToKeysym(dsp, evt.xkey.keycode, 0, 0);
                //SkDebugf("pressed key %i!\n\tKeySym:%i\n", evt.xkey.keycode, XKeycodeToKeysym(dsp, evt.xkey.keycode, 0));
                if (keysym == XK_Escape) {
                    loop = false;
                    break;
                }
                this->handleKey(XKeyToSkKey(keysym));
                long uni = keysym2ucs(keysym);
                if (uni != -1) {
                    this->handleChar((SkUnichar) uni);
                }
                break;
            }
            case KeyRelease:
                //SkDebugf("released key %i\n", evt.xkey.keycode);
                this->handleKeyUp(XKeyToSkKey(XkbKeycodeToKeysym(dsp, evt.xkey.keycode, 0, 0)));
                break;
            case ClientMessage:
                if (SkEvent::ProcessEvent()) {
                    this->post_linuxevent();
                }
                break;
            default:
                // Do nothing for other events
                break;
        }
    }
}

void SkOSWindow::mapWindowAndWait() {
    SkASSERT(NULL != fUnixWindow.fDisplay);
    Display* dsp = fUnixWindow.fDisplay;
    Window win = fUnixWindow.fWin;
    XMapWindow(dsp, win);

    long eventMask = StructureNotifyMask;
    XSelectInput(dsp, win, eventMask);

    // Wait until screen is ready.
    XEvent evt;
    do {
        XNextEvent(dsp, &evt);
    } while(evt.type != MapNotify);

}

bool SkOSWindow::attach(SkBackEndTypes /* attachType */, int msaaSampleCount) {
    this->initWindow(msaaSampleCount);
    if (NULL == fUnixWindow.fDisplay) {
        return false;
    }
    if (NULL == fUnixWindow.fGLContext) {
        SkASSERT(NULL != fVi);

        fUnixWindow.fGLContext = glXCreateContext(fUnixWindow.fDisplay,
                                                  fVi,
                                                  NULL,
                                                  GL_TRUE);
        if (NULL == fUnixWindow.fGLContext) {
            return false;
        }
    }
    glXMakeCurrent(fUnixWindow.fDisplay,
                   fUnixWindow.fWin,
                   fUnixWindow.fGLContext);
    glViewport(0, 0,
               SkScalarRound(this->width()), SkScalarRound(this->height()));
    glClearColor(0, 0, 0, 0);
    glClearStencil(0);
    glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    return true;
}

void SkOSWindow::detach() {
    if (NULL == fUnixWindow.fDisplay || NULL == fUnixWindow.fGLContext) {
        return;
    }
    glXMakeCurrent(fUnixWindow.fDisplay, None, NULL);
    glXDestroyContext(fUnixWindow.fDisplay, fUnixWindow.fGLContext);
    fUnixWindow.fGLContext = NULL;
}

void SkOSWindow::present() {
    if (NULL != fUnixWindow.fDisplay && NULL != fUnixWindow.fGLContext) {
        glXSwapBuffers(fUnixWindow.fDisplay, fUnixWindow.fWin);
    }
}

void SkOSWindow::onSetTitle(const char title[]) {
    if (NULL == fUnixWindow.fDisplay) {
        return;
    }
    XTextProperty textProp;
    textProp.value = (unsigned char*)title;
    textProp.format = 8;
    textProp.nitems = strlen((char*)textProp.value);
    textProp.encoding = XA_STRING;
    XSetWMName(fUnixWindow.fDisplay, fUnixWindow.fWin, &textProp);
}

void SkOSWindow::onHandleInval(const SkIRect&) {
    (new SkEvent("inval-imageview", this->getSinkID()))->post();
}

bool SkOSWindow::onEvent(const SkEvent& evt) {
    if (evt.isType("inval-imageview")) {
        update(NULL);
        if (NULL == fUnixWindow.fGLContext)
            this->doPaint();
        return true;
    }
    return INHERITED::onEvent(evt);
}

static bool convertBitmapToXImage(XImage& image, const SkBitmap& bitmap) {
    sk_bzero(&image, sizeof(image));

    int bitsPerPixel = bitmap.bytesPerPixel() * 8;
    image.width = bitmap.width();
    image.height = bitmap.height();
    image.format = ZPixmap;
    image.data = (char*) bitmap.getPixels();
    image.byte_order = LSBFirst;
    image.bitmap_unit = bitsPerPixel;
    image.bitmap_bit_order = LSBFirst;
    image.bitmap_pad = bitsPerPixel;
    image.depth = 24;
    image.bytes_per_line = bitmap.rowBytes() - bitmap.width() * bitmap.bytesPerPixel();
    image.bits_per_pixel = bitsPerPixel;
    return XInitImage(&image);
}

void SkOSWindow::doPaint() {
    if (NULL == fUnixWindow.fDisplay) {
        return;
    }
    // Draw the bitmap to the screen.
    const SkBitmap& bitmap = getBitmap();
    int width = bitmap.width();
    int height = bitmap.height();

    XImage image;
    if (!convertBitmapToXImage(image, bitmap)) {
        return;
    }

    XPutImage(fUnixWindow.fDisplay,
              fUnixWindow.fWin,
              fUnixWindow.fGc,
              &image,
              0, 0,     // src x,y
              0, 0,     // dst x,y
              width, height);
}

bool SkOSWindow::onHandleChar(SkUnichar) {
    return false;
}

bool SkOSWindow::onHandleKey(SkKey key) {
    return false;
}

bool SkOSWindow::onHandleKeyUp(SkKey key) {
    return false;
}
<|endoftext|>