diff -Nru mapnik-3.0.9+ds/appveyor.yml mapnik-3.0.13+ds/appveyor.yml --- mapnik-3.0.9+ds/appveyor.yml 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/appveyor.yml 2017-02-08 13:06:42.000000000 +0000 @@ -1,6 +1,5 @@ environment: msvs_toolset: 14 - BOOST_VERSION: 59 FASTBUILD: 1 matrix: - platform: x64 @@ -8,11 +7,24 @@ os: Visual Studio 2015 -shallow_clone: true +#shallow_clone: true +# limit clone to latest 5 commits +clone_depth: 5 + +services: + - postgresql94 #if changing this, also change PATH below install: + - SET PGUSER=postgres + - SET PGPASSWORD=Password12! + - SET PATH=C:\Program Files\PostgreSQL\9.4\bin\;%PATH% + +build_script: - scripts\build-appveyor.bat +after_build: + - 7z a visual-test-results.zip C:\tmp\mapnik-visual-images\visual-test-results + artifacts: - path: mapnik-gyp\msbuild-summary.txt name: msbuild-summary.txt @@ -20,7 +32,8 @@ name: msbuild-errors.txt - path: mapnik-gyp\msbuild-warnings.txt name: msbuild-warnings.txt + - path: visual-test-results.zip + name: visual-test-results.zip -build: off test: off deploy: off diff -Nru mapnik-3.0.9+ds/benchmark/bench_framework.hpp mapnik-3.0.13+ds/benchmark/bench_framework.hpp --- mapnik-3.0.9+ds/benchmark/bench_framework.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/benchmark/bench_framework.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,7 +1,8 @@ -#ifndef __MAPNIK_BENCH_FRAMEWORK_HPP__ -#define __MAPNIK_BENCH_FRAMEWORK_HPP__ +#ifndef MAPNIK_BENCH_FRAMEWORK_HPP +#define MAPNIK_BENCH_FRAMEWORK_HPP // mapnik +#include #include #include #include @@ -9,7 +10,8 @@ // stl #include -#include +#include // log10, round +#include // snprintf #include #include #include @@ -18,6 +20,12 @@ namespace benchmark { +template +using milliseconds = std::chrono::duration; + +template +using seconds = std::chrono::duration; + class test_case { protected: @@ -38,26 +46,78 @@ { return iterations_; } + mapnik::parameters const& params() const + { + return params_; + } virtual bool validate() const = 0; virtual bool operator()() const = 0; - virtual ~test_case() {} }; -void handle_args(int argc, char** argv, mapnik::parameters & params) +// gathers --long-option values in 'params'; +// returns the index of the first non-option argument, +// or negated index of an ill-formed option argument +inline int parse_args(int argc, char** argv, mapnik::parameters & params) { - if (argc > 0) { - for (int i=1;i("log")) { + if (*severity == "debug") + mapnik::logger::set_severity(mapnik::logger::debug); + else if (*severity == "warn") + mapnik::logger::set_severity(mapnik::logger::warn); + else if (*severity == "error") + mapnik::logger::set_severity(mapnik::logger::error); + else if (*severity == "none") + mapnik::logger::set_severity(mapnik::logger::none); + else + std::clog << "ignoring option --log='" << *severity + << "' (allowed values are: debug, warn, error, none)\n"; + } +} + +inline int handle_args(int argc, char** argv, mapnik::parameters & params) +{ + int res = parse_args(argc, argv, params); + handle_common_args(params); + return res; } #define BENCHMARK(test_class,name) \ @@ -80,6 +140,29 @@ } \ } \ +struct big_number_fmt +{ + int w; + double v; + const char* u; + + big_number_fmt(int width, double value, int base = 1000) + : w(width), v(value), u("") + { + static const char* suffixes = "\0\0k\0M\0G\0T\0P\0E\0Z\0Y\0\0"; + u = suffixes; + + while (v > 1 && std::log10(std::round(v)) >= width && u[2]) + { + v /= base; + u += 2; + } + + // adjust width for proper alignment without suffix + w += (u == suffixes); + } +}; + template int run(T const& test_runner, std::string const& name) { @@ -88,52 +171,120 @@ if (!test_runner.validate()) { std::clog << "test did not validate: " << name << "\n"; - return -1; + return 1; } // run test once before timing // if it returns false then we'll abort timing - if (test_runner()) + if (!test_runner()) + { + return 2; + } + + std::chrono::high_resolution_clock::time_point start; + std::chrono::high_resolution_clock::duration elapsed; + auto opt_min_duration = test_runner.params().template get("min-duration", 0.0); + std::chrono::duration min_seconds(*opt_min_duration); + auto min_duration = std::chrono::duration_cast(min_seconds); + auto num_iters = test_runner.iterations(); + auto num_threads = test_runner.threads(); + auto total_iters = 0; + + if (num_threads > 0) { - std::chrono::high_resolution_clock::time_point start; - std::chrono::high_resolution_clock::duration elapsed; - std::stringstream s; - s << name << ":" - << std::setw(45 - (int)s.tellp()) << std::right - << " t:" << test_runner.threads() - << " i:" << test_runner.iterations(); - if (test_runner.threads() > 0) + std::mutex mtx_ready; + std::unique_lock lock_ready(mtx_ready); + + auto stub = [&](T const& test_copy) { - using thread_group = std::vector >; - using value_type = thread_group::value_type; - thread_group tg; - for (std::size_t i=0;ijoinable()) t->join();}); - elapsed = std::chrono::high_resolution_clock::now() - start; + // workers will wait on this mutex until the main thread + // constructs all of them and starts measuring time + std::unique_lock my_lock(mtx_ready); + my_lock.unlock(); + test_copy(); + }; + + std::vector tg; + tg.reserve(num_threads); + for (auto i = num_threads; i-- > 0; ) + { + tg.emplace_back(stub, test_runner); } - else + start = std::chrono::high_resolution_clock::now(); + lock_ready.unlock(); + // wait for all workers to finish + for (auto & t : tg) { - start = std::chrono::high_resolution_clock::now(); + if (t.joinable()) + t.join(); + } + elapsed = std::chrono::high_resolution_clock::now() - start; + // this is actually per-thread count, not total, but I think + // reporting average 'iters/thread/second' is more useful + // than 'iters/second' multiplied by the number of threads + total_iters += num_iters; + } + else + { + start = std::chrono::high_resolution_clock::now(); + do { test_runner(); elapsed = std::chrono::high_resolution_clock::now() - start; - } - s << std::setw(65 - (int)s.tellp()) << std::right - << std::chrono::duration_cast(elapsed).count() << " milliseconds\n"; - std::clog << s.str(); + total_iters += num_iters; + } while (elapsed < min_duration); } + + char msg[200]; + double dur_total = milliseconds(elapsed).count(); + auto elapsed_nonzero = std::max(elapsed, decltype(elapsed){1}); + big_number_fmt itersf(4, total_iters); + big_number_fmt ips(5, total_iters / seconds(elapsed_nonzero).count()); + + std::snprintf(msg, sizeof(msg), + "%-43s %3zu threads %*.0f%s iters %6.0f milliseconds %*.0f%s i/s\n", + name.c_str(), + num_threads, + itersf.w, itersf.v, itersf.u, + dur_total, + ips.w, ips.v, ips.u + ); + std::clog << msg; return 0; } catch (std::exception const& ex) { std::clog << "test runner did not complete: " << ex.what() << "\n"; - return -1; + return 4; } - return 0; } +struct sequencer +{ + sequencer(int argc, char** argv) + : exit_code_(0) + { + benchmark::handle_args(argc, argv, params_); + } + + int done() const + { + return exit_code_; + } + + template + sequencer & run(std::string const& name, Args && ...args) + { + // Test instance lifetime is confined to this function + Test test_runner(params_, std::forward(args)...); + // any failing test run will make exit code non-zero + exit_code_ |= benchmark::run(test_runner, name); + return *this; // allow chaining calls + } + +protected: + mapnik::parameters params_; + int exit_code_; +}; + } -#endif // __MAPNIK_BENCH_FRAMEWORK_HPP__ +#endif // MAPNIK_BENCH_FRAMEWORK_HPP diff -Nru mapnik-3.0.9+ds/benchmark/compare_images.hpp mapnik-3.0.13+ds/benchmark/compare_images.hpp --- mapnik-3.0.9+ds/benchmark/compare_images.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/benchmark/compare_images.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,11 +1,10 @@ -#ifndef __MAPNIK_COMPARE_IMAGES_HPP__ -#define __MAPNIK_COMPARE_IMAGES_HPP__ +#ifndef MAPNIK_COMPARE_IMAGES_HPP +#define MAPNIK_COMPARE_IMAGES_HPP #include #include #include -using namespace mapnik; namespace benchmark { @@ -23,15 +22,15 @@ throw mapnik::image_reader_exception("Failed to load: " + src_fn); } - const image_any desc_any = reader1->read(0,0,reader1->width(), reader1->height()); - const image_any src_any = reader2->read(0,0,reader2->width(), reader2->height()); + const mapnik::image_any desc_any = reader1->read(0,0,reader1->width(), reader1->height()); + const mapnik::image_any src_any = reader2->read(0,0,reader2->width(), reader2->height()); - image_rgba8 const& dest = util::get(desc_any); - image_rgba8 const& src = util::get(src_any); + mapnik::image_rgba8 const& dest = mapnik::util::get(desc_any); + mapnik::image_rgba8 const& src = mapnik::util::get(src_any); return compare(dest, src, 0, true) == 0; } } -#endif // __MAPNIK_COMPARE_IMAGES_HPP__ +#endif // MAPNIK_COMPARE_IMAGES_HPP diff -Nru mapnik-3.0.9+ds/benchmark/run mapnik-3.0.13+ds/benchmark/run --- mapnik-3.0.9+ds/benchmark/run 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/benchmark/run 2017-02-08 13:06:42.000000000 +0000 @@ -6,8 +6,14 @@ BASE=./benchmark/out function run { - ${BASE}/$1 --threads 0 --iterations $3; - ${BASE}/$1 --threads $2 --iterations $(expr $3 / $2); + local runner="$BASE/$1 --log=none" + local threads="$2" + local iters="$3" + shift 3 + $runner --threads 0 --iterations $iters "$@" + if test $threads -gt 0; then + $runner --threads $threads --iterations $((iters/threads)) "$@" + fi } run test_getline 30 10000000 #run test_array_allocation 20 100000 @@ -23,6 +29,8 @@ run test_font_registration 10 100 run test_offset_converter 10 1000 +# commented since this is really slow on travis +: ' ./benchmark/out/test_rendering \ --name "text rendering" \ --map benchmark/data/roads.xml \ @@ -31,6 +39,7 @@ --height 600 \ --iterations 20 \ --threads 10 +' ./benchmark/out/test_rendering \ --name "gdal tiff rendering" \ diff -Nru mapnik-3.0.9+ds/benchmark/test_array_allocation.cpp mapnik-3.0.13+ds/benchmark/test_array_allocation.cpp --- mapnik-3.0.9+ds/benchmark/test_array_allocation.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/benchmark/test_array_allocation.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -231,33 +231,6 @@ } }; -class test3d : public benchmark::test_case -{ -public: - uint32_t size_; - std::vector array_; - test3d(mapnik::parameters const& params) - : test_case(params), - size_(*params.get("size",256*256)), - array_(size_,0) { } - bool validate() const - { - return true; - } - bool operator()() const - { - for (std::size_t i=0;i data(size_); - for (std::size_t i=0;i("calloc") + .run("malloc/memcpy") + .run("malloc/memset") + .run("operator new/std::fill") + .run("operator new/memcpy") + .run("vector(N)") + .run("vector/resize") + .run("vector/assign") + .run("deque(N)") + .run("std::string range") + .run("std::string &[0]") + .run("valarray") #if BOOST_VERSION >= 105400 - { - test7 test_runner(params); - return_value = return_value | run(test_runner,"static_vector"); - } + .run("static_vector") #endif - return return_value; + .done(); } diff -Nru mapnik-3.0.9+ds/benchmark/test_getline.cpp mapnik-3.0.13+ds/benchmark/test_getline.cpp --- mapnik-3.0.9+ds/benchmark/test_getline.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/benchmark/test_getline.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,7 +1,7 @@ #include "bench_framework.hpp" -#include -#include -#include "../plugins/input/csv/csv_utils.hpp" +#include "../plugins/input/csv/csv_getline.hpp" + + class test : public benchmark::test_case { diff -Nru mapnik-3.0.9+ds/benchmark/test_numeric_cast_vs_static_cast.cpp mapnik-3.0.13+ds/benchmark/test_numeric_cast_vs_static_cast.cpp --- mapnik-3.0.9+ds/benchmark/test_numeric_cast_vs_static_cast.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/benchmark/test_numeric_cast_vs_static_cast.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -73,16 +73,8 @@ int main(int argc, char** argv) { - mapnik::parameters params; - benchmark::handle_args(argc,argv,params); - int return_value = 0; - { - test_static test_runner(params); - return_value = return_value | run(test_runner,"static_cast"); - } - { - test_numeric test_runner(params); - return_value = return_value | run(test_runner,"numeric_cast"); - } - return return_value; + return benchmark::sequencer(argc, argv) + .run("static_cast") + .run("numeric_cast") + .done(); } diff -Nru mapnik-3.0.9+ds/benchmark/test_png_encoding1.cpp mapnik-3.0.13+ds/benchmark/test_png_encoding1.cpp --- mapnik-3.0.9+ds/benchmark/test_png_encoding1.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/benchmark/test_png_encoding1.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -19,8 +19,8 @@ out.clear(); out = mapnik::save_to_string(im_,"png8:m=h:z=1"); } + return true; } - return true; }; BENCHMARK(test,"encoding blank png") diff -Nru mapnik-3.0.9+ds/benchmark/test_png_encoding2.cpp mapnik-3.0.13+ds/benchmark/test_png_encoding2.cpp --- mapnik-3.0.9+ds/benchmark/test_png_encoding2.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/benchmark/test_png_encoding2.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,8 +30,8 @@ out.clear(); out = mapnik::save_to_string(*im_,"png8:m=h:z=1"); } + return true; } - return true; }; BENCHMARK(test,"encoding multicolor png") diff -Nru mapnik-3.0.9+ds/benchmark/test_polygon_clipping_rendering.cpp mapnik-3.0.13+ds/benchmark/test_polygon_clipping_rendering.cpp --- mapnik-3.0.9+ds/benchmark/test_polygon_clipping_rendering.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/benchmark/test_polygon_clipping_rendering.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -51,30 +51,10 @@ mapnik::box2d z1(-20037508.3428,-8317435.0606,20037508.3428,18399242.7298); // bbox for 16/10491/22911.png mapnik::box2d z16(-13622912.929097254,6026906.8062295765,-13621689.93664469,6028129.79868214); - int return_value = 0; - { - test test_runner(params, - "benchmark/data/polygon_rendering_clip.xml", - z1); - return_value = return_value | run(test_runner,"polygon clip render z1"); - } - { - test test_runner(params, - "benchmark/data/polygon_rendering_no_clip.xml", - z1); - return_value = return_value | run(test_runner,"polygon noclip render z1"); - } - { - test test_runner(params, - "benchmark/data/polygon_rendering_clip.xml", - z16); - return_value = return_value | run(test_runner,"polygon clip render z16"); - } - { - test test_runner(params, - "benchmark/data/polygon_rendering_no_clip.xml", - z16); - return_value = return_value | run(test_runner,"polygon noclip render z16"); - } - return return_value; + return benchmark::sequencer(argc, argv) + .run("polygon clip render z1", "benchmark/data/polygon_rendering_clip.xml", z1) + .run("polygon noclip render z1", "benchmark/data/polygon_rendering_no_clip.xml", z1) + .run("polygon clip render z16", "benchmark/data/polygon_rendering_clip.xml", z16) + .run("polygon noclip render z16", "benchmark/data/polygon_rendering_no_clip.xml", z16) + .done(); } diff -Nru mapnik-3.0.9+ds/benchmark/test_proj_transform1.cpp mapnik-3.0.13+ds/benchmark/test_proj_transform1.cpp --- mapnik-3.0.9+ds/benchmark/test_proj_transform1.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/benchmark/test_proj_transform1.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -59,42 +59,16 @@ // echo -180 -60 | cs2cs -f "%.10f" +init=epsg:4326 +to +init=epsg:3857 int main(int argc, char** argv) { - mapnik::parameters params; - benchmark::handle_args(argc,argv,params); mapnik::box2d from(-180,-80,180,80); mapnik::box2d to(-20037508.3427892476,-15538711.0963092316,20037508.3427892476,15538711.0963092316); std::string from_str("+init=epsg:4326"); std::string to_str("+init=epsg:3857"); std::string from_str2("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"); std::string to_str2("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"); - int return_value = 0; - test test_runner(params, - from_str, - to_str, - from, - to, - true); - return_value = return_value | run(test_runner,"lonlat->merc epsg"); - test test_runner2(params, - from_str2, - to_str2, - from, - to, - true); - return_value = return_value | run(test_runner2,"lonlat->merc literal"); - test test_runner3(params, - to_str, - from_str, - to, - from, - true); - return_value = return_value | run(test_runner3,"merc->lonlat epsg"); - test test_runner4(params, - to_str2, - from_str2, - to, - from, - true); - return_value = return_value | run(test_runner4,"merc->lonlat literal"); - return return_value; + return benchmark::sequencer(argc, argv) + .run("lonlat->merc epsg", from_str, to_str, from, to, true) + .run("lonlat->merc literal", from_str2, to_str2, from, to, true) + .run("merc->lonlat epsg", to_str, from_str, to, from, true) + .run("merc->lonlat literal", to_str2, from_str2, to, from, true) + .done(); } diff -Nru mapnik-3.0.9+ds/bootstrap.sh mapnik-3.0.13+ds/bootstrap.sh --- mapnik-3.0.9+ds/bootstrap.sh 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/bootstrap.sh 2017-02-08 13:06:42.000000000 +0000 @@ -1,6 +1,7 @@ #!/usr/bin/env bash -#set -eu +set -eu +set -o pipefail : ' @@ -10,67 +11,78 @@ - shrink icu data ' +MASON_VERSION="v0.5.0" + function setup_mason() { if [[ ! -d ./.mason ]]; then - git clone --depth 1 https://github.com/mapbox/mason.git ./.mason + git clone https://github.com/mapbox/mason.git ./.mason + (cd ./.mason && git checkout ${MASON_VERSION}) else echo "Updating to latest mason" - (cd ./.mason && git pull) + (cd ./.mason && git fetch && git checkout ${MASON_VERSION} && git pull origin ${MASON_VERSION}) fi - export MASON_DIR=$(pwd)/.mason export PATH=$(pwd)/.mason:$PATH export CXX=${CXX:-clang++} export CC=${CC:-clang} } -if [[ $(uname -s) == 'Darwin' ]]; then - FIND_PATTERN="\/Users\/travis\/build\/mapbox\/mason" -else - FIND_PATTERN="\/home\/travis\/build\/mapbox\/mason" -fi - -REPLACE="$(pwd)" -REPLACE=${REPLACE////\\/} - function install() { MASON_PLATFORM_ID=$(mason env MASON_PLATFORM_ID) if [[ ! -d ./mason_packages/${MASON_PLATFORM_ID}/${1}/${2} ]]; then mason install $1 $2 - mason link $1 $2 - if [[ $3 ]]; then - LA_FILE=$(${MASON_DIR:-~/.mason}/mason prefix $1 $2)/lib/$3.la + if [[ ${3:-false} != false ]]; then + LA_FILE=$(mason prefix $1 $2)/lib/$3.la if [[ -f ${LA_FILE} ]]; then - perl -i -p -e "s/${FIND_PATTERN}/${REPLACE}/g;" ${LA_FILE} + perl -i -p -e 's:\Q$ENV{HOME}/build/mapbox/mason\E:$ENV{PWD}:g' ${LA_FILE} else echo "$LA_FILE not found" fi fi fi + # the rm here is to workaround https://github.com/mapbox/mason/issues/230 + rm -f ./mason_packages/.link/mason.ini + mason link $1 $2 } ICU_VERSION="55.1" function install_mason_deps() { - install gdal 1.11.2 libgdal & - install boost 1.59.0 & - install boost_liball 1.59.0 & - install freetype 2.6 libfreetype & - install harfbuzz 0.9.40 libharfbuzz & - install jpeg_turbo 1.4.0 libjpeg & - install libpng 1.6.17 libpng & - install webp 0.4.2 libwebp & + FAIL=0 + install ccache 3.3.0 & + install zlib system & + install jpeg_turbo 1.5.0 libjpeg & + install libpng 1.6.24 libpng & + install libtiff 4.0.6 libtiff & + install libpq 9.5.2 & + install sqlite 3.14.1 libsqlite3 & + install expat 2.2.0 libexpat & install icu ${ICU_VERSION} & - install proj 4.8.0 libproj & - install libtiff 4.0.4beta libtiff & - install libpq 9.4.0 & - install sqlite 3.8.8.1 libsqlite3 & - install expat 2.1.0 libexpat & - install pixman 0.32.6 libpixman-1 & - install cairo 1.14.2 libcairo & + install proj 4.9.2 libproj & + install pixman 0.34.0 libpixman-1 & + install cairo 1.14.6 libcairo & install protobuf 2.6.1 & - wait # technically protobuf is not a mapnik core dep, but installing # here by default helps make mapnik-vector-tile builds easier + install webp 0.5.1 libwebp & + install gdal 2.1.1 libgdal & + install boost 1.61.0 & + install boost_libsystem 1.61.0 & + install boost_libfilesystem 1.61.0 & + install boost_libprogram_options 1.61.0 & + install boost_libregex_icu 1.61.0 & + # technically boost thread and python are not a core dep, but installing + # here by default helps make python-mapnik builds easier + install boost_libthread 1.61.0 & + install boost_libpython 1.61.0 & + install freetype 2.6.5 libfreetype & + install harfbuzz 1.3.0 libharfbuzz & + for job in $(jobs -p) + do + wait $job || let "FAIL+=1" + done + if [[ "$FAIL" != "0" ]]; then + exit ${FAIL} + fi } MASON_LINKED_ABS=$(pwd)/mason_packages/.link @@ -80,22 +92,16 @@ export LIBRARY_PATH="${MASON_LINKED_ABS}/lib" function make_config() { - if [[ $(uname -s) == 'Darwin' ]]; then - local PATH_REPLACE="/Users/travis/build/mapbox/mason/mason_packages:./mason_packages" - else - local PATH_REPLACE="/home/travis/build/mapbox/mason/mason_packages:./mason_packages" - fi - echo " CXX = '$CXX' CC = '$CC' -CUSTOM_CXXFLAGS = '-fvisibility=hidden -fvisibility-inlines-hidden -DU_CHARSET_IS_UTF8=1' +CUSTOM_CXXFLAGS = '-D_GLIBCXX_USE_CXX11_ABI=0' RUNTIME_LINK = 'static' INPUT_PLUGINS = 'all' PATH = '${MASON_LINKED_REL}/bin' PKG_CONFIG_PATH = '${MASON_LINKED_REL}/lib/pkgconfig' PATH_REMOVE = '/usr:/usr/local' -PATH_REPLACE = '${PATH_REPLACE}' +PATH_REPLACE = '$HOME/build/mapbox/mason/mason_packages:./mason_packages' BOOST_INCLUDES = '${MASON_LINKED_REL}/include' BOOST_LIBS = '${MASON_LINKED_REL}/lib' ICU_INCLUDES = '${MASON_LINKED_REL}/include' @@ -126,8 +132,7 @@ PGSQL2SQLITE = True XMLPARSER = 'ptree' SVG2PNG = True -SAMPLE_INPUT_PLUGINS = True -" > ./config.py +" } # NOTE: the `mapnik-settings.env` is used by test/run (which is run by `make test`) @@ -141,7 +146,7 @@ function main() { setup_mason install_mason_deps - make_config + make_config > ./config.py setup_runtime_settings echo "Ready, now run:" echo "" @@ -149,3 +154,8 @@ } main + +# allow sourcing of script without +# causing the terminal to bail on error +set +eu +set +o pipefail diff -Nru mapnik-3.0.9+ds/CHANGELOG.md mapnik-3.0.13+ds/CHANGELOG.md --- mapnik-3.0.9+ds/CHANGELOG.md 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/CHANGELOG.md 2017-02-08 13:06:42.000000000 +0000 @@ -6,6 +6,114 @@ For a complete change history, see the git log. +## 3.0.13 + +Released: February 8, 2017 + +(Packaged from 2a153c0) + +#### Summary + +- Unbundle `unifont` font from distribution +- GeoJSON: imporoved parsing grammar avoiding temp synthesised attribute (#3507) +- GeoJSON: expose `num_features_to_query` datasource parameter + unit test (#3515) +- Fixed intersecting extents in different projections (PR #3525 ) +- Fixed `blur` implementation by taking into account `scale_factor` +- postgis.input - use 2D box for pgraster bounding box (PR #3551) +- Fixed GroupSymbolizer PairLayout with 3+ items (#3526) +- Simplified `hash` implementation (204d30e58d3553278ab6bcda2d4122b0f13f6392) +- Simplified `mapnik::valu`e conversion rules (#3570) +- Changed `render_thunk_list` to `std::list` (PR #3585) +- Upgraded to variant `v1.1.5` +- CSV.input - fixed `blank` line test (8a3a380b3b5c64681f2478b4f0d06f6a907f5eed) +- GeoJSON - handle empty elements in position grammar (ref #3609) +- mapnik-index - return failure on invalid bounding box (ref #3611) + +## 3.0.12 + +Released: September 8, 2016 + +(Packaged from 1d22d86) + +#### Summary + +- Ensured gdal.input is registered once (refs #3093 #3339 #3340) +- Fixed `mapnik::util::is_clockwise` implementation to use coordinates relative to the origin and avoid numeric precision issues +- `mapnik-index` is updated to fail on first error in input (csv) +- Added `guard` to `get_object_severity` method (ref #3322) +- Improved `hash` calculation for `mapnik::value` (ref #3406) +- AGG - made cover `unsigned` to avoid left shift of negative values (ref #3406) +- Fixed using `scale_factor` in `evaluate_transform(..)` +- Fixed line spacing logic by applying `scale factor` +- ~~Fixed `stringify_object/stringify_array` implementations by disabling white space skipping (ref #3419)~~ +- Added geojson unit test for property types/values +- JSON - added support for object and array type in `json_value` and update `stringifier` +- GDAL.input - fallback to using `overviews` if present (8e8482803bb435726534c3b686a56037b7d3e8ad) +- TopoJSON.input - improved and simplified grammer/parser implementation (https://github.com/mapnik/mapnik/pull/3429) +- GDAL.input - Added support for non-alpha mask band +- TopoJSON.input - fixed order of ellements limitation (ref #3434) +- Fixed stroke-width size not included in markers ellipse bounding box (ref #3445) +- Implemented `char_array_buffer` and removed `boost::iostreams` dependency (2e8c0d36c2237f2815d8004c1b96bad909056eb9) +- JSON.input - `extract_bounding_box_grammar` - make features optional (ref #3463) +- Ensure input plugins return `empty_featureset` rather than `nullptr` (feature_ptr()) +- Added support for quantising small (less than 3 pixel) images (ref #3466) +- Added support for natural logarithm function in expressions (ref #3475) +- Improved logic determining if certain compiler features are available e.g `inheriting constructors` (MSVC) +- GeoJSON - corrected quoting in `stringify` objects (ref #3491) +- GeoJSON - ensured consistent ordering of attribute descriptors (ref #3494) +- GeoJSON - exposed `num_features_to_query` as datasource paramer (ref #3495) +- Replaced `boost::mpl::vector` with `std::tuple` (ref #3503) +- BuildingSymbolizer - fixed closing segment of polygon in building symbolizer (ref #3505) +- Update dependencies versions +- Fixed warnings when compiling with g++5 +- Fixed image swap (ref #3513) +- Stop bundling testdata in source tarball (ref #3335) + +## 3.0.11 + +Released: April 1, 2016 + +(Packaged from 8d9dc27) + +#### Summary + + - Raster scaling: fixed crash and clipping negative pixel values of floating point rasters (https://github.com/mapnik/mapnik/pull/3349) + - Restored support for unquoted strings in expressions (https://github.com/mapnik/mapnik/pull/3390) + - [TWKB](https://github.com/TWKB/) support via https://github.com/mapnik/mapnik/pull/3356 (#3355) + - Visual test runner can render SVG, PDF and Postscript with Cairo renderer (https://github.com/mapnik/mapnik/pull/3418) + - Scale factor is now applied also to `text-line-spacing` and transforms (https://github.com/mapnik/mapnik/pull/3416) + +## 3.0.10 + +Released: February 25, 2016 + +(Packaged from 5c0d496) + +#### Summary + + - The `shapeindex` command now has a `--index-parts` option. When used the index will be bigger + but will allow the Shapefile datasource to only parse polygon parts within the query bounds. + - WARNING: index files generated with this newer Mapnik are invalid for older versions of Mapnik. + - Any `.index` files accompanying a `.shp` must now be regenerated otherwise + it will be skipped. To avoid this problem you can delete the existing `.index` files, or ideally run `shapeindex` to recreate the `.index`. (https://github.com/mapnik/mapnik/pull/3300) + The trigger for this change was an optimization that required a new binary format for the shapefile indexes (https://github.com/mapnik/mapnik/pull/3217). + - Shapeindex - another fix for skipping `null` shapes (#3288) + - Fixed support for filter expressions starting with `not` (https://github.com/mapnik/mapnik/issues/3017) + - Ensure `mapped_memory_cache` acts as singleton across shared objects (#3306) + - Removed miniz support in PNG encoder (#3281) + - Added `-fvisibility=hidden -fvisibility-inlines-hidden` to default compiler flags + - Fixed parsing of SVG `PathElement` (https://github.com/mapnik/mapnik/issues/3225) + - JSON parsing now supports arbitrary (nested) attributes in `geometry` + - Support for rendering `dash-array` in SVGs + - SVG parser is now stricter (fails is all input is not parsable) (#3251) + - SVG parser now correctly handles optional separator `(,)` between multiple command parts + - Optimized parsing of `png` format string + - The `memory_datasource` now dynamically reports correct datasource type (vector or raster) + - Upgraded `mapbox::variant v1.1.0` + - Compare: https://github.com/mapnik/mapnik/compare/v3.0.9...v3.0.10 + + + ## 3.0.9 Released: November 26, 2015 @@ -18,12 +126,12 @@ - Fixed mapnik.util.variant issue when compiling with gcc-5.x and SSO enabled by default (https://github.com/mapnik/mapnik/issues/3103) (via @nkovacs) - Fixed issue with complex scripts where some character sequences weren't rendered correctly (https://github.com/mapnik/mapnik/issues/3050) (via @jkroll20) - Revived postgis.input tests - - JSON: geometry grammar has been refactored and optimized to have expectation points + - JSON: geometry grammar has been re-factored and optimized to have expectation points - Filled missing specializations for value_bool in `mapnik::value` comparison operators - `mapnik.Image` - fixed copy semantics implementation for internal buffer - JSON parsing: unified error_handler across all grammars - Improved unit test coverage - - Raster scaling: fixed nodata handling, acurracy when working with small floats and clipping floats by \[0; 255\] (https://github.com/mapnik/mapnik/pull/3147) + - Raster scaling: fixed nodata handling, accuracy when working with small floats and clipping floats by \[0; 255\] (https://github.com/mapnik/mapnik/pull/3147) - Added [`code of conduct`](http://contributor-covenant.org) - GeoJSON plug-in is updated to skip feature with empty geometries - GeoJSON plug-in : ensure original order of features is preserved (fixed) (https://github.com/mapnik/mapnik/issues/3182) @@ -41,9 +149,9 @@ - Renamed `SHAPE_MEMORY_MAPPED_FILE` define to `MAPNIK_MEMORY_MAPPED_FILE`. Pass `./configure MEMORY_MAPPED_FILE=True|False` to request support for memory mapped files across Mapnik plugins (currently shape, csv, and geojson). - - Unified `mapnik-index` utility supporing GeoJSON and CSV formats + - Unified `mapnik-index` utility supporting GeoJSON and CSV formats - Increased unit test coverage for GeoJSON and CSV plugins - - shape.input - refactor to support *.shx and improve handling various bogus shapefiles + - shape.input - re-factor to support *.shx and improve handling various bogus shapefiles - geojson.input - make JSON parser stricter + support single Feature/Geometry as well as FeatureCollection - maintain 'FT_LOAD_NO_HINTING' + support >= harfbuzz 1.0.5 - geojson.input - implement on-disk-index support @@ -109,7 +217,7 @@ #### Summary -- CSV.input: plug-in has been refactored to minimise memory usage and to improve handling of larger input. +- CSV.input: plug-in has been re-factored to minimise memory usage and to improve handling of larger input. (NOTE: [large_csv](https://github.com/mapnik/mapnik/tree/large_csv) branch adds experimental trunsduction parser with deferred string initialisation) - CSV.input: added internal spatial index (boost::geometry::index::tree) for fast `bounding box` queries (https://github.com/mapnik/mapnik/pull/3010) - Fixed deadlock in recursive datasource registration via @zerebubuth (https://github.com/mapnik/mapnik/pull/3038) @@ -374,7 +482,7 @@ Summary: The 2.2.0 release is primarily a performance and stability release. The code line represents development in the master branch since the release of 2.1.0 in Aug 2012 and therefore includes nearly a year of bug-fixes and optimizations. Nearly 500 new tests have been added bring the total coverage to 925. Shapefile and PostGIS datasources have benefited from numerous stability fixes, 64 bit integer support has been added to support OSM data in the grid renderer and in attribute filtering, and many fixes have landed for higher quality output when using a custom `scale_factor` during rendering. Critical code paths have been optimized include raster rendering, xml map loading, string to number conversion, vector reprojection when using `epsg:4326` and `epsg:3857`, `hextree` encoding, halo rendering, and rendering when using a custom `gamma`. Mapnik 2.2 also compiles faster than previous releases in the 2.x series and drops several unneeded and hard to install dependencies making builds on OS X and Windows easier than any previous release. -- Removed 3 depedencies without loosing any functionality: `ltdl`, `cairomm` and `libsigc++` (#1804,#806,#1681) +- Removed 3 dependencies without loosing any functionality: `ltdl`, `cairomm` and `libsigc++` (#1804,#806,#1681) - Added 64 bit integer support in expressions, feature ids, and the grid_renderer (#1661,#1662,#1662) @@ -499,8 +607,8 @@ - Enabled default input plugin directory and fonts path to be set inherited from environment settings in python bindings to make it easier to run tests locally (#1594). New environment settings are: - - MAPNIK_INPUT_PLUGINS_DIRECTORY - - MAPNIK_FONT_DIRECTORY + - MAPNIK_INPUT_PLUGINS_DIRECTORY + - MAPNIK_FONT_DIRECTORY - Added support for controlling rendering behavior of markers on multi-geometries `marker-multi-policy` (#1555,#1573) @@ -892,7 +1000,7 @@ - Gdal Plugin: Added support for Gdal overviews, enabling fast loading of > 1GB rasters (#54) - * Use the gdaladdo utility to add overviews to existing GDAL datasets + * Use the gdaladdo utility to add overviews to existing GDAL datasets - PostGIS: Added an optional `geometry_table` parameter. The `geometry_table` used by Mapnik to look up metadata in the geometry_columns and calculate extents (when the `geometry_field` and `srid` parameters @@ -917,23 +1025,23 @@ complex queries that may aggregate geometries to be kept fast by allowing proper placement of the bbox query to be used by indexes. (#415) - * Pass the bbox token inside a subquery like: !bbox! + * Pass the bbox token inside a subquery like: !bbox! - * Valid Usages include: + * Valid Usages include: - - (Select ST_Union(geom) as geom from table where ST_Intersects(geometry,!bbox!)) as map - + + (Select ST_Union(geom) as geom from table where ST_Intersects(geometry,!bbox!)) as map + - - (Select * from table where geom && !bbox!) as map - + + (Select * from table where geom && !bbox!) as map + - PostGIS Plugin: Added `scale_denominator` substitution ability in sql query string (#415/#465) - * Pass the scale_denominator token inside a subquery like: !scale_denominator! + * Pass the scale_denominator token inside a subquery like: !scale_denominator! - * e.g. (Select * from table where field_value > !scale_denominator!) as map + * e.g. (Select * from table where field_value > !scale_denominator!) as map - PostGIS Plugin: Added support for quoted table names (r1454) (#393) @@ -965,14 +1073,14 @@ - TextSymbolizer: Large set of new attributes: `text_transform`, `line_spacing`, `character_spacing`, `wrap_character`, `wrap_before`, `horizontal_alignment`, `justify_alignment`, and `opacity`. - * More details at changesets: r1254 and r1341 + * More details at changesets: r1254 and r1341 - SheildSymbolizer: Added special new attributes: `unlock_image`, `VERTEX` placement, `no_text` and many attributes previously only supported in the TextSymbolizer: `allow_overlap`, `vertical_alignment`, `horizontal_alignment`, `justify_alignment`, `wrap_width`, `wrap_character`, `wrap_before`, `text_transform`, `line_spacing`, `character_spacing`, and `opacity`. - * More details at changeset r1341 + * More details at changeset r1341 - XML: Added support for using CDATA with libxml2 parser (r1364) @@ -1200,7 +1308,7 @@ - Plugins: Use memory mapped files for reading shape file (r628) -- Core: Use streams to write images (i/o refactor) (r628) (#15) +- Core: Use streams to write images (i/o re-factor) (r628) (#15) # Mapnik 0.5.1 diff -Nru mapnik-3.0.9+ds/circle.yml mapnik-3.0.13+ds/circle.yml --- mapnik-3.0.9+ds/circle.yml 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/circle.yml 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,41 @@ +machine: + xcode: + version: 7.3 + environment: + XCODE_SCHEME: "no" + XCODE_WORKSPACE: "no" + JOBS: 8 + CCACHE_TEMPDIR: /tmp/.ccache-temp + CCACHE_COMPRESS: 1 + LLVM_VERSION: 3.9.1 + +checkout: + post: + - git submodule update --init + +dependencies: + cache_directories: + - "~/.ccache" + - "~/.apt-cache" + pre: + # https://discuss.circleci.com/t/add-ability-to-cache-apt-get-programs/598/3 + - sudo rm -rf /var/cache/apt/archives && sudo ln -s ~/.apt-cache /var/cache/apt/archives && mkdir -p ~/.apt-cache/partial + - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test + override: + - sudo apt-get update -y + - sudo apt-get install -y libstdc++-5-dev xutils-dev + +database: + pre: + - ./bootstrap.sh + - ./.mason/mason install clang++ ${LLVM_VERSION} + - ./.mason/mason link clang++ ${LLVM_VERSION} + - ./configure CC="$(pwd)/mason_packages/.link/bin/clang" CXX="$(pwd)/mason_packages/.link/bin/ccache $(pwd)/mason_packages/.link/bin/clang++ -Qunused-arguments" + - make + override: + - psql -c 'create database template_postgis;' + - psql -c 'create extension postgis;' -d template_postgis + +test: + override: + - make test diff -Nru mapnik-3.0.9+ds/debian/changelog mapnik-3.0.13+ds/debian/changelog --- mapnik-3.0.9+ds/debian/changelog 2015-11-26 20:10:41.000000000 +0000 +++ mapnik-3.0.13+ds/debian/changelog 2017-11-05 20:51:18.000000000 +0000 @@ -1,3 +1,177 @@ +mapnik (3.0.13+ds-1~xenial2) xenial; urgency=medium + + * No change rebuild for GDAL 2.2.2 transition. + + -- Angelos Tzotsos Sun, 05 Nov 2017 20:00:00 +0200 + +mapnik (3.0.13+ds-1~xenial1) xenial; urgency=medium + + * No change rebuild for GDAL 2.2.1 transition. + + -- Angelos Tzotsos Wed, 26 Jul 2017 10:00:00 +0200 + +mapnik (3.0.13+ds-1~xenial0) xenial; urgency=medium + + * No change rebuild for Xenial. + + -- Angelos Tzotsos Fri, 02 Jun 2017 19:00:00 +0200 + +mapnik (3.0.13+ds-1~exp2) experimental; urgency=medium + + * Merge changes from mapnik (3.0.12+ds-3). + (closes: #859424) + * Drop unused lintian overrides for hardening-no-pie. + + -- Bas Couwenberg Mon, 03 Apr 2017 15:36:12 +0200 + +mapnik (3.0.13+ds-1~exp1) experimental; urgency=medium + + * New upstream release. + + -- Bas Couwenberg Wed, 08 Feb 2017 18:21:29 +0100 + +mapnik (3.0.13~rc2+ds-1~exp1) experimental; urgency=medium + + * New upstream release candidate. + * Require at least mapbox-variant 1.1.5. + + -- Bas Couwenberg Mon, 06 Feb 2017 18:57:41 +0100 + +mapnik (3.0.13~rc1+ds-1~exp1) experimental; urgency=medium + + * New upstream release candidate. + * Re-instate lintian override for hardening-no-pie. + * Drop dependencies-typo.patch, applied upstream. + + -- Bas Couwenberg Thu, 19 Jan 2017 00:11:00 +0100 + +mapnik (3.0.12+ds-3) unstable; urgency=medium + + * Update branch in gbp.conf & Vcs-Git URL. + * Enable PIE hardening buildflags. + (closes: #859424) + + -- Bas Couwenberg Mon, 03 Apr 2017 14:47:38 +0200 + +mapnik (3.0.12+ds-2) unstable; urgency=medium + + * Add patch to fix 'dependencies' typo. + * Drop unused override for hardening-no-pie. + * Change ttf-dejavu dependency to fonts-dejavu. + * Reorder (build) dependencies. + * Override dh_makeshlibs to use -V. + * Add lintian override for no-symbols-control-file. + + -- Bas Couwenberg Sat, 05 Nov 2016 14:15:44 +0100 + +mapnik (3.0.12+ds-1) unstable; urgency=medium + + * New upstream release. + * Update watchfile to not match releases/download. + * Move from experimental to unstable. + + -- Bas Couwenberg Thu, 08 Sep 2016 15:27:37 +0200 + +mapnik (3.0.12~rc7+ds-1~exp1) experimental; urgency=medium + + * New upstream release candidate. + * Update copyright file, changes: + - Add license & copyright for travis-command-wrapper.py + + -- Bas Couwenberg Tue, 06 Sep 2016 11:16:42 +0200 + +mapnik (3.0.12~rc6+ds-1~exp2) experimental; urgency=medium + + * Add libcurl-ssl-dev as alternative to libcurl4-gnutls-dev dependencies. + (closes: #836057) + + -- Bas Couwenberg Tue, 30 Aug 2016 12:59:34 +0200 + +mapnik (3.0.12~rc6+ds-1~exp1) experimental; urgency=medium + + * New upstream release candidate. + + -- Bas Couwenberg Fri, 26 Aug 2016 18:56:15 +0200 + +mapnik (3.0.12~rc5+ds-1~exp1) experimental; urgency=medium + + * New upstream release candidate. + + -- Bas Couwenberg Mon, 22 Aug 2016 22:21:22 +0200 + +mapnik (3.0.12~rc4+ds-1~exp1) experimental; urgency=medium + + * New upstream release candidate. + * Drop Debian OpenStreetMap Team from Uploaders. + + -- Bas Couwenberg Thu, 18 Aug 2016 19:53:39 +0200 + +mapnik (3.0.12~rc3+ds-1~exp1) experimental; urgency=medium + + * New upstream release candidate. + + -- Bas Couwenberg Fri, 12 Aug 2016 19:52:20 +0200 + +mapnik (3.0.12~rc2+ds-1~exp1) experimental; urgency=medium + + * New upstream release candidate. + * Drop patches, applied upstream. + + -- Bas Couwenberg Wed, 10 Aug 2016 12:36:04 +0200 + +mapnik (3.0.12~rc1+ds-1~exp2) experimental; urgency=medium + + * Require at least mapbox-variant 1.1.1 for libmapnik-dev dependency too. + + -- Bas Couwenberg Sat, 06 Aug 2016 13:02:58 +0200 + +mapnik (3.0.12~rc1+ds-1~exp1) experimental; urgency=medium + + * New upstream release candidate. + - Fixes FTBFS with Boost 1.61. + * Bump Standards-Version to 3.9.8, no changes. + * Require at least mapbox-variant 1.1.1. + * Update copyright file, changes: + - Add Upstream-Name to copyright file. + - Reorder Files sections + + -- Bas Couwenberg Fri, 05 Aug 2016 14:56:24 +0200 + +mapnik (3.0.11+ds-1) unstable; urgency=medium + + * New upstream release. + * Drop refactor-markers_placement_finder.patch, applied upstream. + * Refresh remaining patches. + + -- Bas Couwenberg Sat, 02 Apr 2016 01:44:11 +0200 + +mapnik (3.0.10+ds-2) unstable; urgency=medium + + * Remove hurd-i386 & kfreebsd-i386 from supported architectures. + * Add patch to refactor markers_placement_finder. + + -- Bas Couwenberg Sun, 20 Mar 2016 13:22:07 +0100 + +mapnik (3.0.10+ds-1) unstable; urgency=medium + + * New upstream release. + * Update Vcs-Git URL to use HTTPS. + * Add patches for various typos. + * Bump Standards-Version to 3.9.7, no changes. + * Override dh_strip to not generate automatic dbgsym packages, + those debug files have no debug symbols. + * Disable parallel builds on alpha, hurd-i386 & kfreebsd-* too. + * Update copyright file, changes: + - Update copyright years for Artem Pavlenko. + - Drop license & copyright for src/miniz.c, no longer included + * Drop 2001_ftemplate-depth.patch, applied upstream. + * Add --shape-index option to shapeindex manpage. + * Add (build) dependency on libmapbox-variant-dev. + * Enable all hardening buildflags, except pie + (causes python-mapnik build failures). + + -- Bas Couwenberg Fri, 18 Mar 2016 18:13:42 +0100 + mapnik (3.0.9+ds-1) unstable; urgency=medium * New upstream release. diff -Nru mapnik-3.0.9+ds/debian/control mapnik-3.0.13+ds/debian/control --- mapnik-3.0.9+ds/debian/control 2015-11-10 23:09:58.000000000 +0000 +++ mapnik-3.0.13+ds/debian/control 2017-04-03 13:32:19.000000000 +0000 @@ -1,46 +1,46 @@ Source: mapnik Maintainer: Debian GIS Project -Uploaders: Debian OpenStreetMap Team , - David Paleino , +Uploaders: David Paleino , Francesco Paolo Lovergine , Jérémy Lal , Bas Couwenberg Section: libs Priority: optional -Build-Depends: scons, - debhelper (>= 9~), - libtool, +Build-Depends: debhelper (>= 9~), libboost-filesystem-dev, + libboost-program-options-dev, + libboost-regex-dev, libboost-system-dev, libboost-thread-dev, - libboost-regex-dev, - libboost-program-options-dev, + libcairo-dev, + libcurl4-gnutls-dev | libcurl-ssl-dev, + libfreetype6-dev, + libgdal-dev, libharfbuzz-dev, libicu-dev, - libpng-dev, libjpeg-dev, + libmapbox-variant-dev (>= 1.1.5), + libpng-dev, + libpq-dev, + libproj-dev, + libsqlite3-dev, libtiff-dev, - zlib1g-dev, - libfreetype6-dev, + libtool, + libwebp-dev, libxml2-dev, - libproj-dev, - libcairo-dev, pkg-config, - libpq-dev, - libgdal-dev, - libsqlite3-dev, - libcurl4-gnutls-dev, - libwebp-dev -Standards-Version: 3.9.6 + scons, + zlib1g-dev +Standards-Version: 3.9.8 Vcs-Browser: https://anonscm.debian.org/cgit/pkg-grass/mapnik.git -Vcs-Git: git://anonscm.debian.org/pkg-grass/mapnik.git +Vcs-Git: https://anonscm.debian.org/git/pkg-grass/mapnik.git Homepage: http://www.mapnik.org/ Package: libmapnik3.0 -Architecture: any-amd64 any-i386 arm64 armel armhf powerpc ppc64el s390x sparc alpha hppa m68k powerpcspe ppc64 sh4 sparc64 x32 -Depends: ${shlibs:Depends}, - ${misc:Depends}, - ttf-dejavu +Architecture: any-amd64 i386 arm64 armel armhf powerpc ppc64el s390x alpha hppa m68k powerpcspe ppc64 sh4 sparc64 x32 +Depends: fonts-dejavu, + ${shlibs:Depends}, + ${misc:Depends} Suggests: postgis Description: C++ toolkit for developing GIS applications (libraries) Mapnik is an OpenSource C++ toolkit for developing GIS @@ -55,31 +55,33 @@ This package contains the shared library and input plugins. Package: libmapnik-dev -Architecture: any-amd64 any-i386 arm64 armel armhf powerpc ppc64el s390x sparc alpha hppa m68k powerpcspe ppc64 sh4 sparc64 x32 +Architecture: any-amd64 i386 arm64 armel armhf powerpc ppc64el s390x alpha hppa m68k powerpcspe ppc64 sh4 sparc64 x32 Section: libdevel -Depends: ${misc:Depends}, - libmapnik3.0 (= ${binary:Version}), - libc6-dev | libc-dev, +Depends: libmapnik3.0 (= ${binary:Version}), libboost-filesystem-dev, + libboost-program-options-dev, + libboost-regex-dev, libboost-system-dev, libboost-thread-dev, - libboost-regex-dev, - libboost-program-options-dev, - libicu-dev, + libc6-dev | libc-dev, + libcairo2-dev, + libcurl4-gnutls-dev | libcurl-ssl-dev, + libfreetype6-dev, + libgdal-dev, libharfbuzz-dev, - libpng-dev, + libicu-dev, libjpeg-dev, + libmapbox-variant-dev (>= 1.1.5), + libpng-dev, + libpq-dev, + libproj-dev, + libsqlite3-dev, libtiff-dev, - zlib1g-dev, - libfreetype6-dev, + libwebp-dev, libxml2-dev, - libproj-dev, - libcairo2-dev, pkg-config, - libpq-dev, - libgdal-dev, - libsqlite3-dev, - libcurl4-gnutls-dev, + zlib1g-dev, + ${misc:Depends} Recommends: mapnik-doc Breaks: libmapnik2-dev (<< 2.2.0+ds1-1~) Replaces: libmapnik2-dev (<< 2.2.0+ds1-1~) @@ -97,7 +99,7 @@ build utilities. Package: mapnik-utils -Architecture: any-amd64 any-i386 arm64 armel armhf powerpc ppc64el s390x sparc alpha hppa m68k powerpcspe ppc64 sh4 sparc64 x32 +Architecture: any-amd64 i386 arm64 armel armhf powerpc ppc64el s390x alpha hppa m68k powerpcspe ppc64 sh4 sparc64 x32 Section: utils Depends: ${shlibs:Depends}, ${misc:Depends} diff -Nru mapnik-3.0.9+ds/debian/copyright mapnik-3.0.13+ds/debian/copyright --- mapnik-3.0.9+ds/debian/copyright 2015-10-24 10:54:08.000000000 +0000 +++ mapnik-3.0.13+ds/debian/copyright 2017-01-18 23:09:08.000000000 +0000 @@ -1,4 +1,5 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: Mapnik Upstream-Contact: https://github.com/mapnik/mapnik/issues Source: https://github.com/mapnik/mapnik/ Repackaged to ease copyright maintenance @@ -8,7 +9,7 @@ fonts/unifont* Files: * -Copyright: 2006-2015, Artem Pavlenko +Copyright: 2006-2016, Artem Pavlenko 2005-2012, Jean-Francois Doyon 2011, Hermann Kraus 2010, Robert Coup @@ -17,17 +18,6 @@ 2006, 10East Corp. License: LGPL-2.1+ -Files: debian/* -Copyright: 2013, Jérémy Lal - 2013, YunQiang Su - 2010-2011, David Paleino - 2006-2009, Dominic Hargreaves -License: GPL-2+ - -Files: debian/rules -Copyright: 2010-2011, Christoph Egger -License: BSD-3-clause - Files: deps/boost/gil/* Copyright: 2004-2007, Christian Henning License: BSL-1.0 @@ -52,33 +42,20 @@ Natural Resources. All rights reserved. License: Geogratis -Files: src/miniz.c -Copyright: none (Public Domain) -License: public-domain - This is free and unencumbered software released into the public domain. - . - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - . - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - . - 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 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. - . - For more information, please refer to +Files: scripts/travis-command-wrapper.py +Copyright: 2015, Intel Corporation +License: Expat + +Files: debian/* +Copyright: 2013, Jérémy Lal + 2013, YunQiang Su + 2010-2011, David Paleino + 2006-2009, Dominic Hargreaves +License: GPL-2+ + +Files: debian/rules +Copyright: 2010-2011, Christoph Egger +License: BSD-3-clause License: LGPL-2.1+ This package is free software; you can redistribute it and/or @@ -175,6 +152,25 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +License: Expat + 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. + License: Geogratis GEOGRATIS LICENCE AGREEMENT FOR UNRESTRICTED USE OF DIGITAL DATA This is a legal agreement between you ("Licensee") and Her Majesty diff -Nru mapnik-3.0.9+ds/debian/libmapnik3.0.lintian-overrides mapnik-3.0.13+ds/debian/libmapnik3.0.lintian-overrides --- mapnik-3.0.9+ds/debian/libmapnik3.0.lintian-overrides 2015-08-30 13:23:49.000000000 +0000 +++ mapnik-3.0.13+ds/debian/libmapnik3.0.lintian-overrides 2017-04-03 12:47:36.000000000 +0000 @@ -1,6 +1,7 @@ # Build uses -D_FORTIFY_SOURCE=2, but hardening-check reports: # Fortify Source functions: no, only unprotected functions found! -# unprotected: memmove -# unprotected: memcpy libmapnik3.0: hardening-no-fortify-functions usr/lib/mapnik/*/input/*.input +# Symbols are problematic for C++ libraries +libmapnik3.0: no-symbols-control-file * + diff -Nru mapnik-3.0.9+ds/debian/manpages/mapnik-config.1 mapnik-3.0.13+ds/debian/manpages/mapnik-config.1 --- mapnik-3.0.9+ds/debian/manpages/mapnik-config.1 2013-08-09 10:10:51.000000000 +0000 +++ mapnik-3.0.13+ds/debian/manpages/mapnik-config.1 2016-10-15 18:08:15.000000000 +0000 @@ -21,7 +21,7 @@ Print library linking information. .TP .B \-\-dep\-libs -Print library linking information for Mapnik depedencies. +Print library linking information for Mapnik dependencies. .TP .B \-\-ldflags Print library paths (\-L) information. diff -Nru mapnik-3.0.9+ds/debian/manpages/shapeindex.1 mapnik-3.0.13+ds/debian/manpages/shapeindex.1 --- mapnik-3.0.9+ds/debian/manpages/shapeindex.1 2013-08-09 10:10:51.000000000 +0000 +++ mapnik-3.0.13+ds/debian/manpages/shapeindex.1 2016-10-15 18:08:15.000000000 +0000 @@ -42,6 +42,9 @@ .B \-V, \-\-version Show version of program. .TP +.B \-\-shape-index +Index individual shape parts (default: no) +.TP .B \-v, \-\-verbose Show verbose output. .TP diff -Nru mapnik-3.0.9+ds/debian/patches/2001_ftemplate-depth.patch mapnik-3.0.13+ds/debian/patches/2001_ftemplate-depth.patch --- mapnik-3.0.9+ds/debian/patches/2001_ftemplate-depth.patch 2015-11-10 23:15:40.000000000 +0000 +++ mapnik-3.0.13+ds/debian/patches/2001_ftemplate-depth.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -Description: remove gcc ftemplate-depth-300 flag - it can use a lot of memory, and default value works on debian -Forwarded: not-needed, https://github.com/mapnik/mapnik/commit/b01b21f24 -Author: Jérémy Lal -Last-Update: 2015-06-19 ---- a/SConstruct -+++ b/SConstruct -@@ -1785,7 +1785,7 @@ if not preconfigured: - - # Common flags for g++/clang++ CXX compiler. - # TODO: clean up code more to make -Wextra -Wsign-compare -Wsign-conversion -Wconversion viable -- common_cxx_flags = '-Wall %s %s -ftemplate-depth-300 -Wsign-compare -Wshadow ' % (env['WARNING_CXXFLAGS'], pthread) -+ common_cxx_flags = '-Wall %s %s -Wsign-compare -Wshadow ' % (env['WARNING_CXXFLAGS'], pthread) - - if env['DEBUG']: - env.Append(CXXFLAGS = common_cxx_flags + '-O0') diff -Nru mapnik-3.0.9+ds/debian/patches/series mapnik-3.0.13+ds/debian/patches/series --- mapnik-3.0.9+ds/debian/patches/series 2015-09-20 09:57:24.000000000 +0000 +++ mapnik-3.0.13+ds/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -2001_ftemplate-depth.patch diff -Nru mapnik-3.0.9+ds/debian/rules mapnik-3.0.13+ds/debian/rules --- mapnik-3.0.9+ds/debian/rules 2015-11-11 21:22:56.000000000 +0000 +++ mapnik-3.0.13+ds/debian/rules 2017-04-03 13:31:53.000000000 +0000 @@ -4,6 +4,9 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 +# Enable hardening build flags +export DEB_BUILD_MAINT_OPTIONS=hardening=+all + NJOBS := -j1 ifneq (,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) NJOBS := -j$(subst parallel=,,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) @@ -12,7 +15,7 @@ DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) # Disable parallel builds for problematic architectures -NO_PARALLEL_ARCHS = "arm64 armel armhf" +NO_PARALLEL_ARCHS = "arm64 armel armhf alpha hurd-i386 kfreebsd-i386 kfreebsd-amd64" ifeq ($(shell dpkg-vendor --derives-from Ubuntu && echo yes),yes) # From mapnik (3.0.8+ds-1ubuntu1): @@ -76,6 +79,12 @@ override_dh_install: dh_install --list-missing +override_dh_strip: + dh_strip --no-automatic-dbgsym + override_dh_prep: dh_prep -Xdebian/tmp +override_dh_makeshlibs: + dh_makeshlibs -V + diff -Nru mapnik-3.0.9+ds/debian/watch mapnik-3.0.13+ds/debian/watch --- mapnik-3.0.9+ds/debian/watch 2015-08-25 18:28:06.000000000 +0000 +++ mapnik-3.0.13+ds/debian/watch 2016-10-15 18:08:15.000000000 +0000 @@ -2,7 +2,7 @@ opts=\ dversionmangle=s/\+(debian|dfsg|ds|deb)\d*$//,\ uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)(?:-?offset)?\d*)$/$1~$2/;s/RC/rc/,\ -filenamemangle=s/(?:.*?)?(?:rel|v|mapnik)?[\-\_]?(\d\S+)\.(tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))/mapnik-$1.$2/,\ +filenamemangle=s/(?:.*?\/)?(?:rel|v|mapnik)?[\-\_]?(\d\S+)\.(tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))/mapnik-$1.$2/,\ repacksuffix=+ds \ https://github.com/mapnik/mapnik/releases \ -(?:.*?/)?(?:rel|v|mapnik)?[\-\_]?(\d\S+)\.(?:tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz))) +(?:.*?archive/)?(?:rel|v|mapnik)?[\-\_]?(\d\S+)\.(?:tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz))) diff -Nru mapnik-3.0.9+ds/demo/c++/README.md mapnik-3.0.13+ds/demo/c++/README.md --- mapnik-3.0.9+ds/demo/c++/README.md 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/c++/README.md 2017-02-08 13:06:42.000000000 +0000 @@ -52,11 +52,11 @@ Simply type: - make + make Then to run do: - ./rundemo `mapnik-config --prefix` + ./rundemo `mapnik-config --prefix` On OS X you can also create an xcode project: diff -Nru mapnik-3.0.9+ds/demo/c++/rundemo.cpp mapnik-3.0.13+ds/demo/c++/rundemo.cpp --- mapnik-3.0.9+ds/demo/c++/rundemo.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/c++/rundemo.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -55,7 +55,7 @@ try { std::cout << " running demo ... \n"; datasource_cache::instance().register_datasources("plugins/input/"); - freetype_engine::register_font("fonts/dejavu-fonts-ttf-2.34/ttf/DejaVuSans.ttf"); + freetype_engine::register_font("fonts/dejavu-fonts-ttf-2.37/ttf/DejaVuSans.ttf"); Map m(800,600); m.set_background(parse_color("white")); @@ -230,7 +230,7 @@ parameters p; p["type"]="shape"; p["file"]="demo/data/boundaries"; - p["encoding"]="latin1"; + p["encoding"]="utf8"; layer lyr("Provinces"); lyr.set_datasource(datasource_cache::instance().create(p)); @@ -295,7 +295,7 @@ parameters p; p["type"]="shape"; p["file"]="demo/data/popplaces"; - p["encoding"] = "latin1"; + p["encoding"] = "utf8"; layer lyr("Populated Places"); lyr.set_srs(srs_lcc); lyr.set_datasource(datasource_cache::instance().create(p)); Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/boundaries.dbf and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/boundaries.dbf differ Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/boundaries_l.dbf and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/boundaries_l.dbf differ diff -Nru mapnik-3.0.9+ds/demo/data/boundaries_l.prj mapnik-3.0.13+ds/demo/data/boundaries_l.prj --- mapnik-3.0.9+ds/demo/data/boundaries_l.prj 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/data/boundaries_l.prj 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]] \ No newline at end of file Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/boundaries_l.sbx and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/boundaries_l.sbx differ diff -Nru mapnik-3.0.9+ds/demo/data/boundaries.prj mapnik-3.0.13+ds/demo/data/boundaries.prj --- mapnik-3.0.9+ds/demo/data/boundaries.prj 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/data/boundaries.prj 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]] \ No newline at end of file Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/boundaries.sbx and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/boundaries.sbx differ Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/ontdrainage.dbf and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/ontdrainage.dbf differ diff -Nru mapnik-3.0.9+ds/demo/data/ontdrainage.prj mapnik-3.0.13+ds/demo/data/ontdrainage.prj --- mapnik-3.0.9+ds/demo/data/ontdrainage.prj 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/data/ontdrainage.prj 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]] \ No newline at end of file Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/ontdrainage.sbx and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/ontdrainage.sbx differ Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/popplaces.dbf and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/popplaces.dbf differ diff -Nru mapnik-3.0.9+ds/demo/data/popplaces.prj mapnik-3.0.13+ds/demo/data/popplaces.prj --- mapnik-3.0.9+ds/demo/data/popplaces.prj 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/data/popplaces.prj 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]] \ No newline at end of file Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/popplaces.sbx and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/popplaces.sbx differ Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/qcdrainage.dbf and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/qcdrainage.dbf differ diff -Nru mapnik-3.0.9+ds/demo/data/qcdrainage.prj mapnik-3.0.13+ds/demo/data/qcdrainage.prj --- mapnik-3.0.9+ds/demo/data/qcdrainage.prj 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/data/qcdrainage.prj 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]] \ No newline at end of file Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/qcdrainage.sbx and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/qcdrainage.sbx differ Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/roads.dbf and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/roads.dbf differ diff -Nru mapnik-3.0.9+ds/demo/data/roads.prj mapnik-3.0.13+ds/demo/data/roads.prj --- mapnik-3.0.9+ds/demo/data/roads.prj 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/data/roads.prj 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -PROJCS["Atlas of Canada Lambert Conformal Conic",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-95.0],PARAMETER["Standard_Parallel_1",49.0],PARAMETER["Standard_Parallel_2",77.0],PARAMETER["Latitude_Of_Origin",49.0],UNIT["Meter",1.0]] \ No newline at end of file Binary files /tmp/tmp1N_xN9/dg8s3CCtcJ/mapnik-3.0.9+ds/demo/data/roads.sbx and /tmp/tmp1N_xN9/F7lnmqrObw/mapnik-3.0.13+ds/demo/data/roads.sbx differ diff -Nru mapnik-3.0.9+ds/demo/python/rundemo.py mapnik-3.0.13+ds/demo/python/rundemo.py --- mapnik-3.0.9+ds/demo/python/rundemo.py 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/python/rundemo.py 2017-02-08 13:06:42.000000000 +0000 @@ -18,7 +18,7 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from __future__ import print_function import sys from os import path diff -Nru mapnik-3.0.9+ds/demo/viewer/about_dialog.cpp mapnik-3.0.13+ds/demo/viewer/about_dialog.cpp --- mapnik-3.0.9+ds/demo/viewer/about_dialog.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/about_dialog.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/about_dialog.hpp mapnik-3.0.13+ds/demo/viewer/about_dialog.hpp --- mapnik-3.0.9+ds/demo/viewer/about_dialog.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/about_dialog.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/info_dialog.cpp mapnik-3.0.13+ds/demo/viewer/info_dialog.cpp --- mapnik-3.0.9+ds/demo/viewer/info_dialog.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/info_dialog.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/info_dialog.hpp mapnik-3.0.13+ds/demo/viewer/info_dialog.hpp --- mapnik-3.0.9+ds/demo/viewer/info_dialog.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/info_dialog.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/layerdelegate.cpp mapnik-3.0.13+ds/demo/viewer/layerdelegate.cpp --- mapnik-3.0.9+ds/demo/viewer/layerdelegate.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/layerdelegate.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/layerdelegate.hpp mapnik-3.0.13+ds/demo/viewer/layerdelegate.hpp --- mapnik-3.0.9+ds/demo/viewer/layerdelegate.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/layerdelegate.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef LAYER_DELEGATE_HPP diff -Nru mapnik-3.0.9+ds/demo/viewer/layer_info_dialog.cpp mapnik-3.0.13+ds/demo/viewer/layer_info_dialog.cpp --- mapnik-3.0.9+ds/demo/viewer/layer_info_dialog.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/layer_info_dialog.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/layer_info_dialog.hpp mapnik-3.0.13+ds/demo/viewer/layer_info_dialog.hpp --- mapnik-3.0.9+ds/demo/viewer/layer_info_dialog.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/layer_info_dialog.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/layerlistmodel.cpp mapnik-3.0.13+ds/demo/viewer/layerlistmodel.cpp --- mapnik-3.0.9+ds/demo/viewer/layerlistmodel.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/layerlistmodel.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/layerlistmodel.hpp mapnik-3.0.13+ds/demo/viewer/layerlistmodel.hpp --- mapnik-3.0.9+ds/demo/viewer/layerlistmodel.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/layerlistmodel.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/layerwidget.cpp mapnik-3.0.13+ds/demo/viewer/layerwidget.cpp --- mapnik-3.0.9+ds/demo/viewer/layerwidget.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/layerwidget.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/layerwidget.hpp mapnik-3.0.13+ds/demo/viewer/layerwidget.hpp --- mapnik-3.0.9+ds/demo/viewer/layerwidget.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/layerwidget.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/main.cpp mapnik-3.0.13+ds/demo/viewer/main.cpp --- mapnik-3.0.9+ds/demo/viewer/main.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/main.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/mainwindow.cpp mapnik-3.0.13+ds/demo/viewer/mainwindow.cpp --- mapnik-3.0.9+ds/demo/viewer/mainwindow.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/mainwindow.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/mainwindow.hpp mapnik-3.0.13+ds/demo/viewer/mainwindow.hpp --- mapnik-3.0.9+ds/demo/viewer/mainwindow.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/mainwindow.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/mapwidget.cpp mapnik-3.0.13+ds/demo/viewer/mapwidget.cpp --- mapnik-3.0.9+ds/demo/viewer/mapwidget.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/mapwidget.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/mapwidget.hpp mapnik-3.0.13+ds/demo/viewer/mapwidget.hpp --- mapnik-3.0.9+ds/demo/viewer/mapwidget.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/mapwidget.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/styles_model.cpp mapnik-3.0.13+ds/demo/viewer/styles_model.cpp --- mapnik-3.0.9+ds/demo/viewer/styles_model.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/styles_model.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/demo/viewer/styles_model.hpp mapnik-3.0.13+ds/demo/viewer/styles_model.hpp --- mapnik-3.0.9+ds/demo/viewer/styles_model.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/demo/viewer/styles_model.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff -Nru mapnik-3.0.9+ds/deps/agg/include/agg_array.h mapnik-3.0.13+ds/deps/agg/include/agg_array.h --- mapnik-3.0.9+ds/deps/agg/include/agg_array.h 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/deps/agg/include/agg_array.h 2017-02-08 13:06:42.000000000 +0000 @@ -27,8 +27,8 @@ { public: typedef T value_type; - pod_array_adaptor(T* array, unsigned size) : - m_array(array), m_size(size) {} + pod_array_adaptor(T* array, unsigned _size) : + m_array(array), m_size(_size) {} unsigned size() const { return m_size; } const T& operator [] (unsigned i) const { return m_array[i]; } @@ -87,7 +87,7 @@ void clear() { m_size = 0; } void add(const T& v) { m_array[m_size++] = v; } void push_back(const T& v) { m_array[m_size++] = v; } - void inc_size(unsigned size) { m_size += size; } + void inc_size(unsigned _size) { m_size += _size; } unsigned size() const { return m_size; } const T& operator [] (unsigned i) const { return m_array[i]; } @@ -112,9 +112,9 @@ ~pod_array() { pod_allocator::deallocate(m_array, m_size); } pod_array() : m_array(0), m_size(0) {} - pod_array(unsigned size) : - m_array(pod_allocator::allocate(size)), - m_size(size) + pod_array(unsigned _size) : + m_array(pod_allocator::allocate(_size)), + m_size(_size) {} pod_array(const self_type& v) : @@ -124,12 +124,12 @@ memcpy(m_array, v.m_array, sizeof(T) * m_size); } - void resize(unsigned size) + void resize(unsigned _size) { - if(size != m_size) + if(_size != m_size) { pod_allocator::deallocate(m_array, m_size); - m_array = pod_allocator::allocate(m_size = size); + m_array = pod_allocator::allocate(m_size = _size); } } const self_type& operator = (const self_type& v) @@ -191,7 +191,7 @@ void add(const T& v) { m_array[m_size++] = v; } void push_back(const T& v) { m_array[m_size++] = v; } void insert_at(unsigned pos, const T& val); - void inc_size(unsigned size) { m_size += size; } + void inc_size(unsigned _size) { m_size += _size; } unsigned size() const { return m_size; } unsigned byte_size() const { return m_size * sizeof(T); } void serialize(int8u* ptr) const; @@ -230,10 +230,10 @@ //------------------------------------------------------------------------ template - void pod_vector::allocate(unsigned size, unsigned extra_tail) + void pod_vector::allocate(unsigned _size, unsigned extra_tail) { - capacity(size, extra_tail); - m_size = size; + capacity(_size, extra_tail); + m_size = _size; } @@ -245,10 +245,10 @@ { if(new_size > m_capacity) { - T* data = pod_allocator::allocate(new_size); - memcpy(data, m_array, m_size * sizeof(T)); + T* _data = pod_allocator::allocate(new_size); + memcpy(_data, m_array, m_size * sizeof(T)); pod_allocator::deallocate(m_array, m_capacity); - m_array = data; + m_array = _data; } } else @@ -289,11 +289,11 @@ //------------------------------------------------------------------------ template - void pod_vector::deserialize(const int8u* data, unsigned byte_size) + void pod_vector::deserialize(const int8u* _data, unsigned _byte_size) { - byte_size /= sizeof(T); - allocate(byte_size); - if(byte_size) memcpy(m_array, data, byte_size * sizeof(T)); + _byte_size /= sizeof(T); + allocate(_byte_size); + if(_byte_size) memcpy(m_array, _data, _byte_size * sizeof(T)); } //------------------------------------------------------------------------ @@ -371,9 +371,9 @@ } } - void cut_at(unsigned size) + void cut_at(unsigned _size) { - if(size < m_size) m_size = size; + if(_size < m_size) m_size = _size; } unsigned size() const { return m_size; } @@ -529,11 +529,11 @@ //------------------------------------------------------------------------ template - void pod_bvector::free_tail(unsigned size) + void pod_bvector::free_tail(unsigned _size) { - if(size < m_size) + if(_size < m_size) { - unsigned nb = (size + block_mask) >> block_shift; + unsigned nb = (_size + block_mask) >> block_shift; while(m_num_blocks > nb) { pod_allocator::deallocate(m_blocks[--m_num_blocks], block_size); @@ -544,7 +544,7 @@ m_blocks = 0; m_max_blocks = 0; } - m_size = size; + m_size = _size; } } @@ -728,16 +728,16 @@ //------------------------------------------------------------------------ template - void pod_bvector::deserialize(const int8u* data, unsigned byte_size) + void pod_bvector::deserialize(const int8u* _data, unsigned _byte_size) { remove_all(); - byte_size /= sizeof(T); - for(unsigned i = 0; i < byte_size; ++i) + _byte_size /= sizeof(T); + for(unsigned i = 0; i < _byte_size; ++i) { T* ptr = data_ptr(); - memcpy(ptr, data, sizeof(T)); + memcpy(ptr, _data, sizeof(T)); ++m_size; - data += sizeof(T); + _data += sizeof(T); } } @@ -746,27 +746,27 @@ //------------------------------------------------------------------------ template void pod_bvector::deserialize(unsigned start, const T& empty_val, - const int8u* data, unsigned byte_size) + const int8u* _data, unsigned _byte_size) { while(m_size < start) { add(empty_val); } - byte_size /= sizeof(T); - for(unsigned i = 0; i < byte_size; ++i) + _byte_size /= sizeof(T); + for(unsigned i = 0; i < _byte_size; ++i) { if(start + i < m_size) { - memcpy(&((*this)[start + i]), data, sizeof(T)); + memcpy(&((*this)[start + i]), _data, sizeof(T)); } else { T* ptr = data_ptr(); - memcpy(ptr, data, sizeof(T)); + memcpy(ptr, _data, sizeof(T)); ++m_size; } - data += sizeof(T); + _data += sizeof(T); } } @@ -1087,8 +1087,8 @@ public: typedef typename Array::value_type value_type; - range_adaptor(Array& array, unsigned start, unsigned size) : - m_array(array), m_start(start), m_size(size) + range_adaptor(Array& array, unsigned start, unsigned _size) : + m_array(array), m_start(start), m_size(_size) {} unsigned size() const { return m_size; } diff -Nru mapnik-3.0.9+ds/deps/agg/include/agg_conv_clip_polygon.h mapnik-3.0.13+ds/deps/agg/include/agg_conv_clip_polygon.h --- mapnik-3.0.9+ds/deps/agg/include/agg_conv_clip_polygon.h 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/deps/agg/include/agg_conv_clip_polygon.h 2017-02-08 13:06:42.000000000 +0000 @@ -42,9 +42,9 @@ conv_clip_polygon(VertexSource& vs) : conv_adaptor_vpgen(vs) {} - void clip_box(double x1, double y1, double x2, double y2) + void clip_box(double _x1, double _y1, double _x2, double _y2) { - base_type::vpgen().clip_box(x1, y1, x2, y2); + base_type::vpgen().clip_box(_x1, _y1, _x2, _y2); } double x1() const { return base_type::vpgen().x1(); } diff -Nru mapnik-3.0.9+ds/deps/agg/include/agg_conv_clip_polyline.h mapnik-3.0.13+ds/deps/agg/include/agg_conv_clip_polyline.h --- mapnik-3.0.9+ds/deps/agg/include/agg_conv_clip_polyline.h 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/deps/agg/include/agg_conv_clip_polyline.h 2017-02-08 13:06:42.000000000 +0000 @@ -42,9 +42,9 @@ conv_clip_polyline(VertexSource& vs) : conv_adaptor_vpgen(vs) {} - void clip_box(double x1, double y1, double x2, double y2) + void clip_box(double _x1, double _y1, double _x2, double _y2) { - base_type::vpgen().clip_box(x1, y1, x2, y2); + base_type::vpgen().clip_box(_x1, _y1, _x2, _y2); } double x1() const { return base_type::vpgen().x1(); } diff -Nru mapnik-3.0.9+ds/deps/agg/include/agg_rasterizer_scanline_aa.h mapnik-3.0.13+ds/deps/agg/include/agg_rasterizer_scanline_aa.h --- mapnik-3.0.9+ds/deps/agg/include/agg_rasterizer_scanline_aa.h 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/deps/agg/include/agg_rasterizer_scanline_aa.h 2017-02-08 13:06:42.000000000 +0000 @@ -2,15 +2,15 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // -// The author gratefully acknowleges the support of David Turner, -// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType +// The author gratefully acknowleges the support of David Turner, +// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType // libray - in producing this work. See http://www.freetype.org for details. // //---------------------------------------------------------------------------- @@ -19,12 +19,12 @@ // http://www.antigrain.com //---------------------------------------------------------------------------- // -// Adaptation for 32-bit screen coordinates has been sponsored by +// Adaptation for 32-bit screen coordinates has been sponsored by // Liberty Technology Systems, Inc., visit http://lib-sys.com // // Liberty Technology Systems, Inc. is the provider of // PostScript and PDF technology for software developers. -// +// //---------------------------------------------------------------------------- #ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED #define AGG_RASTERIZER_SCANLINE_AA_INCLUDED @@ -39,8 +39,8 @@ //-----------------------------------------------------------------cell_aa - // A pixel cell. There're no constructors defined and it was done - // intentionally in order to avoid extra overhead when allocating an + // A pixel cell. There're no constructors defined and it was done + // intentionally in order to avoid extra overhead when allocating an // array of cells. struct cell_aa { @@ -67,10 +67,10 @@ //==================================================rasterizer_scanline_aa - // Polygon rasterizer that is used to render filled polygons with - // high-quality Anti-Aliasing. Internally, by default, the class uses - // integer coordinates in format 24.8, i.e. 24 bits for integer part - // and 8 bits for fractional - see poly_subpixel_shift. This class can be + // Polygon rasterizer that is used to render filled polygons with + // high-quality Anti-Aliasing. Internally, by default, the class uses + // integer coordinates in format 24.8, i.e. 24 bits for integer part + // and 8 bits for fractional - see poly_subpixel_shift. This class can be // used in the following way: // // 1. filling_rule(filling_rule_e ft) - optional. @@ -79,20 +79,20 @@ // // 3. reset() // - // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create + // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create // more than one contour, but each contour must consist of at least 3 // vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3); // is the absolute minimum of vertices that define a triangle. // The algorithm does not check either the number of vertices nor - // coincidence of their coordinates, but in the worst case it just + // coincidence of their coordinates, but in the worst case it just // won't draw anything. - // The orger of the vertices (clockwise or counterclockwise) + // The orger of the vertices (clockwise or counterclockwise) // is important when using the non-zero filling rule (fill_non_zero). // In this case the vertex order of all the contours must be the same // if you want your intersecting polygons to be without "holes". - // You actually can use different vertices order. If the contours do not - // intersect each other the order is not important anyway. If they do, - // contours with the same vertex order will be rendered without "holes" + // You actually can use different vertices order. If the contours do not + // intersect each other the order is not important anyway. If they do, + // contours with the same vertex order will be rendered without "holes" // while the intersecting contours with different orders will have "holes". // // filling_rule() and gamma() can be called anytime before "sweeping". @@ -122,7 +122,7 @@ }; //-------------------------------------------------------------------- - rasterizer_scanline_aa() : + rasterizer_scanline_aa() : m_outline(), m_clipper(), m_filling_rule(fill_non_zero), @@ -136,8 +136,8 @@ } //-------------------------------------------------------------------- - template - rasterizer_scanline_aa(const GammaF& gamma_function) : + template + rasterizer_scanline_aa(const GammaF& gamma_function) : m_outline(), m_clipper(m_outline), m_filling_rule(fill_non_zero), @@ -150,7 +150,7 @@ } //-------------------------------------------------------------------- - void reset(); + void reset(); void reset_clipping(); void clip_box(double x1, double y1, double x2, double y2); void filling_rule(filling_rule_e filling_rule); @@ -158,7 +158,7 @@ //-------------------------------------------------------------------- template void gamma(const GammaF& gamma_function) - { + { int i; for(i = 0; i < aa_scale; i++) { @@ -167,9 +167,9 @@ } //-------------------------------------------------------------------- - unsigned apply_gamma(unsigned cover) const - { - return m_gamma[cover]; + unsigned apply_gamma(unsigned cover) const + { + return m_gamma[cover]; } //-------------------------------------------------------------------- @@ -198,7 +198,7 @@ add_vertex(x, y, cmd); } } - + //-------------------------------------------------------------------- int min_x() const { return m_outline.min_x(); } int min_y() const { return m_outline.min_y(); } @@ -237,7 +237,7 @@ sl.reset_spans(); unsigned num_cells = m_outline.scanline_num_cells(m_scan_y); const cell_aa* const* cells = m_outline.scanline_cells(m_scan_y); - int cover = 0; + unsigned cover = 0; while(num_cells) { @@ -276,7 +276,7 @@ } } } - + if(sl.num_spans()) break; ++m_scan_y; } @@ -294,7 +294,7 @@ //-------------------------------------------------------------------- // Disable copying rasterizer_scanline_aa(const rasterizer_scanline_aa&); - const rasterizer_scanline_aa& + const rasterizer_scanline_aa& operator = (const rasterizer_scanline_aa&); private: @@ -321,32 +321,32 @@ //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::reset() - { - m_outline.reset(); + template + void rasterizer_scanline_aa::reset() + { + m_outline.reset(); m_status = status_initial; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::filling_rule(filling_rule_e filling_rule) - { - m_filling_rule = filling_rule; + template + void rasterizer_scanline_aa::filling_rule(filling_rule_e filling_rule) + { + m_filling_rule = filling_rule; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::clip_box(double x1, double y1, + template + void rasterizer_scanline_aa::clip_box(double x1, double y1, double x2, double y2) { reset(); - m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), + m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1), conv_type::upscale(x2), conv_type::upscale(y2)); } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::reset_clipping() { reset(); @@ -354,7 +354,7 @@ } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::close_polygon() { if(m_status == status_line_to) @@ -365,56 +365,56 @@ } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::move_to(int x, int y) { if(m_outline.sorted()) reset(); if(m_auto_close) close_polygon(); - m_clipper.move_to(m_start_x = conv_type::downscale(x), + m_clipper.move_to(m_start_x = conv_type::downscale(x), m_start_y = conv_type::downscale(y)); m_status = status_move_to; } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::line_to(int x, int y) { - m_clipper.line_to(m_outline, - conv_type::downscale(x), + m_clipper.line_to(m_outline, + conv_type::downscale(x), conv_type::downscale(y)); m_status = status_line_to; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::move_to_d(double x, double y) - { + template + void rasterizer_scanline_aa::move_to_d(double x, double y) + { if(m_outline.sorted()) reset(); if(m_auto_close) close_polygon(); - m_clipper.move_to(m_start_x = conv_type::upscale(x), - m_start_y = conv_type::upscale(y)); + m_clipper.move_to(m_start_x = conv_type::upscale(x), + m_start_y = conv_type::upscale(y)); m_status = status_move_to; } //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::line_to_d(double x, double y) - { - m_clipper.line_to(m_outline, - conv_type::upscale(x), - conv_type::upscale(y)); + template + void rasterizer_scanline_aa::line_to_d(double x, double y) + { + m_clipper.line_to(m_outline, + conv_type::upscale(x), + conv_type::upscale(y)); m_status = status_line_to; } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::add_vertex(double x, double y, unsigned cmd) { - if(is_move_to(cmd)) + if(is_move_to(cmd)) { move_to_d(x, y); } - else + else if(is_vertex(cmd)) { line_to_d(x, y); @@ -427,32 +427,32 @@ } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::edge(int x1, int y1, int x2, int y2) { if(m_outline.sorted()) reset(); m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1)); - m_clipper.line_to(m_outline, - conv_type::downscale(x2), + m_clipper.line_to(m_outline, + conv_type::downscale(x2), conv_type::downscale(y2)); m_status = status_move_to; } - + //------------------------------------------------------------------------ - template - void rasterizer_scanline_aa::edge_d(double x1, double y1, + template + void rasterizer_scanline_aa::edge_d(double x1, double y1, double x2, double y2) { if(m_outline.sorted()) reset(); - m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); - m_clipper.line_to(m_outline, - conv_type::upscale(x2), - conv_type::upscale(y2)); + m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1)); + m_clipper.line_to(m_outline, + conv_type::upscale(x2), + conv_type::upscale(y2)); m_status = status_move_to; } //------------------------------------------------------------------------ - template + template void rasterizer_scanline_aa::sort() { if(m_auto_close) close_polygon(); @@ -460,12 +460,12 @@ } //------------------------------------------------------------------------ - template + template AGG_INLINE bool rasterizer_scanline_aa::rewind_scanlines() { if(m_auto_close) close_polygon(); m_outline.sort_cells(); - if(m_outline.total_cells() == 0) + if(m_outline.total_cells() == 0) { return false; } @@ -475,14 +475,14 @@ //------------------------------------------------------------------------ - template + template AGG_INLINE bool rasterizer_scanline_aa::navigate_scanline(int y) { if(m_auto_close) close_polygon(); m_outline.sort_cells(); - if(m_outline.total_cells() == 0 || - y < m_outline.min_y() || - y > m_outline.max_y()) + if(m_outline.total_cells() == 0 || + y < m_outline.min_y() || + y > m_outline.max_y()) { return false; } @@ -491,7 +491,7 @@ } //------------------------------------------------------------------------ - template + template bool rasterizer_scanline_aa::hit_test(int tx, int ty) { if(!navigate_scanline(ty)) return false; @@ -507,4 +507,3 @@ #endif - diff -Nru mapnik-3.0.9+ds/deps/agg/include/agg_vcgen_dash.h mapnik-3.0.13+ds/deps/agg/include/agg_vcgen_dash.h --- mapnik-3.0.9+ds/deps/agg/include/agg_vcgen_dash.h 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/deps/agg/include/agg_vcgen_dash.h 2017-02-08 13:06:42.000000000 +0000 @@ -2,8 +2,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -21,6 +21,7 @@ #include "agg_basics.h" #include "agg_vertex_sequence.h" +#include namespace agg { @@ -29,7 +30,7 @@ // // See Implementation agg_vcgen_dash.cpp // - class vcgen_dash + class MAPNIK_DECL vcgen_dash { enum max_dashes_e { diff -Nru mapnik-3.0.9+ds/deps/mapnik/build.py mapnik-3.0.13+ds/deps/mapnik/build.py --- mapnik-3.0.9+ds/deps/mapnik/build.py 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/deps/mapnik/build.py 2017-02-08 13:06:42.000000000 +0000 @@ -4,14 +4,15 @@ Import('env') subdirs = { - 'sparsehash':'sparsehash', - 'sparsehash/internal':'sparsehash/internal', - '../agg/include':'agg', + './sparsehash':{'dir':'sparsehash','glob':'*'}, + './sparsehash/internal':{'dir':'sparsehash/internal','glob':'*'}, + '../agg/include':{'dir':'agg','glob':'agg*'}, + '../mapbox/variant/include':{'dir':'mapbox','glob':'*/*.hpp'} } if 'install' in COMMAND_LINE_TARGETS: for k,v in subdirs.items(): - pathdir = os.path.join(k,'*') + pathdir = os.path.join(k,v['glob']) includes = glob(pathdir) - inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/'+v) + inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/'+v['dir']) env.Alias(target='install', source=env.Install(inc_target, includes)) diff -Nru mapnik-3.0.9+ds/.gitmodules mapnik-3.0.13+ds/.gitmodules --- mapnik-3.0.9+ds/.gitmodules 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/.gitmodules 2017-02-08 13:06:42.000000000 +0000 @@ -5,4 +5,7 @@ [submodule "test/data-visual"] path = test/data-visual url = https://github.com/mapnik/test-data-visual.git - branch = master \ No newline at end of file + branch = master +[submodule "deps/mapbox/variant"] + path = deps/mapbox/variant + url = https://github.com/mapbox/variant.git diff -Nru mapnik-3.0.9+ds/include/mapnik/agg_helpers.hpp mapnik-3.0.13+ds/include/mapnik/agg_helpers.hpp --- mapnik-3.0.9+ds/include/mapnik/agg_helpers.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/agg_helpers.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,8 +26,10 @@ // mapnik #include -// agg +#pragma GCC diagnostic push +#include #include "agg_gamma_functions.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/agg_pattern_source.hpp mapnik-3.0.13+ds/include/mapnik/agg_pattern_source.hpp --- mapnik-3.0.9+ds/include/mapnik/agg_pattern_source.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/agg_pattern_source.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,8 +27,10 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_color_rgba.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/agg_rasterizer.hpp mapnik-3.0.13+ds/include/mapnik/agg_rasterizer.hpp --- mapnik-3.0.9+ds/include/mapnik/agg_rasterizer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/agg_rasterizer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,8 +26,11 @@ // mapnik #include -// agg + +#pragma GCC diagnostic push +#include #include "agg_rasterizer_scanline_aa.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/agg_render_marker.hpp mapnik-3.0.13+ds/include/mapnik/agg_render_marker.hpp --- mapnik-3.0.9+ds/include/mapnik/agg_render_marker.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/agg_render_marker.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,7 +30,8 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_color_rgba.h" #include "agg_renderer_base.h" #include "agg_renderer_scanline.h" @@ -43,6 +44,7 @@ #include "agg_pixfmt_rgba.h" #include "agg_span_image_filter_rgba.h" #include "agg_span_interpolator_linear.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/attribute.hpp mapnik-3.0.13+ds/include/mapnik/attribute.hpp --- mapnik-3.0.9+ds/include/mapnik/attribute.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/attribute.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -36,8 +36,8 @@ struct attribute { std::string name_; - explicit attribute(std::string const& name) - : name_(name) {} + explicit attribute(std::string const& _name) + : name_(_name) {} template V const& value(F const& f) const diff -Nru mapnik-3.0.9+ds/include/mapnik/box2d.hpp mapnik-3.0.13+ds/include/mapnik/box2d.hpp --- mapnik-3.0.9+ds/include/mapnik/box2d.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/box2d.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,8 +27,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // agg // forward declare so that apps using mapnik do not need agg headers @@ -38,9 +40,8 @@ namespace mapnik { -/*! - * A spatial envelope (i.e. bounding box) which also defines some basic operators. - */ +// A spatial envelope (i.e. bounding box) which also defines some basic operators. + template class MAPNIK_DECL box2d : boost::equality_comparable , boost::addable, @@ -48,7 +49,8 @@ boost::multipliable2, T > > > > { public: - using box2d_type = box2d; + using value_type = T; + using box2d_type = box2d; private: T minx_; T miny_; @@ -63,12 +65,22 @@ swap(lhs.maxy_, rhs.maxy_); } public: + box2d(); box2d(T minx,T miny,T maxx,T maxy); box2d(coord const& c0, coord const& c1); box2d(box2d_type const& rhs); box2d(box2d_type const& rhs, agg::trans_affine const& tr); + // move box2d(box2d_type&& rhs); + // converting ctor + template + explicit box2d(box2d other) + : minx_(static_cast(other.minx())), + miny_(static_cast(other.miny())), + maxx_(static_cast(other.maxx())), + maxy_(static_cast(other.maxy())) + {} box2d_type& operator=(box2d_type other); T minx() const; T miny() const; @@ -97,12 +109,14 @@ void re_center(T cx,T cy); void re_center(coord const& c); void init(T x0,T y0,T x1,T y1); + void init(T x, T y); void clip(box2d_type const& other); void pad(T padding); bool from_string(std::string const& str); bool valid() const; void move(T x, T y); std::string to_string() const; + T area() const; // define some operators box2d_type& operator+=(box2d_type const& other); diff -Nru mapnik-3.0.9+ds/include/mapnik/box2d_impl.hpp mapnik-3.0.13+ds/include/mapnik/box2d_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/box2d_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/box2d_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,501 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +// mapnik +#include +#include + +// stl +#include +#include +#include + +#include + +#pragma GCC diagnostic push +#include +#include +#include +#include +#pragma GCC diagnostic pop + +// agg +#include "agg_trans_affine.h" + +BOOST_FUSION_ADAPT_TPL_ADT( + (T), + (mapnik::box2d)(T), + (T, T, obj.minx(), obj.set_minx(mapnik::safe_cast(val))) + (T, T, obj.miny(), obj.set_miny(mapnik::safe_cast(val))) + (T, T, obj.maxx(), obj.set_maxx(mapnik::safe_cast(val))) + (T, T, obj.maxy(), obj.set_maxy(mapnik::safe_cast(val)))) + +namespace mapnik +{ +template +box2d::box2d() + :minx_( std::numeric_limits::max()), + miny_( std::numeric_limits::max()), + maxx_(-std::numeric_limits::max()), + maxy_(-std::numeric_limits::max()) {} + +template +box2d::box2d(T minx,T miny,T maxx,T maxy) +{ + init(minx,miny,maxx,maxy); +} + +template +box2d::box2d(coord const& c0, coord const& c1) +{ + init(c0.x,c0.y,c1.x,c1.y); +} + +template +box2d::box2d(box2d_type const& rhs) + : minx_(rhs.minx_), + miny_(rhs.miny_), + maxx_(rhs.maxx_), + maxy_(rhs.maxy_) {} + +template +box2d::box2d(box2d_type && rhs) + : minx_(std::move(rhs.minx_)), + miny_(std::move(rhs.miny_)), + maxx_(std::move(rhs.maxx_)), + maxy_(std::move(rhs.maxy_)) {} + +template +box2d& box2d::operator=(box2d_type other) +{ + swap(*this, other); + return *this; +} + +template +box2d::box2d(box2d_type const& rhs, agg::trans_affine const& tr) +{ + double x0 = rhs.minx_, y0 = rhs.miny_; + double x1 = rhs.maxx_, y1 = rhs.miny_; + double x2 = rhs.maxx_, y2 = rhs.maxy_; + double x3 = rhs.minx_, y3 = rhs.maxy_; + tr.transform(&x0, &y0); + tr.transform(&x1, &y1); + tr.transform(&x2, &y2); + tr.transform(&x3, &y3); + init(static_cast(x0), static_cast(y0), + static_cast(x2), static_cast(y2)); + expand_to_include(static_cast(x1), static_cast(y1)); + expand_to_include(static_cast(x3), static_cast(y3)); +} + +template +bool box2d::operator==(box2d const& other) const +{ + return minx_==other.minx_ && + miny_==other.miny_ && + maxx_==other.maxx_ && + maxy_==other.maxy_; +} + +template +T box2d::minx() const +{ + return minx_; +} + +template +T box2d::maxx() const +{ + return maxx_; +} + +template +T box2d::miny() const +{ + return miny_; +} + +template +T box2d::maxy() const +{ + return maxy_; +} + +template +void box2d::set_minx(T v) +{ + minx_ = v; +} + +template +void box2d::set_miny(T v) +{ + miny_ = v; +} + +template +void box2d::set_maxx(T v) +{ + maxx_ = v; +} + +template +void box2d::set_maxy(T v) +{ + maxy_ = v; +} + +template +T box2d::width() const +{ + return maxx_-minx_; +} + +template +T box2d::height() const +{ + return maxy_-miny_; +} + +template +void box2d::width(T w) +{ + T cx=center().x; + minx_=static_cast(cx-w*0.5); + maxx_=static_cast(cx+w*0.5); +} + +template +void box2d::height(T h) +{ + T cy=center().y; + miny_=static_cast(cy-h*0.5); + maxy_=static_cast(cy+h*0.5); +} + +template +coord box2d::center() const +{ + return coord(static_cast(0.5*(minx_+maxx_)), + static_cast(0.5*(miny_+maxy_))); +} + +template +void box2d::expand_to_include(coord const& c) +{ + expand_to_include(c.x,c.y); +} + +template +void box2d::expand_to_include(T x,T y) +{ + if (xmaxx_) maxx_=x; + if (ymaxy_) maxy_=y; +} + +template +void box2d::expand_to_include(box2d const& other) +{ + if (other.minx_maxx_) maxx_=other.maxx_; + if (other.miny_maxy_) maxy_=other.maxy_; +} + +template +bool box2d::contains(coord const& c) const +{ + return contains(c.x,c.y); +} + +template +bool box2d::contains(T x,T y) const +{ + return x>=minx_ && x<=maxx_ && y>=miny_ && y<=maxy_; +} + +template +bool box2d::contains(box2d const& other) const +{ + return other.minx_>=minx_ && + other.maxx_<=maxx_ && + other.miny_>=miny_ && + other.maxy_<=maxy_; +} + +template +bool box2d::intersects(coord const& c) const +{ + return intersects(c.x,c.y); +} + +template +bool box2d::intersects(T x,T y) const +{ + return !(x>maxx_ || xmaxy_ || y +bool box2d::intersects(box2d const& other) const +{ + return !(other.minx_>maxx_ || other.maxx_maxy_ || other.maxy_ +box2d box2d::intersect(box2d_type const& other) const +{ + if (intersects(other)) + { + T x0=std::max(minx_,other.minx_); + T y0=std::max(miny_,other.miny_); + T x1=std::min(maxx_,other.maxx_); + T y1=std::min(maxy_,other.maxy_); + return box2d(x0,y0,x1,y1); + } + else + { + return box2d(); + } +} + +template +void box2d::re_center(T cx,T cy) +{ + T dx=cx-center().x; + T dy=cy-center().y; + minx_+=dx; + miny_+=dy; + maxx_+=dx; + maxy_+=dy; +} + +template +void box2d::re_center(coord const& c) +{ + re_center(c.x,c.y); +} + +template +void box2d::init(T x0, T y0, T x1, T y1) +{ + if (x0 < x1) + { + minx_ = x0; + maxx_ = x1; + } + else + { + minx_ = x1; + maxx_ = x0; + } + if (y0 < y1) + { + miny_ = y0; + maxy_ = y1; + } + else + { + miny_ = y1; + maxy_ = y0; + } +} + +template +void box2d::init(T x, T y) +{ + init(x, y, x, y); +} + +template +void box2d::clip(box2d_type const& other) +{ + minx_ = std::max(minx_, other.minx()); + miny_ = std::max(miny_, other.miny()); + maxx_ = std::min(maxx_, other.maxx()); + maxy_ = std::min(maxy_, other.maxy()); +} + +template +void box2d::pad(T padding) +{ + minx_ -= padding; + miny_ -= padding; + maxx_ += padding; + maxy_ += padding; +} + +template +bool box2d::from_string(std::string const& str) +{ + boost::spirit::qi::lit_type lit; + boost::spirit::qi::double_type double_; + boost::spirit::ascii::space_type space; + bool r = boost::spirit::qi::phrase_parse(str.begin(), + str.end(), + double_ >> -lit(',') >> double_ >> -lit(',') >> double_ >> -lit(',') >> double_, + space, + *this); + return r; +} + +template +bool box2d::valid() const +{ + return (minx_ <= maxx_ && miny_ <= maxy_) ; +} + +template +void box2d::move(T x, T y) +{ + minx_ += x; + maxx_ += x; + miny_ += y; + maxy_ += y; +} + +template +std::string box2d::to_string() const +{ + std::ostringstream s; + if (valid()) + { + s << "box2d(" << std::fixed << std::setprecision(16) + << minx_ << ',' << miny_ << ',' + << maxx_ << ',' << maxy_ << ')'; + } + else + { + s << "box2d(INVALID)"; + } + return s.str(); +} + +template +T box2d::area() const +{ + return width() * height(); +} + +template +box2d& box2d::operator+=(box2d const& other) +{ + expand_to_include(other); + return *this; +} + +template +box2d box2d::operator+ (T other) const +{ + return box2d(minx_ - other, miny_ - other, maxx_ + other, maxy_ + other); +} + +template +box2d& box2d::operator+= (T other) +{ + minx_ -= other; + miny_ -= other; + maxx_ += other; + maxy_ += other; + return *this; +} + + +template +box2d& box2d::operator*=(T t) +{ + coord c = center(); + T sx = static_cast(0.5 * width() * t); + T sy = static_cast(0.5 * height() * t); + minx_ = c.x - sx; + maxx_ = c.x + sx; + miny_ = c.y - sy; + maxy_ = c.y + sy; + return *this; +} + +template +box2d& box2d::operator/=(T t) +{ + coord c = center(); + T sx = static_cast(0.5 * width() / t); + T sy = static_cast(0.5 * height() / t); + minx_ = c.x - sx; + maxx_ = c.x + sx; + miny_ = c.y - sy; + maxy_ = c.y + sy; + return *this; +} + +template +T box2d::operator[] (int index) const +{ + switch(index) + { + case 0: + return minx_; + case 1: + return miny_; + case 2: + return maxx_; + case 3: + return maxy_; + case -4: + return minx_; + case -3: + return miny_; + case -2: + return maxx_; + case -1: + return maxy_; + default: + throw std::out_of_range(std::string("index out of range, max value is 3, min value is -4 ")); + } +} + +template +box2d box2d::operator*(agg::trans_affine const& tr) const +{ + return box2d(*this, tr); +} + +template +box2d& box2d::operator*=(agg::trans_affine const& tr) +{ + double x0 = minx_, y0 = miny_; + double x1 = maxx_, y1 = miny_; + double x2 = maxx_, y2 = maxy_; + double x3 = minx_, y3 = maxy_; + tr.transform(&x0, &y0); + tr.transform(&x1, &y1); + tr.transform(&x2, &y2); + tr.transform(&x3, &y3); + init(static_cast(x0), static_cast(y0), + static_cast(x2), static_cast(y2)); + expand_to_include(static_cast(x1), static_cast(y1)); + expand_to_include(static_cast(x3), static_cast(y3)); + return *this; +} +} diff -Nru mapnik-3.0.9+ds/include/mapnik/cairo/cairo_context.hpp mapnik-3.0.13+ds/include/mapnik/cairo/cairo_context.hpp --- mapnik-3.0.9+ds/include/mapnik/cairo/cairo_context.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/cairo/cairo_context.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -38,18 +38,20 @@ #include #include -// stl -#include - -// cairo +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl +#include #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_basics.h" +#pragma GCC diagnostic pop namespace mapnik { @@ -306,6 +308,7 @@ void stroke(); void fill(); void paint(); + void paint(double opacity); void set_pattern(cairo_pattern const& pattern); void set_gradient(cairo_gradient const& pattern, box2d const& bbox); void add_image(double x, double y, image_rgba8 const& data, double opacity = 1.0); @@ -325,6 +328,9 @@ composite_mode_e halo_comp_op = src_over, double scale_factor = 1.0); + void push_group(); + void pop_group(); + template void add_path(T& path, unsigned start_index = 0) { diff -Nru mapnik-3.0.9+ds/include/mapnik/cairo/cairo_renderer.hpp mapnik-3.0.13+ds/include/mapnik/cairo/cairo_renderer.hpp --- mapnik-3.0.9+ds/include/mapnik/cairo/cairo_renderer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/cairo/cairo_renderer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -177,6 +177,7 @@ cairo_context context_; renderer_common common_; cairo_face_manager face_manager_; + bool style_level_compositing_; void setup(Map const& m); }; diff -Nru mapnik-3.0.9+ds/include/mapnik/color.hpp mapnik-3.0.13+ds/include/mapnik/color.hpp --- mapnik-3.0.9+ds/include/mapnik/color.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/color.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,8 +27,10 @@ #include #include -//boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl #include @@ -55,19 +57,19 @@ premultiplied_(false) {} - color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, std::uint8_t alpha = 0xff, bool premultiplied = false) - : red_(red), - green_(green), - blue_(blue), - alpha_(alpha), + color(std::uint8_t _red, std::uint8_t _green, std::uint8_t _blue, std::uint8_t _alpha = 0xff, bool premultiplied = false) + : red_(_red), + green_(_green), + blue_(_blue), + alpha_(_alpha), premultiplied_(premultiplied) {} - color(std::uint32_t rgba, bool premultiplied = false) - : red_(rgba & 0xff), - green_((rgba >> 8) & 0xff), - blue_((rgba >> 16) & 0xff), - alpha_((rgba >> 24) & 0xff), + color(std::uint32_t _rgba, bool premultiplied = false) + : red_(_rgba & 0xff), + green_((_rgba >> 8) & 0xff), + blue_((_rgba >> 16) & 0xff), + alpha_((_rgba >> 24) & 0xff), premultiplied_(premultiplied) {} // copy ctor @@ -128,23 +130,23 @@ return alpha_; } - inline void set_red(std::uint8_t red) + inline void set_red(std::uint8_t _red) { - red_ = red; + red_ = _red; } - inline void set_green(std::uint8_t green) + inline void set_green(std::uint8_t _green) { - green_ = green; + green_ = _green; } - inline void set_blue(std::uint8_t blue) + inline void set_blue(std::uint8_t _blue) { - blue_ = blue; + blue_ = _blue; } - inline void set_alpha(std::uint8_t alpha) + inline void set_alpha(std::uint8_t _alpha) { - alpha_ = alpha; + alpha_ = _alpha; } inline bool get_premultiplied() const { @@ -173,8 +175,7 @@ std::basic_ostream & operator << ( std::basic_ostream & s, mapnik::color const& c ) { - std::string hex_string( c.to_string() ); - s << hex_string; + s << c.to_string(); return s; } diff -Nru mapnik-3.0.9+ds/include/mapnik/config.hpp mapnik-3.0.13+ds/include/mapnik/config.hpp --- mapnik-3.0.9+ds/include/mapnik/config.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/config.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -52,7 +52,4 @@ #define PROJ_ENVELOPE_POINTS 20 -#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS -#define BOOST_MPL_LIMIT_VECTOR_SIZE 30 - #endif // MAPNIK_CONFIG_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/coord.hpp mapnik-3.0.13+ds/include/mapnik/coord.hpp --- mapnik-3.0.9+ds/include/mapnik/coord.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/coord.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,8 +23,10 @@ #ifndef MAPNIK_COORD_HPP #define MAPNIK_COORD_HPP -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { template diff -Nru mapnik-3.0.9+ds/include/mapnik/css_color_grammar.hpp mapnik-3.0.13+ds/include/mapnik/css_color_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/css_color_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/css_color_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -32,261 +32,25 @@ #pragma GCC diagnostic push #include #include -#include -#include -#include -#include -#include -#include -#include #pragma GCC diagnostic pop // stl #include -BOOST_FUSION_ADAPT_ADT( - mapnik::color, - (unsigned, unsigned, obj.red(), obj.set_red(mapnik::safe_cast(val))) - (unsigned, unsigned, obj.green(), obj.set_green(mapnik::safe_cast(val))) - (unsigned, unsigned, obj.blue(), obj.set_blue(mapnik::safe_cast(val))) - (unsigned, unsigned, obj.alpha(), obj.set_alpha(mapnik::safe_cast(val))) - ) - namespace mapnik { namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; -namespace phoenix = boost::phoenix; using ascii_space_type = boost::spirit::ascii::space_type; -struct named_colors_ : qi::symbols -{ - named_colors_() - { - add - ("aliceblue", color(240, 248, 255)) - ("antiquewhite", color(250, 235, 215)) - ("aqua", color(0, 255, 255)) - ("aquamarine", color(127, 255, 212)) - ("azure", color(240, 255, 255)) - ("beige", color(245, 245, 220)) - ("bisque", color(255, 228, 196)) - ("black", color(0, 0, 0)) - ("blanchedalmond", color(255,235,205)) - ("blue", color(0, 0, 255)) - ("blueviolet", color(138, 43, 226)) - ("brown", color(165, 42, 42)) - ("burlywood", color(222, 184, 135)) - ("cadetblue", color(95, 158, 160)) - ("chartreuse", color(127, 255, 0)) - ("chocolate", color(210, 105, 30)) - ("coral", color(255, 127, 80)) - ("cornflowerblue", color(100, 149, 237)) - ("cornsilk", color(255, 248, 220)) - ("crimson", color(220, 20, 60)) - ("cyan", color(0, 255, 255)) - ("darkblue", color(0, 0, 139)) - ("darkcyan", color(0, 139, 139)) - ("darkgoldenrod", color(184, 134, 11)) - ("darkgray", color(169, 169, 169)) - ("darkgreen", color(0, 100, 0)) - ("darkgrey", color(169, 169, 169)) - ("darkkhaki", color(189, 183, 107)) - ("darkmagenta", color(139, 0, 139)) - ("darkolivegreen", color(85, 107, 47)) - ("darkorange", color(255, 140, 0)) - ("darkorchid", color(153, 50, 204)) - ("darkred", color(139, 0, 0)) - ("darksalmon", color(233, 150, 122)) - ("darkseagreen", color(143, 188, 143)) - ("darkslateblue", color(72, 61, 139)) - ("darkslategrey", color(47, 79, 79)) - ("darkturquoise", color(0, 206, 209)) - ("darkviolet", color(148, 0, 211)) - ("deeppink", color(255, 20, 147)) - ("deepskyblue", color(0, 191, 255)) - ("dimgray", color(105, 105, 105)) - ("dimgrey", color(105, 105, 105)) - ("dodgerblue", color(30, 144, 255)) - ("firebrick", color(178, 34, 34)) - ("floralwhite", color(255, 250, 240)) - ("forestgreen", color(34, 139, 34)) - ("fuchsia", color(255, 0, 255)) - ("gainsboro", color(220, 220, 220)) - ("ghostwhite", color(248, 248, 255)) - ("gold", color(255, 215, 0)) - ("goldenrod", color(218, 165, 32)) - ("gray", color(128, 128, 128)) - ("grey", color(128, 128, 128)) - ("green", color(0, 128, 0)) - ("greenyellow", color(173, 255, 47)) - ("honeydew", color(240, 255, 240)) - ("hotpink", color(255, 105, 180)) - ("indianred", color(205, 92, 92)) - ("indigo", color(75, 0, 130)) - ("ivory", color(255, 255, 240)) - ("khaki", color(240, 230, 140)) - ("lavender", color(230, 230, 250)) - ("lavenderblush", color(255, 240, 245)) - ("lawngreen", color(124, 252, 0)) - ("lemonchiffon", color(255, 250, 205)) - ("lightblue", color(173, 216, 230)) - ("lightcoral", color(240, 128, 128)) - ("lightcyan", color(224, 255, 255)) - ("lightgoldenrodyellow", color(250, 250, 210)) - ("lightgray", color(211, 211, 211)) - ("lightgreen", color(144, 238, 144)) - ("lightgrey", color(211, 211, 211)) - ("lightpink", color(255, 182, 193)) - ("lightsalmon", color(255, 160, 122)) - ("lightseagreen", color(32, 178, 170)) - ("lightskyblue", color(135, 206, 250)) - ("lightslategray", color(119, 136, 153)) - ("lightslategrey", color(119, 136, 153)) - ("lightsteelblue", color(176, 196, 222)) - ("lightyellow", color(255, 255, 224)) - ("lime", color(0, 255, 0)) - ("limegreen", color(50, 205, 50)) - ("linen", color(250, 240, 230)) - ("magenta", color(255, 0, 255)) - ("maroon", color(128, 0, 0)) - ("mediumaquamarine", color(102, 205, 170)) - ("mediumblue", color(0, 0, 205)) - ("mediumorchid", color(186, 85, 211)) - ("mediumpurple", color(147, 112, 219)) - ("mediumseagreen", color(60, 179, 113)) - ("mediumslateblue", color(123, 104, 238)) - ("mediumspringgreen", color(0, 250, 154)) - ("mediumturquoise", color(72, 209, 204)) - ("mediumvioletred", color(199, 21, 133)) - ("midnightblue", color(25, 25, 112)) - ("mintcream", color(245, 255, 250)) - ("mistyrose", color(255, 228, 225)) - ("moccasin", color(255, 228, 181)) - ("navajowhite", color(255, 222, 173)) - ("navy", color(0, 0, 128)) - ("oldlace", color(253, 245, 230)) - ("olive", color(128, 128, 0)) - ("olivedrab", color(107, 142, 35)) - ("orange", color(255, 165, 0)) - ("orangered", color(255, 69, 0)) - ("orchid", color(218, 112, 214)) - ("palegoldenrod", color(238, 232, 170)) - ("palegreen", color(152, 251, 152)) - ("paleturquoise", color(175, 238, 238)) - ("palevioletred", color(219, 112, 147)) - ("papayawhip", color(255, 239, 213)) - ("peachpuff", color(255, 218, 185)) - ("peru", color(205, 133, 63)) - ("pink", color(255, 192, 203)) - ("plum", color(221, 160, 221)) - ("powderblue", color(176, 224, 230)) - ("purple", color(128, 0, 128)) - ("red", color(255, 0, 0)) - ("rosybrown", color(188, 143, 143)) - ("royalblue", color(65, 105, 225)) - ("saddlebrown", color(139, 69, 19)) - ("salmon", color(250, 128, 114)) - ("sandybrown", color(244, 164, 96)) - ("seagreen", color(46, 139, 87)) - ("seashell", color(255, 245, 238)) - ("sienna", color(160, 82, 45)) - ("silver", color(192, 192, 192)) - ("skyblue", color(135, 206, 235)) - ("slateblue", color(106, 90, 205)) - ("slategray", color(112, 128, 144)) - ("slategrey", color(112, 128, 144)) - ("snow", color(255, 250, 250)) - ("springgreen", color(0, 255, 127)) - ("steelblue", color(70, 130, 180)) - ("tan", color(210, 180, 140)) - ("teal", color(0, 128, 128)) - ("thistle", color(216, 191, 216)) - ("tomato", color(255, 99, 71)) - ("turquoise", color(64, 224, 208)) - ("violet", color(238, 130, 238)) - ("wheat", color(245, 222, 179)) - ("white", color(255, 255, 255)) - ("whitesmoke", color(245, 245, 245)) - ("yellow", color(255, 255, 0)) - ("yellowgreen", color(154, 205, 50)) - ("transparent", color(0, 0, 0, 0)) - ; - } -} ; - -struct percent_conv_impl -{ - template - struct result - { - using type = unsigned; - }; - - unsigned operator() (double val) const - { - return safe_cast(std::lround((255.0 * val)/100.0)); - } -}; - -struct alpha_conv_impl -{ - template - struct result - { - using type = unsigned; - }; - - unsigned operator() (double val) const - { - return safe_cast(std::lround((255.0 * val))); - } -}; - -struct hsl_conv_impl -{ - template - struct result - { - using type = void; - }; - - template - void operator() (T0 & c, T1 h, T2 s, T3 l) const - { - double m1,m2; - // normalize values - h /= 360.0; - s /= 100.0; - l /= 100.0; - - if (l <= 0.5) - { - m2 = l * (s + 1.0); - } - else - { - m2 = l + s - l*s; - } - m1 = l * 2 - m2; - - double r = hue_to_rgb(m1, m2, h + 1.0/3.0); - double g = hue_to_rgb(m1, m2, h); - double b = hue_to_rgb(m1, m2, h - 1.0/3.0); - - c.set_red(safe_cast(std::lround(255.0 * r))); - c.set_green(safe_cast(std::lround(255.0 * g))); - c.set_blue(safe_cast(std::lround(255.0 * b))); - } -}; - - template struct css_color_grammar : qi::grammar { + // ctor css_color_grammar(); + // rules qi::uint_parser< unsigned, 16, 2, 2 > hex2 ; qi::uint_parser< unsigned, 16, 1, 1 > hex1 ; qi::uint_parser< unsigned, 10, 1, 3 > dec3 ; @@ -296,10 +60,6 @@ qi::rule hex_color; qi::rule hex_color_small; qi::rule css_color; - named_colors_ named; - phoenix::function percent_converter; - phoenix::function alpha_converter; - phoenix::function hsl_converter; }; } diff -Nru mapnik-3.0.9+ds/include/mapnik/css_color_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/css_color_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/css_color_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/css_color_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -22,10 +22,234 @@ // NOTE: This is an implementation header file and is only meant to be included // from implementation files. It therefore doesn't have an include guard. +// mapnik #include +// boost +#pragma GCC diagnostic push +#include +#include +#include +#include +#pragma GCC diagnostic pop + + +BOOST_FUSION_ADAPT_ADT( + mapnik::color, + (unsigned, unsigned, obj.red(), obj.set_red(mapnik::safe_cast(val))) + (unsigned, unsigned, obj.green(), obj.set_green(mapnik::safe_cast(val))) + (unsigned, unsigned, obj.blue(), obj.set_blue(mapnik::safe_cast(val))) + (unsigned, unsigned, obj.alpha(), obj.set_alpha(mapnik::safe_cast(val))) + ) namespace mapnik { +namespace phoenix = boost::phoenix; + +struct percent_conv_impl +{ + using result_type = unsigned; + unsigned operator() (double val) const + { + return safe_cast(std::lround((255.0 * val)/100.0)); + } +}; + +struct alpha_conv_impl +{ + using result_type = unsigned; + unsigned operator() (double val) const + { + return safe_cast(std::lround((255.0 * val))); + } +}; + +struct hsl_conv_impl +{ + using result_type = void; + template + void operator() (T0 & c, T1 h, T2 s, T3 l) const + { + double m1,m2; + // normalize values + h /= 360.0; + s /= 100.0; + l /= 100.0; + + if (l <= 0.5) + { + m2 = l * (s + 1.0); + } + else + { + m2 = l + s - l*s; + } + m1 = l * 2 - m2; + + double r = hue_to_rgb(m1, m2, h + 1.0/3.0); + double g = hue_to_rgb(m1, m2, h); + double b = hue_to_rgb(m1, m2, h - 1.0/3.0); + + c.set_red(safe_cast(std::lround(255.0 * r))); + c.set_green(safe_cast(std::lround(255.0 * g))); + c.set_blue(safe_cast(std::lround(255.0 * b))); + } +}; + +struct named_colors : qi::symbols +{ + named_colors() + { + add + ("aliceblue", color(240, 248, 255)) + ("antiquewhite", color(250, 235, 215)) + ("aqua", color(0, 255, 255)) + ("aquamarine", color(127, 255, 212)) + ("azure", color(240, 255, 255)) + ("beige", color(245, 245, 220)) + ("bisque", color(255, 228, 196)) + ("black", color(0, 0, 0)) + ("blanchedalmond", color(255,235,205)) + ("blue", color(0, 0, 255)) + ("blueviolet", color(138, 43, 226)) + ("brown", color(165, 42, 42)) + ("burlywood", color(222, 184, 135)) + ("cadetblue", color(95, 158, 160)) + ("chartreuse", color(127, 255, 0)) + ("chocolate", color(210, 105, 30)) + ("coral", color(255, 127, 80)) + ("cornflowerblue", color(100, 149, 237)) + ("cornsilk", color(255, 248, 220)) + ("crimson", color(220, 20, 60)) + ("cyan", color(0, 255, 255)) + ("darkblue", color(0, 0, 139)) + ("darkcyan", color(0, 139, 139)) + ("darkgoldenrod", color(184, 134, 11)) + ("darkgray", color(169, 169, 169)) + ("darkgreen", color(0, 100, 0)) + ("darkgrey", color(169, 169, 169)) + ("darkkhaki", color(189, 183, 107)) + ("darkmagenta", color(139, 0, 139)) + ("darkolivegreen", color(85, 107, 47)) + ("darkorange", color(255, 140, 0)) + ("darkorchid", color(153, 50, 204)) + ("darkred", color(139, 0, 0)) + ("darksalmon", color(233, 150, 122)) + ("darkseagreen", color(143, 188, 143)) + ("darkslateblue", color(72, 61, 139)) + ("darkslategrey", color(47, 79, 79)) + ("darkturquoise", color(0, 206, 209)) + ("darkviolet", color(148, 0, 211)) + ("deeppink", color(255, 20, 147)) + ("deepskyblue", color(0, 191, 255)) + ("dimgray", color(105, 105, 105)) + ("dimgrey", color(105, 105, 105)) + ("dodgerblue", color(30, 144, 255)) + ("firebrick", color(178, 34, 34)) + ("floralwhite", color(255, 250, 240)) + ("forestgreen", color(34, 139, 34)) + ("fuchsia", color(255, 0, 255)) + ("gainsboro", color(220, 220, 220)) + ("ghostwhite", color(248, 248, 255)) + ("gold", color(255, 215, 0)) + ("goldenrod", color(218, 165, 32)) + ("gray", color(128, 128, 128)) + ("grey", color(128, 128, 128)) + ("green", color(0, 128, 0)) + ("greenyellow", color(173, 255, 47)) + ("honeydew", color(240, 255, 240)) + ("hotpink", color(255, 105, 180)) + ("indianred", color(205, 92, 92)) + ("indigo", color(75, 0, 130)) + ("ivory", color(255, 255, 240)) + ("khaki", color(240, 230, 140)) + ("lavender", color(230, 230, 250)) + ("lavenderblush", color(255, 240, 245)) + ("lawngreen", color(124, 252, 0)) + ("lemonchiffon", color(255, 250, 205)) + ("lightblue", color(173, 216, 230)) + ("lightcoral", color(240, 128, 128)) + ("lightcyan", color(224, 255, 255)) + ("lightgoldenrodyellow", color(250, 250, 210)) + ("lightgray", color(211, 211, 211)) + ("lightgreen", color(144, 238, 144)) + ("lightgrey", color(211, 211, 211)) + ("lightpink", color(255, 182, 193)) + ("lightsalmon", color(255, 160, 122)) + ("lightseagreen", color(32, 178, 170)) + ("lightskyblue", color(135, 206, 250)) + ("lightslategray", color(119, 136, 153)) + ("lightslategrey", color(119, 136, 153)) + ("lightsteelblue", color(176, 196, 222)) + ("lightyellow", color(255, 255, 224)) + ("lime", color(0, 255, 0)) + ("limegreen", color(50, 205, 50)) + ("linen", color(250, 240, 230)) + ("magenta", color(255, 0, 255)) + ("maroon", color(128, 0, 0)) + ("mediumaquamarine", color(102, 205, 170)) + ("mediumblue", color(0, 0, 205)) + ("mediumorchid", color(186, 85, 211)) + ("mediumpurple", color(147, 112, 219)) + ("mediumseagreen", color(60, 179, 113)) + ("mediumslateblue", color(123, 104, 238)) + ("mediumspringgreen", color(0, 250, 154)) + ("mediumturquoise", color(72, 209, 204)) + ("mediumvioletred", color(199, 21, 133)) + ("midnightblue", color(25, 25, 112)) + ("mintcream", color(245, 255, 250)) + ("mistyrose", color(255, 228, 225)) + ("moccasin", color(255, 228, 181)) + ("navajowhite", color(255, 222, 173)) + ("navy", color(0, 0, 128)) + ("oldlace", color(253, 245, 230)) + ("olive", color(128, 128, 0)) + ("olivedrab", color(107, 142, 35)) + ("orange", color(255, 165, 0)) + ("orangered", color(255, 69, 0)) + ("orchid", color(218, 112, 214)) + ("palegoldenrod", color(238, 232, 170)) + ("palegreen", color(152, 251, 152)) + ("paleturquoise", color(175, 238, 238)) + ("palevioletred", color(219, 112, 147)) + ("papayawhip", color(255, 239, 213)) + ("peachpuff", color(255, 218, 185)) + ("peru", color(205, 133, 63)) + ("pink", color(255, 192, 203)) + ("plum", color(221, 160, 221)) + ("powderblue", color(176, 224, 230)) + ("purple", color(128, 0, 128)) + ("red", color(255, 0, 0)) + ("rosybrown", color(188, 143, 143)) + ("royalblue", color(65, 105, 225)) + ("saddlebrown", color(139, 69, 19)) + ("salmon", color(250, 128, 114)) + ("sandybrown", color(244, 164, 96)) + ("seagreen", color(46, 139, 87)) + ("seashell", color(255, 245, 238)) + ("sienna", color(160, 82, 45)) + ("silver", color(192, 192, 192)) + ("skyblue", color(135, 206, 235)) + ("slateblue", color(106, 90, 205)) + ("slategray", color(112, 128, 144)) + ("slategrey", color(112, 128, 144)) + ("snow", color(255, 250, 250)) + ("springgreen", color(0, 255, 127)) + ("steelblue", color(70, 130, 180)) + ("tan", color(210, 180, 140)) + ("teal", color(0, 128, 128)) + ("thistle", color(216, 191, 216)) + ("tomato", color(255, 99, 71)) + ("turquoise", color(64, 224, 208)) + ("violet", color(238, 130, 238)) + ("wheat", color(245, 222, 179)) + ("white", color(255, 255, 255)) + ("whitesmoke", color(245, 245, 245)) + ("yellow", color(255, 255, 0)) + ("yellowgreen", color(154, 205, 50)) + ("transparent", color(0, 0, 0, 0)) + ; + } +}; template css_color_grammar::css_color_grammar() @@ -42,6 +266,12 @@ qi::lexeme_type lexeme; ascii::no_case_type no_case; using phoenix::at_c; + // symbols + named_colors named; + // functions + phoenix::function percent_converter; + phoenix::function alpha_converter; + phoenix::function hsl_converter; css_color %= rgba_color | rgba_percent_color diff -Nru mapnik-3.0.9+ds/include/mapnik/csv/csv_grammar.hpp mapnik-3.0.13+ds/include/mapnik/csv/csv_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/csv/csv_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/csv/csv_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -20,80 +20,60 @@ * *****************************************************************************/ -#ifndef MAPNIK_CVS_GRAMMAR_HPP -#define MAPNIK_CVS_GRAMMAR_HPP - -//#define BOOST_SPIRIT_DEBUG +#ifndef MAPNIK_CSV_GRAMMAR_HPP +#define MAPNIK_CSV_GRAMMAR_HPP +#include #include -#include namespace mapnik { namespace qi = boost::spirit::qi; -using csv_value = std::string; -using csv_line = std::vector; -using csv_data = std::vector; -template -struct csv_white_space_skipper : qi::grammar +struct csv_white_space_skipper : qi::primitive_parser { - csv_white_space_skipper() - : csv_white_space_skipper::base_type(skip) + template + struct attribute + { + typedef qi::unused_type type; + }; + + template + bool parse(Iterator& first, Iterator const& last + , Context& /*context*/, Skipper const& skipper + , Attribute& /*attr*/) const { - using namespace qi; - qi::lit_type lit; - skip = +lit(' ') - ; + qi::skip_over(first, last, skipper); + if (first != last && *first == ' ') + { + while (++first != last && *first == ' ') + ; + return true; + } + return false; + } + + template + qi::info what(Context& /*context*/) const + { + return qi::info("csv_white_space_skipper"); } - qi::rule skip; }; -template > + +template struct csv_line_grammar : qi::grammar { - csv_line_grammar() - : csv_line_grammar::base_type(line) - { - using namespace qi; - qi::_a_type _a; - qi::_r1_type _r1; - qi::_r2_type _r2; - qi::lit_type lit; - qi::_1_type _1; - qi::char_type char_; - qi::omit_type omit; - unesc_char.add - ("\\a", '\a') - ("\\b", '\b') - ("\\f", '\f') - ("\\n", '\n') - ("\\r", '\r') - ("\\t", '\t') - ("\\v", '\v') - ("\\\\",'\\') - ("\\\'", '\'') - ("\\\"", '\"') - ("\"\"", '\"') // double quote - ; - line = -omit[char_("\n\r")] >> column(_r1, _r2) % lit(_r1) - ; - column = quoted(_r2) | *(char_ - (lit(_r1))) - ; - quoted = omit[char_(_r1)[_a = _1]] > text(_a) > -lit(_a) // support unmatched quotes or not (??) - ; - text = *(unesc_char | (char_ - lit(_r1))) - ; - BOOST_SPIRIT_DEBUG_NODES((line)(column)(quoted)); - } + csv_line_grammar(); private: qi::rule line; qi::rule column; // no-skip qi::rule text; // no-skip - qi::rule, csv_value(char)> quoted; //no-skip + qi::rule quoted; // no-skip qi::symbols unesc_char; }; } -#endif // MAPNIK_CVS_GRAMMAR_HPP +#endif // MAPNIK_CSV_GRAMMAR_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/csv/csv_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/csv/csv_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/csv/csv_grammar_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/csv/csv_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,61 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + +namespace mapnik { + +namespace qi = boost::spirit::qi; + +template +csv_line_grammar::csv_line_grammar() + : csv_line_grammar::base_type(line) +{ + qi::_r1_type _r1; + qi::_r2_type _r2; + qi::lit_type lit; + qi::char_type char_; + unesc_char.add + ("\\a", '\a') + ("\\b", '\b') + ("\\f", '\f') + ("\\n", '\n') + ("\\r", '\r') + ("\\t", '\t') + ("\\v", '\v') + ("\\\\",'\\') + ("\\\'", '\'') + ("\\\"", '\"') + ("\"\"", '\"') // double quote + ; + line = -lit("\r") > -lit("\n") > column(_r1, _r2) % lit(_r1) + ; + column = quoted(_r2) | *(char_ - lit(_r1)) + ; + quoted = lit(_r1) > text(_r1) > lit(_r1) // support unmatched quotes or not (??) + ; + text = *(unesc_char | (char_ - lit(_r1))) + ; + BOOST_SPIRIT_DEBUG_NODES((line)(column)(quoted)); +} + +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/include/mapnik/csv/csv_types.hpp mapnik-3.0.13+ds/include/mapnik/csv/csv_types.hpp --- mapnik-3.0.9+ds/include/mapnik/csv/csv_types.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/csv/csv_types.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,37 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_CSV_TYPES_HPP +#define MAPNIK_CSV_TYPES_HPP + +#include +#include + +namespace mapnik { + +using csv_value = std::string; +using csv_line = std::vector; +using csv_data = std::vector; + +} + +#endif // MAPNIK_CSV_TYPES_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/cxx11_support.hpp mapnik-3.0.13+ds/include/mapnik/cxx11_support.hpp --- mapnik-3.0.9+ds/include/mapnik/cxx11_support.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/cxx11_support.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,43 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_CXX11_SUPPORT_HPP +#define MAPNIK_CXX11_SUPPORT_HPP + +#include + +namespace mapnik { +namespace detail { + +template +using conditional_t = typename std::conditional::type; + +template +using decay_t = typename std::decay::type; + +template +using enable_if_t = typename std::enable_if::type; + +} // namespace detail +} // namespace mapnik + +#endif // MAPNIK_CXX11_SUPPORT_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/debug.hpp mapnik-3.0.13+ds/include/mapnik/debug.hpp --- mapnik-3.0.9+ds/include/mapnik/debug.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/debug.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -69,15 +69,15 @@ static void set_severity(severity_type severity_level) { -//#ifdef MAPNIK_THREADSAFE -// std::lock_guard lock(severity_mutex_); -//#endif severity_level_ = severity_level; } // per object security levels static severity_type get_object_severity(std::string const& object_name) { +#ifdef MAPNIK_THREADSAFE + std::lock_guard lock(severity_mutex_); +#endif severity_map::iterator it = object_severity_level_.find(object_name); if (object_name.empty() || it == object_severity_level_.end()) { diff -Nru mapnik-3.0.9+ds/include/mapnik/enumeration.hpp mapnik-3.0.13+ds/include/mapnik/enumeration.hpp --- mapnik-3.0.9+ds/include/mapnik/enumeration.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/enumeration.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,7 +28,6 @@ #include // stl -#include #include #include #include @@ -41,8 +40,8 @@ illegal_enum_value(): what_() {} - illegal_enum_value( std::string const& what ) : - what_( what ) + illegal_enum_value( std::string const& _what ) : + what_( _what ) { } virtual ~illegal_enum_value() throw() {} @@ -59,9 +58,9 @@ /** Slim wrapper for enumerations. It creates a new type from a native enum and * a char pointer array. It almost exactly behaves like a native enumeration - * type. It supports string conversion through stream operators. This is usefull + * type. It supports string conversion through stream operators. This is useful * for debugging, serialization/deserialization and also helps with implementing - * language bindings. The two convinient macros DEFINE_ENUM() and IMPLEMENT_ENUM() + * language bindings. The two convenient macros DEFINE_ENUM() and IMPLEMENT_ENUM() * are provided to help with instanciation. * * @par Limitations: @@ -189,7 +188,12 @@ } for (unsigned i = 0; i < THE_MAX; ++i) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc +#pragma GCC diagnostic ignored "-Wpragmas" // gcc +#pragma GCC diagnostic ignored "-Wundefined-var-template" if (str_copy == our_strings_[i]) +#pragma GCC diagnostic pop { value_ = static_cast(i); if (deprecated) @@ -199,59 +203,24 @@ return; } } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc +#pragma GCC diagnostic ignored "-Wpragmas" // gcc +#pragma GCC diagnostic ignored "-Wundefined-var-template" throw illegal_enum_value(std::string("Illegal enumeration value '") + str + "' for enum " + our_name_); - } - - /** Parses the input stream @p is for a word consisting of characters and - * digits (a-z, A-Z, 0-9) and underscores (_). - * The failbit of the stream is set if the word is not a valid identifier. - */ - std::istream & parse(std::istream & is) - { - std::string word; - char c; - - while ( is.peek() != std::char_traits< char >::eof()) - { - is >> c; - if ( isspace(c) && word.empty() ) - { - continue; - } - if ( isalnum(c) || (c == '_') || c == '-' ) - { - word += c; - } - else - { - is.unget(); - break; - } - } - - try - { - from_string( word ); - } - catch (illegal_enum_value const&) - { - is.setstate(std::ios::failbit); - } - - return is; +#pragma GCC diagnostic pop } /** Returns the current value as a string identifier. */ std::string as_string() const { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc +#pragma GCC diagnostic ignored "-Wpragmas" // gcc +#pragma GCC diagnostic ignored "-Wundefined-var-template" return our_strings_[value_]; - } - - /** Prints the string identifier to the output stream @p os. */ - std::ostream & print(std::ostream & os = std::cerr) const - { - return os << our_strings_[value_]; +#pragma GCC diagnostic pop } /** Static helper function to iterate over valid identifiers. */ @@ -284,22 +253,6 @@ return true; } - static std::string const& get_full_qualified_name() - { - return our_name_; - } - - static std::string get_name() - { - std::string::size_type idx = our_name_.find_last_of(":"); - if ( idx == std::string::npos ) - { - return our_name_; - } else { - return our_name_.substr( idx + 1 ); - } - } - private: ENUM value_; static const char ** our_strings_ ; @@ -314,19 +267,7 @@ std::ostream & operator<<(std::ostream & os, const mapnik::enumeration & e) { - e.print( os ); - return os; -} - -/** istream operator for enumeration - * @relates mapnik::enumeration - */ -template -std::istream & -operator>>(std::istream & is, mapnik::enumeration & e) -{ - e.parse( is ); - return is; + return os << e.as_string(); } } // end of namespace diff -Nru mapnik-3.0.9+ds/include/mapnik/expression_evaluator.hpp mapnik-3.0.13+ds/include/mapnik/expression_evaluator.hpp --- mapnik-3.0.9+ds/include/mapnik/expression_evaluator.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/expression_evaluator.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -45,27 +45,27 @@ : feature_(f), vars_(v) {} - value_integer operator() (value_integer val) const + value_type operator() (value_integer val) const { return val; } - value_double operator() (value_double val) const + value_type operator() (value_double val) const { return val; } - value_bool operator() (value_bool val) const + value_type operator() (value_bool val) const { return val; } - value_null operator() (value_null val) const + value_type operator() (value_null val) const { return val; } - value_unicode_string const& operator() (value_unicode_string const& str) const + value_type operator() (value_unicode_string const& str) const { return str; } @@ -90,16 +90,16 @@ return geom.value(feature_); } - value_type operator() (binary_node const & x) const + value_type operator() (binary_node const& x) const { return (util::apply_visitor(*this, x.left).to_bool()) && (util::apply_visitor(*this, x.right).to_bool()); } - value_type operator() (binary_node const & x) const + value_type operator() (binary_node const& x) const { - return (util::apply_visitor(*this,x.left).to_bool()) - || (util::apply_visitor(*this,x.right).to_bool()); + return (util::apply_visitor(*this, x.left).to_bool()) + || (util::apply_visitor(*this, x.right).to_bool()); } template diff -Nru mapnik-3.0.9+ds/include/mapnik/expression_grammar.hpp mapnik-3.0.13+ds/include/mapnik/expression_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/expression_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/expression_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,125 +25,18 @@ // mapnik #include -#include -#include #include -#include - #pragma GCC diagnostic push #include #include -#include -#include -#include #pragma GCC diagnostic pop -BOOST_FUSION_ADAPT_STRUCT(mapnik::unary_function_call, - (mapnik::unary_function_impl, fun) - (mapnik::unary_function_call::argument_type, arg)) - -BOOST_FUSION_ADAPT_STRUCT(mapnik::binary_function_call, - (mapnik::binary_function_impl, fun) - (mapnik::binary_function_call::argument_type, arg1) - (mapnik::binary_function_call::argument_type, arg2)) - namespace mapnik { namespace qi = boost::spirit::qi; namespace standard_wide = boost::spirit::standard_wide; using standard_wide::space_type; -struct unicode_impl -{ - template - struct result - { - using type = mapnik::value_unicode_string; - }; - - explicit unicode_impl(mapnik::transcoder const& tr) - : tr_(tr) {} - - mapnik::value_unicode_string operator()(std::string const& str) const - { - return tr_.transcode(str.c_str()); - } - - mapnik::transcoder const& tr_; -}; - -struct regex_match_impl -{ - template - struct result - { - using type = expr_node; - }; - - explicit regex_match_impl(mapnik::transcoder const& tr) - : tr_(tr) {} - - template - expr_node operator() (T0 & node, T1 const& pattern) const; - - mapnik::transcoder const& tr_; -}; - -struct regex_replace_impl -{ - - template - struct result - { - using type = expr_node; - }; - - explicit regex_replace_impl(mapnik::transcoder const& tr) - : tr_(tr) {} - - template - expr_node operator() (T0 & node, T1 const& pattern, T2 const& format) const; - - mapnik::transcoder const& tr_; -}; - -struct geometry_types : qi::symbols -{ - geometry_types() - { - add - ("point", 1) - ("linestring", 2) - ("polygon",3) - ("collection",4) - ; - } -}; - -struct boolean_constants : qi::symbols -{ - boolean_constants() - { - add - ("true", true) - ("false", false) - ; - } -}; - -struct floating_point_constants : qi::symbols -{ - floating_point_constants() - { - add - ("pi", 3.1415926535897932384626433832795) - ("deg_to_rad",0.017453292519943295769236907684886) - ("rad_to_deg",57.295779513082320876798154814105) - ; - } -}; - - template struct integer_parser { @@ -176,9 +69,7 @@ qi::real_parser > strict_double; typename integer_parser::type int__; mapnik::transcoder tr_; - boost::phoenix::function unicode_; - boost::phoenix::function regex_match_; - boost::phoenix::function regex_replace_; + rule_type expr; rule_type equality_expr; rule_type cond_expr; @@ -196,13 +87,12 @@ qi::rule attr; qi::rule global_attr; qi::rule > quoted_ustring; + qi::rule unquoted_ustring; qi::rule ustring; qi::symbols unesc_char; qi::rule quote_char; - geometry_types geom_type; - boolean_constants bool_const; - floating_point_constants float_const; + qi::symbols constant; unary_function_types unary_func_type; binary_function_types binary_func_type; diff -Nru mapnik-3.0.9+ds/include/mapnik/expression_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/expression_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/expression_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/expression_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -32,11 +32,21 @@ #pragma GCC diagnostic push #include -#include +#include #include #include +#include #pragma GCC diagnostic pop +BOOST_FUSION_ADAPT_STRUCT(mapnik::unary_function_call, + (mapnik::unary_function_impl, fun) + (mapnik::unary_function_call::argument_type, arg)) + +BOOST_FUSION_ADAPT_STRUCT(mapnik::binary_function_call, + (mapnik::binary_function_impl, fun) + (mapnik::binary_function_call::argument_type, arg1) + (mapnik::binary_function_call::argument_type, arg2)) + // fwd declare namespace mapnik { struct attribute; @@ -46,6 +56,44 @@ namespace mapnik { +struct unicode_impl +{ + using result_type = mapnik::value_unicode_string; + explicit unicode_impl(mapnik::transcoder const& tr) + : tr_(tr) {} + + mapnik::value_unicode_string operator()(std::string const& str) const + { + return tr_.transcode(str.c_str()); + } + + mapnik::transcoder const& tr_; +}; + +struct regex_match_impl +{ + using result_type = expr_node; + explicit regex_match_impl(mapnik::transcoder const& tr) + : tr_(tr) {} + + template + expr_node operator() (T0 & node, T1 const& pattern) const; + + mapnik::transcoder const& tr_; +}; + +struct regex_replace_impl +{ + using result_type = expr_node; + explicit regex_replace_impl(mapnik::transcoder const& tr) + : tr_(tr) {} + + template + expr_node operator() (T0 & node, T1 const& pattern, T2 const& format) const; + + mapnik::transcoder const& tr_; +}; + unary_function_types::unary_function_types() { add @@ -54,6 +102,7 @@ ("tan", tan_impl()) ("atan", atan_impl()) ("exp", exp_impl()) + ("log", log_impl()) ("abs", abs_impl()) ("length",length_impl()) ; @@ -83,10 +132,7 @@ template expression_grammar::expression_grammar(std::string const& encoding) : expression_grammar::base_type(expr), - tr_(encoding), - unicode_(unicode_impl(tr_)), - regex_match_(regex_match_impl(tr_)), - regex_replace_(regex_replace_impl(tr_)) + tr_(encoding) { qi::_1_type _1; qi::_a_type _a; @@ -103,8 +149,28 @@ standard_wide::char_type char_; standard_wide::no_case_type no_case; using boost::phoenix::construct; + using boost::phoenix::if_else; + + boost::phoenix::function unicode = unicode_impl(tr_); + boost::phoenix::function regex_match = regex_match_impl(tr_); + boost::phoenix::function regex_replace = regex_replace_impl(tr_); + + constant.add + ("null", mapnik::value_null()) + ("false", mapnik::value_bool(false)) + ("true", mapnik::value_bool(true)) + ("point", mapnik::value_integer(1)) + ("linestring", mapnik::value_integer(2)) + ("polygon", mapnik::value_integer(3)) + ("collection", mapnik::value_integer(4)) + ("pi", mapnik::value_double(3.1415926535897932384626433832795)) + ("deg_to_rad", mapnik::value_double(0.017453292519943295769236907684886)) + ("rad_to_deg", mapnik::value_double(57.295779513082320876798154814105)) + ; - expr = logical_expr.alias(); + expr = logical_expr [_val = _1] + //| ustring [_val = unicode(_1)] + ; logical_expr = not_expr [_val = _1] >> @@ -140,7 +206,7 @@ >> quoted_ustring [_a = _1] >> lit(',') >> quoted_ustring [_b = _1] - >> lit(')') [_val = regex_replace_(_r1,_a,_b)] + >> lit(')') [_val = regex_replace(_r1,_a,_b)] ; relational_expr = additive_expr[_val = _1] @@ -162,15 +228,16 @@ >> *( '*' >> unary_expr [_val *= _1] | '/' >> unary_expr [_val /= _1] | '%' >> unary_expr [_val %= construct(_1)] //needed by clang++ with -std=c++11 - | regex_match_expr[_val = regex_match_(_val, _1)] + | regex_match_expr[_val = regex_match(_val, _1)] | regex_replace_expr(_val) [_val = _1] ) ; - unary_function_expr = unary_func_type > lit('(') > expr > lit(')') + unary_function_expr = unary_func_type >> '(' > logical_expr > ')' ; - binary_function_expr = binary_func_type > lit('(') > expr > lit(',') > expr > lit(')') + binary_function_expr = binary_func_type >> '(' > logical_expr > ',' + > logical_expr > ')' ; unary_expr = primary_expr [_val = _1] @@ -180,19 +247,18 @@ primary_expr = strict_double [_val = _1] | int__[_val = _1] - | no_case[bool_const][_val = _1] - | no_case[lit("null")] [_val = value_null() ] - | no_case[geom_type][_val = _1 ] - | no_case[float_const] [_val = _1 ] - | quoted_ustring [_val = unicode_(_1)] - | lit("[mapnik::geometry_type]")[_val = construct()] - | attr [_val = construct( _1 ) ] + | no_case[constant] [_val = _1] + | quoted_ustring [_val = unicode(_1)] + | attr [if_else(_1 == "mapnik::geometry_type", + _val = construct(), + _val = construct(_1))] | global_attr [_val = construct( _1 )] - | lit("not") >> expr [_val = !_1] | unary_function_expr [_val = _1] | binary_function_expr [_val = _1] - | '(' >> expr [_val = _1 ] >> ')' - | ustring[_val = unicode_(_1)] // if we get here then try parsing as unquoted string + | '(' > logical_expr [_val = _1 ] > ')' + // TODO: this is a backward compatibility hack to allow unquoted strings + | unquoted_ustring [_val = unicode(_1)] + // ^ https://github.com/mapnik/mapnik/pull/3389 ; unesc_char.add("\\a", '\a')("\\b", '\b')("\\f", '\f')("\\n", '\n') @@ -205,6 +271,7 @@ quoted_ustring %= omit[quote_char[_a = _1]] >> *(unesc_char | "\\x" >> hex | (char_ - lit(_a))) >> lit(_a); + unquoted_ustring %= no_skip[alpha >> *alnum] - lit("not"); attr %= '[' >> no_skip[+~char_(']')] >> ']'; global_attr %= '@' >> no_skip[alpha >> * (alnum | char_('-'))]; diff -Nru mapnik-3.0.9+ds/include/mapnik/expression_node.hpp mapnik-3.0.13+ds/include/mapnik/expression_node.hpp --- mapnik-3.0.9+ds/include/mapnik/expression_node.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/expression_node.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -31,6 +31,8 @@ #include #include #include +// stl +#include namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/feature.hpp mapnik-3.0.13+ds/include/mapnik/feature.hpp --- mapnik-3.0.9+ds/include/mapnik/feature.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/feature.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -90,7 +90,7 @@ using context_type = context >; using context_ptr = std::shared_ptr; -static const value default_feature_value; +static const value default_feature_value{}; class MAPNIK_DECL feature_impl : private util::noncopyable { @@ -101,15 +101,15 @@ using cont_type = std::vector; using iterator = feature_kv_iterator; - feature_impl(context_ptr const& ctx, mapnik::value_integer id) - : id_(id), + feature_impl(context_ptr const& ctx, mapnik::value_integer _id) + : id_(_id), ctx_(ctx), data_(ctx_->mapping_.size()), geom_(geometry::geometry_empty()), raster_() {} inline mapnik::value_integer id() const { return id_;} - inline void set_id(mapnik::value_integer id) { id_ = id;} + inline void set_id(mapnik::value_integer _id) { id_ = _id;} template inline void put(context_type::key_type const& key, T const& val) { @@ -154,7 +154,7 @@ inline bool has_key(context_type::key_type const& key) const { - return (ctx_->mapping_.find(key) != ctx_->mapping_.end()); + return (ctx_->mapping_.count(key) == 1); } inline value_type const& get(context_type::key_type const& key) const diff -Nru mapnik-3.0.9+ds/include/mapnik/feature_kv_iterator.hpp mapnik-3.0.13+ds/include/mapnik/feature_kv_iterator.hpp --- mapnik-3.0.9+ds/include/mapnik/feature_kv_iterator.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/feature_kv_iterator.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,12 +27,14 @@ #include #include #include -// boost +#pragma GCC diagnostic push +#include #include #include #include #include +#pragma GCC diagnostic pop // stl #include @@ -44,12 +46,11 @@ class MAPNIK_DECL feature_kv_iterator : public boost::iterator_facade const, + std::tuple const, boost::forward_traversal_tag> { public: using value_type = std::tuple; - feature_kv_iterator (feature_impl const& f, bool begin = false); private: friend class boost::iterator_core_access; diff -Nru mapnik-3.0.9+ds/include/mapnik/feature_layer_desc.hpp mapnik-3.0.13+ds/include/mapnik/feature_layer_desc.hpp --- mapnik-3.0.9+ds/include/mapnik/feature_layer_desc.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/feature_layer_desc.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -94,12 +94,21 @@ { return extra_params_; } + bool has_name(std::string const& name) const { auto result = std::find_if(std::begin(descriptors_), std::end(descriptors_), [&name](attribute_descriptor const& desc) { return name == desc.get_name();}); return result != std::end(descriptors_); } + void order_by_name() + { + std::sort(std::begin(descriptors_), std::end(descriptors_), + [](attribute_descriptor const& d0, attribute_descriptor const& d1) + { + return d0.get_name() < d1.get_name(); + }); + } private: std::string name_; std::string encoding_; diff -Nru mapnik-3.0.9+ds/include/mapnik/featureset.hpp mapnik-3.0.13+ds/include/mapnik/featureset.hpp --- mapnik-3.0.9+ds/include/mapnik/featureset.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/featureset.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -41,8 +41,27 @@ virtual ~Featureset() {} }; +struct MAPNIK_DECL invalid_featureset final : Featureset +{ + feature_ptr next() + { + return feature_ptr(); + } + ~invalid_featureset() {} +}; + using featureset_ptr = std::shared_ptr; +inline featureset_ptr make_invalid_featureset() +{ + return std::make_shared(); +} + +inline bool is_valid(featureset_ptr const& ptr) +{ + return (dynamic_cast(ptr.get()) == nullptr) ? true : false; +} + } #endif // MAPNIK_FEATURESET_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/feature_style_processor_impl.hpp mapnik-3.0.13+ds/include/mapnik/feature_style_processor_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/feature_style_processor_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/feature_style_processor_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -266,6 +266,7 @@ } box2d layer_ext = lay.envelope(); + const box2d buffered_query_ext_map_srs = buffered_query_ext; bool fw_success = false; bool early_return = false; @@ -281,9 +282,9 @@ early_return = true; } // next try intersection of layer extent back projected into map srs - else if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext.intersects(layer_ext)) + else if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext_map_srs.intersects(layer_ext)) { - layer_ext.clip(buffered_query_ext); + layer_ext.clip(buffered_query_ext_map_srs); // forward project layer extent back into native projection if (! prj_trans.forward(layer_ext, PROJ_ENVELOPE_POINTS)) { diff -Nru mapnik-3.0.9+ds/include/mapnik/feature_type_style.hpp mapnik-3.0.13+ds/include/mapnik/feature_type_style.hpp --- mapnik-3.0.9+ds/include/mapnik/feature_type_style.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/feature_type_style.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,8 +29,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/include/mapnik/font_engine_freetype.hpp mapnik-3.0.13+ds/include/mapnik/font_engine_freetype.hpp --- mapnik-3.0.9+ds/include/mapnik/font_engine_freetype.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/font_engine_freetype.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -100,10 +100,8 @@ static font_memory_cache_type global_memory_fonts_; }; -class MAPNIK_DECL face_manager : private util::noncopyable +class MAPNIK_DECL face_manager { - using face_ptr_cache_type = std::map; - public: face_manager(font_library & library, freetype_engine::font_file_mapping_type const& font_file_mapping, @@ -112,9 +110,13 @@ face_set_ptr get_face_set(std::string const& name); face_set_ptr get_face_set(font_set const& fset); face_set_ptr get_face_set(std::string const& name, boost::optional fset); - inline stroker_ptr get_stroker() { return stroker_; } + stroker_ptr get_stroker() const { return stroker_; } + private: - face_ptr_cache_type face_ptr_cache_; + using face_cache = std::map; + using face_cache_ptr = std::shared_ptr; + + face_cache_ptr face_cache_; font_library & library_; freetype_engine::font_file_mapping_type const& font_file_mapping_; freetype_engine::font_memory_cache_type const& font_memory_cache_; diff -Nru mapnik-3.0.9+ds/include/mapnik/function_call.hpp mapnik-3.0.13+ds/include/mapnik/function_call.hpp --- mapnik-3.0.9+ds/include/mapnik/function_call.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/function_call.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -50,6 +50,17 @@ }; +// log +struct log_impl +{ + //using type = T; + value_type operator() (value_type const& val) const + { + return std::log(val.to_double()); + } + +}; + // sin struct sin_impl { diff -Nru mapnik-3.0.9+ds/include/mapnik/geometry_envelope.hpp mapnik-3.0.13+ds/include/mapnik/geometry_envelope.hpp --- mapnik-3.0.9+ds/include/mapnik/geometry_envelope.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/geometry_envelope.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,11 +26,11 @@ #include #include -namespace mapnik { +namespace mapnik { namespace geometry { template -MAPNIK_DECL mapnik::box2d envelope(T const& geom); +MAPNIK_DECL auto envelope(T const& geom) -> box2d; } // end ns geometry } // end ns mapnik diff -Nru mapnik-3.0.9+ds/include/mapnik/geometry_envelope_impl.hpp mapnik-3.0.13+ds/include/mapnik/geometry_envelope_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/geometry_envelope_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/geometry_envelope_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,23 +28,24 @@ namespace detail { +template struct geometry_envelope { - using bbox_type = box2d; + using coord_type = T; + using bbox_type = box2d; bbox_type & bbox; geometry_envelope(bbox_type & bbox_) : bbox(bbox_) {} - template - void operator() (T const& geom) const + template + void operator() (U const& geom) const { return mapnik::util::apply_visitor(*this, geom); } - + void operator() (mapnik::geometry::geometry_empty const&) const {} - template void operator() (mapnik::geometry::point const& pt) const { if (!bbox.valid()) @@ -54,61 +55,62 @@ bbox.expand_to_include(pt.x, pt.y); } - template void operator() (mapnik::geometry::line_string const& line) const { bool first = true; for (auto const& pt : line) { - if (first && !bbox.valid()) + if (first && !bbox.valid()) { bbox.init(pt.x, pt.y, pt.x, pt.y); first = false; } - else + else { bbox.expand_to_include(pt.x, pt.y); } } } - template + void operator() (mapnik::geometry::linear_ring const& ring) const + { + (*this)(static_cast const&>(ring)); + } + void operator() (mapnik::geometry::polygon const& poly) const { bool first = true; for (auto const& pt : poly.exterior_ring) { - if (first && !bbox.valid()) + if (first && !bbox.valid()) { bbox.init(pt.x, pt.y, pt.x, pt.y); first = false; } - else + else { bbox.expand_to_include(pt.x, pt.y); } } } - template void operator() (mapnik::geometry::multi_point const& multi_point) const { bool first = true; for (auto const& pt : multi_point) { - if (first && !bbox.valid()) + if (first && !bbox.valid()) { bbox.init(pt.x, pt.y, pt.x, pt.y); first = false; } - else + else { bbox.expand_to_include(pt.x, pt.y); } } } - template void operator() (mapnik::geometry::multi_line_string const& multi_line) const { for (auto const& line : multi_line) @@ -117,7 +119,6 @@ } } - template void operator() (mapnik::geometry::multi_polygon const& multi_poly) const { for (auto const& poly : multi_poly) @@ -126,7 +127,6 @@ } } - template void operator() (mapnik::geometry::geometry_collection const& collection) const { for (auto const& geom : collection) @@ -139,14 +139,14 @@ } // end ns detail template -mapnik::box2d envelope(T const& geom) -{ - box2d bbox; - detail::geometry_envelope op(bbox); +auto envelope(T const& geom) -> box2d +{ + using coord_type = typename T::coord_type; + box2d bbox; + detail::geometry_envelope op(bbox); op(geom); return bbox; } } // end ns geometry } // end ns mapnik - diff -Nru mapnik-3.0.9+ds/include/mapnik/geometry.hpp mapnik-3.0.13+ds/include/mapnik/geometry.hpp --- mapnik-3.0.9+ds/include/mapnik/geometry.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/geometry.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,53 +24,44 @@ #define MAPNIK_GEOMETRY_HPP #include -#include #include #include #include - - namespace mapnik { namespace geometry { template struct point { - using value_type = T; + using coord_type = T; point() {} point(T x_, T y_) : x(x_), y(y_) {} - // temp - remove when geometry is templated on value_type - point(mapnik::coord const& c) - : x(c.x), y(c.y) {} - - point(point const& other) = default; - point(point && other) noexcept = default; - point & operator=(point const& other) = default; - friend inline bool operator== (point const& a, point const& b) - { - return a.x == b.x && a.y == b.y; - } - friend inline bool operator!= (point const& a, point const& b) - { - return a.x != b.x || a.y != b.y; - } - value_type x; - value_type y; + + coord_type x; + coord_type y; }; +template +bool operator==(point const& lhs, point const& rhs) +{ + return lhs.x == rhs.x && lhs.y == rhs.y; +} + +template +bool operator!=(point const& lhs, point const& rhs) +{ + return !(lhs == rhs); +} template struct line_string : std::vector > { + using coord_type = T; line_string() = default; - line_string (std::size_t size) + explicit line_string(std::size_t size) : std::vector >(size) {} - line_string (line_string && other) = default ; - line_string& operator=(line_string &&) = default; - line_string (line_string const& ) = default; - line_string& operator=(line_string const&) = default; inline std::size_t num_points() const { return std::vector>::size(); } inline void add_coord(T x, T y) { std::vector>::template emplace_back(x,y);} }; @@ -78,18 +69,14 @@ template struct linear_ring : line_string { + using coord_type = T; linear_ring() = default; - linear_ring(std::size_t size) + explicit linear_ring(std::size_t size) : line_string(size) {} - linear_ring (linear_ring && other) = default ; - linear_ring& operator=(linear_ring &&) = default; linear_ring(line_string && other) - : line_string(other) {} - linear_ring (linear_ring const& ) = default; + : line_string(std::move(other)) {} linear_ring(line_string const& other) : line_string(other) {} - linear_ring& operator=(linear_ring const&) = default; - }; template @@ -98,11 +85,11 @@ template class InteriorRings = rings_container> struct polygon { - linear_ring exterior_ring; + using coord_type = T; using rings_container = InteriorRings; + linear_ring exterior_ring; rings_container interior_rings; - polygon() = default; inline void set_exterior_ring(linear_ring && ring) { exterior_ring = std::move(ring); @@ -122,13 +109,22 @@ }; template -struct multi_point : line_string {}; +struct multi_point : line_string +{ + using coord_type = T; +}; template -struct multi_line_string : std::vector> {}; +struct multi_line_string : std::vector> +{ + using coord_type = T; +}; template -struct multi_polygon : std::vector> {}; +struct multi_polygon : std::vector> +{ + using coord_type = T; +}; template struct geometry_collection; @@ -144,23 +140,32 @@ multi_point, multi_line_string, multi_polygon, - mapnik::util::recursive_wrapper > >; + geometry_collection >; template struct geometry : geometry_base { - using value_type = T; + using coord_type = T; + +#if __cpp_inheriting_constructors >= 200802 + + using geometry_base::geometry_base; - geometry() - : geometry_base() {} // empty +#else + + geometry() = default; template geometry(G && geom) : geometry_base(std::forward(geom)) {} +#endif }; template -struct geometry_collection : std::vector> {}; +struct geometry_collection : std::vector> +{ + using coord_type = T; +}; }} diff -Nru mapnik-3.0.9+ds/include/mapnik/geometry_reprojection_impl.hpp mapnik-3.0.13+ds/include/mapnik/geometry_reprojection_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/geometry_reprojection_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/geometry_reprojection_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -36,7 +36,7 @@ } template -point reproject_internal(point const & p, proj_transform const& proj_trans, unsigned int & n_err) +point reproject_internal(point const& p, proj_transform const& proj_trans, unsigned int & n_err) { point new_p(p); if (!proj_trans.forward(new_p)) @@ -47,7 +47,7 @@ } template -line_string reproject_internal(line_string const & ls, proj_transform const& proj_trans, unsigned int & n_err) +line_string reproject_internal(line_string const& ls, proj_transform const& proj_trans, unsigned int & n_err) { line_string new_ls(ls); unsigned int err = proj_trans.forward(new_ls); @@ -59,7 +59,7 @@ } template -polygon reproject_internal(polygon const & poly, proj_transform const& proj_trans, unsigned int & n_err) +polygon reproject_internal(polygon const& poly, proj_transform const& proj_trans, unsigned int & n_err) { polygon new_poly; linear_ring new_ext(poly.exterior_ring); @@ -171,18 +171,19 @@ } template -struct geom_reproj_copy_visitor { +struct geom_reproj_copy_visitor +{ geom_reproj_copy_visitor(proj_transform const & proj_trans, unsigned int & n_err) : proj_trans_(proj_trans), n_err_(n_err) {} - geometry operator() (geometry_empty const&) + geometry operator() (geometry_empty const&) const { return geometry_empty(); } - geometry operator() (point const& p) + geometry operator() (point const& p) const { geometry geom; // default empty unsigned int intial_err = n_err_; @@ -192,7 +193,7 @@ return geom; } - geometry operator() (line_string const& ls) + geometry operator() (line_string const& ls) const { geometry geom; // default empty unsigned int intial_err = n_err_; @@ -202,7 +203,7 @@ return geom; } - geometry operator() (polygon const& poly) + geometry operator() (polygon const& poly) const { geometry geom; // default empty polygon new_poly = reproject_internal(poly, proj_trans_, n_err_); @@ -211,7 +212,7 @@ return geom; } - geometry operator() (multi_point const& mp) + geometry operator() (multi_point const& mp) const { geometry geom; // default empty multi_point new_mp = reproject_internal(mp, proj_trans_, n_err_); @@ -220,7 +221,7 @@ return geom; } - geometry operator() (multi_line_string const& mls) + geometry operator() (multi_line_string const& mls) const { geometry geom; // default empty multi_line_string new_mls = reproject_internal(mls, proj_trans_, n_err_); @@ -229,7 +230,7 @@ return geom; } - geometry operator() (multi_polygon const& mpoly) + geometry operator() (multi_polygon const& mpoly) const { geometry geom; // default empty multi_polygon new_mpoly = reproject_internal(mpoly, proj_trans_, n_err_); @@ -238,7 +239,7 @@ return geom; } - geometry operator() (geometry_collection const& c) + geometry operator() (geometry_collection const& c) const { geometry geom; // default empty geometry_collection new_c = reproject_internal(c, proj_trans_, n_err_); @@ -283,15 +284,15 @@ : proj_trans_(proj_trans) {} template - bool operator() (geometry & geom) + bool operator() (geometry & geom) const { return mapnik::util::apply_visitor((*this), geom); } - bool operator() (geometry_empty &) { return true; } + bool operator() (geometry_empty &) const { return true; } template - bool operator() (point & p) + bool operator() (point & p) const { if (!proj_trans_.forward(p)) { @@ -301,7 +302,7 @@ } template - bool operator() (line_string & ls) + bool operator() (line_string & ls) const { if (proj_trans_.forward(ls) > 0) { @@ -311,7 +312,7 @@ } template - bool operator() (polygon & poly) + bool operator() (polygon & poly) const { if (proj_trans_.forward(poly.exterior_ring) > 0) { @@ -329,13 +330,13 @@ } template - bool operator() (multi_point & mp) + bool operator() (multi_point & mp) const { return (*this) (static_cast &>(mp)); } template - bool operator() (multi_line_string & mls) + bool operator() (multi_line_string & mls) const { for (auto & ls : mls) { @@ -348,7 +349,7 @@ } template - bool operator() (multi_polygon & mpoly) + bool operator() (multi_polygon & mpoly) const { for (auto & poly : mpoly) { @@ -361,7 +362,7 @@ } template - bool operator() (geometry_collection & c) + bool operator() (geometry_collection & c) const { for (auto & g : c) { diff -Nru mapnik-3.0.9+ds/include/mapnik/geometry_unique.hpp mapnik-3.0.13+ds/include/mapnik/geometry_unique.hpp --- mapnik-3.0.9+ds/include/mapnik/geometry_unique.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/geometry_unique.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2015 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 - * - *****************************************************************************/ - -#ifndef MAPNIK_GEOMETRY_UNIQUE_HPP -#define MAPNIK_GEOMETRY_UNIQUE_HPP - -#include -#include -#include - -#include - -namespace mapnik { namespace geometry { - -namespace detail { - -struct geometry_unique -{ - using result_type = void; - - result_type operator() (geometry & geom) const - { - mapnik::util::apply_visitor(*this, geom); - } - - result_type operator() (geometry_collection & collection) const - { - for (auto & geom : collection) - { - (*this)(geom); - } - } - - result_type operator() (line_string & line) const - { - boost::geometry::unique(line); - } - - result_type operator() (polygon & poly) const - { - boost::geometry::unique(poly); - } - - template - result_type operator() (T & geom) const - { - // no-op - } - -}; - -} - -template -inline void unique(GeomType & geom) -{ - static_assert(!std::is_const::value,"mapnik::geometry::unique on const& is invalid"); - detail::geometry_unique()(geom); -} - -}} - -#endif // MAPNIK_GEOMETRY_UNIQUE_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/global.hpp mapnik-3.0.13+ds/include/mapnik/global.hpp --- mapnik-3.0.9+ds/include/mapnik/global.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/global.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -99,14 +99,14 @@ // read double XDR (big endian) inline void read_double_xdr(const char* data, double & val) { - std::int64_t bits = ((std::int64_t)data[7] & 0xff) | - ((std::int64_t)data[6] & 0xff) << 8 | - ((std::int64_t)data[5] & 0xff) << 16 | - ((std::int64_t)data[4] & 0xff) << 24 | - ((std::int64_t)data[3] & 0xff) << 32 | - ((std::int64_t)data[2] & 0xff) << 40 | - ((std::int64_t)data[1] & 0xff) << 48 | - ((std::int64_t)data[0] & 0xff) << 56 ; + std::int64_t bits = (static_cast(data[7]) & 0xff) | + (static_cast(data[6]) & 0xff) << 8 | + (static_cast(data[5]) & 0xff) << 16 | + (static_cast(data[4]) & 0xff) << 24 | + (static_cast(data[3]) & 0xff) << 32 | + (static_cast(data[2]) & 0xff) << 40 | + (static_cast(data[1]) & 0xff) << 48 | + (static_cast(data[0]) & 0xff) << 56 ; std::memcpy(&val,&bits,8); } diff -Nru mapnik-3.0.9+ds/include/mapnik/gradient.hpp mapnik-3.0.13+ds/include/mapnik/gradient.hpp --- mapnik-3.0.9+ds/include/mapnik/gradient.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/gradient.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,12 +23,13 @@ #ifndef MAPNIK_GRADIENT_HPP #define MAPNIK_GRADIENT_HPP -// agg +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // mapnik #include -#include // stl #include @@ -39,26 +40,20 @@ using stop_pair = std::pair; using stop_array = std::vector; -enum gradient_enum +enum gradient_e { NO_GRADIENT, LINEAR, - RADIAL, - gradient_enum_MAX + RADIAL }; -DEFINE_ENUM( gradient_e, gradient_enum ); - -enum gradient_unit_enum +enum gradient_unit_e { USER_SPACE_ON_USE, USER_SPACE_ON_USE_BOUNDING_BOX, // used to indicate % age values were specified. This are % of the svg image extent. - OBJECT_BOUNDING_BOX, // (i.e., the abstract coordinate system where (0,0) is at the top/left of the object bounding box and (1,1) is at the bottom/right of the object bounding box) - gradient_unit_enum_MAX + OBJECT_BOUNDING_BOX // (i.e., the abstract coordinate system where (0,0) is at the top/left of the object bounding box and (1,1) is at the bottom/right of the object bounding box) }; -DEFINE_ENUM( gradient_unit_e, gradient_unit_enum ); - class MAPNIK_DECL gradient { // transform diff -Nru mapnik-3.0.9+ds/include/mapnik/grid/grid_rasterizer.hpp mapnik-3.0.13+ds/include/mapnik/grid/grid_rasterizer.hpp --- mapnik-3.0.9+ds/include/mapnik/grid/grid_rasterizer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/grid/grid_rasterizer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,7 +24,11 @@ #define MAPNIK_GRID_RASTERIZER_HPP #include + +#pragma GCC diagnostic push +#include #include "agg_rasterizer_scanline_aa.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/grid/grid_renderer_base.hpp mapnik-3.0.13+ds/include/mapnik/grid/grid_renderer_base.hpp --- mapnik-3.0.9+ds/include/mapnik/grid/grid_renderer_base.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/grid/grid_renderer_base.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,11 +24,11 @@ #define MAPNIK_GRID_RENDERER_BASE_HPP #pragma GCC diagnostic push -#include -#include "agg_renderer_base.h" +#include #include -#pragma GCC diagnostic pop #include +#include "agg_renderer_base.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/grid/grid_rendering_buffer.hpp mapnik-3.0.13+ds/include/mapnik/grid/grid_rendering_buffer.hpp --- mapnik-3.0.9+ds/include/mapnik/grid/grid_rendering_buffer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/grid/grid_rendering_buffer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,7 +24,11 @@ #define MAPNIK_GRID_RENDERING_BUFFER_HPP #include + +#pragma GCC diagnostic push +#include #include "agg_rendering_buffer.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/grid/grid_render_marker.hpp mapnik-3.0.13+ds/include/mapnik/grid/grid_render_marker.hpp --- mapnik-3.0.9+ds/include/mapnik/grid/grid_render_marker.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/grid/grid_render_marker.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,7 +26,8 @@ // mapnik #include -// agg +#pragma GCC diagnostic push +#include #include "agg_renderer_scanline.h" #include "agg_scanline_bin.h" #include "agg_image_filters.h" @@ -34,7 +35,7 @@ #include "agg_span_allocator.h" #include "agg_image_accessors.h" #include "agg_span_image_filter_gray.h" - +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/group/group_layout_manager.hpp mapnik-3.0.13+ds/include/mapnik/group/group_layout_manager.hpp --- mapnik-3.0.9+ds/include/mapnik/group/group_layout_manager.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/group/group_layout_manager.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -31,43 +31,51 @@ // stl #include -using std::vector; - namespace mapnik { -using bound_box = box2d; - struct group_layout_manager { - group_layout_manager(group_layout const& layout) + using bound_box = box2d; + + group_layout_manager() + : update_layout_(false) + {} + + explicit group_layout_manager(group_layout const& layout) : layout_(layout), - input_origin_(0, 0), - member_boxes_(vector()), - member_offsets_(vector()), - update_layout_(true) + update_layout_(false) { } group_layout_manager(group_layout const& layout, pixel_position const& input_origin) : layout_(layout), input_origin_(input_origin), - member_boxes_(vector()), - member_offsets_(vector()), - update_layout_(true) + update_layout_(false) { } group_layout_manager(group_layout const& layout, pixel_position const& input_origin, - vector const& item_boxes) + std::vector const& item_boxes) : layout_(layout), input_origin_(input_origin), member_boxes_(item_boxes), - member_offsets_(vector()), update_layout_(true) { } + void set_input_origin(double x, double y) + { + input_origin_.set(x, y); + update_layout_ = true; + } + + void set_input_origin(pixel_position const& input_origin) + { + input_origin_ = input_origin; + update_layout_ = true; + } + inline void set_layout(group_layout const& layout) { layout_ = layout; @@ -94,8 +102,8 @@ group_layout layout_; pixel_position input_origin_; - vector member_boxes_; - vector member_offsets_; + std::vector member_boxes_; + std::vector member_offsets_; bool update_layout_; }; diff -Nru mapnik-3.0.9+ds/include/mapnik/group/group_symbolizer_helper.hpp mapnik-3.0.13+ds/include/mapnik/group/group_symbolizer_helper.hpp --- mapnik-3.0.9+ds/include/mapnik/group/group_symbolizer_helper.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/group/group_symbolizer_helper.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -68,16 +68,6 @@ box_elements_.push_back(box_element(box, repeat_key)); } - inline void clear_box_elements() - { - box_elements_.clear(); - } - - inline text_symbolizer_properties const& get_properties() const - { - return info_ptr_->properties; - } - pixel_position_list const& get(); // Iterate over the given path, placing line-following labels or point labels with respect to label_spacing. diff -Nru mapnik-3.0.9+ds/include/mapnik/hextree.hpp mapnik-3.0.13+ds/include/mapnik/hextree.hpp --- mapnik-3.0.9+ds/include/mapnik/hextree.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/hextree.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -365,20 +365,20 @@ if (r->count>0) { printf("%d: (+%d/%d/%.5f) (%d %d %d %d)\n", - id, (int)r->count, (int)r->pixel_count, r->reduce_cost, - (int)round(gamma(r->reds / r->count, gamma_)), - (int)round(gamma(r->greens / r->count, gamma_)), - (int)round(gamma(r->blues / r->count, gamma_)), - (int)(r->alphas / r->count)); + id, static_cast(r->count), static_cast(r->pixel_count), r->reduce_cost, + static_cast(round(gamma(r->reds / r->count, gamma_))), + static_cast(round(gamma(r->greens / r->count, gamma_))), + static_cast(round(gamma(r->blues / r->count, gamma_))), + static_cast((r->alphas / r->count))); } else { printf("%d: (%d/%d/%.5f) (%d %d %d %d)\n", id, - (int)r->count, (int)r->pixel_count, r->reduce_cost, - (int)round(gamma(r->reds / r->pixel_count, gamma_)), - (int)round(gamma(r->greens / r->pixel_count, gamma_)), - (int)round(gamma(r->blues / r->pixel_count, gamma_)), - (int)(r->alphas / r->pixel_count)); + static_cast(r->count), static_cast(r->pixel_count), r->reduce_cost, + static_cast(round(gamma(r->reds / r->pixel_count, gamma_))), + static_cast(round(gamma(r->greens / r->pixel_count, gamma_))), + static_cast(round(gamma(r->blues / r->pixel_count, gamma_))), + static_cast((r->alphas / r->pixel_count))); } for (unsigned idx=0; idx < 16; ++idx) { @@ -399,9 +399,9 @@ std::uint8_t a = std::uint8_t(itr->alphas/float(count)); if (a > InsertPolicy::MAX_ALPHA) a = 255; if (a < InsertPolicy::MIN_ALPHA) a = 0; - palette.push_back(rgba((std::uint8_t)round(gamma(itr->reds / count, gamma_)), - (std::uint8_t)round(gamma(itr->greens / count, gamma_)), - (std::uint8_t)round(gamma(itr->blues / count, gamma_)), a)); + palette.push_back(rgba(static_cast(round(gamma(itr->reds / count, gamma_))), + static_cast(round(gamma(itr->greens / count, gamma_))), + static_cast(round(gamma(itr->blues / count, gamma_))), a)); } for (unsigned idx=0; idx < 16; ++idx) { diff -Nru mapnik-3.0.9+ds/include/mapnik/image_any.hpp mapnik-3.0.13+ds/include/mapnik/image_any.hpp --- mapnik-3.0.9+ds/include/mapnik/image_any.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_any.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -55,8 +55,9 @@ bool painted = false); template - image_any(T && _data) noexcept - : image_base(std::move(_data)) {} + image_any(T && _data) + noexcept(std::is_nothrow_constructible::value) + : image_base(std::forward(_data)) {} unsigned char const* bytes() const; unsigned char* bytes(); diff -Nru mapnik-3.0.9+ds/include/mapnik/image_compositing.hpp mapnik-3.0.13+ds/include/mapnik/image_compositing.hpp --- mapnik-3.0.9+ds/include/mapnik/image_compositing.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_compositing.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,8 +26,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/include/mapnik/image_filter_grammar.hpp mapnik-3.0.13+ds/include/mapnik/image_filter_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/image_filter_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_filter_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -20,19 +20,19 @@ * *****************************************************************************/ -#ifndef MAPNIK_IMAGE_FILITER_GRAMMAR_HPP -#define MAPNIK_IMAGE_FILITER_GRAMMAR_HPP +#ifndef MAPNIK_IMAGE_FILTER_GRAMMAR_HPP +#define MAPNIK_IMAGE_FILTER_GRAMMAR_HPP + +// mapnik +#include +#include +#include #pragma GCC diagnostic push #include #include -#include #pragma GCC diagnostic pop -// mapnik -#include -#include - // stl #include @@ -43,26 +43,11 @@ struct colorize_alpha; } -} - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::filter::color_stop, - (mapnik::color, color ) - (double, offset) -) - -namespace mapnik { - namespace qi = boost::spirit::qi; struct percent_offset_impl { - template - struct result - { - using type = double; - }; - + using result_type = double; double operator() (double val) const { double result = std::abs(val/100.0); @@ -76,21 +61,27 @@ struct image_filter_grammar : qi::grammar { + using alternative_type = qi::rule; + image_filter_grammar(); + qi::rule start; - qi::rule filter; - qi::rule, void(ContType&), qi::ascii::space_type> agg_blur_filter; - qi::rule, - void(ContType&), qi::ascii::space_type> scale_hsla_filter; - qi::rule, void(ContType&), qi::ascii::space_type> colorize_alpha_filter; + qi::rule> filter; qi::rule no_args; + qi::symbols alternatives; qi::uint_parser< unsigned, 10, 1, 3 > radius_; css_color_grammar css_color_; - qi::rule color_stop_offset; - phoenix::function percent_offset; - qi::rule, void(ContType&), qi::ascii::space_type> color_to_alpha_filter; + qi::rule color_stop_; + qi::rule color_stop_offset; + +private: + alternative_type & add(std::string const& symbol); + static constexpr unsigned max_alternatives = 16; + unsigned num_alternatives = 0; + alternative_type alternative_storage[max_alternatives]; }; -} +} // namespace mapnik -#endif // MAPNIK_IMAGE_FILITER_PARSER_HPP +#endif // MAPNIK_IMAGE_FILTER_GRAMMAR_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/image_filter_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/image_filter_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/image_filter_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_filter_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,6 +29,14 @@ #include #pragma GCC diagnostic pop +namespace { // internal + + BOOST_PHOENIX_ADAPT_FUNCTION( + typename std::remove_reference::type, ovo, // = optional_value_or + boost::get_optional_value_or, 2) + +} // namespace internal + namespace mapnik { namespace qi = boost::spirit::qi; @@ -41,97 +49,93 @@ qi::lit_type lit; qi::_val_type _val; qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + qi::_5_type _5; + qi::_6_type _6; + qi::_7_type _7; + qi::_8_type _8; qi::_a_type _a; - qi::_b_type _b; - qi::_c_type _c; - qi::_d_type _d; - qi::_e_type _e; - qi::_f_type _f; - qi::_g_type _g; - qi::_h_type _h; - qi::_r1_type _r1; - qi::eps_type eps; - qi::char_type char_; + qi::attr_type attr; qi::double_type double_; - qi::no_skip_type no_skip; + qi::hold_type hold; + qi::omit_type omit; using phoenix::push_back; using phoenix::construct; - using phoenix::at_c; - start = -(filter % no_skip[*char_(", ")]) + + // functions + phoenix::function percent_offset; + + start = -(filter % *lit(',')) ; - filter = - lit("emboss") >> no_args [push_back(_val,construct())] - | - lit("blur") >> no_args [push_back(_val,construct())] - | - lit("gray") >> no_args [push_back(_val,construct())] - | - lit("edge-detect") >> no_args [push_back(_val,construct())] - | - lit("sobel") >> no_args [push_back(_val,construct())] - | - lit("sharpen") >> no_args [push_back(_val,construct())] - | - lit("x-gradient") >> no_args [push_back(_val,construct())] - | - lit("y-gradient") >> no_args [push_back(_val,construct())] - | - lit("invert") >> no_args [push_back(_val,construct())] - | - lit("color-blind-protanope") >> no_args [push_back(_val,construct())] - | - lit("color-blind-deuteranope") >> no_args [push_back(_val,construct())] - | - lit("color-blind-tritanope") >> no_args [push_back(_val,construct())] - | - agg_blur_filter(_val) - | - scale_hsla_filter(_val) - | - colorize_alpha_filter(_val) + filter = omit[alternatives[_a = _1]] >> qi::lazy(*_a) + ; + + add("emboss") = no_args >> attr(construct()); + add("blur") = no_args >> attr(construct()); + add("gray") = no_args >> attr(construct()); + add("edge-detect") = no_args >> attr(construct()); + add("sobel") = no_args >> attr(construct()); + add("sharpen") = no_args >> attr(construct()); + add("x-gradient") = no_args >> attr(construct()); + add("y-gradient") = no_args >> attr(construct()); + add("invert") = no_args >> attr(construct()); + add("color-blind-protanope") = no_args >> attr(construct()); + add("color-blind-deuteranope") = no_args >> attr(construct()); + add("color-blind-tritanope") = no_args >> attr(construct()); + + add("agg-stack-blur") = + (lit('(') >> radius_ >> -( lit(',') >> radius_ ) >> lit(')')) + [push_back(_val, construct(_1, ovo(_2, _1)))] | - color_to_alpha_filter(_val) + no_args + [push_back(_val, construct(1, 1))] ; - agg_blur_filter = lit("agg-stack-blur")[_a = 1, _b = 1] - >> -( lit('(') >> -( radius_[_a = _1][_b = _1] - >> -(lit(',') >> radius_[_b = _1])) - >> lit(')')) - [push_back(_r1,construct(_a,_b))] + add("scale-hsla") = + (lit('(') + >> double_ >> lit(',') >> double_ >> lit(',') + >> double_ >> lit(',') >> double_ >> lit(',') + >> double_ >> lit(',') >> double_ >> lit(',') + >> double_ >> lit(',') >> double_ >> lit(')')) + [push_back(_val, construct(_1,_2,_3,_4,_5,_6,_7,_8))] ; - scale_hsla_filter = lit("scale-hsla") - >> lit('(') - >> double_[_a = _1] >> lit(',') >> double_[_b = _1] >> lit(',') - >> double_[_c = _1] >> lit(',') >> double_[_d = _1] >> lit(',') - >> double_[_e = _1] >> lit(',') >> double_[_f = _1] >> lit(',') - >> double_[_g = _1] >> lit(',') >> double_[_h = _1] >> lit(')') - [push_back(_r1, construct(_a,_b,_c,_d,_e,_f,_g,_h))] + add("colorize-alpha") = qi::as() + [lit('(') >> color_stop_ % lit(',') >> lit(')')] + [push_back(_val, _1)] ; - colorize_alpha_filter = lit("colorize-alpha")[_a = construct()] - >> lit('(') - >> (css_color_[at_c<0>(_b) = _1, at_c<1>(_b) = 0] - >> -color_stop_offset(_b)) [push_back(_a,_b)] - >> -(+(lit(',') >> css_color_[at_c<0>(_b) =_1,at_c<1>(_b) = 0] - >> -color_stop_offset(_b))[push_back(_a,_b)]) - >> lit(')') [push_back(_r1,_a)] + color_stop_ = (css_color_ >> -color_stop_offset) + [_val = construct(_1, ovo(_2, 0.0))] ; - color_stop_offset = (double_ >> lit('%'))[at_c<1>(_r1) = percent_offset(_1)] - | - double_[at_c<1>(_r1) = _1] + color_stop_offset = double_[_val = _1] + >> -lit('%')[_val = percent_offset(_val)] ; - color_to_alpha_filter = lit("color-to-alpha") - >> lit('(') - >> css_color_[_a = _1] - >> lit(')') - [push_back(_r1,construct(_a))] + add("color-to-alpha") = + hold[lit('(') >> css_color_ >> lit(')')] + [push_back(_val, construct(_1))] ; no_args = -(lit('(') >> lit(')')); } +template +auto image_filter_grammar::add(std::string const& symbol) + -> alternative_type & +{ + if (num_alternatives >= max_alternatives) + { + throw std::length_error("too many alternatives in image_filter_grammar"); + } + + alternative_storage[num_alternatives].name(symbol); + alternatives.add(symbol, &alternative_storage[num_alternatives]); + return alternative_storage[num_alternatives++]; } + +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/include/mapnik/image_filter.hpp mapnik-3.0.13+ds/include/mapnik/image_filter.hpp --- mapnik-3.0.9+ds/include/mapnik/image_filter.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_filter.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -34,7 +34,8 @@ #include #pragma GCC diagnostic pop -// agg +#pragma GCC diagnostic push +#include #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_color_rgba.h" @@ -42,6 +43,8 @@ #include "agg_scanline_u.h" #include "agg_blur.h" #include "agg_gradient_lut.h" +#pragma GCC diagnostic pop + // stl #include @@ -387,7 +390,7 @@ } template -void apply_filter(Src & src, Filter const& filter) +void apply_filter(Src & src, Filter const& filter, double /*scale_factor*/) { demultiply_alpha(src); double_buffer tb(src); @@ -395,12 +398,12 @@ } template -void apply_filter(Src & src, agg_stack_blur const& op) +void apply_filter(Src & src, agg_stack_blur const& op, double scale_factor) { premultiply_alpha(src); agg::rendering_buffer buf(src.bytes(),src.width(),src.height(), src.row_size()); agg::pixfmt_rgba32_pre pixf(buf); - agg::stack_blur_rgba32(pixf,op.rx,op.ry); + agg::stack_blur_rgba32(pixf, op.rx * scale_factor, op.ry * scale_factor); } inline double channel_delta(double source, double match) @@ -417,7 +420,7 @@ } template -void apply_filter(Src & src, color_to_alpha const& op) +void apply_filter(Src & src, color_to_alpha const& op, double /*scale_factor*/) { using namespace boost::gil; bool premultiplied = src.get_premultiplied(); @@ -478,7 +481,7 @@ } template -void apply_filter(Src & src, colorize_alpha const& op) +void apply_filter(Src & src, colorize_alpha const& op, double /*scale_factor*/) { using namespace boost::gil; std::ptrdiff_t size = op.size(); @@ -587,7 +590,7 @@ } template -void apply_filter(Src & src, scale_hsla const& transform) +void apply_filter(Src & src, scale_hsla const& transform, double /*scale_factor*/) { using namespace boost::gil; bool tinting = !transform.is_identity(); @@ -683,7 +686,7 @@ using namespace boost::gil; rgba8_view_t src_view = rgba8_view(src); bool premultiplied = src.get_premultiplied(); - + for (std::ptrdiff_t y = 0; y < src_view.height(); ++y) { rgba8_view_t::x_iterator src_it = src_view.row_begin(static_cast(y)); @@ -738,7 +741,7 @@ X = deviate_x * Y / deviate_y; Z = (1.0 - (deviate_x + deviate_y)) * Y / deviate_y; // Neutral grey calculated from luminance (in D65) - double neutral_X = 0.312713 * Y / 0.329016; + double neutral_X = 0.312713 * Y / 0.329016; double neutral_Z = 0.358271 * Y / 0.329016; // Difference between simulated color and neutral grey double diff_X = neutral_X - X; @@ -761,12 +764,12 @@ // Convert to RGB color space dr = X * 3.24071 + Y * -1.53726 + Z * -0.498571; // XYZ->RGB (sRGB:D65) dg = X * -0.969258 + Y * 1.87599 + Z * 0.0415557; - db = X * 0.0556352 + Y * -0.203996 + Z * 1.05707; + db = X * 0.0556352 + Y * -0.203996 + Z * 1.05707; // Compensate simulated color towards a neutral fit in RGB space double fit_r = ((dr < 0.0 ? 0.0 : 1.0) - dr) / diff_r; double fit_g = ((dg < 0.0 ? 0.0 : 1.0) - dg) / diff_g; double fit_b = ((db < 0.0 ? 0.0 : 1.0) - db) / diff_b; - double adjust = std::max( (fit_r > 1.0 || fit_r < 0.0) ? 0.0 : fit_r, + double adjust = std::max( (fit_r > 1.0 || fit_r < 0.0) ? 0.0 : fit_r, (fit_g > 1.0 || fit_g < 0.0) ? 0.0 : fit_g ); adjust = std::max((fit_b > 1.0 || fit_b < 0.0) ? 0.0 : fit_b, adjust); @@ -777,7 +780,7 @@ // Apply gamma correction dr = std::pow(dr, 1.0 / 2.2); dg = std::pow(dg, 1.0 / 2.2); - db = std::pow(db, 1.0 / 2.2); + db = std::pow(db, 1.0 / 2.2); // premultiply dr *= da; dg *= da; @@ -799,25 +802,25 @@ } template -void apply_filter(Src & src, color_blind_protanope const& op) +void apply_filter(Src & src, color_blind_protanope const& op, double /*scale_factor*/) { color_blind_filter(src, op); } template -void apply_filter(Src & src, color_blind_deuteranope const& op) +void apply_filter(Src & src, color_blind_deuteranope const& op, double /*scale_factor*/) { color_blind_filter(src, op); } template -void apply_filter(Src & src, color_blind_tritanope const& op) +void apply_filter(Src & src, color_blind_tritanope const& op, double /*scale_factor*/) { color_blind_filter(src, op); } template -void apply_filter(Src & src, gray const& /*op*/) +void apply_filter(Src & src, gray const& /*op*/, double /*scale_factor*/) { premultiply_alpha(src); using namespace boost::gil; @@ -868,7 +871,7 @@ } template -void apply_filter(Src & src, x_gradient const& /*op*/) +void apply_filter(Src & src, x_gradient const& /*op*/, double /*scale_factor*/) { premultiply_alpha(src); double_buffer tb(src); @@ -876,7 +879,7 @@ } template -void apply_filter(Src & src, y_gradient const& /*op*/) +void apply_filter(Src & src, y_gradient const& /*op*/, double /*scale_factor*/) { premultiply_alpha(src); double_buffer tb(src); @@ -885,7 +888,7 @@ } template -void apply_filter(Src & src, invert const& /*op*/) +void apply_filter(Src & src, invert const& /*op*/, double /*scale_factor*/) { premultiply_alpha(src); using namespace boost::gil; @@ -913,16 +916,18 @@ template struct filter_visitor { - filter_visitor(Src & src) - : src_(src) {} + filter_visitor(Src & src, double scale_factor=1.0) + : src_(src), + scale_factor_(scale_factor) {} template - void operator () (T const& filter) + void operator () (T const& filter) const { - apply_filter(src_, filter); + apply_filter(src_, filter, scale_factor_); } Src & src_; + double scale_factor_; }; struct filter_radius_visitor @@ -931,9 +936,9 @@ filter_radius_visitor(int & radius) : radius_(radius) {} template - void operator () (T const& /*filter*/) {} + void operator () (T const& /*filter*/) const {} - void operator () (agg_stack_blur const& op) + void operator () (agg_stack_blur const& op) const { if (static_cast(op.rx) > radius_) radius_ = static_cast(op.rx); if (static_cast(op.ry) > radius_) radius_ = static_cast(op.ry); @@ -941,14 +946,14 @@ }; template -void filter_image(Src & src, std::string const& filter) +void filter_image(Src & src, std::string const& filter, double scale_factor=1) { std::vector filter_vector; if(!parse_image_filters(filter, filter_vector)) { throw std::runtime_error("Failed to parse filter argument in filter_image: '" + filter + "'"); } - filter_visitor visitor(src); + filter_visitor visitor(src, scale_factor); for (filter_type const& filter_tag : filter_vector) { util::apply_visitor(visitor, filter_tag); @@ -956,7 +961,7 @@ } template -Src filter_image(Src const& src, std::string const& filter) +Src filter_image(Src const& src, std::string const& filter, double scale_factor=1) { std::vector filter_vector; if(!parse_image_filters(filter, filter_vector)) @@ -964,7 +969,7 @@ throw std::runtime_error("Failed to parse filter argument in filter_image: '" + filter + "'"); } Src new_src(src); - filter_visitor visitor(new_src); + filter_visitor visitor(new_src, scale_factor); for (filter_type const& filter_tag : filter_vector) { util::apply_visitor(visitor, filter_tag); diff -Nru mapnik-3.0.9+ds/include/mapnik/image.hpp mapnik-3.0.13+ds/include/mapnik/image.hpp --- mapnik-3.0.9+ds/include/mapnik/image.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -54,9 +54,6 @@ struct image_dimensions { image_dimensions(int width, int height); - image_dimensions(image_dimensions const& other) = default; - image_dimensions(image_dimensions && other) = default; - image_dimensions& operator= (image_dimensions rhs); std::size_t width() const; std::size_t height() const; private: @@ -79,7 +76,6 @@ private: detail::image_dimensions<65535> dimensions_; detail::buffer buffer_; - pixel_type *pData_; double offset_; double scaling_; bool premultiplied_alpha_; diff -Nru mapnik-3.0.9+ds/include/mapnik/image_impl.hpp mapnik-3.0.13+ds/include/mapnik/image_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/image_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -44,14 +44,6 @@ } template -image_dimensions& image_dimensions::operator= (image_dimensions rhs) -{ - std::swap(width_, rhs.width_); - std::swap(height_, rhs.height_); - return *this; -} - -template std::size_t image_dimensions::width() const { return width_; @@ -70,7 +62,6 @@ image::image() : dimensions_(0,0), buffer_(0), - pData_(nullptr), offset_(0.0), scaling_(1.0), premultiplied_alpha_(false), @@ -81,7 +72,6 @@ image::image(int width, int height, unsigned char* data, bool premultiplied, bool painted) : dimensions_(width, height), buffer_(data, width * height * sizeof(pixel_size)), - pData_(reinterpret_cast(buffer_.data())), offset_(0.0), scaling_(1.0), premultiplied_alpha_(premultiplied), @@ -91,15 +81,14 @@ image::image(int width, int height, bool initialize, bool premultiplied, bool painted) : dimensions_(width, height), buffer_(dimensions_.width() * dimensions_.height() * pixel_size), - pData_(reinterpret_cast(buffer_.data())), offset_(0.0), scaling_(1.0), premultiplied_alpha_(premultiplied), painted_(painted) { - if (pData_ && initialize) + if (initialize) { - std::fill(pData_, pData_ + dimensions_.width() * dimensions_.height(), 0); + std::fill(begin(), end(), 0); } } @@ -107,7 +96,6 @@ image::image(image const& rhs) : dimensions_(rhs.dimensions_), buffer_(rhs.buffer_), - pData_(reinterpret_cast(buffer_.data())), offset_(rhs.offset_), scaling_(rhs.scaling_), premultiplied_alpha_(rhs.premultiplied_alpha_), @@ -117,14 +105,12 @@ image::image(image && rhs) noexcept : dimensions_(std::move(rhs.dimensions_)), buffer_(std::move(rhs.buffer_)), - pData_(reinterpret_cast(buffer_.data())), offset_(rhs.offset_), scaling_(rhs.scaling_), premultiplied_alpha_(rhs.premultiplied_alpha_), painted_(rhs.painted_) { rhs.dimensions_ = { 0, 0 }; - rhs.pData_ = nullptr; } template @@ -161,14 +147,14 @@ inline typename image::pixel_type& image::operator() (std::size_t i, std::size_t j) { assert(i < dimensions_.width() && j < dimensions_.height()); - return pData_[j * dimensions_.width() + i]; + return *get_row(j, i); } template inline const typename image::pixel_type& image::operator() (std::size_t i, std::size_t j) const { assert(i < dimensions_.width() && j < dimensions_.height()); - return pData_[j * dimensions_.width() + i]; + return *get_row(j, i); } template @@ -198,19 +184,19 @@ template inline void image::set(pixel_type const& t) { - std::fill(pData_, pData_ + dimensions_.width() * dimensions_.height(), t); + std::fill(begin(), end(), t); } template inline const typename image::pixel_type* image::data() const { - return pData_; + return reinterpret_cast(buffer_.data()); } template inline typename image::pixel_type* image::data() { - return pData_; + return reinterpret_cast(buffer_.data()); } template @@ -227,40 +213,40 @@ // iterator interface template -inline typename image::iterator image::begin() { return pData_; } +inline typename image::iterator image::begin() { return data(); } template -inline typename image::iterator image::end() { return pData_ + dimensions_.width() * dimensions_.height(); } +inline typename image::iterator image::end() { return data() + dimensions_.width() * dimensions_.height(); } template -inline typename image::const_iterator image::begin() const { return pData_; } +inline typename image::const_iterator image::begin() const { return data(); } template -inline typename image::const_iterator image::end() const{ return pData_ + dimensions_.width() * dimensions_.height(); } +inline typename image::const_iterator image::end() const{ return data() + dimensions_.width() * dimensions_.height(); } template inline typename image::pixel_type const* image::get_row(std::size_t row) const { - return pData_ + row * dimensions_.width(); + return data() + row * dimensions_.width(); } template inline const typename image::pixel_type* image::get_row(std::size_t row, std::size_t x0) const { - return pData_ + row * dimensions_.width() + x0; + return data() + row * dimensions_.width() + x0; } template inline typename image::pixel_type* image::get_row(std::size_t row) { - return pData_ + row * dimensions_.width(); + return data() + row * dimensions_.width(); } template inline typename image::pixel_type* image::get_row(std::size_t row, std::size_t x0) { - return pData_ + row * dimensions_.width() + x0; + return data() + row * dimensions_.width() + x0; } template @@ -268,7 +254,7 @@ { assert(row < dimensions_.height()); assert(size <= dimensions_.width()); - std::copy(buf, buf + size, pData_ + row * dimensions_.width()); + std::copy(buf, buf + size, get_row(row)); } template @@ -276,7 +262,7 @@ { assert(row < dimensions_.height()); assert ((x1 - x0) <= dimensions_.width() ); - std::copy(buf, buf + (x1 - x0), pData_ + row * dimensions_.width() + x0); + std::copy(buf, buf + (x1 - x0), get_row(row, x0)); } template diff -Nru mapnik-3.0.9+ds/include/mapnik/image_null.hpp mapnik-3.0.13+ds/include/mapnik/image_null.hpp --- mapnik-3.0.9+ds/include/mapnik/image_null.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_null.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,6 +25,7 @@ // mapnik #include +#include #include //stl @@ -47,9 +48,6 @@ bool /*initialize*/ = true, bool /*premultiplied*/ = false, bool /*painted*/ = false) {} - image(image const&) {} - image(image &&) noexcept {} - image& operator=(image) { return *this; } bool operator==(image const&) const { return true; } bool operator<(image const&) const { return false; } diff -Nru mapnik-3.0.9+ds/include/mapnik/image_options.hpp mapnik-3.0.13+ds/include/mapnik/image_options.hpp --- mapnik-3.0.9+ds/include/mapnik/image_options.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_options.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,7 +25,12 @@ #include #include + +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop + namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/image_reader.hpp mapnik-3.0.13+ds/include/mapnik/image_reader.hpp --- mapnik-3.0.9+ds/include/mapnik/image_reader.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_reader.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,8 +29,12 @@ #include #include #include -// boost + +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop + // stl #include #include diff -Nru mapnik-3.0.9+ds/include/mapnik/image_scaling.hpp mapnik-3.0.13+ds/include/mapnik/image_scaling.hpp --- mapnik-3.0.9+ds/include/mapnik/image_scaling.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_scaling.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,8 +30,11 @@ // stl #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop + namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/image_scaling_traits.hpp mapnik-3.0.13+ds/include/mapnik/image_scaling_traits.hpp --- mapnik-3.0.9+ds/include/mapnik/image_scaling_traits.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_scaling_traits.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,9 +24,12 @@ #define MAPNIK_IMAGE_SCALING_TRAITS_HPP // mapnik -#include +#include +#include +#include -// agg +#pragma GCC diagnostic push +#include #include "agg_image_accessors.h" #include "agg_pixfmt_rgba.h" #include "agg_pixfmt_gray.h" @@ -34,6 +37,7 @@ #include "agg_span_image_filter_gray.h" #include "agg_span_image_filter_rgba.h" #include "agg_span_interpolator_linear.h" +#pragma GCC diagnostic pop namespace mapnik { namespace detail { diff -Nru mapnik-3.0.9+ds/include/mapnik/image_util_jpeg.hpp mapnik-3.0.13+ds/include/mapnik/image_util_jpeg.hpp --- mapnik-3.0.9+ds/include/mapnik/image_util_jpeg.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_util_jpeg.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,6 +23,8 @@ #ifndef MAPNIK_IMAGE_UTIL_JPEG_HPP #define MAPNIK_IMAGE_UTIL_JPEG_HPP +#include + // stl #include #include diff -Nru mapnik-3.0.9+ds/include/mapnik/image_util_png.hpp mapnik-3.0.13+ds/include/mapnik/image_util_png.hpp --- mapnik-3.0.9+ds/include/mapnik/image_util_png.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_util_png.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,6 +23,8 @@ #ifndef MAPNIK_IMAGE_UTIL_PNG_HPP #define MAPNIK_IMAGE_UTIL_PNG_HPP +#include + // stl #include #include diff -Nru mapnik-3.0.9+ds/include/mapnik/image_view_any.hpp mapnik-3.0.13+ds/include/mapnik/image_view_any.hpp --- mapnik-3.0.9+ds/include/mapnik/image_view_any.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_view_any.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -47,8 +47,9 @@ image_view_any() = default; template - image_view_any(T && data) noexcept - : image_view_base(std::move(data)) {} + image_view_any(T && _data) + noexcept(std::is_nothrow_constructible::value) + : image_view_base(std::forward(_data)) {} std::size_t width() const; std::size_t height() const; diff -Nru mapnik-3.0.9+ds/include/mapnik/image_view.hpp mapnik-3.0.13+ds/include/mapnik/image_view.hpp --- mapnik-3.0.9+ds/include/mapnik/image_view.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_view.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -37,11 +37,7 @@ static constexpr std::size_t pixel_size = sizeof(pixel_type); image_view(std::size_t x, std::size_t y, std::size_t width, std::size_t height, T const& data); - ~image_view(); - image_view(image_view const& rhs); - image_view(image_view && other) noexcept; - image_view& operator=(image_view rhs) = delete; bool operator==(image_view const& rhs) const; bool operator<(image_view const& rhs) const; diff -Nru mapnik-3.0.9+ds/include/mapnik/image_view_impl.hpp mapnik-3.0.13+ds/include/mapnik/image_view_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/image_view_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_view_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -43,25 +43,6 @@ } template -image_view::~image_view() {} - -template -image_view::image_view(image_view const& rhs) - : x_(rhs.x_), - y_(rhs.y_), - width_(rhs.width_), - height_(rhs.height_), - data_(rhs.data_) {} - -template -image_view::image_view(image_view && other) noexcept - : x_(std::move(other.x_)), - y_(std::move(other.y_)), - width_(std::move(other.width_)), - height_(std::move(other.height_)), - data_(std::move(other.data_)) {} - -template bool image_view::operator==(image_view const& rhs) const { return rhs.data_.bytes() == data_.bytes(); diff -Nru mapnik-3.0.9+ds/include/mapnik/image_view_null.hpp mapnik-3.0.13+ds/include/mapnik/image_view_null.hpp --- mapnik-3.0.9+ds/include/mapnik/image_view_null.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/image_view_null.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,7 +23,7 @@ #ifndef MAPNIK_IMAGE_VIEW_NULL_HPP #define MAPNIK_IMAGE_VIEW_NULL_HPP -#include +#include //stl #include diff -Nru mapnik-3.0.9+ds/include/mapnik/json/attribute_value_visitor.hpp mapnik-3.0.13+ds/include/mapnik/json/attribute_value_visitor.hpp --- mapnik-3.0.9+ds/include/mapnik/json/attribute_value_visitor.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/attribute_value_visitor.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,68 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_JSON_ATTRIBUTE_VALUE_VISITOR_HPP +#define MAPNIK_JSON_ATTRIBUTE_VALUE_VISITOR_HPP + +// mapnik +#include +#include +#include +#include + +namespace mapnik { namespace json { + +struct attribute_value_visitor +{ +public: + attribute_value_visitor(mapnik::transcoder const& tr) + : tr_(tr) {} + + mapnik::value operator()(std::string const& val) const + { + return mapnik::value(tr_.transcode(val.c_str())); + } + + mapnik::value operator()(std::vector const& array) const + { + std::string str = stringifier()(array); + return mapnik::value(tr_.transcode(str.c_str())); + } + + mapnik::value operator()(std::vector > const& object) const + { + std::string str = stringifier()(object); + return mapnik::value(tr_.transcode(str.c_str())); + } + + template + mapnik::value operator()(T const& val) const + { + return mapnik::value(val); + } + + mapnik::transcoder const& tr_; +}; + +}} + +#endif //MAPNIK_JSON_ATTRIBUTE_VALUE_VISITOR_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/json/error_handler.hpp mapnik-3.0.13+ds/include/mapnik/json/error_handler.hpp --- mapnik-3.0.9+ds/include/mapnik/json/error_handler.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/error_handler.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,13 +24,18 @@ #define MAPNIK_JSON_ERROR_HANDLER_HPP #include + #pragma GCC diagnostic push #include -#include -#include +#include +namespace boost { namespace spirit { struct info; } } #pragma GCC diagnostic pop + // mapnik +#ifdef MAPNIK_LOG #include +#endif + // stl #include #include diff -Nru mapnik-3.0.9+ds/include/mapnik/json/extract_bounding_box_grammar.hpp mapnik-3.0.13+ds/include/mapnik/json/extract_bounding_box_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/json/extract_bounding_box_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/extract_bounding_box_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -32,73 +32,31 @@ #pragma GCC diagnostic push #include #include -#include -#include #pragma GCC diagnostic pop -// stl -#include - namespace mapnik { namespace json { -using position_type = mapnik::geometry::point; -using boxes_type = std::vector, std::pair>>; - namespace qi = boost::spirit::qi; -struct calculate_bounding_box_impl -{ - using result_type = void; - template - result_type operator() (T0 & bbox, T1 const& pos) const - { - if (pos) - { - double x = pos->x; - double y = pos->y; - if (!bbox.valid()) - { - bbox.init(x, y, x, y); //TODO: add init(x,y) convinience method - } - else - { - bbox.expand_to_include(x, y); - } - } - } -}; - -struct push_box_impl -{ - using result_type = void; - template - void operator() (T0 & boxes, T1 const& begin, T2 const& box, T3 const& range) const - { - if (box.valid()) boxes.emplace_back(box, std::make_pair(std::distance(begin, range.begin()), std::distance(range.begin(), range.end()))); - } -}; - -template > +template > struct extract_bounding_box_grammar : - qi::grammar + qi::grammar { + using position_type = mapnik::geometry::point; + using boxes_type = Boxes; + using box_type = typename Boxes::value_type::first_type; extract_bounding_box_grammar(); // rules qi::rule start; qi::rule, void(boxes_type&), space_type> features; - qi::rule>, void(boxes_type&, Iterator const&), space_type> feature; - qi::rule>, box2d(), space_type> coords; - qi::rule(), space_type> pos; - qi::rule&), space_type> ring; - qi::rule&), space_type> rings; - qi::rule&), space_type> rings_array; + qi::rule, void(boxes_type&, Iterator const&), space_type> feature; + qi::rule, box_type(), space_type> coords; + qi::rule pos; + qi::rule ring; + qi::rule rings; + qi::rule rings_array; // generic JSON support json::generic_json json; - // phoenix functions - boost::phoenix::function push_box; - boost::phoenix::function calculate_bounding_box; - // error handler - boost::phoenix::function const error_handler; }; }} diff -Nru mapnik-3.0.9+ds/include/mapnik/json/extract_bounding_box_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/json/extract_bounding_box_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/json/extract_bounding_box_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/extract_bounding_box_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -22,24 +22,57 @@ // mapnik #include - +#include // boost #include #include #include #include #include +#include // stl #include #include namespace mapnik { namespace json { +struct calculate_bounding_box_impl +{ + using result_type = void; + template + result_type operator() (T0 & bbox, T1 const& pos) const + { + typename T0::value_type x = pos.x; + typename T0::value_type y = pos.y; + if (!bbox.valid()) + { + bbox.init(x, y); + } + else + { + bbox.expand_to_include(x, y); + } + } +}; + +struct push_box_impl +{ + using result_type = void; + template + void operator() (T0 & boxes, T1 const& begin, T2 const& box, T3 const& range) const + { + boxes.emplace_back(box, + std::make_pair(std::distance(begin, + range.begin()), + std::distance(range.begin(), range.end()))); + } +}; + namespace repo = boost::spirit::repository; -template -extract_bounding_box_grammar::extract_bounding_box_grammar() - : extract_bounding_box_grammar::base_type(start,"bounding boxes") +template +extract_bounding_box_grammar::extract_bounding_box_grammar() + : extract_bounding_box_grammar::base_type(start, "GeoJSON bounding boxes") { qi::lit_type lit; qi::double_type double_; @@ -61,6 +94,12 @@ using qi::fail; using qi::on_error; + // phoenix functions + boost::phoenix::function push_box; + boost::phoenix::function calculate_bounding_box; + // error handler + boost::phoenix::function const error_handler; + start = features(_r1) ; @@ -68,7 +107,7 @@ >> *((json.key_value - lit("\"features\"")) >> lit(',')) >> lit("\"features\"") >> lit(':')) - >> lit('[') >> (feature(_r1,_a) % lit(',')) >> lit(']') + >> lit('[') >> -(feature(_r1,_a) % lit(',')) >> lit(']') ; feature = raw[lit('{')[_a = 1] @@ -90,41 +129,16 @@ >> lit(':') >> (rings_array(_a) | rings (_a) | ring(_a) | pos[calculate_bounding_box(_a,_1)])[_val = _a] ; - pos = lit('[') > -(double_ > lit(',') > double_) > omit[*(lit(',') > double_)] > lit(']') - ; - - ring = lit('[') >> pos[calculate_bounding_box(_r1,_1)] % lit(',') > lit(']') - ; - - rings = lit('[') >> ring(_r1) % lit(',') > lit(']') - ; - - rings_array = lit('[') >> rings(_r1) % lit(',') > lit(']') - ; - - // 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) + pos = lit('[') > double_ > lit(',') > double_ > omit[*(lit(',') > double_)] > lit(']') ; - json.object = lit('{') >> *json.pairs >> lit('}') + ring = lit('[') >> -(pos[calculate_bounding_box(_r1,_1)] % lit(',')) >> lit(']') ; - json.array = lit('[') - >> json.value >> *(lit(',') >> json.value) - >> lit(']') + rings = lit('[') >> (ring(_r1) % lit(',') > lit(']')) ; - json.number = json.strict_double - | json.int__ - | lit("true") - | lit("false") - | lit("null") + rings_array = lit('[') >> (rings(_r1) % lit(',') > lit(']')) ; coords.name("Coordinates"); diff -Nru mapnik-3.0.9+ds/include/mapnik/json/feature_grammar.hpp mapnik-3.0.13+ds/include/mapnik/json/feature_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/json/feature_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/feature_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,14 +24,10 @@ #define MAPNIK_FEATURE_GRAMMAR_HPP // mapnik -#include #include #include -#include -#include -#include -#include - +#include +#include #pragma GCC diagnostic push #include #include @@ -45,27 +41,6 @@ namespace phoenix = boost::phoenix; namespace fusion = boost::fusion; -class attribute_value_visitor - -{ -public: - attribute_value_visitor(mapnik::transcoder const& tr) - : tr_(tr) {} - - mapnik::value operator()(std::string const& val) const - { - return mapnik::value(tr_.transcode(val.c_str())); - } - - template - mapnik::value operator()(T const& val) const - { - return mapnik::value(val); - } - - mapnik::transcoder const& tr_; -}; - struct put_property { using result_type = void; @@ -89,24 +64,19 @@ } }; -template > -struct feature_grammar : - qi::grammar +template > +struct feature_grammar : qi::grammar { - feature_grammar(mapnik::transcoder const& tr); - + explicit feature_grammar(mapnik::transcoder const& tr); // generic JSON generic_json json_; // geoJSON qi::rule start; - qi::rule, void(FeatureType&),space_type> feature; + qi::rule, void(FeatureType&), space_type> feature; + qi::rule feature_part; qi::rule feature_type; qi::rule properties; qi::rule, void(FeatureType &),space_type> attributes; - qi::rule attribute_value; - qi::rule, std::string(), space_type> stringify_object; - qi::rule, std::string(), space_type> stringify_array; // functions phoenix::function put_property_; phoenix::function set_geometry; diff -Nru mapnik-3.0.9+ds/include/mapnik/json/feature_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/json/feature_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/json/feature_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/feature_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -35,13 +35,13 @@ qi::lit_type lit; qi::long_long_type long_long; qi::double_type double_; - qi::_val_type _val; qi::_1_type _1; qi::_2_type _2; qi::_3_type _3; qi::_4_type _4; qi::_a_type _a; qi::_r1_type _r1; + qi::_r2_type _r2; qi::eps_type eps; qi::char_type char_; using qi::fail; @@ -49,31 +49,6 @@ using phoenix::new_; 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()] - ; - // geojson types feature_type = lit("\"type\"") > lit(':') > lit("\"Feature\"") ; @@ -81,38 +56,30 @@ start = feature(_r1); feature = eps[_a = false] > lit('{') > - (feature_type[_a = true] - | - (lit("\"geometry\"") > lit(':') > geometry_grammar_[set_geometry(_r1, _1)]) - | - properties(_r1) - | - json_.key_value) % lit(',') + feature_part(_r1, _a) % lit(',') > eps(_a) > lit('}') ; - properties = lit("\"properties\"") - > lit(':') > ((lit('{') > -attributes(_r1) > lit('}')) | lit("null")) + feature_part = feature_type[_r2 = true] + | + (lit("\"geometry\"") > lit(':') > geometry_grammar_[set_geometry(_r1, _1)]) + | + properties(_r1) + | + json_.key_value ; - attributes = (json_.string_ [_a = _1] > lit(':') > attribute_value [put_property_(_r1,_a,_1)]) % lit(',') - ; - - attribute_value %= json_.number | json_.string_ | stringify_object | stringify_array - ; - - stringify_object %= char_('{')[_a = 1 ] > *(eps(_a > 0) > (char_('{')[_a +=1] | char_('}')[_a -=1] | char_)) + properties = lit("\"properties\"") + > lit(':') > ((lit('{') > -attributes(_r1) > lit('}')) | lit("null")) ; - stringify_array %= char_('[')[_a = 1 ] > *(eps(_a > 0) > (char_('[')[_a +=1] | char_(']')[_a -=1] | char_)) + attributes = (json_.string_ [_a = _1] > lit(':') > json_.value [put_property_(_r1,_a,_1)]) % lit(',') ; feature.name("Feature"); feature_type.name("type"); properties.name("properties"); attributes.name("Attributes"); - attribute_value.name("Attribute Value"); - on_error(feature, error_handler(_1, _2, _3, _4)); } diff -Nru mapnik-3.0.9+ds/include/mapnik/json/generic_json.hpp mapnik-3.0.13+ds/include/mapnik/json/generic_json.hpp --- mapnik-3.0.9+ds/include/mapnik/json/generic_json.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/generic_json.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -31,15 +31,47 @@ #include #include #include +#include #pragma GCC diagnostic pop +#include + namespace mapnik { namespace json { namespace qi = boost::spirit::qi; namespace standard = boost::spirit::standard; namespace phoenix = boost::phoenix; using space_type = standard::space_type; -using json_value = mapnik::util::variant; + +struct json_value; + +using json_array = std::vector; +using json_object_element = std::pair; +using json_object = std::vector; +using json_value_base = mapnik::util::variant, + mapnik::util::recursive_wrapper >; +struct json_value : json_value_base +{ +#if __cpp_inheriting_constructors >= 200802 + + using json_value_base::json_value_base; + +#else + + json_value() = default; + + template + json_value(T && val) + : json_value_base(std::forward(val)) {} + +#endif +}; + using uchar = std::uint32_t; // a unicode code point // unicode string grammar via boost/libs/spirit/example/qi/json/json/parser/grammar.hpp @@ -97,7 +129,7 @@ } }; -template< typename Iterator > +template< typename Iterator> unicode_string::unicode_string() : unicode_string::base_type(double_quoted) { @@ -121,10 +153,14 @@ escape = ('x' > hex) [push_utf8(_r1, _1)] - | ('u' > hex4) [push_utf8(_r1, _1)] - | ('U' > hex8) [push_utf8(_r1, _1)] - | char_("0abtnvfre\"/\\N_LP \t") [push_esc(_r1, _1)] - | eol // continue to next line + | + ('u' > hex4) [push_utf8(_r1, _1)] + | + ('U' > hex8) [push_utf8(_r1, _1)] + | + char_("0abtnvfre\"/\\N_LP \t") [push_esc(_r1, _1)] + | + eol // continue to next line ; char_esc = @@ -132,27 +168,27 @@ ; double_quoted = - '"' + '"' > *(char_esc(_val) | (~char_('"')) [_val += _1]) > '"' ; } template -struct generic_json +struct generic_json : qi::grammar { - qi::rule value; - qi::int_parser int__; + generic_json(); + qi::rule value; + qi::int_parser int__; unicode_string string_; - qi::rule key_value; - qi::rule number; - qi::rule object; - qi::rule array; - qi::rule pairs; - qi::real_parser > strict_double; + qi::rule key_value; + qi::rule number; + qi::rule object; + qi::rule array; + qi::real_parser> strict_double; // conversions - boost::phoenix::function > integer_converter; - boost::phoenix::function > double_converter; + boost::phoenix::function> integer_converter; + boost::phoenix::function> double_converter; }; }} diff -Nru mapnik-3.0.9+ds/include/mapnik/json/geometry_generator_grammar.hpp mapnik-3.0.13+ds/include/mapnik/json/geometry_generator_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/json/geometry_generator_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/geometry_generator_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,12 +27,12 @@ #include #include #include -#include // boost #pragma GCC diagnostic push #include #include #include +#include #include // for vc++ and android whose c++11 libs lack std::trunc #include #pragma GCC diagnostic pop diff -Nru mapnik-3.0.9+ds/include/mapnik/json/geometry_generator_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/json/geometry_generator_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/json/geometry_generator_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/geometry_generator_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,6 +24,7 @@ #include #include #include +#include // boost #pragma GCC diagnostic push diff -Nru mapnik-3.0.9+ds/include/mapnik/json/geometry_grammar.hpp mapnik-3.0.13+ds/include/mapnik/json/geometry_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/json/geometry_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/geometry_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,9 +30,11 @@ #include #include -// spirit::qi +#pragma GCC diagnostic push +#include #include #include +#pragma GCC diagnostic pop namespace mapnik { namespace json { @@ -45,10 +47,13 @@ geometry_grammar(); qi::rule(), space_type> start; qi::rule, mapnik::geometry::geometry(), space_type> geometry; + qi::rule&), space_type> geometry_part; qi::rule(), space_type> geometry_collection; qi::symbols geometry_type_dispatch; positions_grammar coordinates; boost::phoenix::function create_geometry; + // generic JSON + generic_json json_; // error handler ErrorHandler error_handler; }; diff -Nru mapnik-3.0.9+ds/include/mapnik/json/geometry_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/json/geometry_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/json/geometry_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/geometry_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,14 +24,10 @@ #include #include #include -#include - +#include // boost -#include #include -#include -#include // for clog, endl, etc -#include // for string +#include namespace mapnik { namespace json { @@ -50,6 +46,9 @@ qi::_4_type _4; qi::_a_type _a; qi::_b_type _b; + qi::_r1_type _r1; + qi::_r2_type _r2; + qi::_r3_type _r3; qi::eps_type eps; using qi::fail; using qi::on_error; @@ -58,12 +57,16 @@ start = geometry.alias() | lit("null"); geometry = lit('{')[_a = 0] - > (-lit(',') >> (lit("\"type\"") > lit(':') > geometry_type_dispatch[_a = _1]) - ^ - (-lit(',') >> (lit("\"coordinates\"") > lit(':') > coordinates[_b = _1])) - ^ - (-lit(',') >> (lit("\"geometries\"") > lit(':') > lit('[') > geometry_collection[_val = _1] > lit(']'))))[create_geometry(_val,_a,_b)] - > lit('}') + > (geometry_part(_a, _b, _val) % lit(','))[create_geometry(_val, _a, _b)] + > lit('}'); + + geometry_part = ((lit("\"type\"") > lit(':') > geometry_type_dispatch[_r1 = _1]) + | + (lit("\"coordinates\"") > lit(':') > coordinates[_r2 = _1]) + | + (lit("\"geometries\"") > lit(':') > lit('[') > geometry_collection[_r3 = _1] > lit(']')) + | + json_.key_value) ; geometry_collection = geometry[push_back(_val, _1)] % lit(',') diff -Nru mapnik-3.0.9+ds/include/mapnik/json/geometry_parser.hpp mapnik-3.0.13+ds/include/mapnik/json/geometry_parser.hpp --- mapnik-3.0.9+ds/include/mapnik/json/geometry_parser.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/geometry_parser.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,25 +24,13 @@ #define MAPNIK_JSON_GEOMETRY_PARSER_HPP // mapnik +#include - -#include - -// boost -#include -#include +#include namespace mapnik { namespace json { -inline bool from_geojson(std::string const& json, mapnik::geometry::geometry & geom) -{ - using namespace boost::spirit; - static const geometry_grammar g; - standard::space_type space; - char const* start = json.c_str(); - char const* end = start + json.length(); - return qi::phrase_parse(start, end, g, space, geom); -} +bool from_geojson(std::string const& json, mapnik::geometry::geometry & geom); }} diff -Nru mapnik-3.0.9+ds/include/mapnik/json/geometry_util.hpp mapnik-3.0.13+ds/include/mapnik/json/geometry_util.hpp --- mapnik-3.0.9+ds/include/mapnik/json/geometry_util.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/geometry_util.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,6 +25,7 @@ #include #include +#include namespace mapnik { namespace json { diff -Nru mapnik-3.0.9+ds/include/mapnik/json/positions_grammar.hpp mapnik-3.0.13+ds/include/mapnik/json/positions_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/json/positions_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/positions_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,51 +24,19 @@ #define MAPNIK_JSON_POSITIONS_GRAMMAR_HPP // mapnik -#include -#include +#include #include -#include -#include - #pragma GCC diagnostic push #include #include -#include -#include #pragma GCC diagnostic pop -// stl -#include namespace mapnik { namespace json { -struct empty {}; - -using position = mapnik::geometry::point; -using positions = std::vector; -using coordinates = util::variant, std::vector > > ; - namespace qi = boost::spirit::qi; - -struct set_position_impl -{ - using result_type = void; - template - result_type operator() (T0 & coords, T1 const& pos) const - { - if (pos) coords = *pos; - } -}; - -struct push_position_impl -{ - using result_type = void; - template - result_type operator() (T0 & coords, T1 const& pos) const - { - if (pos) coords.push_back(*pos); - } -}; +namespace standard = boost::spirit::standard; +using space_type = standard::space_type; template > struct positions_grammar : @@ -76,12 +44,10 @@ { positions_grammar(ErrorHandler & error_handler); qi::rule coords; - qi::rule(), space_type> pos; + qi::rule pos; qi::rule ring; qi::rule(), space_type> rings; qi::rule >(), space_type> rings_array; - boost::phoenix::function set_position; - boost::phoenix::function push_position; }; }} diff -Nru mapnik-3.0.9+ds/include/mapnik/json/positions_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/json/positions_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/json/positions_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/positions_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -22,18 +22,39 @@ // mapnik #include - +#include // boost #include #include #include #include +#include // stl #include #include namespace mapnik { namespace json { +struct set_position_impl +{ + using result_type = void; + template + result_type operator() (T0 & coords, T1 const& pos) const + { + coords = pos; + } +}; + +struct push_position_impl +{ + using result_type = void; + template + result_type operator() (T0 & coords, T1 const& pos) const + { + coords.emplace_back(pos); + } +}; + template positions_grammar::positions_grammar(ErrorHandler & error_handler) : positions_grammar::base_type(coords,"coordinates") @@ -49,15 +70,18 @@ using qi::fail; using qi::on_error; + boost::phoenix::function set_position; + boost::phoenix::function push_position; + coords = rings_array[_val = _1] | rings [_val = _1] | ring[_val = _1] | pos[set_position(_val,_1)] ; - pos = lit('[') > -(double_ > lit(',') > double_) > omit[*(lit(',') > double_)] > lit(']') + pos = lit('[') > double_ > lit(',') > double_ > omit[*(lit(',') > double_)] > lit(']') ; - ring = lit('[') >> pos[push_position(_val,_1)] % lit(',') > lit(']') + ring = lit('[') >> -(pos[push_position(_val,_1)] % lit(',')) >> lit(']') ; - rings = lit('[') >> ring % lit(',') > lit(']') + rings = lit('[') >> (ring % lit(',') > lit(']')) ; - rings_array = lit('[') >> rings % lit(',') > lit(']') + rings_array = lit('[') >> (rings % lit(',') > lit(']')) ; coords.name("Coordinates"); pos.name("Position"); diff -Nru mapnik-3.0.9+ds/include/mapnik/json/positions.hpp mapnik-3.0.13+ds/include/mapnik/json/positions.hpp --- mapnik-3.0.9+ds/include/mapnik/json/positions.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/positions.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,40 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_JSON_POSITIONS_HPP +#define MAPNIK_JSON_POSITIONS_HPP + +// mapnik +#include +#include + +namespace mapnik { namespace json { + +struct empty {}; + +using position = mapnik::geometry::point; +using positions = std::vector; +using coordinates = util::variant, std::vector > > ; + +}} + +#endif // MAPNIK_JSON_POSITIONS_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/json/properties_generator_grammar.hpp mapnik-3.0.13+ds/include/mapnik/json/properties_generator_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/json/properties_generator_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/properties_generator_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,23 +25,20 @@ #include #include -#include #pragma GCC diagnostic push #include #include -#include #include -#include -#include -#include -#include -#include -#include #pragma GCC diagnostic pop +#include +#include + namespace mapnik { namespace json { +namespace karma = boost::spirit::karma; + template struct escaped_string : karma::grammar diff -Nru mapnik-3.0.9+ds/include/mapnik/json/stringifier.hpp mapnik-3.0.13+ds/include/mapnik/json/stringifier.hpp --- mapnik-3.0.9+ds/include/mapnik/json/stringifier.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/stringifier.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,101 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_JSON_STRINGIFIER_HPP +#define MAPNIK_JSON_STRINGIFIER_HPP + +// mapnik +#include +#include +#include +// stl +#include + + +namespace mapnik { namespace json { + +struct stringifier +{ + std::string operator()(std::string const& val) const + { + return "\"" + val + "\""; + } + + std::string operator()(value_null) const + { + return "null"; + } + + std::string operator()(value_bool val) const + { + return val ? "true" : "false"; + } + + std::string operator()(value_integer val) const + { + std::string str; + util::to_string(str, val); + return str; + } + + std::string operator()(value_double val) const + { + std::string str; + util::to_string(str, val); + return str; + } + + std::string operator()(std::vector const& array) const + { + std::string str = "["; + bool first = true; + for (auto const& val : array) + { + if (first) first = false; + else str += ","; + str += mapnik::util::apply_visitor(*this, val); + } + str += "]"; + return str; + } + + std::string operator()(std::vector> const& object) const + { + std::string str = "{"; + bool first = true; + for (auto const& kv : object) + { + if (first) first = false; + else str += ","; + str += "\"" + kv.first + "\""; + str += ":"; + str += mapnik::util::apply_visitor(*this, kv.second); + } + str += "}"; + return str; + } +}; + +}} + + +#endif // MAPNIK_JSON_STRINGIFIER_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/json/symbolizer_grammar.hpp mapnik-3.0.13+ds/include/mapnik/json/symbolizer_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/json/symbolizer_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/symbolizer_grammar.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,216 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2015 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 - * - *****************************************************************************/ - -#ifndef MAPNIK_SYMBOLIZER_GRAMMAR_HPP -#define MAPNIK_SYMBOLIZER_GRAMMAR_HPP - -#include - -// boost -#include -#include - -// mapnik -#include -#include -#include -#include -#include - -namespace mapnik { namespace json { - -namespace qi = boost::spirit::qi; -namespace phoenix = boost::phoenix; -namespace fusion = boost::fusion; -namespace standard_wide = boost::spirit::standard_wide; -using standard_wide::space_type; - -template -struct json_value_visitor -{ - json_value_visitor(Symbolizer & sym, mapnik::keys key) - : sym_(sym), key_(key) {} - - void operator() (value_bool val) const - { - put(sym_, key_, val); - } - - void operator() (value_integer val) const - { - put(sym_, key_, val); - } - - void operator() (value_double val) const - { - put(sym_, key_, val); - } - - void operator() (std::string const& val) const - { - set_property(sym_, key_, val); - } - - template - void operator() (T const& val) const - { - std::cerr << std::get<0>(get_meta(key_)) << ":" << val << std::endl; - //put(sym_, key_, val); - } - - Symbolizer & sym_; - keys key_; -}; - -template -struct put_property_visitor -{ - using value_type = T; - - put_property_visitor(mapnik::keys key, value_type const& val) - : key_(key), val_(val) {} - - template - void operator() (Symbolizer & sym) const - { - mapnik::util::apply_visitor(json_value_visitor(sym, key_), val_); - } - - keys key_; - value_type const& val_; -}; - -struct put_property -{ - using result_type = void; - template - result_type operator() (T0 & sym, T1 const& name, T2 const& val) const - { - try - { - mapnik::util::apply_visitor(put_property_visitor(get_key(name),val), sym); - } - catch (std::runtime_error const& err) - { - std::cerr << err.what() << std::endl; - } - } -}; - -template > -struct symbolizer_grammar : qi::grammar -{ - using json_value_type = util::variant; - symbolizer_grammar() - : symbolizer_grammar::base_type(sym, "symbolizer"), - json_() - { - qi::lit_type lit; - qi::double_type double_; - qi::int_type int_; - qi::no_skip_type no_skip; - qi::_val_type _val; - qi::_a_type _a; - qi::_r1_type _r1; - qi::_1_type _1; - standard_wide::char_type char_; - 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 - | json_.int__ - | lit("true") [_val = true] - | lit ("false") [_val = false] - | lit("null")[_val = construct()] - ; - json_.unesc_char.add - ("\\\"", '\"') // quotation mark - ("\\\\", '\\') // reverse solidus - ("\\/", '/') // solidus - ("\\b", '\b') // backspace - ("\\f", '\f') // formfeed - ("\\n", '\n') // newline - ("\\r", '\r') // carrige return - ("\\t", '\t') // tab - ; - - json_.string_ %= lit('"') >> no_skip[*(json_.unesc_char | "\\u" >> json_.hex4 | (char_ - lit('"')))] >> lit('"') - ; - - sym = lit('{') - >> lit("\"type\"") >> lit(':') - >> (lit("\"PointSymbolizer\"")[_val = construct()] - | - lit("\"LineSymbolizer\"")[_val = construct()] - | - lit("\"PolygonSymbolizer\"")[_val = construct()] - ) - >> lit(',') - >> lit("\"properties\"") >> lit(':') - >> ((lit('{') >> *property(_val) >> lit('}')) | lit("null")) - >> lit('}') - ; - - property = (json_.string_ [_a = _1] >> lit(':') >> property_value [put_property_(_r1,_a,_1)]) % lit(',') - ; - - property_value %= json_.number | json_.string_ ; - - - } - - // generic JSON - generic_json json_; - // symbolizer - qi::rule sym; - qi::rule, void(mapnik::symbolizer&),space_type> property; - qi::rule property_value; - - phoenix::function put_property_; - // error - //qi::on_error(sym, error_handler(_1, _2, _3, _4)); -}; - - -}} - -#endif // MAPNIK_SYMBOLIZER_GRAMMAR_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/json/topojson_grammar.hpp mapnik-3.0.13+ds/include/mapnik/json/topojson_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/json/topojson_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/topojson_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,14 +25,12 @@ // mapnik #include -#include #include #include #pragma GCC diagnostic push #include #include -#include #pragma GCC diagnostic pop // stl @@ -44,6 +42,138 @@ namespace fusion = boost::fusion; using space_type = mapnik::json::space_type; +struct create_point +{ + using result_type = mapnik::topojson::point; + template + result_type operator()(T0 & coord, T1 & props) const + { + mapnik::topojson::point pt; + if (coord.template is()) + { + auto const& coord_ = coord.template get(); + pt.coord = coord_; + pt.props = props; + } + return pt; + } +}; + +struct create_multi_point +{ + using result_type = mapnik::topojson::multi_point; + template + result_type operator()(T0 & coords, T1 & props) const + { + mapnik::topojson::multi_point mpt; + if (coords.template is>()) + { + auto const& points = coords.template get>(); + mpt. points = points; + mpt.props = props; + } + return mpt; + } +}; + +struct create_line_string +{ + using result_type = mapnik::topojson::linestring; + template + result_type operator()(T0 & arcs, T1 & props) const + { + mapnik::topojson::linestring line; + if (arcs.template is>()) + { + auto const& arcs_ = arcs.template get>(); + line.rings = arcs_; + line.props = props; + } + return line; + } +}; + +struct create_multi_line_string +{ + using result_type = mapnik::topojson::multi_linestring; + template + result_type operator()(T0 & arcs, T1 & props) const + { + mapnik::topojson::multi_linestring mline; + if (arcs.template is>>()) + { + auto const& arcs_ = arcs.template get>>(); + mline.lines = arcs_; + mline.props = props; + } + return mline; + } +}; + +struct create_polygon +{ + using result_type = mapnik::topojson::polygon; + template + result_type operator()(T0 & arcs, T1 & props) const + { + mapnik::topojson::polygon poly; + if (arcs.template is>>()) + { + auto const& arcs_ = arcs.template get>>(); + poly.rings = arcs_; + poly.props = props; + } + return poly; + } +}; + +struct create_multi_polygon +{ + using result_type = mapnik::topojson::multi_polygon; + template + result_type operator()(T0 & arcs, T1 & props) const + { + mapnik::topojson::multi_polygon mpoly; + if (arcs.template is>>>()) + { + auto const& arcs_ = arcs.template get>>>(); + mpoly.polygons = arcs_; + mpoly.props = props; + } + return mpoly; + } +}; + + +struct create_geometry_impl +{ + using result_type = mapnik::topojson::geometry; + template + result_type operator()(T0 geom_type, T1 & coord, T2 & arcs, T3 & props) const + { + switch (geom_type) + { + case 1: //Point + return create_point()(coord, props); + case 2: //LineString + return create_line_string()(arcs, props); + case 3: //Polygon + return create_polygon()(arcs, props); + case 4: //MultiPoint + return create_multi_point()(coord, props); + case 5: //MultiLineString + return create_multi_line_string()(arcs, props); + case 6: //MultiPolygon + return create_multi_polygon()(arcs, props); + default: + break; + } + return mapnik::topojson::geometry(); //empty + } +}; + +using coordinates_type = util::variant>; +using arcs_type = util::variant, std::vector>, std::vector>>>; template > struct topojson_grammar : qi::grammar @@ -51,34 +181,24 @@ topojson_grammar(); private: // generic JSON support - json::generic_json json_; + json::generic_json json; // topoJSON qi::rule topology; qi::rule()> objects; qi::rule()> arcs; qi::rule arc; - qi::rule coordinate; + qi::rule coordinate_; + qi::rule coordinates; qi::rule transform; qi::rule bbox; - qi::rule geometry; - qi::rule point; - qi::rule multi_point; - qi::rule linestring; - qi::rule multi_linestring; - qi::rule polygon; - qi::rule multi_polygon; + qi::rule, mapnik::topojson::geometry(), space_type> geometry; qi::rule&)> geometry_collection; - qi::rule()> ring; - + qi::rule>()> rings; + qi::rule rings_array; // properties - qi::rule properties; - qi::rule attributes; - qi::rule attribute_value; - // id - qi::rule id; - // error handler - boost::phoenix::function const error_handler; + qi::rule properties_; + qi::symbols geometry_type_dispatch; }; }} diff -Nru mapnik-3.0.9+ds/include/mapnik/json/topojson_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/json/topojson_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/json/topojson_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/topojson_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -21,6 +21,51 @@ *****************************************************************************/ #include +#include + +#pragma GCC diagnostic push +#include +#include +#include +#include +#pragma GCC diagnostic pop + +BOOST_FUSION_ADAPT_STRUCT( + mapnik::topojson::coordinate, + (double, x) + (double, y) + ) + +BOOST_FUSION_ADAPT_STRUCT( + mapnik::topojson::arc, + (std::list, coordinates) + ) + +BOOST_FUSION_ADAPT_STRUCT( + mapnik::topojson::transform, + (double, scale_x) + (double, scale_y) + (double, translate_x) + (double, translate_y) + ) + +BOOST_FUSION_ADAPT_STRUCT( + mapnik::topojson::bounding_box, + (double, minx) + (double, miny) + (double, maxx) + (double, maxy) + ) + +BOOST_FUSION_ADAPT_STRUCT( + mapnik::topojson::topology, + (std::vector, geometries) + (std::vector, arcs) + (boost::optional, tr) + (boost::optional, bbox) + ) + + namespace mapnik { namespace topojson { @@ -42,34 +87,27 @@ qi::_3_type _3; qi::_4_type _4; qi::_r1_type _r1; + qi::_a_type _a; + qi::_b_type _b; + qi::_c_type _c; + qi::_d_type _d; 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('}') + geometry_type_dispatch.add + ("\"Point\"",1) + ("\"LineString\"",2) + ("\"Polygon\"",3) + ("\"MultiPoint\"",4) + ("\"MultiLineString\"",5) + ("\"MultiPolygon\"",6) + ("\"GeometryCollection\"",7) ; - 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()] - ; + // error handler + boost::phoenix::function const error_handler; + boost::phoenix::function const create_geometry; // topo json topology = lit('{') >> lit("\"type\"") >> lit(':') >> lit("\"Topology\"") @@ -96,117 +134,70 @@ objects = lit("\"objects\"") >> lit(':') >> lit('{') - >> -((omit[json_.string_] + >> -((omit[json.string_] >> lit(':') - >> (geometry_collection(_val) | geometry)) % lit(',')) + >> (geometry_collection(_val) | geometry[push_back(_val, _1)]) % lit(','))) >> lit('}') ; - geometry = - point | - linestring | - polygon | - multi_point | - multi_linestring | - multi_polygon | - omit[json_.object] + geometry = lit('{')[_a = 0] + > ((lit("\"type\"") > lit(':') > geometry_type_dispatch[_a = _1]) + | + (lit("\"coordinates\"") > lit(':') > coordinates[_b = _1]) + | + (lit("\"arcs\"") > lit(':') > rings_array[_c = _1]) + | + properties_[_d = _1] + | + json.key_value) % lit(',') + > lit('}')[_val = create_geometry(_a, _b, _c, _d)] ; - 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])) + geometry_collection = lit('{') + >> lit("\"type\"") >> lit(':') >> lit("\"GeometryCollection\"") + >> lit(',') >> lit("\"geometries\"") >> lit(':') + >> lit('[') + >> -(geometry[push_back(_r1, _1)] % lit(',')) + >> lit(']') >> 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('}') + ring = lit('[') >> -(int_ % lit(',')) >> lit(']') ; - - id = lit("\"id\"") >> lit(':') >> omit[json_.value] + rings = lit('[') >> -(ring % lit(',')) >> lit(']') ; - - ring = lit('[') >> -(int_ % lit(',')) >> lit(']') + rings_array = lit('[') >> -(rings % lit(',')) >> lit(']') + | + rings + | + ring ; - properties = lit("\"properties\"") + properties_ = lit("\"properties\"") >> lit(':') - >> (( lit('{') >> attributes >> lit('}')) | json_.object) + >> lit('{') >> (json.string_ >> lit(':') >> json.value) % lit(',') >> lit('}') ; - 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(']') ; + arc = lit('[') >> -(coordinate_ % lit(',')) >> lit(']') ; - coordinate = lit('[') >> double_ >> lit(',') >> double_ >> lit(']'); + coordinate_ = lit('[') > double_ > lit(',') > double_ > lit(']'); + + coordinates = (lit('[') >> coordinate_ % lit(',') > lit(']')) + | coordinate_; 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"); + json.value.name("value"); + coordinate_.name("coordinate"); + geometry.name("geometry"); + properties_.name("properties"); geometry_collection.name("geometry_collection"); // error handler on_error(topology, error_handler(_1, _2, _3, _4)); diff -Nru mapnik-3.0.9+ds/include/mapnik/json/topojson_utils.hpp mapnik-3.0.13+ds/include/mapnik/json/topojson_utils.hpp --- mapnik-3.0.9+ds/include/mapnik/json/topojson_utils.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/topojson_utils.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -2,7 +2,7 @@ * * This file is part of Mapnik (c++ mapping toolkit) * - * Copyright (C) 2015 Artem Pavlenko + * Copyright (C) 2016 Artem Pavlenko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,7 +25,12 @@ // mapnik #include +#include #include +#include +#include +#include +#include namespace mapnik { namespace topojson { @@ -35,6 +40,11 @@ : topo_(topo), num_arcs_(topo_.arcs.size()) {} + box2d operator() (mapnik::topojson::empty const&) const + { + return box2d(); + } + box2d operator() (mapnik::topojson::point const& pt) const { double x = pt.coord.x; @@ -50,79 +60,42 @@ box2d operator() (mapnik::topojson::multi_point const& multi_pt) const { box2d bbox; - if (num_arcs_ > 0) + bool first = true; + double px = 0, py = 0; + for (auto const& pt : multi_pt.points) { - bool first = true; - for (auto const& pt : multi_pt.points) + double x = pt.x; + double y = pt.y; + if (topo_.tr) { - double x = pt.x; - double y = pt.y; - if (topo_.tr) - { - x = x * (*topo_.tr).scale_x + (*topo_.tr).translate_x; - y = y * (*topo_.tr).scale_y + (*topo_.tr).translate_y; // TODO : delta encoded ? - } - if (first) - { - first = false; - bbox.init(x,y,x,y); - } - else - { - bbox.expand_to_include(x,y); - } + x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x; + y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y; } - } - return bbox; - } - - box2d operator() (mapnik::topojson::linestring const& line) const - { - box2d bbox; - if (num_arcs_ > 0) - { - index_type index = line.ring; - index_type arc_index = index < 0 ? std::abs(index) - 1 : index; - if (arc_index >= 0 && arc_index < static_cast(num_arcs_)) + if (first) { - bool first = true; - double px = 0, py = 0; - auto const& arcs = topo_.arcs[arc_index]; - for (auto pt : arcs.coordinates) - { - double x = pt.x; - double y = pt.y; - if (topo_.tr) - { - x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x; - y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y; - } - if (first) - { - first = false; - bbox.init(x, y, x, y); - } - else - { - bbox.expand_to_include(x, y); - } - } + first = false; + bbox.init(x,y,x,y); + } + else + { + bbox.expand_to_include(x,y); } } return bbox; } - box2d operator() (mapnik::topojson::multi_linestring const& multi_line) const + box2d operator() (mapnik::topojson::linestring const& line) const { box2d bbox; + bool first = true; if (num_arcs_ > 0) { - bool first = true; - for (auto index : multi_line.rings) + for (auto index : line.rings) { index_type arc_index = index < 0 ? std::abs(index) - 1 : index; if (arc_index >= 0 && arc_index < static_cast(num_arcs_)) { + double px = 0, py = 0; auto const& arcs = topo_.arcs[arc_index]; for (auto pt : arcs.coordinates) @@ -150,6 +123,47 @@ return bbox; } + box2d operator() (mapnik::topojson::multi_linestring const& multi_line) const + { + box2d bbox; + if (num_arcs_ > 0) + { + bool first = true; + for (auto const& line : multi_line.lines) + { + for (auto index : line) + { + index_type arc_index = index < 0 ? std::abs(index) - 1 : index; + if (arc_index >= 0 && arc_index < static_cast(num_arcs_)) + { + double px = 0, py = 0; + auto const& arcs = topo_.arcs[arc_index]; + for (auto pt : arcs.coordinates) + { + double x = pt.x; + double y = pt.y; + if (topo_.tr) + { + x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x; + y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y; + } + if (first) + { + first = false; + bbox.init(x, y, x, y); + } + else + { + bbox.expand_to_include(x, y); + } + } + } + } + } + } + return bbox; + } + box2d operator() (mapnik::topojson::polygon const& poly) const { box2d bbox; @@ -243,6 +257,321 @@ std::size_t num_arcs_; }; +namespace { + +template +void assign_properties(mapnik::feature_impl & feature, T const& geom, mapnik::transcoder const& tr) +{ + if ( geom.props) + { + for (auto const& p : *geom.props) + { + feature.put_new(std::get<0>(p), mapnik::util::apply_visitor(mapnik::json::attribute_value_visitor(tr),std::get<1>(p))); + } + } +} + +} + +template +struct feature_generator +{ + feature_generator(Context & ctx, mapnik::transcoder const& tr, topology const& topo, std::size_t feature_id) + : ctx_(ctx), + tr_(tr), + topo_(topo), + num_arcs_(topo.arcs.size()), + feature_id_(feature_id) {} + + feature_ptr operator() (point const& pt) const + { + mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); + double x = pt.coord.x; + double y = pt.coord.y; + if (topo_.tr) + { + x = x * (*topo_.tr).scale_x + (*topo_.tr).translate_x; + y = y * (*topo_.tr).scale_y + (*topo_.tr).translate_y; + } + mapnik::geometry::point point(x, y); + feature->set_geometry(std::move(point)); + assign_properties(*feature, pt, tr_); + return feature; + } + + feature_ptr operator() (multi_point const& multi_pt) const + { + mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); + mapnik::geometry::multi_point multi_point; + multi_point.reserve(multi_pt.points.size()); + for (auto const& pt : multi_pt.points) + { + double x = pt.x; + double y = pt.y; + if (topo_.tr) + { + x = x * (*topo_.tr).scale_x + (*topo_.tr).translate_x; + y = y * (*topo_.tr).scale_y + (*topo_.tr).translate_y; + } + multi_point.add_coord(x, y); + } + feature->set_geometry(std::move(multi_point)); + assign_properties(*feature, multi_pt, tr_); + return feature; + } + + feature_ptr operator() (linestring const& line) const + { + mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); + if (num_arcs_ > 0) + { + mapnik::geometry::line_string line_string; + + for (auto index : line.rings) + { + index_type arc_index = index < 0 ? std::abs(index) - 1 : index; + if (arc_index >= 0 && arc_index < static_cast(num_arcs_)) + { + auto const& arcs = topo_.arcs[arc_index]; + double px = 0, py = 0; + line_string.reserve(line_string.size() + arcs.coordinates.size()); + for (auto pt : arcs.coordinates) + { + double x = pt.x; + double y = pt.y; + if (topo_.tr) + { + x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x; + y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y; + } + line_string.add_coord(x,y); + } + } + } + feature->set_geometry(std::move(line_string)); + assign_properties(*feature, line, tr_); + } + return feature; + } + + feature_ptr operator() (multi_linestring const& multi_line) const + { + mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); + if (num_arcs_ > 0) + { + mapnik::geometry::multi_line_string multi_line_string; + bool hit = false; + for (auto const& line : multi_line.lines) + { + multi_line_string.reserve(multi_line_string.size() + line.size()); + mapnik::geometry::line_string line_string; + for (auto index : line) + { + index_type arc_index = index < 0 ? std::abs(index) - 1 : index; + if (arc_index >= 0 && arc_index < static_cast(num_arcs_)) + { + hit = true; + double px = 0, py = 0; + auto const& arcs = topo_.arcs[arc_index]; + line_string.reserve(line_string.size() + arcs.coordinates.size()); + for (auto pt : arcs.coordinates) + { + double x = pt.x; + double y = pt.y; + if (topo_.tr) + { + x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x; + y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y; + } + line_string.add_coord(x, y); + } + + } + } + multi_line_string.push_back(std::move(line_string)); + } + if (hit) + { + feature->set_geometry(std::move(multi_line_string)); + assign_properties(*feature, multi_line, tr_); + } + } + return feature; + } + + feature_ptr operator() (polygon const& poly) const + { + mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); + if (num_arcs_ > 0) + { + std::vector processed_coords; + mapnik::geometry::polygon polygon; + if (poly.rings.size() > 1) polygon.interior_rings.reserve(poly.rings.size() - 1); + bool first = true; + bool hit = false; + for (auto const& ring : poly.rings) + { + mapnik::geometry::linear_ring linear_ring; + for (auto const& index : ring) + { + double px = 0, py = 0; + bool reverse = index < 0; + index_type arc_index = reverse ? std::abs(index) - 1 : index; + if (arc_index >= 0 && arc_index < static_cast(num_arcs_)) + { + hit = true; + auto const& arcs = topo_.arcs[arc_index]; + auto const& coords = arcs.coordinates; + processed_coords.clear(); + processed_coords.reserve(coords.size()); + for (auto const& pt : coords ) + { + double x = pt.x; + double y = pt.y; + + if (topo_.tr) + { + transform const& tr = *topo_.tr; + x = (px += x) * tr.scale_x + tr.translate_x; + y = (py += y) * tr.scale_y + tr.translate_y; + } + processed_coords.emplace_back(coordinate{x,y}); + } + linear_ring.reserve(linear_ring.size() + processed_coords.size()); + if (reverse) + { + for (auto const& c : processed_coords | boost::adaptors::reversed) + { + linear_ring.emplace_back(c.x, c.y); + } + } + else + { + for (auto const& c : processed_coords) + { + linear_ring.emplace_back(c.x, c.y); + } + } + } + } + if (first) + { + first = false; + polygon.set_exterior_ring(std::move(linear_ring)); + } + else + { + polygon.add_hole(std::move(linear_ring)); + } + } + if (hit) + { + mapnik::geometry::correct(polygon); + feature->set_geometry(std::move(polygon)); + assign_properties(*feature, poly, tr_); + } + } + return feature; + } + + feature_ptr operator() (multi_polygon const& multi_poly) const + { + mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); + if (num_arcs_ > 0) + { + std::vector processed_coords; + mapnik::geometry::multi_polygon multi_polygon; + multi_polygon.reserve(multi_poly.polygons.size()); + bool hit = false; + for (auto const& poly : multi_poly.polygons) + { + bool first = true; + mapnik::geometry::polygon polygon; + if (poly.size() > 1) polygon.interior_rings.reserve(poly.size() - 1); + + for (auto const& ring : poly) + { + mapnik::geometry::linear_ring linear_ring; + for (auto const& index : ring) + { + double px = 0, py = 0; + bool reverse = index < 0; + index_type arc_index = reverse ? std::abs(index) - 1 : index; + if (arc_index >= 0 && arc_index < static_cast(num_arcs_)) + { + hit = true; + auto const& arcs = topo_.arcs[arc_index]; + auto const& coords = arcs.coordinates; + processed_coords.clear(); + processed_coords.reserve(coords.size()); + for (auto const& pt : coords ) + { + double x = pt.x; + double y = pt.y; + + if (topo_.tr) + { + transform const& tr = *topo_.tr; + x = (px += x) * tr.scale_x + tr.translate_x; + y = (py += y) * tr.scale_y + tr.translate_y; + } + processed_coords.emplace_back(coordinate{x,y}); + } + + using namespace boost::adaptors; + linear_ring.reserve(linear_ring.size() + processed_coords.size()); + if (reverse) + { + for (auto const& c : (processed_coords | reversed)) + { + linear_ring.add_coord(c.x, c.y); + } + } + else + { + for (auto const& c : processed_coords) + { + linear_ring.add_coord(c.x, c.y); + } + } + } + } + if (first) + { + first = false; + polygon.set_exterior_ring(std::move(linear_ring)); + } + else + { + polygon.add_hole(std::move(linear_ring)); + } + } + multi_polygon.push_back(std::move(polygon)); + } + if (hit) + { + mapnik::geometry::correct(multi_polygon); + feature->set_geometry(std::move(multi_polygon)); + assign_properties(*feature, multi_poly, tr_); + } + } + return feature; + } + + template + feature_ptr operator() (T const& ) const + { + return feature_ptr(); + } + + Context & ctx_; + mapnik::transcoder const& tr_; + topology const& topo_; + std::size_t num_arcs_; + std::size_t feature_id_; +}; + + }} #endif //MAPNIK_TOPOJSON_UTILS_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/json/topology.hpp mapnik-3.0.13+ds/include/mapnik/json/topology.hpp --- mapnik-3.0.9+ds/include/mapnik/json/topology.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/json/topology.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,8 +28,6 @@ #pragma GCC diagnostic push #include -#include -#include #include #pragma GCC diagnostic pop @@ -64,13 +62,13 @@ struct linestring { - index_type ring ; + std::vector rings ; boost::optional props; }; struct multi_linestring { - std::vector rings; + std::vector > lines; boost::optional props; }; @@ -86,7 +84,10 @@ boost::optional props; }; -using geometry = util::variant, coordinates) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::transform, - (double, scale_x) - (double, scale_y) - (double, translate_x) - (double, translate_y) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::bounding_box, - (double, minx) - (double, miny) - (double, maxx) - (double, maxy) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::point, - (mapnik::topojson::coordinate, coord) - (boost::optional, props) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::multi_point, - (std::vector, points) - (boost::optional, props) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::linestring, - (mapnik::topojson::index_type, ring) - (boost::optional, props) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::multi_linestring, - (std::vector, rings) - (boost::optional, props) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::polygon, - (std::vector >, rings) - (boost::optional, props) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::multi_polygon, - (std::vector > >, polygons) - (boost::optional, props) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::topology, - (std::vector, geometries) - (std::vector, arcs) - (boost::optional, tr) - (boost::optional, bbox) - ) - #endif // MAPNIK_TOPOLOGY_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/label_collision_detector.hpp mapnik-3.0.13+ds/include/mapnik/label_collision_detector.hpp --- mapnik-3.0.9+ds/include/mapnik/label_collision_detector.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/label_collision_detector.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,8 +28,10 @@ #include #include -// icu +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl #include @@ -145,17 +147,17 @@ public: using query_iterator = tree_t::query_iterator; - explicit label_collision_detector4(box2d const& extent) - : tree_(extent) {} + explicit label_collision_detector4(box2d const& _extent) + : tree_(_extent) {} bool has_placement(box2d const& box) { - tree_t::query_iterator itr = tree_.query_in_box(box); - tree_t::query_iterator end = tree_.query_end(); + tree_t::query_iterator tree_itr = tree_.query_in_box(box); + tree_t::query_iterator tree_end = tree_.query_end(); - for ( ;itr != end; ++itr) + for ( ;tree_itr != tree_end; ++tree_itr) { - if (itr->get().box.intersects(box)) return false; + if (tree_itr->get().box.intersects(box)) return false; } return true; @@ -168,12 +170,12 @@ box.maxx() + margin, box.maxy() + margin) : box); - tree_t::query_iterator itr = tree_.query_in_box(margin_box); - tree_t::query_iterator end = tree_.query_end(); + tree_t::query_iterator tree_itr = tree_.query_in_box(margin_box); + tree_t::query_iterator tree_end = tree_.query_end(); - for (;itr != end; ++itr) + for (;tree_itr != tree_end; ++tree_itr) { - if (itr->get().box.intersects(margin_box)) + if (tree_itr->get().box.intersects(margin_box)) { return false; } @@ -196,12 +198,12 @@ box.maxx() + margin, box.maxy() + margin) : box); - tree_t::query_iterator itr = tree_.query_in_box(repeat_box); - tree_t::query_iterator end = tree_.query_end(); + tree_t::query_iterator tree_itr = tree_.query_in_box(repeat_box); + tree_t::query_iterator tree_end = tree_.query_end(); - for ( ;itr != end; ++itr) + for ( ;tree_itr != tree_end; ++tree_itr) { - if (itr->get().box.intersects(margin_box) || (text == itr->get().text && itr->get().box.intersects(repeat_box))) + if (tree_itr->get().box.intersects(margin_box) || (text == tree_itr->get().text && tree_itr->get().box.intersects(repeat_box))) { return false; } diff -Nru mapnik-3.0.9+ds/include/mapnik/map.hpp mapnik-3.0.13+ds/include/mapnik/map.hpp --- mapnik-3.0.9+ds/include/mapnik/map.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/map.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -34,8 +34,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/include/mapnik/mapped_memory_cache.hpp mapnik-3.0.13+ds/include/mapnik/mapped_memory_cache.hpp --- mapnik-3.0.9+ds/include/mapnik/mapped_memory_cache.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/mapped_memory_cache.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,10 +28,15 @@ #include #include -// boost #include +#include #include + +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop + namespace boost { namespace interprocess { class mapped_region; } } @@ -52,6 +57,8 @@ void clear(); }; +extern template class MAPNIK_DECL singleton; + } #endif // MAPNIK_MAPPED_MEMORY_CACHE_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/marker_helpers.hpp mapnik-3.0.13+ds/include/mapnik/marker_helpers.hpp --- mapnik-3.0.9+ds/include/mapnik/marker_helpers.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/marker_helpers.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -35,9 +35,13 @@ #include #include #include +#include +#include -// agg +#pragma GCC diagnostic push +#include #include "agg_trans_affine.h" +#pragma GCC diagnostic pop // stl #include @@ -52,60 +56,53 @@ struct vector_markers_dispatch : util::noncopyable { vector_markers_dispatch(svg_path_ptr const& src, + svg_path_adapter & path, + svg_attribute_type const& attrs, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, double scale_factor, feature_impl const& feature, - attributes const& vars) - : src_(src), - marker_trans_(marker_trans), - sym_(sym), - detector_(detector), - feature_(feature), - vars_(vars), - scale_factor_(scale_factor) + attributes const& vars, + bool snap_to_pixels, + markers_renderer_context & renderer_context) + : params_(src->bounding_box(), recenter(src) * marker_trans, + sym, feature, vars, scale_factor, snap_to_pixels) + , renderer_context_(renderer_context) + , src_(src) + , path_(path) + , attrs_(attrs) + , detector_(detector) {} - virtual ~vector_markers_dispatch() {} - template void add_path(T & path) { - marker_placement_enum placement_method = get(sym_, feature_, vars_); - value_bool ignore_placement = get(sym_, feature_, vars_); - value_bool allow_overlap = get(sym_, feature_, vars_); - value_bool avoid_edges = get(sym_, feature_, vars_); - value_double opacity = get(sym_, feature_, vars_); - value_double spacing = get(sym_, feature_, vars_); - value_double max_error = get(sym_, feature_, vars_); - coord2d center = src_->bounding_box().center(); - agg::trans_affine_translation recenter(-center.x, -center.y); - agg::trans_affine tr = recenter * marker_trans_; - direction_enum direction = get(sym_, feature_, vars_); - markers_placement_params params { src_->bounding_box(), tr, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction }; markers_placement_finder placement_finder( - placement_method, path, detector_, params); + params_.placement_method, path, detector_, params_.placement_params); double x, y, angle = .0; - while (placement_finder.get_point(x, y, angle, ignore_placement)) + while (placement_finder.get_point(x, y, angle, params_.ignore_placement)) { - agg::trans_affine matrix = tr; + agg::trans_affine matrix = params_.placement_params.tr; matrix.rotate(angle); matrix.translate(x, y); - render_marker(matrix, opacity); + renderer_context_.render_marker(src_, path_, attrs_, params_, matrix); } } - virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0; - protected: + static agg::trans_affine recenter(svg_path_ptr const& src) + { + coord2d center = src->bounding_box().center(); + return agg::trans_affine_translation(-center.x, -center.y); + } + + markers_dispatch_params params_; + markers_renderer_context & renderer_context_; svg_path_ptr const& src_; - agg::trans_affine const& marker_trans_; - symbolizer_base const& sym_; + svg_path_adapter & path_; + svg_attribute_type const& attrs_; Detector & detector_; - feature_impl const& feature_; - attributes const& vars_; - double scale_factor_; }; template @@ -117,53 +114,35 @@ Detector & detector, double scale_factor, feature_impl const& feature, - attributes const& vars) - : src_(src), - marker_trans_(marker_trans), - sym_(sym), - detector_(detector), - feature_(feature), - vars_(vars), - scale_factor_(scale_factor) + attributes const& vars, + markers_renderer_context & renderer_context) + : params_(box2d(0, 0, src.width(), src.height()), + marker_trans, sym, feature, vars, scale_factor) + , renderer_context_(renderer_context) + , src_(src) + , detector_(detector) {} - virtual ~raster_markers_dispatch() {} - template void add_path(T & path) { - marker_placement_enum placement_method = get(sym_, feature_, vars_); - value_bool allow_overlap = get(sym_, feature_, vars_); - value_bool avoid_edges = get(sym_, feature_, vars_); - value_double opacity = get(sym_, feature_, vars_); - value_bool ignore_placement = get(sym_, feature_, vars_); - value_double spacing = get(sym_, feature_, vars_); - value_double max_error = get(sym_, feature_, vars_); - box2d bbox(0,0, src_.width(),src_.height()); - direction_enum direction = get(sym_, feature_, vars_); - markers_placement_params params { bbox, marker_trans_, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction }; markers_placement_finder placement_finder( - placement_method, path, detector_, params); + params_.placement_method, path, detector_, params_.placement_params); double x, y, angle = .0; - while (placement_finder.get_point(x, y, angle, ignore_placement)) + while (placement_finder.get_point(x, y, angle, params_.ignore_placement)) { - agg::trans_affine matrix = marker_trans_; + agg::trans_affine matrix = params_.placement_params.tr; matrix.rotate(angle); matrix.translate(x, y); - render_marker(matrix, opacity); + renderer_context_.render_marker(src_, params_, matrix); } } - virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0; - protected: + markers_dispatch_params params_; + markers_renderer_context & renderer_context_; image_rgba8 const& src_; - agg::trans_affine const& marker_trans_; - symbolizer_base const& sym_; Detector & detector_; - feature_impl const& feature_; - attributes const& vars_; - double scale_factor_; }; void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, attributes const& vars, @@ -182,85 +161,29 @@ attributes const& vars, symbolizer_base const& sym); +using vertex_converter_type = vertex_converter; + // Apply markers to a feature with multiple geometries -template -void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, Processor & proc, symbolizer_base const& sym) -{ - using vertex_converter_type = Converter; - using apply_vertex_converter_type = detail::apply_vertex_converter; - using vertex_processor_type = geometry::vertex_processor; - - auto const& geom = feature.get_geometry(); - geometry::geometry_types type = geometry::geometry_type(geom); - - if (type == geometry::geometry_types::Point - || type == geometry::geometry_types::LineString - || type == geometry::geometry_types::Polygon) - { - apply_vertex_converter_type apply(converter, proc); - mapnik::util::apply_visitor(vertex_processor_type(apply), geom); - } - else - { +template +void apply_markers_multi(feature_impl const& feature, attributes const& vars, + vertex_converter_type & converter, Processor & proc, symbolizer_base const& sym); - marker_multi_policy_enum multi_policy = get(sym, feature, vars); - marker_placement_enum placement = get(sym, feature, vars); - if (placement == MARKER_POINT_PLACEMENT && - multi_policy == MARKER_WHOLE_MULTI) - { - geometry::point pt; - // test if centroid is contained by bounding box - if (geometry::centroid(geom, pt) && converter.disp_.args_.bbox.contains(pt.x, pt.y)) - { - // unset any clipping since we're now dealing with a point - converter.template unset(); - geometry::point_vertex_adapter va(pt); - converter.apply(va, proc); - } - } - else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) && - multi_policy == MARKER_LARGEST_MULTI) - { - // Only apply to path with largest envelope area - // TODO: consider using true area for polygon types - if (type == geometry::geometry_types::MultiPolygon) - { - geometry::multi_polygon const& multi_poly = mapnik::util::get >(geom); - double maxarea = 0; - geometry::polygon const* largest = 0; - for (geometry::polygon const& poly : multi_poly) - { - box2d bbox = geometry::envelope(poly); - double area = bbox.width() * bbox.height(); - if (area > maxarea) - { - maxarea = area; - largest = &poly; - } - } - if (largest) - { - geometry::polygon_vertex_adapter va(*largest); - converter.apply(va, proc); - } - } - else - { - MAPNIK_LOG_WARN(marker_symbolizer) << "TODO: if you get here -> open an issue"; - } - } - else - { - if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT) - { - MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'"; - } - apply_vertex_converter_type apply(converter, proc); - mapnik::util::apply_visitor(vertex_processor_type(apply), geom); - } - } -} +using vector_dispatch_type = vector_markers_dispatch; +using raster_dispatch_type = raster_markers_dispatch; + +extern template void apply_markers_multi(feature_impl const& feature, attributes const& vars, + vertex_converter_type & converter, vector_dispatch_type & proc, symbolizer_base const& sym); + +extern template void apply_markers_multi(feature_impl const& feature, attributes const& vars, + vertex_converter_type & converter, raster_dispatch_type & proc, symbolizer_base const& sym); + } diff -Nru mapnik-3.0.9+ds/include/mapnik/marker.hpp mapnik-3.0.13+ds/include/mapnik/marker.hpp --- mapnik-3.0.9+ds/include/mapnik/marker.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/marker.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,8 +29,10 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_array.h" +#pragma GCC diagnostic pop // stl #include @@ -41,8 +43,10 @@ struct image_any; namespace svg { struct path_attributes; } -using attr_storage = agg::pod_bvector; -using svg_storage_type = mapnik::svg::svg_storage; +using svg::svg_path_adapter; + +using svg_attribute_type = agg::pod_bvector; +using svg_storage_type = svg::svg_storage; using svg_path_ptr = std::shared_ptr; using image_ptr = std::shared_ptr; @@ -56,23 +60,17 @@ bitmap_data_.set(0xff000000); } - marker_rgba8(image_rgba8 const & data) + explicit marker_rgba8(image_rgba8 const& data) : bitmap_data_(data) {} - marker_rgba8(image_rgba8 && data) + explicit marker_rgba8(image_rgba8 && data) noexcept : bitmap_data_(std::move(data)) {} - marker_rgba8(marker_rgba8 const& rhs) - : bitmap_data_(rhs.bitmap_data_) {} - - marker_rgba8(marker_rgba8 && rhs) noexcept - : bitmap_data_(std::move(rhs.bitmap_data_)) {} - box2d bounding_box() const { - std::size_t width = bitmap_data_.width(); - std::size_t height = bitmap_data_.height(); - return box2d(static_cast(0), static_cast(0), static_cast(width), static_cast(height)); + std::size_t _width = bitmap_data_.width(); + std::size_t _height = bitmap_data_.height(); + return box2d(static_cast(0), static_cast(0), static_cast(_width), static_cast(_height)); } inline double width() const @@ -97,18 +95,12 @@ struct marker_svg { public: - marker_svg() { } + marker_svg() = default; - marker_svg(mapnik::svg_path_ptr data) + explicit marker_svg(mapnik::svg_path_ptr data) noexcept : vector_data_(data) {} - marker_svg(marker_svg const& rhs) - : vector_data_(rhs.vector_data_) {} - - marker_svg(marker_svg && rhs) noexcept - : vector_data_(rhs.vector_data_) {} - - box2d bounding_box() const + inline box2d bounding_box() const { return vector_data_->bounding_box(); } @@ -122,11 +114,15 @@ return vector_data_->bounding_box().height(); } - mapnik::svg_path_ptr get_data() const + inline mapnik::svg_path_ptr get_data() const { return vector_data_; } + inline std::tuple dimensions() const + { + return std::make_tuple(vector_data_->width(), vector_data_->height()); + } private: mapnik::svg_path_ptr vector_data_; @@ -134,9 +130,8 @@ struct marker_null { - marker_null() = default; public: - box2d bounding_box() const + inline box2d bounding_box() const { return box2d(); } @@ -189,8 +184,9 @@ marker() = default; template - marker(T && data) noexcept - : marker_base(std::move(data)) {} + marker(T && _data) + noexcept(std::is_nothrow_constructible::value) + : marker_base(std::forward(_data)) {} double width() const { diff -Nru mapnik-3.0.9+ds/include/mapnik/markers_placement.hpp mapnik-3.0.13+ds/include/mapnik/markers_placement.hpp --- mapnik-3.0.9+ds/include/mapnik/markers_placement.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/markers_placement.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,7 +29,6 @@ #include #include #include -#include namespace mapnik { @@ -38,70 +37,99 @@ class markers_placement_finder : util::noncopyable { public: - using markers_placement = util::variant, - markers_line_placement, - markers_interior_placement, - markers_vertex_first_placement, - markers_vertex_last_placement>; - - class get_point_visitor - { - public: - get_point_visitor(double &x, double &y, double &angle, bool ignore_placement) - : x_(x), y_(y), angle_(angle), ignore_placement_(ignore_placement) - { - } - - template - bool operator()(T &placement) const - { - return placement.get_point(x_, y_, angle_, ignore_placement_); - } - - private: - double &x_, &y_, &angle_; - bool ignore_placement_; - }; - markers_placement_finder(marker_placement_e placement_type, Locator &locator, Detector &detector, markers_placement_params const& params) - : placement_(create(placement_type, locator, detector, params)) + : placement_type_(placement_type) { + switch (placement_type) + { + default: + case MARKER_POINT_PLACEMENT: + construct(&point_, locator, detector, params); + break; + case MARKER_INTERIOR_PLACEMENT: + construct(&interior_, locator, detector, params); + break; + case MARKER_LINE_PLACEMENT: + construct(&line_, locator, detector, params); + break; + case MARKER_VERTEX_FIRST_PLACEMENT: + construct(&vertex_first_, locator, detector, params); + break; + case MARKER_VERTEX_LAST_PLACEMENT: + construct(&vertex_last_, locator, detector, params); + break; + } } - // Get next point where the marker should be placed. Returns true if a place is found, false if none is found. - bool get_point(double &x, double &y, double &angle, bool ignore_placement) + ~markers_placement_finder() { - return util::apply_visitor(get_point_visitor(x, y, angle, ignore_placement), placement_); + switch (placement_type_) + { + default: + case MARKER_POINT_PLACEMENT: + destroy(&point_); + break; + case MARKER_INTERIOR_PLACEMENT: + destroy(&interior_); + break; + case MARKER_LINE_PLACEMENT: + destroy(&line_); + break; + case MARKER_VERTEX_FIRST_PLACEMENT: + destroy(&vertex_first_); + break; + case MARKER_VERTEX_LAST_PLACEMENT: + destroy(&vertex_last_); + break; + } } -private: - // Factory function for particular placement implementations. - static markers_placement create(marker_placement_e placement_type, - Locator &locator, - Detector &detector, - markers_placement_params const& params) + // Get next point where the marker should be placed. Returns true if a place is found, false if none is found. + bool get_point(double &x, double &y, double &angle, bool ignore_placement) { - switch (placement_type) + switch (placement_type_) { + default: case MARKER_POINT_PLACEMENT: - return markers_point_placement(locator,detector,params); + return point_.get_point(x, y, angle, ignore_placement); case MARKER_INTERIOR_PLACEMENT: - return markers_interior_placement(locator,detector,params); + return interior_.get_point(x, y, angle, ignore_placement); case MARKER_LINE_PLACEMENT: - return markers_line_placement(locator,detector,params); + return line_.get_point(x, y, angle, ignore_placement); case MARKER_VERTEX_FIRST_PLACEMENT: - return markers_vertex_first_placement(locator,detector,params); + return vertex_first_.get_point(x, y, angle, ignore_placement); case MARKER_VERTEX_LAST_PLACEMENT: - return markers_vertex_last_placement(locator,detector,params); - default: // point - return markers_point_placement(locator,detector,params); + return vertex_last_.get_point(x, y, angle, ignore_placement); } } - markers_placement placement_; +private: + marker_placement_e const placement_type_; + + union + { + markers_point_placement point_; + markers_line_placement line_; + markers_interior_placement interior_; + markers_vertex_first_placement vertex_first_; + markers_vertex_last_placement vertex_last_; + }; + + template + static T* construct(T* what, Locator & locator, Detector & detector, + markers_placement_params const& params) + { + return new(what) T(locator, detector, params); + } + + template + static void destroy(T* what) + { + what->~T(); + } }; } diff -Nru mapnik-3.0.9+ds/include/mapnik/markers_placements/basic.hpp mapnik-3.0.13+ds/include/mapnik/markers_placements/basic.hpp --- mapnik-3.0.9+ds/include/mapnik/markers_placements/basic.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/markers_placements/basic.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,104 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_MARKERS_PLACEMENTS_BASIC_HPP +#define MAPNIK_MARKERS_PLACEMENTS_BASIC_HPP + +// mapnik +#include +#include +#include +#include + +#pragma GCC diagnostic push +#include +#include "agg_basics.h" +#include "agg_trans_affine.h" +#pragma GCC diagnostic pop + +namespace mapnik { + +struct markers_placement_params +{ + box2d size; + agg::trans_affine tr; + double spacing; + double max_error; + bool allow_overlap; + bool avoid_edges; + direction_enum direction; +}; + +class markers_basic_placement : util::noncopyable +{ +public: + markers_basic_placement(markers_placement_params const& params) + : params_(params) + { + } + +protected: + markers_placement_params const& params_; + + // Rotates the size_ box and translates the position. + box2d perform_transform(double angle, double dx, double dy) const + { + auto tr = params_.tr * agg::trans_affine_rotation(angle).translate(dx, dy); + return box2d(params_.size, tr); + } + + bool set_direction(double & angle) const + { + switch (params_.direction) + { + case DIRECTION_UP: + angle = 0; + return true; + case DIRECTION_DOWN: + angle = M_PI; + return true; + case DIRECTION_AUTO: + if (std::fabs(util::normalize_angle(angle)) > 0.5 * M_PI) + angle += M_PI; + return true; + case DIRECTION_AUTO_DOWN: + if (std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI) + angle += M_PI; + return true; + case DIRECTION_LEFT: + angle += M_PI; + return true; + case DIRECTION_LEFT_ONLY: + angle += M_PI; + return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI; + case DIRECTION_RIGHT_ONLY: + return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI; + case DIRECTION_RIGHT: + default: + return true; + } + } +}; + +} // namespace mapnik + +#endif // MAPNIK_MARKERS_PLACEMENTS_BASIC_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/markers_placements/interior.hpp mapnik-3.0.13+ds/include/mapnik/markers_placements/interior.hpp --- mapnik-3.0.9+ds/include/mapnik/markers_placements/interior.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/markers_placements/interior.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -33,14 +33,8 @@ class markers_interior_placement : public markers_point_placement { public: - markers_interior_placement(Locator &locator, Detector &detector, markers_placement_params const& params) - : markers_point_placement(locator, detector, params) - { - } - - markers_interior_placement(markers_interior_placement && rhs) - : markers_point_placement(std::move(rhs)) - {} + using point_placement = markers_point_placement; + using point_placement::point_placement; bool get_point(double &x, double &y, double &angle, bool ignore_placement) { @@ -51,7 +45,7 @@ if (this->locator_.type() == geometry::geometry_types::Point) { - return markers_point_placement::get_point(x, y, angle, ignore_placement); + return point_placement::get_point(x, y, angle, ignore_placement); } if (this->locator_.type() == geometry::geometry_types::LineString) @@ -73,21 +67,11 @@ angle = 0; - box2d box = this->perform_transform(angle, x, y); - if (this->params_.avoid_edges && !this->detector_.extent().contains(box)) - { - return false; - } - if (!this->params_.allow_overlap && !this->detector_.has_placement(box)) + if (!this->push_to_detector(x, y, angle, ignore_placement)) { return false; } - if (!ignore_placement) - { - this->detector_.insert(box); - } - this->done_ = true; return true; } diff -Nru mapnik-3.0.9+ds/include/mapnik/markers_placements/line.hpp mapnik-3.0.13+ds/include/mapnik/markers_placements/line.hpp --- mapnik-3.0.9+ds/include/mapnik/markers_placements/line.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/markers_placements/line.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -35,29 +35,23 @@ class markers_line_placement : public markers_point_placement { public: - markers_line_placement(Locator &locator, Detector &detector, markers_placement_params const& params) - : markers_point_placement(locator, detector, params), + using point_placement = markers_point_placement; + using point_placement::point_placement; + + markers_line_placement(Locator & locator, Detector & detector, + markers_placement_params const& params) + : point_placement(locator, detector, params), first_point_(true), spacing_(0.0), marker_width_((params.size * params.tr).width()), path_(locator) { spacing_ = params.spacing < 1 ? 100 : params.spacing; - rewind(); } - markers_line_placement(markers_line_placement && rhs) - : markers_point_placement(std::move(rhs)), - first_point_(std::move(rhs.first_point_)), - spacing_(std::move(rhs.spacing_)), - marker_width_(std::move(rhs.marker_width_)), - path_(std::move(rhs.path_)) - {} - void rewind() { - this->locator_.rewind(0); - this->done_ = false; + point_placement::rewind(); first_point_ = true; } @@ -70,7 +64,7 @@ if (this->locator_.type() == geometry::geometry_types::Point) { - return markers_point_placement::get_point(x, y, angle, ignore_placement); + return point_placement::get_point(x, y, angle, ignore_placement); } double move = spacing_; @@ -102,16 +96,10 @@ { continue; } - box2d box = this->perform_transform(angle, x, y); - if ((this->params_.avoid_edges && !this->detector_.extent().contains(box)) - || (!this->params_.allow_overlap && !this->detector_.has_placement(box))) + if (!this->push_to_detector(x, y, angle, ignore_placement)) { continue; } - if (!ignore_placement) - { - this->detector_.insert(box); - } return true; } } diff -Nru mapnik-3.0.9+ds/include/mapnik/markers_placements/point.hpp mapnik-3.0.13+ds/include/mapnik/markers_placements/point.hpp --- mapnik-3.0.9+ds/include/mapnik/markers_placements/point.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/markers_placements/point.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,53 +23,26 @@ #ifndef MAPNIK_MARKERS_PLACEMENTS_POINT_HPP #define MAPNIK_MARKERS_PLACEMENTS_POINT_HPP -#include #include #include -#include -#include -#include -#include - -#include "agg_basics.h" -#include "agg_trans_affine.h" - -#include +#include namespace mapnik { -struct markers_placement_params -{ - box2d const& size; - agg::trans_affine const& tr; - double spacing; - double max_error; - bool allow_overlap; - bool avoid_edges; - direction_enum direction; -}; - template -class markers_point_placement : util::noncopyable +class markers_point_placement : public markers_basic_placement { public: - markers_point_placement(Locator &locator, Detector &detector, markers_placement_params const& params) - : locator_(locator), + markers_point_placement(Locator & locator, Detector & detector, + markers_placement_params const& params) + : markers_basic_placement(params), + locator_(locator), detector_(detector), - params_(params), done_(false) { - rewind(); + locator_.rewind(0); } - markers_point_placement(markers_point_placement && rhs) - : locator_(rhs.locator_), - detector_(rhs.detector_), - params_(rhs.params_), - done_(rhs.done_) - {} - - // Start again at first marker. Returns the same list of markers only works when they were NOT added to the detector. void rewind() { @@ -80,105 +53,66 @@ // Get next point where the marker should be placed. Returns true if a place is found, false if none is found. bool get_point(double &x, double &y, double &angle, bool ignore_placement) { - if (done_) + if (this->done_) { return false; } - if (locator_.type() == geometry::geometry_types::LineString) + if (this->locator_.type() == geometry::geometry_types::LineString) { - if (!label::middle_point(locator_, x, y)) + if (!label::middle_point(this->locator_, x, y)) { - done_ = true; + this->done_ = true; return false; } } else { - if (!label::centroid(locator_, x, y)) + if (!label::centroid(this->locator_, x, y)) { - done_ = true; + this->done_ = true; return false; } } angle = 0; - box2d box = perform_transform(angle, x, y); - if (params_.avoid_edges && !detector_.extent().contains(box)) - { - return false; - } - if (!params_.allow_overlap && !detector_.has_placement(box)) + if (!this->push_to_detector(x, y, angle, ignore_placement)) { return false; } - if (!ignore_placement) - { - detector_.insert(box); - } - - done_ = true; + this->done_ = true; return true; } protected: - Locator &locator_; - Detector &detector_; - markers_placement_params const& params_; + Locator & locator_; + Detector & detector_; bool done_; - // Rotates the size_ box and translates the position. - box2d perform_transform(double angle, double dx, double dy) - { - double x1 = params_.size.minx(); - double x2 = params_.size.maxx(); - double y1 = params_.size.miny(); - double y2 = params_.size.maxy(); - agg::trans_affine tr = params_.tr * agg::trans_affine_rotation(angle).translate(dx, dy); - double xA = x1, yA = y1, - xB = x2, yB = y1, - xC = x2, yC = y2, - xD = x1, yD = y2; - tr.transform(&xA, &yA); - tr.transform(&xB, &yB); - tr.transform(&xC, &yC); - tr.transform(&xD, &yD); - box2d result(xA, yA, xC, yC); - result.expand_to_include(xB, yB); - result.expand_to_include(xD, yD); - return result; - } - - bool set_direction(double & angle) + // Checks transformed box placement with collision detector. + // returns false if the box: + // - a) isn't wholly inside extent and avoid_edges == true + // - b) collides with something and allow_overlap == false + // otherwise returns true, and if ignore_placement == false, + // also adds the box to collision detector + bool push_to_detector(double x, double y, double angle, bool ignore_placement) { - switch (params_.direction) + auto box = perform_transform(angle, x, y); + if (params_.avoid_edges && !detector_.extent().contains(box)) + { + return false; + } + if (!params_.allow_overlap && !detector_.has_placement(box)) + { + return false; + } + if (!ignore_placement) { - case DIRECTION_UP: - angle = .0; - return true; - case DIRECTION_DOWN: - angle = M_PI; - return true; - case DIRECTION_AUTO: - angle = (std::fabs(util::normalize_angle(angle)) > 0.5 * M_PI) ? (angle + M_PI) : angle; - return true; - case DIRECTION_AUTO_DOWN: - angle = (std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI) ? (angle + M_PI) : angle; - return true; - case DIRECTION_LEFT: - angle += M_PI; - return true; - case DIRECTION_LEFT_ONLY: - angle += M_PI; - return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI; - case DIRECTION_RIGHT_ONLY: - return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI; - case DIRECTION_RIGHT: - default: - return true; + detector_.insert(box); } + return true; } }; diff -Nru mapnik-3.0.9+ds/include/mapnik/markers_placements/vertext_first.hpp mapnik-3.0.13+ds/include/mapnik/markers_placements/vertext_first.hpp --- mapnik-3.0.9+ds/include/mapnik/markers_placements/vertext_first.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/markers_placements/vertext_first.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -31,14 +31,8 @@ class markers_vertex_first_placement : public markers_point_placement { public: - markers_vertex_first_placement(Locator &locator, Detector &detector, markers_placement_params const& params) - : markers_point_placement(locator, detector, params) - { - } - - markers_vertex_first_placement(markers_vertex_first_placement && rhs) - : markers_point_placement(std::move(rhs)) - {} + using point_placement = markers_point_placement; + using point_placement::point_placement; bool get_point(double &x, double &y, double &angle, bool ignore_placement) { @@ -49,7 +43,7 @@ if (this->locator_.type() == mapnik::geometry::geometry_types::Point) { - return markers_point_placement::get_point(x, y, angle, ignore_placement); + return point_placement::get_point(x, y, angle, ignore_placement); } double x0, y0; @@ -75,21 +69,11 @@ } } - box2d box = this->perform_transform(angle, x, y); - if (this->params_.avoid_edges && !this->detector_.extent().contains(box)) - { - return false; - } - if (!this->params_.allow_overlap && !this->detector_.has_placement(box)) + if (!this->push_to_detector(x, y, angle, ignore_placement)) { return false; } - if (!ignore_placement) - { - this->detector_.insert(box); - } - this->done_ = true; return true; } diff -Nru mapnik-3.0.9+ds/include/mapnik/markers_placements/vertext_last.hpp mapnik-3.0.13+ds/include/mapnik/markers_placements/vertext_last.hpp --- mapnik-3.0.9+ds/include/mapnik/markers_placements/vertext_last.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/markers_placements/vertext_last.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -31,13 +31,8 @@ class markers_vertex_last_placement : public markers_point_placement { public: - markers_vertex_last_placement(Locator &locator, Detector &detector, markers_placement_params const& params) - : markers_point_placement(locator, detector, params) - {} - - markers_vertex_last_placement(markers_vertex_last_placement && rhs) - : markers_point_placement(std::move(rhs)) - {} + using point_placement = markers_point_placement; + using point_placement::point_placement; bool get_point(double &x, double &y, double &angle, bool ignore_placement) { @@ -80,20 +75,10 @@ } } - box2d box = this->perform_transform(angle, x, y); - if (this->params_.avoid_edges && !this->detector_.extent().contains(box)) + if (!this->push_to_detector(x, y, angle, ignore_placement)) { return false; } - if (!this->params_.allow_overlap && !this->detector_.has_placement(box)) - { - return false; - } - - if (!ignore_placement) - { - this->detector_.insert(box); - } this->done_ = true; return true; diff -Nru mapnik-3.0.9+ds/include/mapnik/memory_datasource.hpp mapnik-3.0.13+ds/include/mapnik/memory_datasource.hpp --- mapnik-3.0.9+ds/include/mapnik/memory_datasource.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/memory_datasource.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -55,6 +55,7 @@ mapnik::layer_descriptor desc_; datasource::datasource_t type_; bool bbox_check_; + bool type_set_; mutable box2d extent_; mutable bool dirty_extent_ = true; }; diff -Nru mapnik-3.0.9+ds/include/mapnik/miniz_png.hpp mapnik-3.0.13+ds/include/mapnik/miniz_png.hpp --- mapnik-3.0.9+ds/include/mapnik/miniz_png.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/miniz_png.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2015 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 - * - *****************************************************************************/ - -#ifndef MAPNIK_MINIZ_PNG_HPP -#define MAPNIK_MINIZ_PNG_HPP - -// mapnik -#include -#include - -// stl -#include -#include -#include - -#include -#include - -/* miniz.c porting issues: - - duplicate symbols in python bindings require moving miniz.c include to just cpp file - - due to http://code.google.com/p/miniz/issues/detail?id=7 - - avoiding including miniz.c here requires fwd declaring the two structs below - - being able to fwd declare requires removing typedef from struct declarations in miniz.c - - being able to fwd declare also requires using pointers to structs - - if updated, need to apply c++11 fix: https://github.com/mapnik/mapnik/issues/1967 -*/ - -// TODO: try using #define MINIZ_HEADER_FILE_ONLY -struct tdefl_output_buffer; -struct tdefl_compressor; - -namespace mapnik { namespace MiniZ { - -using mapnik::rgb; - -class MAPNIK_DECL PNGWriter { - -public: - PNGWriter(int level, int strategy); - ~PNGWriter(); -private: - inline void writeUInt32BE(unsigned char *target, unsigned int value); - size_t startChunk(const unsigned char header[], size_t length); - void finishChunk(size_t start); -public: - void writeIHDR(unsigned int width, unsigned int height, unsigned char pixel_depth); - void writePLTE(std::vector const& palette); - void writetRNS(std::vector const& alpha); - template - void writeIDAT(T const& image); - template - void writeIDATStripAlpha(T const& image); - void writeIEND(); - void toStream(std::ostream& stream); - -private: - tdefl_compressor *compressor; - tdefl_output_buffer *buffer; - static const unsigned char preamble[]; - static const unsigned char IHDR_tpl[]; - static const unsigned char PLTE_tpl[]; - static const unsigned char tRNS_tpl[]; - static const unsigned char IDAT_tpl[]; - static const unsigned char IEND_tpl[]; -}; - -extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_gray8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_view_gray8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_rgba8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_view_rgba8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha(image_rgba8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha(image_view_rgba8 const& image); - -}} - -#endif // MAPNIK_MINIZ_PNG_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/offset_converter.hpp mapnik-3.0.13+ds/include/mapnik/offset_converter.hpp --- mapnik-3.0.9+ds/include/mapnik/offset_converter.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/offset_converter.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -77,18 +77,18 @@ return threshold_; } - void set_offset(double value) + void set_offset(double val) { - if (offset_ != value) + if (offset_ != val) { - offset_ = value; + offset_ = val; reset(); } } - void set_threshold(double value) + void set_threshold(double val) { - threshold_ = value; + threshold_ = val; // no need to reset(), since threshold doesn't affect // offset vertices' computation, it only controls how // far will we be looking for self-intersections @@ -482,7 +482,6 @@ } start_v2.x = v2.x; start_v2.y = v2.y; - bool continue_loop = true; vertex2d tmp_prev(vertex2d::no_init); while (i < points.size()) @@ -515,7 +514,6 @@ else if (v2.cmd == SEG_END) { if (!is_polygon) break; - continue_loop = false; v2.x = start_v2.x; v2.y = start_v2.y; } diff -Nru mapnik-3.0.9+ds/include/mapnik/palette.hpp mapnik-3.0.13+ds/include/mapnik/palette.hpp --- mapnik-3.0.9+ds/include/mapnik/palette.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/palette.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -43,6 +43,7 @@ // stl #include +#include #define U2RED(x) ((x)&0xff) #define U2GREEN(x) (((x)>>8)&0xff) @@ -53,7 +54,8 @@ struct rgba; -struct MAPNIK_DECL rgb { +struct MAPNIK_DECL rgb +{ std::uint8_t r; std::uint8_t g; std::uint8_t b; @@ -92,7 +94,7 @@ b(U2BLUE(c)), a(U2ALPHA(c)) {} - inline bool operator==(const rgba& y) const + inline bool operator==(rgba const& y) const { return r == y.r && g == y.g && b == y.b && a == y.a; } @@ -103,18 +105,27 @@ bool operator() (const rgba& x, const rgba& y) const; }; + inline bool operator<(rgba const& y) const + { + return std::tie(r, g, b, a) < std::tie(y.r, y.g, y.b, y.a); + } + }; -class MAPNIK_DECL rgba_palette : private util::noncopyable { +class MAPNIK_DECL rgba_palette : private util::noncopyable +{ public: enum palette_type { PALETTE_RGBA = 0, PALETTE_RGB = 1, PALETTE_ACT = 2 }; explicit rgba_palette(std::string const& pal, palette_type type = PALETTE_RGBA); rgba_palette(); - const std::vector& palette() const; - const std::vector& alphaTable() const; + inline std::vector const& palette() const { return rgb_pal_;} + inline std::vector const& alpha_table() const { return alpha_pal_;} + + inline std::vector& palette() { return rgb_pal_;} + inline std::vector& alpha_table() { return alpha_pal_;} unsigned char quantize(unsigned c) const; diff -Nru mapnik-3.0.9+ds/include/mapnik/params.hpp mapnik-3.0.13+ds/include/mapnik/params.hpp --- mapnik-3.0.9+ds/include/mapnik/params.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/params.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,8 +27,11 @@ #include #include #include -// boost + +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl #include @@ -48,9 +51,14 @@ value_holder() : value_holder_base() {} + // C-string -> std::string + value_holder(char const* str) + : value_holder(std::string(str)) {} + // perfect forwarding template - value_holder(T && obj) noexcept + value_holder(T && obj) + noexcept(std::is_nothrow_constructible::value) : value_holder_base(std::forward(obj)) {} }; diff -Nru mapnik-3.0.9+ds/include/mapnik/path_expression_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/path_expression_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/path_expression_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/path_expression_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,10 +24,13 @@ #include #include -// boost + +#pragma GCC diagnostic push +#include #include #include #include +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/plugin.hpp mapnik-3.0.13+ds/include/mapnik/plugin.hpp --- mapnik-3.0.9+ds/include/mapnik/plugin.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/plugin.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -38,7 +38,8 @@ class PluginInfo : util::noncopyable { public: - using name_func = const char* (*) (); + using callable_returning_string = const char* (*) (); + using callable_returning_void = void (*) (); PluginInfo (std::string const& filename, std::string const& library_name); ~PluginInfo(); diff -Nru mapnik-3.0.9+ds/include/mapnik/png_io.hpp mapnik-3.0.13+ds/include/mapnik/png_io.hpp --- mapnik-3.0.9+ds/include/mapnik/png_io.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/png_io.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,19 +27,20 @@ #include #include #include -#include #include +#pragma GCC diagnostic push +#include + // zlib #include // for Z_DEFAULT_COMPRESSION -// boost - - extern "C" { #include } +#include +#pragma GCC diagnostic pop #define MAX_OCTREE_LEVELS 4 @@ -53,7 +54,6 @@ double gamma; bool paletted; bool use_hextree; - bool use_miniz; png_options() : colors(256), compression(Z_DEFAULT_COMPRESSION), @@ -61,8 +61,7 @@ trans_mode(-1), gamma(-1), paletted(true), - use_hextree(true), - use_miniz(false) {} + use_hextree(true) {} }; template @@ -85,23 +84,6 @@ png_options const& opts) { - if (opts.use_miniz) - { - MiniZ::PNGWriter writer(opts.compression,opts.strategy); - if (opts.trans_mode == 0) - { - writer.writeIHDR(image.width(), image.height(), 24); - writer.writeIDATStripAlpha(image); - } - else - { - writer.writeIHDR(image.width(), image.height(), 32); - writer.writeIDAT(image); - } - writer.writeIEND(); - writer.toStream(file); - return; - } png_voidp error_ptr=0; png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr,0, 0); @@ -119,10 +101,10 @@ png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { - png_destroy_write_struct(&png_ptr,(png_infopp)0); + png_destroy_write_struct(&png_ptr,static_cast(0)); return; } - jmp_buf* jmp_context = (jmp_buf*) png_get_error_ptr(png_ptr); + jmp_buf* jmp_context = static_cast(png_get_error_ptr(png_ptr)); if (jmp_context) { png_destroy_write_struct(&png_ptr, &info_ptr); @@ -140,7 +122,7 @@ const std::unique_ptr row_pointers(new png_bytep[image.height()]); for (unsigned int i = 0; i < image.height(); i++) { - row_pointers[i] = (png_bytep)image.get_row(i); + row_pointers[i] = const_cast(reinterpret_cast(image.get_row(i))); } png_set_rows(png_ptr, info_ptr, row_pointers.get()); png_write_png(png_ptr, info_ptr, (opts.trans_mode == 0) ? PNG_TRANSFORM_STRIP_FILLER_AFTER : PNG_TRANSFORM_IDENTITY, nullptr); @@ -181,7 +163,7 @@ break; } } - if (idx>=0 && idx<(int)alpha.size()) + if (idx>=0 && idx < static_cast(alpha.size())) { alpha[idx]+=U2ALPHA(val); alphaCount[idx]++; @@ -232,7 +214,7 @@ break; } } - if (idx>=0 && idx<(int)alpha.size()) + if (idx>=0 && idx < static_cast(alpha.size())) { alpha[idx]+=U2ALPHA(val); alphaCount[idx]++; @@ -273,19 +255,6 @@ std::vector const&alpha, png_options const& opts) { - if (opts.use_miniz) - { - MiniZ::PNGWriter writer(opts.compression,opts.strategy); - // image.width()/height() does not reflect the actual image dimensions; it - // refers to the quantized scanlines. - writer.writeIHDR(width, height, color_depth); - writer.writePLTE(palette); - writer.writetRNS(alpha); - writer.writeIDAT(image); - writer.writeIEND(); - writer.toStream(file); - return; - } png_voidp error_ptr=0; png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr,0, 0); @@ -306,10 +275,10 @@ png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { - png_destroy_write_struct(&png_ptr,(png_infopp)0); + png_destroy_write_struct(&png_ptr,static_cast(0)); return; } - jmp_buf* jmp_context = (jmp_buf*) png_get_error_ptr(png_ptr); + jmp_buf* jmp_context = static_cast(png_get_error_ptr(png_ptr)); if (jmp_context) { png_destroy_write_struct(&png_ptr, &info_ptr); @@ -343,14 +312,14 @@ } if (alphaSize>0) { - png_set_tRNS(png_ptr, info_ptr, (png_bytep)&trans[0], alphaSize, 0); + png_set_tRNS(png_ptr, info_ptr, static_cast(&trans[0]), alphaSize, 0); } } png_write_info(png_ptr, info_ptr); for (unsigned i=0;i(image.get_row(i))); } png_write_end(png_ptr, info_ptr); @@ -385,7 +354,7 @@ { for (unsigned x = 0; x < width; ++x) { - unsigned val = U2ALPHA((unsigned)image.get_row(y)[x]); + unsigned val = U2ALPHA(static_cast(image.get_row(y)[x])); alphaHist[val]++; meanAlpha += val; if (val>0 && val<255) @@ -546,19 +515,19 @@ } //transparency values per palette index - std::vector alphaTable; - //alphaTable.resize(palette.size());//allow semitransparency also in almost opaque range + std::vector alpha_table; + //alpha_table.resize(palette.size());//allow semitransparency also in almost opaque range if (opts.trans_mode != 0) { - alphaTable.resize(palette.size() - cols[TRANSPARENCY_LEVELS-1]); + alpha_table.resize(palette.size() - cols[TRANSPARENCY_LEVELS-1]); } if (palette.size() > 16 ) { // >16 && <=256 colors -> write 8-bit color depth image_gray8 reduced_image(width,height); - reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable); - save_as_png(file,palette,reduced_image,width,height,8,alphaTable,opts); + reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alpha_table); + save_as_png(file,palette,reduced_image,width,height,8,alpha_table,opts); } else if (palette.size() == 1) { @@ -566,13 +535,13 @@ unsigned image_width = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary unsigned image_height = height; image_gray8 reduced_image(image_width,image_height); - reduce_1(image,reduced_image,trees, limits, alphaTable); + reduce_1(image,reduced_image,trees, limits, alpha_table); if (meanAlpha<255 && cols[0]==0) { - alphaTable.resize(1); - alphaTable[0] = meanAlpha; + alpha_table.resize(1); + alpha_table[0] = meanAlpha; } - save_as_png(file,palette,reduced_image,width,height,1,alphaTable,opts); + save_as_png(file,palette,reduced_image,width,height,1,alpha_table,opts); } else { @@ -580,8 +549,8 @@ unsigned image_width = ((width + 7) >> 1) & ~3U; // 4-bit image, round up to 32-bit boundary unsigned image_height = height; image_gray8 reduced_image(image_width,image_height); - reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable); - save_as_png(file,palette,reduced_image,width,height,4,alphaTable,opts); + reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alpha_table); + save_as_png(file,palette,reduced_image,width,height,4,alpha_table,opts); } } @@ -591,7 +560,7 @@ T2 const& image, T3 const & tree, std::vector const& palette, - std::vector const& alphaTable, + std::vector const& alpha_table, png_options const& opts) { unsigned width = image.width(); @@ -610,7 +579,7 @@ row_out[x] = tree.quantize(row[x]); } } - save_as_png(file, palette, reduced_image, width, height, 8, alphaTable, opts); + save_as_png(file, palette, reduced_image, width, height, 8, alpha_table, opts); } else if (palette.size() == 1) { @@ -619,7 +588,7 @@ unsigned image_height = height; image_gray8 reduced_image(image_width, image_height); reduced_image.set(0); - save_as_png(file, palette, reduced_image, width, height, 1, alphaTable, opts); + save_as_png(file, palette, reduced_image, width, height, 1, alpha_table, opts); } else { @@ -643,7 +612,7 @@ row_out[x>>1] |= index; } } - save_as_png(file, palette, reduced_image, width, height, 4, alphaTable, opts); + save_as_png(file, palette, reduced_image, width, height, 4, alpha_table, opts); } } @@ -654,6 +623,7 @@ { unsigned width = image.width(); unsigned height = image.height(); + if (width + height > 3) // at least 3 pixels (hextree implementation requirement) { // structure for color quantization @@ -678,20 +648,44 @@ } //transparency values per palette index - std::vector pal; - tree.create_palette(pal); + std::vector rgba_palette; + tree.create_palette(rgba_palette); + auto size = rgba_palette.size(); std::vector palette; - std::vector alphaTable; - for (unsigned i=0; i alpha_table; + palette.reserve(size); + alpha_table.reserve(size); + for (auto const& c : rgba_palette) { - palette.push_back(rgb(pal[i].r, pal[i].g, pal[i].b)); - alphaTable.push_back(pal[i].a); + palette.emplace_back(c.r, c.g, c.b); + alpha_table.push_back(c.a); } - save_as_png8 >(file, image, tree, palette, alphaTable, opts); + save_as_png8 >(file, image, tree, palette, alpha_table, opts); } else { - throw std::runtime_error("Can't quantize images with less than 3 pixels"); + + std::set colors; + for (unsigned y = 0; y < height; ++y) + { + typename T2::pixel_type const * row = image.get_row(y); + + for (unsigned x = 0; x < width; ++x) + { + unsigned val = row[x]; + colors.emplace(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val)); + } + } + std::string str; + for (auto c : colors) + { + str.push_back(c.r); + str.push_back(c.g); + str.push_back(c.b); + str.push_back(c.a); + } + rgba_palette pal(str, rgba_palette::PALETTE_RGBA); + save_as_png8(file, image, pal, pal.palette(), pal.alpha_table(), opts); } } @@ -701,7 +695,7 @@ rgba_palette const& pal, png_options const& opts) { - save_as_png8(file, image, pal, pal.palette(), pal.alphaTable(), opts); + save_as_png8(file, image, pal, pal.palette(), pal.alpha_table(), opts); } } diff -Nru mapnik-3.0.9+ds/include/mapnik/pool.hpp mapnik-3.0.13+ds/include/mapnik/pool.hpp --- mapnik-3.0.9+ds/include/mapnik/pool.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/pool.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,7 +24,6 @@ #define MAPNIK_POOL_HPP // mapnik -#include #include // boost diff -Nru mapnik-3.0.9+ds/include/mapnik/projection.hpp mapnik-3.0.13+ds/include/mapnik/projection.hpp --- mapnik-3.0.9+ds/include/mapnik/projection.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/projection.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,8 +27,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/include/mapnik/ptree_helpers.hpp mapnik-3.0.13+ds/include/mapnik/ptree_helpers.hpp --- mapnik-3.0.9+ds/include/mapnik/ptree_helpers.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/ptree_helpers.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,8 +26,10 @@ // stl #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/quad_tree.hpp mapnik-3.0.13+ds/include/mapnik/quad_tree.hpp --- mapnik-3.0.9+ds/include/mapnik/quad_tree.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/quad_tree.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -36,26 +36,27 @@ namespace mapnik { -template +template > class quad_tree : util::noncopyable { - using value_type = T; + using value_type = T0; + using bbox_type = T1; struct node { - using cont_type = std::vector; + using cont_type = std::vector; using iterator = typename cont_type::iterator; using const_iterator = typename cont_type::const_iterator; - box2d extent_; + bbox_type extent_; cont_type cont_; node * children_[4]; - explicit node(box2d const& ext) + explicit node(bbox_type const& ext) : extent_(ext) { std::fill(children_, children_ + 4, nullptr); } - box2d const& extent() const + bbox_type const& extent() const { return extent_; } @@ -99,10 +100,10 @@ public: using iterator = typename nodes_type::iterator; using const_iterator = typename nodes_type::const_iterator; - using result_type = typename std::vector >; + using result_type = typename std::vector >; using query_iterator = typename result_type::iterator; - explicit quad_tree(box2d const& ext, + explicit quad_tree(bbox_type const& ext, unsigned int max_depth = 8, double ratio = 0.55) : max_depth_(max_depth), @@ -114,13 +115,13 @@ root_ = nodes_[0].get(); } - void insert(T data, box2d const& box) + void insert(value_type data, bbox_type const& box) { - unsigned int depth=0; - do_insert_data(data,box,root_,depth); + unsigned int depth = 0; + do_insert_data(data, box, root_, depth); } - query_iterator query_in_box(box2d const& box) + query_iterator query_in_box(bbox_type const& box) { query_result_.clear(); query_node(box, query_result_, root_); @@ -145,13 +146,13 @@ void clear () { - box2d ext = root_->extent_; + bbox_type ext = root_->extent_; nodes_.clear(); nodes_.push_back(std::make_unique(ext)); root_ = nodes_[0].get(); } - box2d const& extent() const + bbox_type const& extent() const { return root_->extent_; } @@ -179,22 +180,17 @@ "Values stored in quad-tree must be standard layout types to allow serialisation"); char header[16]; std::memset(header,0,16); - header[0]='m'; - header[1]='a'; - header[2]='p'; - header[3]='n'; - header[4]='i'; - header[5]='k'; + std::strcpy(header,"mapnik-index"); out.write(header,16); write_node(out,root_); } private: - void query_node(box2d const& box, result_type & result, node * node_) const + void query_node(bbox_type const& box, result_type & result, node * node_) const { if (node_) { - box2d const& node_extent = node_->extent(); + bbox_type const& node_extent = node_->extent(); if (box.intersects(node_extent)) { for (auto & n : *node_) @@ -209,7 +205,7 @@ } } - void do_insert_data(T data, box2d const& box, node * n, unsigned int& depth) + void do_insert_data(value_type data, bbox_type const& box, node * n, unsigned int& depth) { if (++depth >= max_depth_) { @@ -217,8 +213,8 @@ } else { - box2d const& node_extent = n->extent(); - box2d ext[4]; + bbox_type const& node_extent = n->extent(); + bbox_type ext[4]; split_box(node_extent,ext); for (int i = 0; i < 4; ++i) { @@ -237,20 +233,19 @@ } } - void split_box(box2d const& node_extent,box2d * ext) + void split_box(bbox_type const& node_extent,bbox_type * ext) { - double width=node_extent.width(); - double height=node_extent.height(); - - double lox=node_extent.minx(); - double loy=node_extent.miny(); - double hix=node_extent.maxx(); - double hiy=node_extent.maxy(); - - ext[0]=box2d(lox,loy,lox + width * ratio_,loy + height * ratio_); - ext[1]=box2d(hix - width * ratio_,loy,hix,loy + height * ratio_); - ext[2]=box2d(lox,hiy - height*ratio_,lox + width * ratio_,hiy); - ext[3]=box2d(hix - width * ratio_,hiy - height*ratio_,hix,hiy); + typename bbox_type::value_type width = node_extent.width(); + typename bbox_type::value_type height = node_extent.height(); + typename bbox_type::value_type lox = node_extent.minx(); + typename bbox_type::value_type loy = node_extent.miny(); + typename bbox_type::value_type hix = node_extent.maxx(); + typename bbox_type::value_type hiy = node_extent.maxy(); + + ext[0] = bbox_type(lox, loy, lox + width * ratio_, loy + height * ratio_); + ext[1] = bbox_type(hix - width * ratio_, loy, hix, loy + height * ratio_); + ext[2] = bbox_type(lox, hiy - height * ratio_, lox + width * ratio_, hiy); + ext[3] = bbox_type(hix - width * ratio_, hiy - height * ratio_, hix, hiy); } void trim_tree(node *& n) @@ -309,7 +304,7 @@ { if (n->children_[i]) { - offset +=sizeof(box2d) + (n->children_[i]->cont_.size() * sizeof(value_type)) + 3 * sizeof(int); + offset +=sizeof(bbox_type) + (n->children_[i]->cont_.size() * sizeof(value_type)) + 3 * sizeof(int); offset +=subnode_offset(n->children_[i]); } } @@ -321,17 +316,17 @@ { if (n) { - int offset=subnode_offset(n); - int shape_count=n->cont_.size(); - int recsize=sizeof(box2d) + 3 * sizeof(int) + shape_count * sizeof(value_type); + int offset = subnode_offset(n); + int shape_count = n->cont_.size(); + int recsize = sizeof(bbox_type) + 3 * sizeof(int) + shape_count * sizeof(value_type); std::unique_ptr node_record(new char[recsize]); std::memset(node_record.get(), 0, recsize); std::memcpy(node_record.get(), &offset, 4); - std::memcpy(node_record.get() + 4, &n->extent_, sizeof(box2d)); - std::memcpy(node_record.get() + 36, &shape_count, 4); + std::memcpy(node_record.get() + 4, &n->extent_, sizeof(bbox_type)); + std::memcpy(node_record.get() + 4 + sizeof(bbox_type), &shape_count, 4); for (int i=0; i < shape_count; ++i) { - memcpy(node_record.get() + 40 + i * sizeof(value_type), &(n->cont_[i]),sizeof(value_type)); + memcpy(node_record.get() + 8 + sizeof(bbox_type) + i * sizeof(value_type), &(n->cont_[i]), sizeof(value_type)); } int num_subnodes=0; for (int i = 0; i < 4; ++i) @@ -341,7 +336,7 @@ ++num_subnodes; } } - std::memcpy(node_record.get() + 40 + shape_count * sizeof(value_type),&num_subnodes,4); + std::memcpy(node_record.get() + 8 + sizeof(bbox_type) + shape_count * sizeof(value_type), &num_subnodes, 4); out.write(node_record.get(),recsize); for (int i = 0; i < 4; ++i) { diff -Nru mapnik-3.0.9+ds/include/mapnik/raster_colorizer.hpp mapnik-3.0.13+ds/include/mapnik/raster_colorizer.hpp --- mapnik-3.0.9+ds/include/mapnik/raster_colorizer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/raster_colorizer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -41,12 +41,13 @@ #include #include #include - // boost + +#pragma GCC diagnostic push +#include #include -// boost -#include +#pragma GCC diagnostic pop -// stl +#include #include namespace mapnik @@ -92,7 +93,7 @@ //! \brief Set the stop value //! \param[in] value The stop value - inline void set_value(float value) { value_ = value; } + inline void set_value(float v) { value_ = v; } //! \brief Get the stop value //! \return The stop value @@ -164,7 +165,7 @@ void set_default_mode(colorizer_mode mode) { - default_mode_ = (mode == COLORIZER_INHERIT) ? COLORIZER_LINEAR:(colorizer_mode_enum)mode; + default_mode_ = (mode == COLORIZER_INHERIT) ? COLORIZER_LINEAR : static_cast(mode); } void set_default_mode_enum(colorizer_mode_enum mode) { set_default_mode(mode); } @@ -204,7 +205,7 @@ //! //! \param[in] value Input value //! \return color associated with the value - unsigned get_color(float value) const; + unsigned get_color(float v) const; //! \brief Set the epsilon value for exact mode diff -Nru mapnik-3.0.9+ds/include/mapnik/raster.hpp mapnik-3.0.13+ds/include/mapnik/raster.hpp --- mapnik-3.0.9+ds/include/mapnik/raster.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/raster.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,8 +28,11 @@ #include #include #include - // boost + +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/renderer_common/apply_vertex_converter.hpp mapnik-3.0.13+ds/include/mapnik/renderer_common/apply_vertex_converter.hpp --- mapnik-3.0.9+ds/include/mapnik/renderer_common/apply_vertex_converter.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/renderer_common/apply_vertex_converter.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -31,7 +31,7 @@ apply_vertex_converter(VertexConverter & converter, Processor & proc) : converter_(converter), proc_(proc) {} template - void operator() (Adapter const& adapter) const + void operator() (Adapter const& adapter) { converter_.apply(adapter, proc_); } diff -Nru mapnik-3.0.9+ds/include/mapnik/renderer_common/process_building_symbolizer.hpp mapnik-3.0.13+ds/include/mapnik/renderer_common/process_building_symbolizer.hpp --- mapnik-3.0.9+ds/include/mapnik/renderer_common/process_building_symbolizer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/renderer_common/process_building_symbolizer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -38,9 +38,10 @@ template void make_building(geometry::polygon const& poly, double height, F1 const& face_func, F2 const& frame_func, F3 const& roof_func) { - const std::unique_ptr frame(new path_type(path_type::types::LineString)); - const std::unique_ptr roof(new path_type(path_type::types::Polygon)); + path_type frame(path_type::types::LineString); + path_type roof(path_type::types::Polygon); std::deque face_segments; + double ring_begin_x, ring_begin_y; double x0 = 0; double y0 = 0; double x,y; @@ -51,16 +52,22 @@ { if (cm == SEG_MOVETO) { - frame->move_to(x,y); + frame.move_to(x,y); + ring_begin_x = x; + ring_begin_y = y; } else if (cm == SEG_LINETO) { - frame->line_to(x,y); - face_segments.push_back(segment_t(x0,y0,x,y)); + frame.line_to(x,y); + face_segments.emplace_back(x0,y0,x,y); } else if (cm == SEG_CLOSE) { - frame->close_path(); + frame.close_path(); + if (!face_segments.empty()) + { + face_segments.emplace_back(x0, y0, ring_begin_x, ring_begin_y); + } } x0 = x; y0 = y; @@ -69,16 +76,16 @@ std::sort(face_segments.begin(),face_segments.end(), y_order); for (auto const& seg : face_segments) { - const std::unique_ptr faces(new path_type(path_type::types::Polygon)); - faces->move_to(std::get<0>(seg),std::get<1>(seg)); - faces->line_to(std::get<2>(seg),std::get<3>(seg)); - faces->line_to(std::get<2>(seg),std::get<3>(seg) + height); - faces->line_to(std::get<0>(seg),std::get<1>(seg) + height); + path_type faces(path_type::types::Polygon); + faces.move_to(std::get<0>(seg),std::get<1>(seg)); + faces.line_to(std::get<2>(seg),std::get<3>(seg)); + faces.line_to(std::get<2>(seg),std::get<3>(seg) + height); + faces.line_to(std::get<0>(seg),std::get<1>(seg) + height); - face_func(*faces); + face_func(faces); // - frame->move_to(std::get<0>(seg),std::get<1>(seg)); - frame->line_to(std::get<0>(seg),std::get<1>(seg)+height); + frame.move_to(std::get<0>(seg),std::get<1>(seg)); + frame.line_to(std::get<0>(seg),std::get<1>(seg)+height); } va.rewind(0); @@ -87,23 +94,23 @@ { if (cm == SEG_MOVETO) { - frame->move_to(x,y+height); - roof->move_to(x,y+height); + frame.move_to(x,y+height); + roof.move_to(x,y+height); } else if (cm == SEG_LINETO) { - frame->line_to(x,y+height); - roof->line_to(x,y+height); + frame.line_to(x,y+height); + roof.line_to(x,y+height); } else if (cm == SEG_CLOSE) { - frame->close_path(); - roof->close_path(); + frame.close_path(); + roof.close_path(); } } - frame_func(*frame); - roof_func(*roof); + frame_func(frame); + roof_func(roof); } } // ns detail diff -Nru mapnik-3.0.9+ds/include/mapnik/renderer_common/process_group_symbolizer.hpp mapnik-3.0.13+ds/include/mapnik/renderer_common/process_group_symbolizer.hpp --- mapnik-3.0.9+ds/include/mapnik/renderer_common/process_group_symbolizer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/renderer_common/process_group_symbolizer.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,403 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2015 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 - * - *****************************************************************************/ - -#ifndef MAPNIK_RENDERER_COMMON_PROCESS_GROUP_SYMBOLIZER_HPP -#define MAPNIK_RENDERER_COMMON_PROCESS_GROUP_SYMBOLIZER_HPP - -// mapnik -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// agg -#include - -namespace mapnik { - -class text_symbolizer_helper; - -using svg::svg_path_adapter; -using svg_attribute_type = agg::pod_bvector; - -struct virtual_renderer_common : private util::noncopyable -{ - virtual_renderer_common(renderer_common & common) : - width_(common.width_), - height_(common.height_), - scale_factor_(common.scale_factor_), - vars_(common.vars_), - shared_font_library_(common.shared_font_library_), - font_library_(*shared_font_library_), - font_manager_(common.font_manager_), - query_extent_(common.query_extent_), - t_(common.t_), - detector_(std::make_shared(common.detector_->extent())) {} - - unsigned & width_; - unsigned & height_; - double & scale_factor_; - attributes & vars_; - // TODO: dirty hack for cairo renderer, figure out how to remove this - std::shared_ptr & shared_font_library_; - font_library & font_library_; - face_manager_freetype & font_manager_; - box2d & query_extent_; - view_transform & t_; - std::shared_ptr detector_; -}; - - -// General: - -// The approach here is to run the normal symbolizers, but in -// a 'virtual' blank environment where the changes that they -// make are recorded (the detector, the render_* calls). -// -// The recorded boxes are then used to lay out the items and -// the offsets from old to new positions can be used to perform -// the actual rendering calls. - -// This should allow us to re-use as much as possible of the -// existing symbolizer layout and rendering code while still -// being able to interpose our own decisions about whether -// a collision has occurred or not. - -// Thunk for rendering a particular instance of a point - this -// stores all the arguments necessary to re-render this point -// symbolizer at a later time. - -struct vector_marker_render_thunk : util::noncopyable -{ - svg_path_ptr src_; - svg_attribute_type attrs_; - agg::trans_affine tr_; - double opacity_; - composite_mode_e comp_op_; - bool snap_to_pixels_; - - vector_marker_render_thunk(svg_path_ptr const& src, - svg_attribute_type const& attrs, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels); - - vector_marker_render_thunk(vector_marker_render_thunk && rhs); -}; - -struct raster_marker_render_thunk : util::noncopyable -{ - image_rgba8 const& src_; - agg::trans_affine tr_; - double opacity_; - composite_mode_e comp_op_; - bool snap_to_pixels_; - - raster_marker_render_thunk(image_rgba8 const& src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels); - - raster_marker_render_thunk(raster_marker_render_thunk && rhs); -}; - -using helper_ptr = std::unique_ptr; - -struct text_render_thunk : util::noncopyable -{ - // helper is stored here in order - // to keep in scope the text rendering structures - helper_ptr helper_; - placements_list const& placements_; - double opacity_; - composite_mode_e comp_op_; - halo_rasterizer_enum halo_rasterizer_; - - text_render_thunk(helper_ptr && helper, - double opacity, composite_mode_e comp_op, - halo_rasterizer_enum halo_rasterizer); - - text_render_thunk(text_render_thunk && rhs); - -}; - -// Variant type for render thunks to allow us to re-render them -// via a static visitor later. - -using render_thunk = util::variant; -using render_thunk_ptr = std::unique_ptr; -using render_thunk_list = std::list; - -// Base class for extracting the bounding boxes associated with placing -// a symbolizer at a fake, virtual point - not real geometry. -// -// The bounding boxes can be used for layout, and the thunks are -// used to re-render at locations according to the group layout. - -struct render_thunk_extractor -{ - render_thunk_extractor(box2d & box, - render_thunk_list & thunks, - feature_impl & feature, - attributes const& vars, - proj_transform const& prj_trans, - virtual_renderer_common & common, - box2d const& clipping_extent); - - void operator()(markers_symbolizer const& sym) const; - - void operator()(text_symbolizer const& sym) const; - - void operator()(shield_symbolizer const& sym) const; - - template - void operator()(T const& ) const - { - // TODO: warning if unimplemented? - } - -private: - void extract_text_thunk(helper_ptr && helper, text_symbolizer const& sym) const; - - box2d & box_; - render_thunk_list & thunks_; - feature_impl & feature_; - attributes const& vars_; - proj_transform const& prj_trans_; - virtual_renderer_common & common_; - box2d clipping_extent_; - - void update_box() const; -}; - -template -void render_offset_placements(placements_list const& placements, - pixel_position const& offset, - F render_text) { - - for (auto const& glyphs : placements) - { - // move the glyphs to the correct offset - pixel_position base_point = glyphs->get_base_point(); - glyphs->set_base_point(base_point + offset); - - // update the position of any marker - marker_info_ptr marker_info = glyphs->get_marker(); - pixel_position marker_pos = glyphs->marker_pos(); - if (marker_info) - { - glyphs->set_marker(marker_info, marker_pos + offset); - } - - render_text(glyphs); - - // Need to put the base_point back how it was in case something else calls this again - // (don't want to add offset twice) or calls with a different offset. - glyphs->set_base_point(base_point); - if (marker_info) - { - glyphs->set_marker(marker_info, marker_pos); - } - } -} - -template -void render_group_symbolizer(group_symbolizer const& sym, - feature_impl & feature, - attributes const& vars, - proj_transform const& prj_trans, - box2d const& clipping_extent, - renderer_common & common, - F render_thunks) -{ - // find all column names referenced in the group rules and symbolizers - std::set columns; - group_attribute_collector column_collector(columns, false); - column_collector(sym); - - group_symbolizer_properties_ptr props = get(sym, keys::group_properties); - - // create a new context for the sub features of this group - context_ptr sub_feature_ctx = std::make_shared(); - - // populate new context with column names referenced in the group rules and symbolizers - for (auto const& col_name : columns) - { - sub_feature_ctx->push(col_name); - } - - // keep track of the sub features that we'll want to symbolize - // along with the group rules that they matched - std::vector< std::pair > matches; - - // create a copied 'virtual' common renderer for processing sub feature symbolizers - // create an empty detector for it, so we are sure we won't hit anything - virtual_renderer_common virtual_renderer(common); - - // keep track of which lists of render thunks correspond to - // entries in the group_layout_manager. - std::vector layout_thunks; - size_t num_layout_thunks = 0; - - // layout manager to store and arrange bboxes of matched features - group_layout_manager layout_manager(props->get_layout(), pixel_position(common.width_ / 2.0, common.height_ / 2.0)); - - // run feature or sub feature through the group rules & symbolizers - // for each index value in the range - value_integer start = get(sym, keys::start_column); - value_integer end = start + get(sym, keys::num_columns); - for (value_integer col_idx = start; col_idx < end; ++col_idx) - { - // create sub feature with indexed column values - feature_ptr sub_feature = feature_factory::create(sub_feature_ctx, col_idx); - - // copy the necessary columns to sub feature - for(auto const& col_name : columns) - { - if (col_name.find('%') != std::string::npos) - { - if (col_name.size() == 1) - { - // column name is '%' by itself, so give the index as the value - sub_feature->put(col_name, col_idx); - } - else - { - // indexed column - std::string col_idx_str; - if (mapnik::util::to_string(col_idx_str,col_idx)) - { - std::string col_idx_name = col_name; - boost::replace_all(col_idx_name, "%", col_idx_str); - sub_feature->put(col_name, feature.get(col_idx_name)); - } - } - } - else - { - // non-indexed column - sub_feature->put(col_name, feature.get(col_name)); - } - } - - // add a single point geometry at pixel origin - double x = common.width_ / 2.0, y = common.height_ / 2.0, z = 0.0; - common.t_.backward(&x, &y); - prj_trans.forward(x, y, z); - // note that we choose a point in the middle of the screen to - // try to ensure that we don't get edge artefacts due to any - // symbolizers with avoid-edges set: only the avoid-edges of - // the group symbolizer itself should matter. - geometry::point origin_pt(x,y); - sub_feature->set_geometry(origin_pt); - // get the layout for this set of properties - for (auto const& rule : props->get_rules()) - { - if (util::apply_visitor(evaluate(*sub_feature,common.vars_), - *(rule->get_filter())).to_bool()) - { - // add matched rule and feature to the list of things to draw - matches.emplace_back(rule, sub_feature); - - // construct a bounding box around all symbolizers for the matched rule - bound_box bounds; - render_thunk_list thunks; - render_thunk_extractor extractor(bounds, thunks, *sub_feature, common.vars_, prj_trans, - virtual_renderer, clipping_extent); - - for (auto const& _sym : *rule) - { - // TODO: construct layout and obtain bounding box - util::apply_visitor(extractor, _sym); - } - - // add the bounding box to the layout manager - layout_manager.add_member_bound_box(bounds); - layout_thunks.emplace_back(std::move(thunks)); - ++num_layout_thunks; - break; - } - } - } - - // create a symbolizer helper - group_symbolizer_helper helper(sym, feature, vars, prj_trans, - common.width_, common.height_, - common.scale_factor_, common.t_, - *common.detector_, clipping_extent); - - for (size_t i = 0; i < matches.size(); ++i) - { - group_rule_ptr match_rule = matches[i].first; - feature_ptr match_feature = matches[i].second; - value_unicode_string rpt_key_value = ""; - - // get repeat key from matched group rule - expression_ptr rpt_key_expr = match_rule->get_repeat_key(); - - // if no repeat key was defined, use default from group symbolizer - if (!rpt_key_expr) - { - rpt_key_expr = get(sym, keys::repeat_key); - } - - // evaluate the repeat key with the matched sub feature if we have one - if (rpt_key_expr) - { - rpt_key_value = util::apply_visitor(evaluate(*match_feature,common.vars_), - *rpt_key_expr).to_unicode(); - } - helper.add_box_element(layout_manager.offset_box_at(i), rpt_key_value); - } - - pixel_position_list positions = helper.get(); - for (pixel_position const& pos : positions) - { - for (size_t layout_i = 0; layout_i < num_layout_thunks; ++layout_i) - { - pixel_position const& offset = layout_manager.offset_at(layout_i); - pixel_position render_offset = pos + offset; - render_thunks(layout_thunks[layout_i], render_offset); - } - } -} - -} // namespace mapnik - -#endif // MAPNIK_RENDERER_COMMON_PROCESS_GROUP_SYMBOLIZER_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/renderer_common/process_markers_symbolizer.hpp mapnik-3.0.13+ds/include/mapnik/renderer_common/process_markers_symbolizer.hpp --- mapnik-3.0.9+ds/include/mapnik/renderer_common/process_markers_symbolizer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/renderer_common/process_markers_symbolizer.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,275 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2015 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 - * - *****************************************************************************/ - -#ifndef MAPNIK_RENDERER_COMMON_PROCESS_MARKERS_SYMBOLIZER_HPP -#define MAPNIK_RENDERER_COMMON_PROCESS_MARKERS_SYMBOLIZER_HPP - -#include -#include -#include -#include -#include -#include - -namespace mapnik { - -template -struct render_marker_symbolizer_visitor -{ - using vector_dispatch_type = VD; - using raster_dispatch_type = RD; - using buffer_type = typename std::tuple_element<0,ContextType>::type; - - using vertex_converter_type = vertex_converter; - - render_marker_symbolizer_visitor(std::string const& filename, - markers_symbolizer const& sym, - mapnik::feature_impl & feature, - proj_transform const& prj_trans, - RendererType const& common, - box2d const& clip_box, - ContextType const& renderer_context) - : filename_(filename), - sym_(sym), - feature_(feature), - prj_trans_(prj_trans), - common_(common), - clip_box_(clip_box), - renderer_context_(renderer_context) {} - - void operator() (marker_null const&) {} - - void operator() (marker_svg const& mark) - { - using namespace mapnik::svg; - bool clip = get(sym_, feature_, common_.vars_); - double offset = get(sym_, feature_, common_.vars_); - double simplify_tolerance = get(sym_, feature_, common_.vars_); - double smooth = get(sym_, feature_, common_.vars_); - - // https://github.com/mapnik/mapnik/issues/1316 - bool snap_to_pixels = !mapnik::marker_cache::instance().is_uri(filename_); - - agg::trans_affine geom_tr; - auto transform = get_optional(sym_, keys::geometry_transform); - if (transform) evaluate_transform(geom_tr, feature_, common_.vars_, *transform, common_.scale_factor_); - agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); - - boost::optional const& stock_vector_marker = mark.get_data(); - - // special case for simple ellipse markers - // to allow for full control over rx/ry dimensions - if (filename_ == "shape://ellipse" - && (has_key(sym_,keys::width) || has_key(sym_,keys::height))) - { - svg_path_ptr marker_ellipse = std::make_shared(); - vertex_stl_adapter stl_storage(marker_ellipse->source()); - svg_path_adapter svg_path(stl_storage); - build_ellipse(sym_, feature_, common_.vars_, *marker_ellipse, svg_path); - svg_attribute_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym_, feature_, common_.vars_); - auto image_transform = get_optional(sym_, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); - vector_dispatch_type rasterizer_dispatch(marker_ellipse, - svg_path, - result ? attributes : (*stock_vector_marker)->attributes(), - image_tr, - sym_, - *common_.detector_, - common_.scale_factor_, - feature_, - common_.vars_, - snap_to_pixels, - renderer_context_); - - vertex_converter_type converter(clip_box_, - sym_, - common_.t_, - prj_trans_, - geom_tr, - feature_, - common_.vars_, - common_.scale_factor_); - if (clip) - { - geometry::geometry_types type = geometry::geometry_type(feature_.get_geometry()); - if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon) - converter.template set(); - else if (type == geometry::geometry_types::LineString || type == geometry::geometry_types::MultiLineString) - converter.template set(); - } - - converter.template set(); //always transform - if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset - converter.template set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature_, common_.vars_, converter, rasterizer_dispatch, sym_); - } - else - { - box2d const& bbox = mark.bounding_box(); - setup_transform_scaling(image_tr, bbox.width(), bbox.height(), feature_, common_.vars_, sym_); - auto image_transform = get_optional(sym_, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); - vertex_stl_adapter stl_storage((*stock_vector_marker)->source()); - svg_path_adapter svg_path(stl_storage); - svg_attribute_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym_, feature_, common_.vars_); - vector_dispatch_type rasterizer_dispatch(*stock_vector_marker, - svg_path, - result ? attributes : (*stock_vector_marker)->attributes(), - image_tr, - sym_, - *common_.detector_, - common_.scale_factor_, - feature_, - common_.vars_, - snap_to_pixels, - renderer_context_); - - vertex_converter_type converter(clip_box_, - sym_, - common_.t_, - prj_trans_, - geom_tr, - feature_, - common_.vars_, - common_.scale_factor_); - if (clip) - { - geometry::geometry_types type = geometry::geometry_type(feature_.get_geometry()); - if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon) - converter.template set(); - else if (type == geometry::geometry_types::LineString || type == geometry::geometry_types::MultiLineString) - converter.template set(); - } - - converter.template set(); //always transform - if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset - converter.template set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature_, common_.vars_, converter, rasterizer_dispatch, sym_); - } - } - - void operator() (marker_rgba8 const& mark) - { - using namespace mapnik::svg; - bool clip = get(sym_, feature_, common_.vars_); - double offset = get(sym_, feature_, common_.vars_); - double simplify_tolerance = get(sym_, feature_, common_.vars_); - double smooth = get(sym_, feature_, common_.vars_); - - agg::trans_affine geom_tr; - auto transform = get_optional(sym_, keys::geometry_transform); - if (transform) evaluate_transform(geom_tr, feature_, common_.vars_, *transform, common_.scale_factor_); - agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); - - setup_transform_scaling(image_tr, mark.width(), mark.height(), feature_, common_.vars_, sym_); - auto image_transform = get_optional(sym_, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); - box2d const& bbox = mark.bounding_box(); - mapnik::image_rgba8 const& marker = mark.get_data(); - // - clamp sizes to > 4 pixels of interactivity - coord2d center = bbox.center(); - agg::trans_affine_translation recenter(-center.x, -center.y); - agg::trans_affine marker_trans = recenter * image_tr; - raster_dispatch_type rasterizer_dispatch(marker, - marker_trans, - sym_, - *common_.detector_, - common_.scale_factor_, - feature_, - common_.vars_, - renderer_context_); - - - vertex_converter_type converter(clip_box_, - sym_, - common_.t_, - prj_trans_, - geom_tr, - feature_, - common_.vars_, - common_.scale_factor_); - - if (clip) - { - geometry::geometry_types type = geometry::geometry_type(feature_.get_geometry()); - if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon) - converter.template set(); - else if (type == geometry::geometry_types::LineString || type == geometry::geometry_types::MultiLineString) - converter.template set(); - } - converter.template set(); //always transform - if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset - converter.template set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature_, common_.vars_, converter, rasterizer_dispatch, sym_); - } - - private: - std::string const& filename_; - markers_symbolizer const& sym_; - mapnik::feature_impl & feature_; - proj_transform const& prj_trans_; - RendererType const& common_; - box2d const& clip_box_; - ContextType const& renderer_context_; -}; - -template -void render_markers_symbolizer(markers_symbolizer const& sym, - mapnik::feature_impl & feature, - proj_transform const& prj_trans, - RendererType const& common, - box2d const& clip_box, - ContextType const& renderer_context) -{ - using namespace mapnik::svg; - std::string filename = get(sym, keys::file, feature, common.vars_, "shape://ellipse"); - if (!filename.empty()) - { - std::shared_ptr mark = mapnik::marker_cache::instance().find(filename, true); - render_marker_symbolizer_visitor visitor(filename, - sym, - feature, - prj_trans, - common, - clip_box, - renderer_context); - util::apply_visitor(visitor, *mark); - } -} - -} // namespace mapnik - -#endif // MAPNIK_RENDERER_COMMON_PROCESS_MARKERS_SYMBOLIZER_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/renderer_common/process_point_symbolizer.hpp mapnik-3.0.13+ds/include/mapnik/renderer_common/process_point_symbolizer.hpp --- mapnik-3.0.9+ds/include/mapnik/renderer_common/process_point_symbolizer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/renderer_common/process_point_symbolizer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -61,7 +61,7 @@ agg::trans_affine tr; auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(tr, feature, common.vars_, *image_transform); + if (image_transform) evaluate_transform(tr, feature, common.vars_, *image_transform, common.scale_factor_); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine recenter_tr = recenter * tr; diff -Nru mapnik-3.0.9+ds/include/mapnik/renderer_common/process_raster_symbolizer.hpp mapnik-3.0.13+ds/include/mapnik/renderer_common/process_raster_symbolizer.hpp --- mapnik-3.0.9+ds/include/mapnik/renderer_common/process_raster_symbolizer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/renderer_common/process_raster_symbolizer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -32,13 +32,15 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" #include "agg_pixfmt_gray.h" #include "agg_rasterizer_scanline_aa.h" #include "agg_scanline_u.h" #include "agg_renderer_scanline.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/renderer_common/render_group_symbolizer.hpp mapnik-3.0.13+ds/include/mapnik/renderer_common/render_group_symbolizer.hpp --- mapnik-3.0.9+ds/include/mapnik/renderer_common/render_group_symbolizer.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/renderer_common/render_group_symbolizer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,66 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_RENDERER_COMMON_RENDER_GROUP_SYMBOLIZER_HPP +#define MAPNIK_RENDERER_COMMON_RENDER_GROUP_SYMBOLIZER_HPP + +// mapnik +#include +#include +#include +#include +#include + +namespace mapnik { + +struct render_thunk_list_dispatch +{ + virtual void operator()(vector_marker_render_thunk const& thunk) = 0; + virtual void operator()(raster_marker_render_thunk const& thunk) = 0; + virtual void operator()(text_render_thunk const& thunk) = 0; + + void render_list(render_thunk_list const& thunks, pixel_position const& offset) + { + offset_ = offset; + + for (render_thunk const& thunk : thunks) + { + util::apply_visitor(std::ref(*this), thunk); + } + } + +protected: + pixel_position offset_; +}; + +MAPNIK_DECL +void render_group_symbolizer(group_symbolizer const& sym, + feature_impl & feature, + attributes const& vars, + proj_transform const& prj_trans, + box2d const& clipping_extent, + renderer_common & common, + render_thunk_list_dispatch & render_thunks); + +} // namespace mapnik + +#endif // MAPNIK_RENDERER_COMMON_RENDER_GROUP_SYMBOLIZER_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/renderer_common/render_markers_symbolizer.hpp mapnik-3.0.13+ds/include/mapnik/renderer_common/render_markers_symbolizer.hpp --- mapnik-3.0.9+ds/include/mapnik/renderer_common/render_markers_symbolizer.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/renderer_common/render_markers_symbolizer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,76 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_RENDERER_COMMON_RENDER_MARKERS_SYMBOLIZER_HPP +#define MAPNIK_RENDERER_COMMON_RENDER_MARKERS_SYMBOLIZER_HPP + +#include +#include +#include +#include + +namespace mapnik { + +struct markers_dispatch_params +{ + // placement + markers_placement_params placement_params; + marker_placement_enum placement_method; + value_bool ignore_placement; + // rendering + bool snap_to_pixels; + double scale_factor; + value_double opacity; + + markers_dispatch_params(box2d const& size, + agg::trans_affine const& tr, + symbolizer_base const& sym, + feature_impl const& feature, + attributes const& vars, + double scale_factor = 1.0, + bool snap_to_pixels = false); +}; + +struct markers_renderer_context : util::noncopyable +{ + virtual void render_marker(image_rgba8 const& src, + markers_dispatch_params const& params, + agg::trans_affine const& marker_tr) = 0; + + virtual void render_marker(svg_path_ptr const& src, + svg_path_adapter & path, + svg_attribute_type const& attrs, + markers_dispatch_params const& params, + agg::trans_affine const& marker_tr) = 0; +}; + +MAPNIK_DECL +void render_markers_symbolizer(markers_symbolizer const& sym, + mapnik::feature_impl & feature, + proj_transform const& prj_trans, + renderer_common const& common, + box2d const& clip_box, + markers_renderer_context & renderer_context); + +} // namespace mapnik + +#endif // MAPNIK_RENDERER_COMMON_RENDER_MARKERS_SYMBOLIZER_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/renderer_common/render_thunk_extractor.hpp mapnik-3.0.13+ds/include/mapnik/renderer_common/render_thunk_extractor.hpp --- mapnik-3.0.9+ds/include/mapnik/renderer_common/render_thunk_extractor.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/renderer_common/render_thunk_extractor.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,97 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_RENDERER_COMMON_RENDER_THUNK_EXTRACTOR_HPP +#define MAPNIK_RENDERER_COMMON_RENDER_THUNK_EXTRACTOR_HPP + +// mapnik +#include +#include +#include +#include + +namespace mapnik { + +// The approach here is to run the normal symbolizers, but in +// a 'virtual' blank environment where the changes that they +// make are recorded (the detector, the render_* calls). +// +// The recorded boxes are then used to lay out the items and +// the offsets from old to new positions can be used to perform +// the actual rendering calls. + +// This should allow us to re-use as much as possible of the +// existing symbolizer layout and rendering code while still +// being able to interpose our own decisions about whether +// a collision has occurred or not. + +struct virtual_renderer_common : renderer_common +{ + explicit virtual_renderer_common(renderer_common const& other); +}; + +// Base class for extracting the bounding boxes associated with placing +// a symbolizer at a fake, virtual point - not real geometry. +// +// The bounding boxes can be used for layout, and the thunks are +// used to re-render at locations according to the group layout. + +struct render_thunk_extractor +{ + render_thunk_extractor(box2d & box, + render_thunk_list & thunks, + feature_impl & feature, + attributes const& vars, + proj_transform const& prj_trans, + virtual_renderer_common & common, + box2d const& clipping_extent); + + void operator()(markers_symbolizer const& sym) const; + + void operator()(text_symbolizer const& sym) const; + + void operator()(shield_symbolizer const& sym) const; + + template + void operator()(T const& ) const + { + // TODO: warning if unimplemented? + } + +private: + void extract_text_thunk(text_render_thunk::helper_ptr && helper, + text_symbolizer const& sym) const; + + box2d & box_; + render_thunk_list & thunks_; + feature_impl & feature_; + attributes const& vars_; + proj_transform const& prj_trans_; + virtual_renderer_common & common_; + box2d clipping_extent_; + + void update_box() const; +}; + +} // namespace mapnik + +#endif // MAPNIK_RENDERER_COMMON_RENDER_THUNK_EXTRACTOR_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/renderer_common/render_thunk.hpp mapnik-3.0.13+ds/include/mapnik/renderer_common/render_thunk.hpp --- mapnik-3.0.9+ds/include/mapnik/renderer_common/render_thunk.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/renderer_common/render_thunk.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,114 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_RENDERER_COMMON_RENDER_THUNK_HPP +#define MAPNIK_RENDERER_COMMON_RENDER_THUNK_HPP + +// mapnik +#include // composite_mode_e +#include // svg_attribute_type, svg_path_ptr +#include // halo_rasterizer_enum +#include +#include +#include +#include + +// agg +#include + +namespace mapnik { + +// Thunk for rendering a particular instance of a point - this +// stores all the arguments necessary to re-render this point +// symbolizer at a later time. + +struct vector_marker_render_thunk : util::movable +{ + svg_path_ptr src_; + svg_attribute_type attrs_; + agg::trans_affine tr_; + double opacity_; + composite_mode_e comp_op_; + bool snap_to_pixels_; + + vector_marker_render_thunk(svg_path_ptr const& src, + svg_attribute_type const& attrs, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), attrs_(attrs), tr_(marker_trans), opacity_(opacity), + comp_op_(comp_op), snap_to_pixels_(snap_to_pixels) + {} +}; + +struct raster_marker_render_thunk : util::movable +{ + image_rgba8 const& src_; + agg::trans_affine tr_; + double opacity_; + composite_mode_e comp_op_; + bool snap_to_pixels_; + + raster_marker_render_thunk(image_rgba8 const& src, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) + {} +}; + +struct text_render_thunk : util::movable +{ + using helper_ptr = std::unique_ptr; + // helper is stored here in order + // to keep in scope the text rendering structures + helper_ptr helper_; + placements_list const& placements_; + double opacity_; + composite_mode_e comp_op_; + halo_rasterizer_enum halo_rasterizer_; + + text_render_thunk(helper_ptr && helper, + double opacity, composite_mode_e comp_op, + halo_rasterizer_enum halo_rasterizer) + : helper_(std::move(helper)), + placements_(helper_->get()), + opacity_(opacity), + comp_op_(comp_op), + halo_rasterizer_(halo_rasterizer) + {} +}; + +// Variant type for render thunks to allow us to re-render them +// via a static visitor later. + +using render_thunk = util::variant; +using render_thunk_list = std::list; + +} // namespace mapnik + +#endif // MAPNIK_RENDERER_COMMON_RENDER_THUNK_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/renderer_common.hpp mapnik-3.0.13+ds/include/mapnik/renderer_common.hpp --- mapnik-3.0.9+ds/include/mapnik/renderer_common.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/renderer_common.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -42,13 +42,16 @@ struct renderer_common : private util::noncopyable { + using detector_ptr = std::shared_ptr; + renderer_common(Map const &m, attributes const& vars, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height, double scale_factor); renderer_common(Map const &m, attributes const& vars, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height, double scale_factor, - std::shared_ptr detector); + detector_ptr detector); renderer_common(Map const &m, request const &req, attributes const& vars, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height, double scale_factor); + ~renderer_common(); unsigned width_; unsigned height_; @@ -60,11 +63,18 @@ face_manager_freetype font_manager_; box2d query_extent_; view_transform t_; - std::shared_ptr detector_; + detector_ptr detector_; + +protected: + // it's desirable to keep this class implicitly noncopyable to prevent + // inadvertent copying from other places; + // this copy constructor is therefore protected and should only be used + // by virtual_renderer_common + renderer_common(renderer_common const& other); private: renderer_common(Map const &m, unsigned width, unsigned height, double scale_factor, - attributes const& vars, view_transform &&t, std::shared_ptr detector); + attributes const& vars, view_transform && t, detector_ptr detector); }; } diff -Nru mapnik-3.0.9+ds/include/mapnik/simplify_converter.hpp mapnik-3.0.13+ds/include/mapnik/simplify_converter.hpp --- mapnik-3.0.9+ds/include/mapnik/simplify_converter.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/simplify_converter.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -41,7 +41,7 @@ vertex2d const& A = prev->coord; vertex2d const& B = next->coord; vertex2d const& C = coord; - return std::abs((double)((A.x - C.x) * (B.y - A.y) - (A.x - B.x) * (C.y - A.y))) / 2.0; + return std::abs(static_cast((A.x - C.x) * (B.y - A.y) - (A.x - B.x) * (C.y - A.y))) / 2.0; } struct ascending_sort @@ -76,16 +76,16 @@ bool inside(vertex2d const& q) { - bool inside=false; + bool _inside=false; for (unsigned i=0;i<4;++i) { if ((((v[i+1].y <= q.y) && (q.y < v[i].y)) || ((v[i].y <= q.y) && (q.y < v[i+1].y))) && (q.x < (v[i].x - v[i+1].x) * (q.y - v[i+1].y)/ (v[i].y - v[i+1].y) + v[i+1].x)) - inside=!inside; + _inside=!_inside; } - return inside; + return _inside; } }; @@ -120,11 +120,11 @@ return algorithm_; } - void set_simplify_algorithm(simplify_algorithm_e value) + void set_simplify_algorithm(simplify_algorithm_e val) { - if (algorithm_ != value) + if (algorithm_ != val) { - algorithm_ = value; + algorithm_ = val; reset(); } } @@ -134,11 +134,11 @@ return tolerance_; } - void set_simplify_tolerance(double value) + void set_simplify_tolerance(double val) { - if (tolerance_ != value) + if (tolerance_ != val) { - tolerance_ = value; + tolerance_ = val; reset(); } } @@ -592,11 +592,11 @@ } // Slurp the points back out that haven't been marked as discarded - for (vertex2d const& vertex : vertices) + for (vertex2d const& v : vertices) { - if (vertex.cmd != SEG_END) + if (v.cmd != SEG_END) { - vertices_.emplace_back(vertex); + vertices_.emplace_back(v); } } diff -Nru mapnik-3.0.9+ds/include/mapnik/simplify.hpp mapnik-3.0.13+ds/include/mapnik/simplify.hpp --- mapnik-3.0.9+ds/include/mapnik/simplify.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/simplify.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -7,8 +7,10 @@ // stl #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/span_image_filter.h mapnik-3.0.13+ds/include/mapnik/span_image_filter.h --- mapnik-3.0.9+ds/include/mapnik/span_image_filter.h 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/span_image_filter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,178 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2015 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 - * - *****************************************************************************/ - -#ifndef MAPNIK_SPAN_IMAGE_FILTER_INCLUDED -#define MAPNIK_SPAN_IMAGE_FILTER_INCLUDED - -#include "agg_span_image_filter_gray.h" -#include "agg_span_image_filter_rgba.h" - -#include - -namespace mapnik -{ - -template -class span_image_resample_gray_affine : public agg::span_image_resample_affine -{ -public: - using source_type = Source; - using color_type = typename source_type::color_type; - using base_type = agg::span_image_resample_affine; - using interpolator_type = typename base_type::interpolator_type; - using value_type = typename color_type::value_type; - using long_type = typename color_type::long_type; - - enum base_scale_e - { - downscale_shift = agg::image_filter_shift, - base_mask = color_type::base_mask - }; - - span_image_resample_gray_affine(source_type & src, - interpolator_type & inter, - agg::image_filter_lut const & filter, - boost::optional const & nodata_value) : - base_type(src, inter, filter), - nodata_value_(nodata_value) - { } - - void generate(color_type* span, int x, int y, unsigned len) - { - base_type::interpolator().begin(x + base_type::filter_dx_dbl(), - y + base_type::filter_dy_dbl(), len); - - long_type fg; - - int diameter = base_type::filter().diameter(); - int filter_scale = diameter << agg::image_subpixel_shift; - int radius_x = (diameter * base_type::m_rx) >> 1; - int radius_y = (diameter * base_type::m_ry) >> 1; - int len_x_lr = - (diameter * base_type::m_rx + agg::image_subpixel_mask) >> - agg::image_subpixel_shift; - - const agg::int16* weight_array = base_type::filter().weight_array(); - - do - { - base_type::interpolator().coordinates(&x, &y); - - int src_x = x >> agg::image_subpixel_shift; - int src_y = y >> agg::image_subpixel_shift; - const value_type* pix = reinterpret_cast(base_type::source().span(src_x, src_y, 0)); - if (nodata_value_ && *nodata_value_ == *pix) - { - span->v = *nodata_value_; - span->a = base_mask; - ++span; - ++base_type::interpolator(); - continue; - } - - x += base_type::filter_dx_int() - radius_x; - y += base_type::filter_dy_int() - radius_y; - - fg = 0; - - int y_lr = y >> agg::image_subpixel_shift; - int y_hr = ((agg::image_subpixel_mask - (y & agg::image_subpixel_mask)) * - base_type::m_ry_inv) >> - agg::image_subpixel_shift; - int total_weight = 0; - int x_lr = x >> agg::image_subpixel_shift; - int x_hr = ((agg::image_subpixel_mask - (x & agg::image_subpixel_mask)) * - base_type::m_rx_inv) >> - agg::image_subpixel_shift; - - int x_hr2 = x_hr; - const value_type* fg_ptr = reinterpret_cast(base_type::source().span(x_lr, y_lr, len_x_lr)); - for(;;) - { - int weight_y = weight_array[y_hr]; - x_hr = x_hr2; - for(;;) - { - int weight = (weight_y * weight_array[x_hr] + - agg::image_filter_scale) >> - downscale_shift; - if (!nodata_value_ || *nodata_value_ != *fg_ptr) - { - fg += *fg_ptr * weight; - total_weight += weight; - } - x_hr += base_type::m_rx_inv; - if (x_hr >= filter_scale) break; - fg_ptr = reinterpret_cast(base_type::source().next_x()); - } - y_hr += base_type::m_ry_inv; - if (y_hr >= filter_scale) break; - fg_ptr = reinterpret_cast(base_type::source().next_y()); - } - - fg /= total_weight; - if (fg < std::numeric_limits::min()) - { - span->v = std::numeric_limits::min(); - } - else if (fg > std::numeric_limits::max()) - { - span->v = std::numeric_limits::max(); - } - else - { - span->v = static_cast(fg); - } - span->a = base_mask; - - ++span; - ++base_type::interpolator(); - } while(--len); - } - -private: - boost::optional nodata_value_; -}; - -template -class span_image_resample_rgba_affine : public agg::span_image_resample_rgba_affine -{ -public: - using source_type = Source; - using color_type = typename source_type::color_type; - using order_type = typename source_type::order_type; - using base_type = agg::span_image_resample_rgba_affine; - using interpolator_type = typename base_type::interpolator_type; - using value_type = typename color_type::value_type; - using long_type = typename color_type::long_type; - - span_image_resample_rgba_affine(source_type & src, - interpolator_type & inter, - agg::image_filter_lut const & filter, - boost::optional const & nodata_value) : - agg::span_image_resample_rgba_affine(src, inter, filter) - { } -}; - -} - -#endif diff -Nru mapnik-3.0.9+ds/include/mapnik/span_image_filter.hpp mapnik-3.0.13+ds/include/mapnik/span_image_filter.hpp --- mapnik-3.0.9+ds/include/mapnik/span_image_filter.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/span_image_filter.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,187 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_SPAN_IMAGE_FILTER_INCLUDED +#define MAPNIK_SPAN_IMAGE_FILTER_INCLUDED + +#include + +#pragma GCC diagnostic push +#include +#include +#pragma GCC diagnostic pop + +#pragma GCC diagnostic push +#include +#include "agg_span_image_filter_gray.h" +#include "agg_span_image_filter_rgba.h" +#pragma GCC diagnostic pop + +#include + +namespace mapnik +{ + +template +class span_image_resample_gray_affine : public agg::span_image_resample_affine +{ +public: + using source_type = Source; + using color_type = typename source_type::color_type; + using base_type = agg::span_image_resample_affine; + using interpolator_type = typename base_type::interpolator_type; + using value_type = typename color_type::value_type; + using long_type = typename color_type::long_type; + + enum base_scale_e + { + downscale_shift = agg::image_filter_shift, + base_mask = color_type::base_mask + }; + + span_image_resample_gray_affine(source_type & src, + interpolator_type & inter, + agg::image_filter_lut const & filter, + boost::optional const & nodata_value) : + base_type(src, inter, filter), + nodata_value_(nodata_value) + { } + + void generate(color_type* span, int x, int y, unsigned len) + { + base_type::interpolator().begin(x + base_type::filter_dx_dbl(), + y + base_type::filter_dy_dbl(), len); + + long_type fg; + + int diameter = base_type::filter().diameter(); + int filter_scale = diameter << agg::image_subpixel_shift; + int radius_x = (diameter * base_type::m_rx) >> 1; + int radius_y = (diameter * base_type::m_ry) >> 1; + int len_x_lr = + (diameter * base_type::m_rx + agg::image_subpixel_mask) >> + agg::image_subpixel_shift; + + const agg::int16* weight_array = base_type::filter().weight_array(); + + do + { + base_type::interpolator().coordinates(&x, &y); + + if (nodata_value_) + { + int src_x = x >> agg::image_subpixel_shift; + int src_y = y >> agg::image_subpixel_shift; + const value_type* pix = reinterpret_cast(base_type::source().span(src_x, src_y, 1)); + if (*nodata_value_ == *pix) + { + span->v = *nodata_value_; + span->a = base_mask; + ++span; + ++base_type::interpolator(); + continue; + } + } + + x += base_type::filter_dx_int() - radius_x; + y += base_type::filter_dy_int() - radius_y; + + fg = 0; + + int y_lr = y >> agg::image_subpixel_shift; + int y_hr = ((agg::image_subpixel_mask - (y & agg::image_subpixel_mask)) * + base_type::m_ry_inv) >> + agg::image_subpixel_shift; + int total_weight = 0; + int x_lr = x >> agg::image_subpixel_shift; + int x_hr = ((agg::image_subpixel_mask - (x & agg::image_subpixel_mask)) * + base_type::m_rx_inv) >> + agg::image_subpixel_shift; + + int x_hr2 = x_hr; + const value_type* fg_ptr = reinterpret_cast(base_type::source().span(x_lr, y_lr, len_x_lr)); + for(;;) + { + int weight_y = weight_array[y_hr]; + x_hr = x_hr2; + for(;;) + { + int weight = (weight_y * weight_array[x_hr] + + agg::image_filter_scale) >> + downscale_shift; + if (!nodata_value_ || *nodata_value_ != *fg_ptr) + { + fg += *fg_ptr * weight; + total_weight += weight; + } + x_hr += base_type::m_rx_inv; + if (x_hr >= filter_scale) break; + fg_ptr = reinterpret_cast(base_type::source().next_x()); + } + y_hr += base_type::m_ry_inv; + if (y_hr >= filter_scale) break; + fg_ptr = reinterpret_cast(base_type::source().next_y()); + } + + if (total_weight == 0) + { + span->v = *nodata_value_; + } + else + { + span->v = safe_cast(fg / total_weight); + } + + span->a = base_mask; + + ++span; + ++base_type::interpolator(); + } while(--len); + } + +private: + boost::optional nodata_value_; +}; + +template +class span_image_resample_rgba_affine : public agg::span_image_resample_rgba_affine +{ +public: + using source_type = Source; + using color_type = typename source_type::color_type; + using order_type = typename source_type::order_type; + using base_type = agg::span_image_resample_rgba_affine; + using interpolator_type = typename base_type::interpolator_type; + using value_type = typename color_type::value_type; + using long_type = typename color_type::long_type; + + span_image_resample_rgba_affine(source_type & src, + interpolator_type & inter, + agg::image_filter_lut const & filter, + boost::optional const & nodata_value) : + agg::span_image_resample_rgba_affine(src, inter, filter) + { } +}; + +} + +#endif diff -Nru mapnik-3.0.9+ds/include/mapnik/stringify_macro.hpp mapnik-3.0.13+ds/include/mapnik/stringify_macro.hpp --- mapnik-3.0.9+ds/include/mapnik/stringify_macro.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/stringify_macro.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,26 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_STRINGIFY +#define MAPNIK_STRINGIFY(n) MAPNIK_STRINGIFY_HELPER(n) +#define MAPNIK_STRINGIFY_HELPER(n) #n +#endif \ No newline at end of file diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/geometry_svg_generator.hpp mapnik-3.0.13+ds/include/mapnik/svg/geometry_svg_generator.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/geometry_svg_generator.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/geometry_svg_generator.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -36,15 +36,13 @@ #pragma GCC diagnostic push #include #include -#include -#include -#include #include -#include +#include #include #include #pragma GCC diagnostic pop +#include // adapted to conform to the concepts // required by Karma to be recognized as a container of diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/output/svg_output_grammars.hpp mapnik-3.0.13+ds/include/mapnik/svg/output/svg_output_grammars.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/output/svg_output_grammars.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/output/svg_output_grammars.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -40,53 +40,8 @@ #include #include #include -#include #pragma GCC diagnostic pop -/*! - * mapnik::svg::path_output_attributes is adapted as a fusion sequence - * in order to be used directly by the svg_path_attributes_grammar (below). - * - * This adaptation is the primary reason why the attributes are stored in - * this structure before being passed to the generate_path method. - */ -BOOST_FUSION_ADAPT_STRUCT( - mapnik::svg::path_output_attributes, - (std::string, fill_color_) - (double, fill_opacity_) - (std::string, stroke_color_) - (double, stroke_opacity_) - (double, stroke_width_) - (std::string, stroke_linecap_) - (std::string, stroke_linejoin_) - (double, stroke_dashoffset_) - ); - -/*! - * mapnik::svg::rect_output_attributes is adapted as a fusion sequence - * in order to be used directly by the svg_rect_attributes_grammar (below). - */ -BOOST_FUSION_ADAPT_STRUCT( - mapnik::svg::rect_output_attributes, - (int, x_) - (int, y_) - (unsigned, width_) - (unsigned, height_) - (std::string, fill_color_) - ); - -/*! - * mapnik::svg::root_output_attributes is adapted as a fusion sequence - * in order to be used directly by the svg_root_attributes_grammar (below). - */ -BOOST_FUSION_ADAPT_STRUCT( - mapnik::svg::root_output_attributes, - (unsigned, width_) - (unsigned, height_) - (double, svg_version_) - (std::string, svg_namespace_url_) - ); - namespace mapnik { namespace svg { using namespace boost::spirit; diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/output/svg_output_grammars_impl.hpp mapnik-3.0.13+ds/include/mapnik/svg/output/svg_output_grammars_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/output/svg_output_grammars_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/output/svg_output_grammars_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,8 +30,53 @@ #include #include #include +#include #pragma GCC diagnostic pop +/*! + * mapnik::svg::path_output_attributes is adapted as a fusion sequence + * in order to be used directly by the svg_path_attributes_grammar (below). + * + * This adaptation is the primary reason why the attributes are stored in + * this structure before being passed to the generate_path method. + */ +BOOST_FUSION_ADAPT_STRUCT( + mapnik::svg::path_output_attributes, + (std::string, fill_color_) + (double, fill_opacity_) + (std::string, stroke_color_) + (double, stroke_opacity_) + (double, stroke_width_) + (std::string, stroke_linecap_) + (std::string, stroke_linejoin_) + (double, stroke_dashoffset_) + ); + +/*! + * mapnik::svg::rect_output_attributes is adapted as a fusion sequence + * in order to be used directly by the svg_rect_attributes_grammar (below). + */ +BOOST_FUSION_ADAPT_STRUCT( + mapnik::svg::rect_output_attributes, + (int, x_) + (int, y_) + (unsigned, width_) + (unsigned, height_) + (std::string, fill_color_) + ); + +/*! + * mapnik::svg::root_output_attributes is adapted as a fusion sequence + * in order to be used directly by the svg_root_attributes_grammar (below). + */ +BOOST_FUSION_ADAPT_STRUCT( + mapnik::svg::root_output_attributes, + (unsigned, width_) + (unsigned, height_) + (double, svg_version_) + (std::string, svg_namespace_url_) + ); + namespace mapnik { namespace svg { using namespace boost::spirit; diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_converter.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_converter.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_converter.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_converter.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,7 +29,8 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_path_storage.h" #include "agg_conv_transform.h" #include "agg_conv_stroke.h" @@ -37,6 +38,7 @@ #include "agg_conv_curve.h" #include "agg_color_rgba.h" #include "agg_bounding_rect.h" +#pragma GCC diagnostic pop // stl #include @@ -224,7 +226,15 @@ attr.stroke_color.opacity(a * s.opacity()); attr.stroke_flag = true; } - + void dash_array(dash_array && dash) + { + path_attributes& attr = cur_attr(); + attr.dash = std::move(dash); + } + void dash_offset(double offset) + { + cur_attr().dash_offset = offset; + } void even_odd(bool flag) { cur_attr().even_odd_flag = flag; diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_path_adapter.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_path_adapter.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_path_adapter.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_path_adapter.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,10 +28,12 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_math.h" #include "agg_array.h" #include "agg_bezier_arc.h" +#pragma GCC diagnostic pop // stl #include @@ -49,7 +51,7 @@ using self_type = path_adapter; //-------------------------------------------------------------------- - path_adapter(VertexContainer & vertices) : vertices_(vertices), iterator_(0) {} + path_adapter(VertexContainer & _vertices) : vertices_(_vertices), iterator_(0) {} //void remove_all() { vertices_.remove_all(); iterator_ = 0; } //void free_all() { vertices_.free_all(); iterator_ = 0; } diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_path_attributes.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_path_attributes.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_path_attributes.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_path_attributes.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,13 +23,16 @@ #ifndef MAPNIK_SVG_PATH_ATTRIBUTES_HPP #define MAPNIK_SVG_PATH_ATTRIBUTES_HPP -// agg +// mapnik +#include +#include // dash_array + +#pragma GCC diagnostic push +#include #include "agg_math_stroke.h" #include "agg_color_rgba.h" #include "agg_trans_affine.h" - -// mapnik -#include +#pragma GCC diagnostic pop namespace mapnik { namespace svg { @@ -56,7 +59,8 @@ bool even_odd_flag; bool visibility_flag; bool display_flag; - + dash_array dash; + double dash_offset; // Empty constructor path_attributes() : fill_gradient(), @@ -78,9 +82,10 @@ stroke_none(false), even_odd_flag(false), visibility_flag(true), - display_flag(true) - { - } + display_flag(true), + dash(), + dash_offset(0.0) + {} // Copy constructor path_attributes(path_attributes const& attr) @@ -103,7 +108,9 @@ stroke_none(attr.stroke_none), even_odd_flag(attr.even_odd_flag), visibility_flag(attr.visibility_flag), - display_flag(attr.display_flag) + display_flag(attr.display_flag), + dash(attr.dash), + dash_offset(attr.dash_offset) {} // Copy constructor with new index value path_attributes(path_attributes const& attr, unsigned idx) @@ -126,7 +133,9 @@ stroke_none(attr.stroke_none), even_odd_flag(attr.even_odd_flag), visibility_flag(attr.visibility_flag), - display_flag(attr.display_flag) + display_flag(attr.display_flag), + dash(attr.dash), + dash_offset(attr.dash_offset) {} }; diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_path_commands.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_path_commands.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_path_commands.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_path_commands.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,241 +29,130 @@ #pragma GCC diagnostic push #include -#include -#include -#include -#include +#include #pragma GCC diagnostic pop -namespace mapnik { namespace svg { +namespace mapnik { +namespace svg { -using namespace boost::fusion; inline double deg2rad(double deg) { - return (M_PI * deg)/180.0; + return (M_PI * deg) / 180.0; } -template struct move_to { + using result_type = void; - template - struct result - { - using type = void; - }; - - explicit move_to(PathType & path) - : path_(path) {} - - template - void operator() (T0 v, T1 rel) const + template + void operator()(PathType& path, T0 v, T1 rel) const { - path_.move_to(at_c<0>(v),at_c<1>(v),rel); // impl + path.move_to(boost::fusion::at_c<0>(v), boost::fusion::at_c<1>(v), rel); // impl } - - PathType & path_; }; -template struct hline_to { - template - struct result - { - using type = void; - }; - - explicit hline_to(PathType & path) - : path_(path) {} - - template - void operator() (T0 const& x, T1 rel) const + using result_type = void; + template + void operator()(PathType& path, T0 const& x, T1 rel) const { - path_.hline_to(x,rel); + path.hline_to(x, rel); } - - PathType & path_; }; - -template struct vline_to { - template - struct result - { - using type = void; - }; - - explicit vline_to(PathType & path) - : path_(path) {} - - template - void operator() (T0 const& y, T1 rel) const + using result_type = void; + template + void operator()(PathType& path, T0 const& y, T1 rel) const { - path_.vline_to(y,rel); + path.vline_to(y, rel); } - - PathType & path_; }; -template struct line_to { - template - struct result - { - using type = void; - }; - - explicit line_to(PathType & path) - : path_(path) {} - - template - void operator() (T0 const& v, T1 rel) const + using result_type = void; + template + void operator()(PathType& path, T0 const& v, T1 rel) const { - path_.line_to(at_c<0>(v),at_c<1>(v),rel); // impl + path.line_to(boost::fusion::at_c<0>(v), boost::fusion::at_c<1>(v), rel); // impl } - - PathType & path_; }; - -template struct curve4 { - template - struct result - { - using type = void; - }; - - explicit curve4(PathType & path) - : path_(path) {} - - template - void operator() (T0 const& v0, T1 const& v1, T2 const& v2, T3 rel) const + using result_type = void; + template + void operator()(PathType& path, T0 const& v0, T1 const& v1, T2 const& v2, T3 rel) const { - path_.curve4(at_c<0>(v0),at_c<1>(v0), - at_c<0>(v1),at_c<1>(v1), - at_c<0>(v2),at_c<1>(v2), - rel); // impl + path.curve4(boost::fusion::at_c<0>(v0), boost::fusion::at_c<1>(v0), + boost::fusion::at_c<0>(v1), boost::fusion::at_c<1>(v1), + boost::fusion::at_c<0>(v2), boost::fusion::at_c<1>(v2), + rel); // impl } - - PathType & path_; }; - -template struct curve4_smooth { - template - struct result - { - using type = void; - }; - - explicit curve4_smooth(PathType & path) - : path_(path) {} - - template - void operator() (T0 const& v0, T1 const& v1, T2 rel) const + using result_type = void; + template + void operator()(PathType& path, T0 const& v0, T1 const& v1, T2 rel) const { - path_.curve4(at_c<0>(v0),at_c<1>(v0), - at_c<0>(v1),at_c<1>(v1), - rel); // impl + path.curve4(boost::fusion::at_c<0>(v0), boost::fusion::at_c<1>(v0), + boost::fusion::at_c<0>(v1), boost::fusion::at_c<1>(v1), + rel); // impl } - PathType & path_; }; -template struct curve3 { - template - struct result - { - using type = void; - }; - - explicit curve3(PathType & path) - : path_(path) {} - - template - void operator() (T0 const& v0, T1 const& v1, T2 rel) const + using result_type = void; + template + void operator()(PathType& path, T0 const& v0, T1 const& v1, T2 rel) const { - path_.curve3(at_c<0>(v0),at_c<1>(v0), - at_c<0>(v1),at_c<1>(v1), - rel); // impl + path.curve3(boost::fusion::at_c<0>(v0), boost::fusion::at_c<1>(v0), + boost::fusion::at_c<0>(v1), boost::fusion::at_c<1>(v1), + rel); // impl } - - PathType & path_; }; -template struct curve3_smooth { - template - struct result - { - using type = void; - }; - - explicit curve3_smooth(PathType & path) - : path_(path) {} - - template - void operator() (T0 const& v0, T1 rel) const + using result_type = void; + template + void operator()(PathType& path, T0 const& v0, T1 rel) const { - path_.curve3(at_c<0>(v0),at_c<1>(v0), - rel); // impl + path.curve3(boost::fusion::at_c<0>(v0), boost::fusion::at_c<1>(v0), + rel); // impl } - - PathType & path_; }; -template struct arc_to { - template - struct result - { - using type = void; - }; - - explicit arc_to(PathType & path) - : path_(path) {} - - template - void operator() (T0 const& rv, T1 const& angle, T2 large_arc_flag, T3 sweep_flag, T4 const& v, T5 rel) const + using result_type = void; + template + void operator()(PathType& path, T0 const& rv, T1 const& angle, T2 large_arc_flag, T3 sweep_flag, T4 const& v, T5 rel) const { - path_.arc_to(at_c<0>(rv),at_c<1>(rv), - deg2rad(angle),large_arc_flag,sweep_flag, - at_c<0>(v),at_c<1>(v), - rel); + path.arc_to(boost::fusion::at_c<0>(rv), boost::fusion::at_c<1>(rv), + deg2rad(angle), large_arc_flag, sweep_flag, + boost::fusion::at_c<0>(v), boost::fusion::at_c<1>(v), + rel); } - - PathType & path_; }; -template struct close { using result_type = void; - - explicit close(PathType & path) - : path_(path) {} - - void operator()() const + template + void operator()(PathType& path) const { - path_.close_subpath(); + path.close_subpath(); } - - PathType & path_; }; - -}} - +} // namespace svg +} // namespace mapnik #endif // MAPNIK_SVG_COMMANDS_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_path_grammar.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_path_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_path_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_path_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -2,7 +2,7 @@ * * This file is part of Mapnik (c++ mapping toolkit) * - * Copyright (C) 2015 Artem Pavlenko + * Copyright (C) 2016 Artem Pavlenko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,133 +23,39 @@ #ifndef MAPNIK_SVG_PATH_GRAMMAR_HPP #define MAPNIK_SVG_PATH_GRAMMAR_HPP -// mapnik -#include - // spirit +#pragma GCC diagnostic push +#include #include -#include -#include -#include +#pragma GCC diagnostic pop namespace mapnik { namespace svg { - using namespace boost::spirit; - using namespace boost::phoenix; +using namespace boost::spirit; - template - struct svg_path_grammar : qi::grammar - { - explicit svg_path_grammar(PathType & path) - : svg_path_grammar::base_type(start), - move_to_(move_to(path)), - hline_to_(hline_to(path)), - vline_to_(vline_to(path)), - line_to_(line_to(path)), - curve4_(curve4(path)), - curve4_smooth_(curve4_smooth(path)), - curve3_(curve3(path)), - curve3_smooth_(curve3_smooth(path)), - arc_to_(arc_to(path)), - close_(close(path)) - { - qi::_1_type _1; - qi::_2_type _2; - qi::_3_type _3; - qi::_4_type _4; - qi::_5_type _5; - qi::_a_type _a; - qi::lit_type lit; - qi::double_type double_; - qi::int_type int_; - qi::no_case_type no_case; - - start = +cmd; - cmd = M >> *drawto_cmd; - drawto_cmd = L | H | V | C | S | Q | T | A | Z; - - M = (lit('M')[_a = false] | lit('m')[_a = true] ) - >> coord[move_to_(_1,_a)] // move_to - >> *(-lit(',') >> coord [ line_to_(_1,_a) ] ); // *line_to - - H = (lit('H')[_a = false] | lit('h')[_a = true]) - >> +double_[ hline_to_(_1,_a) ] ; // +hline_to - - V = (lit('V')[_a = false] | lit('v')[_a = true]) - >> +double_ [ vline_to_(_1,_a) ]; // +vline_to - - L = (lit('L')[_a = false] | lit('l')[_a = true]) - >> +coord [ line_to_(_1,_a) ]; // +line_to - - C = (lit('C')[_a = false] | lit('c')[_a = true]) - >> +(coord - >> -lit(',') - >> coord - >> -lit(',') - >> coord) [ curve4_(_1,_2,_3,_a) ]; // +curve4 - - S = (lit('S')[_a = false] | lit('s')[_a = true]) - >> +(coord - >> -lit(',') - >> coord) [ curve4_smooth_(_1,_2,_a) ]; // +curve4_smooth (smooth curveto) - - Q = (lit('Q')[_a = false] | lit('q')[_a = true]) - >> +(coord - >> -lit(',') - >> coord) [ curve3_(_1,_2,_a) ]; // +curve3 (quadratic-bezier-curveto) - - T = (lit('T')[_a = false] | lit('t')[_a = true]) - >> +(coord ) [ curve3_smooth_(_1,_a) ]; // +curve3_smooth (smooth-quadratic-bezier-curveto) - - A = (lit('A')[_a = false] | lit('a')[_a = true]) - >> +(coord - >> -lit(',') - >> double_ - >> -lit(',') - >> int_ - >> -lit(',') - >> int_ - >> -lit(',') - >> coord) [arc_to_(_1,_2,_3,_4,_5,_a)]; // arc_to; - - - - Z = no_case[lit('z')] [close_()]; // close path - - coord = double_ >> -lit(',') >> double_; - } - - // rules - qi::rule start; - qi::rule cmd; - qi::rule drawto_cmd; - qi::rule,SkipType> M; // M,m - qi::rule,SkipType> L; // L,l - qi::rule,SkipType> H; // H,h - qi::rule,SkipType> V; // V,v - qi::rule,SkipType> C; // C,c - qi::rule,SkipType> S; // S,s - qi::rule,SkipType> Q; // Q,q - qi::rule,SkipType> T; // T,t - qi::rule,SkipType> A; // A,a - qi::rule Z; // Z,z - - qi::rule(),SkipType> coord; - - // commands - function > move_to_; - function > hline_to_; - function > vline_to_; - function > line_to_; - function > curve4_; - function > curve4_smooth_; - function > curve3_; - function > curve3_smooth_; - function > arc_to_; - function > close_; - }; +template +struct svg_path_grammar : qi::grammar +{ + // ctor + svg_path_grammar(); + // rules + qi::rule start; + qi::rule cmd; + qi::rule drawto_cmd; + qi::rule, void(PathType&), SkipType> M; // M,m + qi::rule, void(PathType&), SkipType> L; // L,l + qi::rule, void(PathType&), SkipType> H; // H,h + qi::rule, void(PathType&), SkipType> V; // V,v + qi::rule, void(PathType&), SkipType> C; // C,c + qi::rule, void(PathType&), SkipType> S; // S,s + qi::rule, void(PathType&), SkipType> Q; // Q,q + qi::rule, void(PathType&), SkipType> T; // T,t + qi::rule, void(PathType&), SkipType> A; // A,a + qi::rule Z; // Z,z + qi::rule(), SkipType> coord; +}; - }} +}} #endif // MAPNIK_SVG_PATH_GRAMMAR_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_path_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_path_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_path_grammar_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_path_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,112 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +// NOTE: This is an implementation header file and is only meant to be included +// from implementation files. It therefore doesn't have an include guard. + +// mapnik +#include +#include + +// spirit +#pragma GCC diagnostic push +#include +#include +#include +#include +#pragma GCC diagnostic pop + +namespace mapnik { namespace svg { + +using namespace boost::spirit; +using namespace boost::phoenix; + + +template +svg_path_grammar::svg_path_grammar() + : svg_path_grammar::base_type(start) +{ + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + qi::_5_type _5; + qi::_a_type _a; + qi::lit_type lit; + qi::_r1_type _r1; + qi::double_type double_; + qi::int_type int_; + qi::no_case_type no_case; + + // commands + function move_to_; + function hline_to_; + function vline_to_; + function line_to_; + function curve4_; + function curve4_smooth_; + function curve3_; + function curve3_smooth_; + function arc_to_; + function close_; + // + start = +cmd(_r1); + + cmd = M(_r1) >> *drawto_cmd(_r1); + + drawto_cmd = L(_r1) | H(_r1) | V(_r1) | C(_r1) | S(_r1) | Q(_r1) | T(_r1) | A(_r1) | Z(_r1); + + M = (lit('M')[_a = false] | lit('m')[_a = true]) >> coord[move_to_(_r1, _1, _a)] // move_to + >> *(-lit(',') >> coord[line_to_(_r1, _1, _a)]); // *line_to + + H = (lit('H')[_a = false] | lit('h')[_a = true]) + >> (double_[ hline_to_(_r1, _1,_a) ] % -lit(',')) ; // +hline_to + + V = (lit('V')[_a = false] | lit('v')[_a = true]) + >> (double_ [ vline_to_(_r1, _1,_a) ] % -lit(',')); // +vline_to + + L = (lit('L')[_a = false] | lit('l')[_a = true]) + >> (coord [ line_to_(_r1, _1, _a) ] % -lit(',')); // +line_to + + C = (lit('C')[_a = false] | lit('c')[_a = true]) + >> ((coord >> -lit(',') >> coord >> -lit(',') >> coord)[curve4_(_r1, _1, _2, _3, _a)] % -lit(',')); // +curve4 + + S = (lit('S')[_a = false] | lit('s')[_a = true]) + >> ((coord >> -lit(',') >> coord) [ curve4_smooth_(_r1, _1,_2,_a) ] % -lit(',')); // +curve4_smooth (smooth curveto) + + Q = (lit('Q')[_a = false] | lit('q')[_a = true]) + >> ((coord >> -lit(',') >> coord) [ curve3_(_r1, _1,_2,_a) ] % -lit(',')); // +curve3 (quadratic-bezier-curveto) + + T = (lit('T')[_a = false] | lit('t')[_a = true]) + >> ((coord ) [ curve3_smooth_(_r1, _1,_a) ] % -lit(',')); // +curve3_smooth (smooth-quadratic-bezier-curveto) + + A = (lit('A')[_a = false] | lit('a')[_a = true]) + >> ((coord >> -lit(',') >> double_ >> -lit(',') >> int_ >> -lit(',') >> int_ >> -lit(',') >> coord) + [arc_to_(_r1, _1, _2, _3, _4, _5, _a)] % -lit(',')); // arc_to; + + Z = no_case[lit('z')] [close_(_r1)]; // close path + + coord = double_ >> -lit(',') >> double_; +} + +} // namespace svg +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_path_parser.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_path_parser.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_path_parser.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_path_parser.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,20 +23,32 @@ #ifndef MAPNIK_SVG_PATH_PARSER_HPP #define MAPNIK_SVG_PATH_PARSER_HPP +// mapnik #include +#include +#include +// stl #include -namespace mapnik { namespace svg { +namespace mapnik { +namespace svg { - template - bool parse_path(const char * wkt, PathType & p); +template +bool parse_path(const char* wkt, PathType& p); - template - bool parse_points(const char * wkt, PathType & p); +template +bool parse_points(const char* wkt, PathType& p); + +template +bool MAPNIK_DECL parse_svg_transform(const char* wkt, TransformType& tr); + +// +extern template bool MAPNIK_DECL parse_path(const char*, svg_converter_type&); +extern template bool MAPNIK_DECL parse_points(const char*, svg_converter_type&); +extern template bool MAPNIK_DECL parse_svg_transform(const char*, svg_converter_type&); +} +} - template - bool MAPNIK_DECL parse_svg_transform(const char * wkt, TransformType & tr); -}} #endif // MAPNIK_SVG_PATH_PARSER_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_points_grammar.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_points_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_points_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_points_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,46 +29,22 @@ #pragma GCC diagnostic push #include #include -#include -#include -#include #pragma GCC diagnostic pop namespace mapnik { namespace svg { - using namespace boost::spirit; - using namespace boost::phoenix; - - template - struct svg_points_grammar : qi::grammar - { - explicit svg_points_grammar(PathType & path) - : svg_points_grammar::base_type(start), - move_to_(move_to(path)), - line_to_(line_to(path)), - close_(close(path)) - { - qi::_1_type _1; - qi::lit_type lit; - qi::double_type double_; - - start = coord[move_to_(_1,false)] // move_to - >> *(-lit(',') >> coord [ line_to_(_1,false) ] ); // *line_to - - coord = double_ >> -lit(',') >> double_; - } - - // rules - qi::rule start; - qi::rule(),SkipType> coord; - - // commands - function > move_to_; - function > line_to_; - function > close_; - }; - - }} +using namespace boost::spirit; +using namespace boost::phoenix; +template +struct svg_points_grammar : qi::grammar +{ + // ctor + svg_points_grammar(); + // rules + qi::rule start; + qi::rule(), SkipType> coord; +}; +}} #endif // SVG_POINTS_GRAMMAR_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_points_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_points_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_points_grammar_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_points_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,61 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + * + *****************************************************************************/ + +// NOTE: This is an implementation header file and is only meant to be included +// from implementation files. It therefore doesn't have an include guard. +// mapnik +#include +#include + +#pragma GCC diagnostic push +#include +#include +#include +#include +#include +#pragma GCC diagnostic pop + +namespace mapnik { namespace svg { + +using namespace boost::spirit; +using namespace boost::phoenix; + +template +svg_points_grammar::svg_points_grammar() + : svg_points_grammar::base_type(start) +{ + qi::_1_type _1; + qi::_r1_type _r1; + qi::lit_type lit; + qi::double_type double_; + // commands + function move_to_; + function line_to_; + function close_; + + start = coord[move_to_(_r1, _1, false)] // move_to + >> *(-lit(',') >> coord [ line_to_(_r1, _1,false) ] ); // *line_to + + coord = double_ >> -lit(',') >> double_; +} + +}} diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_renderer_agg.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_renderer_agg.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_renderer_agg.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_renderer_agg.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -37,12 +37,14 @@ #pragma GCC diagnostic pop #endif -// agg +#pragma GCC diagnostic push +#include #include "agg_path_storage.h" #include "agg_conv_transform.h" #include "agg_conv_stroke.h" #include "agg_conv_contour.h" #include "agg_conv_curve.h" +#include "agg_conv_dash.h" #include "agg_color_rgba.h" #include "agg_bounding_rect.h" #include "agg_rendering_buffer.h" @@ -56,16 +58,15 @@ #include "agg_gradient_lut.h" #include "agg_gamma_lut.h" #include "agg_span_interpolator_linear.h" +#pragma GCC diagnostic pop namespace mapnik { namespace svg { +// Arbitrary linear gradient specified by two control points. Gradient +// value is taken as the normalised distance along the line segment +// represented by the two points. -/** - * Arbitrary linear gradient specified by two control points. Gradient - * value is taken as the normalised distance along the line segment - * represented by the two points. - */ class linear_gradient_from_segment { public: @@ -105,19 +106,28 @@ class svg_renderer_agg : util::noncopyable { public: - using curved_type = agg::conv_curve ; - using curved_stroked_type = agg::conv_stroke ; + using curved_type = agg::conv_curve; + // stroke + using curved_stroked_type = agg::conv_stroke; using curved_stroked_trans_type = agg::conv_transform; - using curved_trans_type = agg::conv_transform ; - using curved_trans_contour_type = agg::conv_contour ; - using renderer_base = agg::renderer_base ; - using vertex_source_type = VertexSource ; - using attribute_source_type = AttributeSource ; + // stroke dash-array + using curved_dashed_type = agg::conv_dash; + using curved_dashed_stroked_type = agg::conv_stroke; + using curved_dashed_stroked_trans_type = agg::conv_transform; + // fill + using curved_trans_type = agg::conv_transform; + using curved_trans_contour_type = agg::conv_contour; + // renderer + using renderer_base = agg::renderer_base; + using vertex_source_type = VertexSource; + using attribute_source_type = AttributeSource; svg_renderer_agg(VertexSource & source, AttributeSource const& attributes) : source_(source), curved_(source_), + curved_dashed_(curved_), curved_stroked_(curved_), + curved_dashed_stroked_(curved_dashed_), attributes_(attributes) {} template @@ -191,11 +201,11 @@ // scale everything up since agg turns things into integers a bit too soon int scaleup=255; - radius*=scaleup; - x1*=scaleup; - y1*=scaleup; - x2*=scaleup; - y2*=scaleup; + radius *= scaleup; + x1 *= scaleup; + y1 *= scaleup; + x2 *= scaleup; + y2 *= scaleup; transform.scale(scaleup,scaleup); interpolator_type span_interpolator(transform); @@ -217,10 +227,10 @@ color_func_type>; // scale everything up since agg turns things into integers a bit too soon int scaleup=255; - x1*=scaleup; - y1*=scaleup; - x2*=scaleup; - y2*=scaleup; + x1 *= scaleup; + y1 *= scaleup; + x2 *= scaleup; + y2 *= scaleup; transform.scale(scaleup,scaleup); @@ -247,10 +257,11 @@ { using namespace agg; - trans_affine transform; + curved_stroked_trans_type curved_stroked_trans(curved_stroked_,transform); - curved_trans_type curved_trans(curved_,transform); + curved_dashed_stroked_trans_type curved_dashed_stroked_trans(curved_dashed_stroked_, transform); + curved_trans_type curved_trans(curved_,transform); curved_trans_contour_type curved_trans_contour(curved_trans); curved_trans_contour.auto_detect_orientation(true); @@ -274,7 +285,6 @@ if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT) { ras.reset(); - // https://github.com/mapnik/mapnik/issues/1129 if(std::fabs(curved_trans_contour.width()) <= 1) { @@ -288,7 +298,8 @@ if(attr.fill_gradient.get_gradient_type() != NO_GRADIENT) { - render_gradient(ras, sl, ren, attr.fill_gradient, transform, attr.fill_opacity * attr.opacity * opacity, symbol_bbox, curved_trans, attr.index); + render_gradient(ras, sl, ren, attr.fill_gradient, transform, + attr.fill_opacity * attr.opacity * opacity, symbol_bbox, curved_trans, attr.index); } else { @@ -304,37 +315,79 @@ if (attr.stroke_flag || attr.stroke_gradient.get_gradient_type() != NO_GRADIENT) { - curved_stroked_.width(attr.stroke_width); - //m_curved_stroked.line_join((attr.line_join == miter_join) ? miter_join_round : attr.line_join); - curved_stroked_.line_join(attr.line_join); - curved_stroked_.line_cap(attr.line_cap); - curved_stroked_.miter_limit(attr.miter_limit); - curved_stroked_.inner_join(inner_round); - curved_stroked_.approximation_scale(scl); - - // If the *visual* line width is considerable we - // turn on processing of curve cusps. - //--------------------- - if(attr.stroke_width * scl > 1.0) + if (attr.dash.size() > 0) { - curved_.angle_tolerance(0.2); - } - ras.reset(); - ras.add_path(curved_stroked_trans, attr.index); - - if(attr.stroke_gradient.get_gradient_type() != NO_GRADIENT) - { - render_gradient(ras, sl, ren, attr.stroke_gradient, transform, attr.stroke_opacity * attr.opacity * opacity, symbol_bbox, curved_trans, attr.index); + curved_dashed_stroked_.width(attr.stroke_width); + curved_dashed_stroked_.line_join(attr.line_join); + curved_dashed_stroked_.line_cap(attr.line_cap); + curved_dashed_stroked_.miter_limit(attr.miter_limit); + curved_dashed_stroked_.inner_join(inner_round); + curved_dashed_stroked_.approximation_scale(scl); + + // If the *visual* line width is considerable we + // turn on processing of curve cups. + //--------------------- + if (attr.stroke_width * scl > 1.0) + { + curved_.angle_tolerance(0.2); + } + ras.reset(); + curved_dashed_.remove_all_dashes(); + for (auto d : attr.dash) + { + curved_dashed_.add_dash(std::get<0>(d),std::get<1>(d)); + } + curved_dashed_.dash_start(attr.dash_offset); + ras.add_path(curved_dashed_stroked_trans, attr.index); + if (attr.stroke_gradient.get_gradient_type() != NO_GRADIENT) + { + render_gradient(ras, sl, ren, attr.stroke_gradient, transform, + attr.stroke_opacity * attr.opacity * opacity, symbol_bbox, curved_trans, attr.index); + } + else + { + ras.filling_rule(fill_non_zero); + color = attr.stroke_color; + color.opacity(color.opacity() * attr.stroke_opacity * attr.opacity * opacity); + ScanlineRenderer ren_s(ren); + color.premultiply(); + ren_s.color(color); + render_scanlines(ras, sl, ren_s); + } } else { - ras.filling_rule(fill_non_zero); - color = attr.stroke_color; - color.opacity(color.opacity() * attr.stroke_opacity * attr.opacity * opacity); - ScanlineRenderer ren_s(ren); - color.premultiply(); - ren_s.color(color); - render_scanlines(ras, sl, ren_s); + curved_stroked_.width(attr.stroke_width); + curved_stroked_.line_join(attr.line_join); + curved_stroked_.line_cap(attr.line_cap); + curved_stroked_.miter_limit(attr.miter_limit); + curved_stroked_.inner_join(inner_round); + curved_stroked_.approximation_scale(scl); + + // If the *visual* line width is considerable we + // turn on processing of curve cups. + //--------------------- + if (attr.stroke_width * scl > 1.0) + { + curved_.angle_tolerance(0.2); + } + ras.reset(); + ras.add_path(curved_stroked_trans, attr.index); + if (attr.stroke_gradient.get_gradient_type() != NO_GRADIENT) + { + render_gradient(ras, sl, ren, attr.stroke_gradient, transform, + attr.stroke_opacity * attr.opacity * opacity, symbol_bbox, curved_trans, attr.index); + } + else + { + ras.filling_rule(fill_non_zero); + color = attr.stroke_color; + color.opacity(color.opacity() * attr.stroke_opacity * attr.opacity * opacity); + ScanlineRenderer ren_s(ren); + color.premultiply(); + ren_s.color(color); + render_scanlines(ras, sl, ren_s); + } } } } @@ -409,7 +462,7 @@ // If the *visual* line width is considerable we // turn on processing of curve cusps. //--------------------- - if(attr.stroke_width * scl > 1.0) + if (attr.stroke_width * scl > 1.0) { curved_.angle_tolerance(0.2); } @@ -431,7 +484,9 @@ VertexSource & source_; curved_type curved_; + curved_dashed_type curved_dashed_; curved_stroked_type curved_stroked_; + curved_dashed_stroked_type curved_dashed_stroked_; AttributeSource const& attributes_; }; diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_transform_grammar.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_transform_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_transform_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_transform_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,240 +26,31 @@ // mapnik #include -// agg -#include - #pragma GCC diagnostic push #include #include -#include -#include -#include -#include #pragma GCC diagnostic pop namespace mapnik { namespace svg { - using namespace boost::spirit; - using namespace boost::fusion; - using namespace boost::phoenix; - - inline double deg2rad(double d) - { - return M_PI * d / 180.0; - } - - template - struct process_matrix - { - template - struct result - { - using type = void; - }; - - explicit process_matrix( TransformType & tr) - :tr_(tr) {} - - void operator () (double a, double b, double c, double d, double e, double f) const - { - tr_ = agg::trans_affine(a,b,c,d,e,f) * tr_; - } - - TransformType & tr_; - }; - - template - struct process_rotate - { - template - struct result - { - using type = void; - }; - - explicit process_rotate( TransformType & tr) - :tr_(tr) {} - - template - void operator () (T0 a, T1 cx, T2 cy) const - { - if (cx == 0.0 && cy == 0.0) - { - tr_ = agg::trans_affine_rotation(deg2rad(a)) * tr_; - } - else - { - agg::trans_affine t = agg::trans_affine_translation(-cx,-cy); - t *= agg::trans_affine_rotation(deg2rad(a)); - t *= agg::trans_affine_translation(cx, cy); - tr_ = t * tr_; - } - } - - TransformType & tr_; - }; - - template - struct process_translate - { - template - struct result - { - using type = void; - }; - - explicit process_translate( TransformType & tr) - :tr_(tr) {} - - template - void operator () (T0 tx, T1 ty) const - { - if (ty) tr_ = agg::trans_affine_translation(tx,*ty) * tr_; - else tr_ = agg::trans_affine_translation(tx,0.0) * tr_; - } - - TransformType & tr_; - }; - - template - struct process_scale - { - template - struct result - { - using type = void; - }; - - explicit process_scale( TransformType & tr) - :tr_(tr) {} - - template - void operator () (T0 sx, T1 sy) const - { - if (sy) tr_ = agg::trans_affine_scaling(sx,*sy) * tr_; - else tr_ = agg::trans_affine_scaling(sx,sx) * tr_; - } - - TransformType & tr_; - }; - - - template - struct process_skew - { - template - struct result - { - using type = void; - }; - - explicit process_skew( TransformType & tr) - :tr_(tr) {} - - template - void operator () (T0 skew_x, T1 skew_y) const - { - tr_ = agg::trans_affine_skewing(deg2rad(skew_x),deg2rad(skew_y)) * tr_; - } - - TransformType & tr_; - }; - - // commented as this does not appear used and crashes clang when used with pch - /* - struct print_action - { - template - void operator()(T const& c, qi::unused_type, qi::unused_type) const - { - MAPNIK_LOG_DEBUG(svg) << typeid(c).name(); - } - }; - */ - - template - struct svg_transform_grammar : qi::grammar - { - explicit svg_transform_grammar(TransformType & tr) - : svg_transform_grammar::base_type(start), - matrix_action(process_matrix(tr)), - rotate_action(process_rotate(tr)), - translate_action(process_translate(tr)), - scale_action(process_scale(tr)), - skew_action(process_skew(tr)) - { - qi::_1_type _1; - qi::_2_type _2; - qi::_3_type _3; - qi::_4_type _4; - qi::_5_type _5; - qi::_6_type _6; - qi::_a_type _a; - qi::_b_type _b; - qi::_c_type _c; - qi::lit_type lit; - qi::double_type double_; - qi::no_case_type no_case; - - start = +transform_ ; - - transform_ = matrix | rotate | translate | scale | rotate | skewX | skewY ; - - matrix = no_case[lit("matrix")] - >> lit('(') - >> ( - double_ >> -lit(',') - >> double_ >> -lit(',') - >> double_ >> -lit(',') - >> double_ >> -lit(',') - >> double_ >> -lit(',') - >> double_) [ matrix_action(_1,_2,_3,_4,_5,_6) ] - >> lit(')') - ; - - translate = no_case[lit("translate")] - >> lit('(') - >> (double_ >> -lit(',') - >> -double_) [ translate_action(_1,_2) ] - >> lit(')'); - - scale = no_case[lit("scale")] - >> lit('(') - >> (double_ >> -lit(',') - >> -double_ )[ scale_action(_1,_2)] - >> lit(')'); - - rotate = no_case[lit("rotate")] - >> lit('(') - >> double_[_a = _1] >> -lit(',') - >> -(double_ [_b = _1] >> -lit(',') >> double_[_c = _1]) - >> lit(')') [ rotate_action(_a,_b,_c)]; - - skewX = no_case[lit("skewX")] >> lit('(') >> double_ [ skew_action(_1, 0.0)] >> lit(')'); - - skewY = no_case[lit("skewY")] >> lit('(') >> double_ [ skew_action(0.0, _1)] >> lit(')'); - - } - - // rules - qi::rule start; - qi::rule transform_; - qi::rule matrix; - qi::rule translate; - qi::rule scale; - qi::rule, SkipType> rotate; - qi::rule skewX; - qi::rule skewY; - - // actions - function > matrix_action; - function > rotate_action; - function > translate_action; - function > scale_action; - function > skew_action; - }; +using namespace boost::spirit; + +template +struct svg_transform_grammar : qi::grammar +{ + // ctor + svg_transform_grammar(); + // rules + qi::rule start; + qi::rule transform_; + qi::rule matrix; + qi::rule translate; + qi::rule scale; + qi::rule, void(TransformType&), SkipType> rotate; + qi::rule skewX; + qi::rule skewY; +}; - }} +}} #endif // MAPNIK_SVG_TRANSFORM_GRAMMAR_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/svg/svg_transform_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/svg/svg_transform_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/svg/svg_transform_grammar_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/svg/svg_transform_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,172 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + * + *****************************************************************************/ + +// NOTE: This is an implementation header file and is only meant to be included +// from implementation files. It therefore doesn't have an include guard. +// mapnik +#include + +#pragma GCC diagnostic push +#include +#include +#include +#include +#include +#pragma GCC diagnostic pop + +#pragma GCC diagnostic push +#include +#include +#pragma GCC diagnostic pop + +namespace mapnik { namespace svg { + +using namespace boost::spirit; +using namespace boost::fusion; +using namespace boost::phoenix; + +inline double deg2rad(double d) +{ + return M_PI * d / 180.0; +} + +struct process_matrix +{ + using result_type = void; + template + void operator () (TransformType & tr, double a, double b, double c, double d, double e, double f) const + { + tr = agg::trans_affine(a,b,c,d,e,f) * tr; + } +}; + +struct process_rotate +{ + using result_type = void; + + template + void operator () (TransformType & tr, T0 a, T1 cx, T2 cy) const + { + if (cx == 0.0 && cy == 0.0) + { + tr = agg::trans_affine_rotation(deg2rad(a)) * tr; + } + else + { + agg::trans_affine t = agg::trans_affine_translation(-cx,-cy); + t *= agg::trans_affine_rotation(deg2rad(a)); + t *= agg::trans_affine_translation(cx, cy); + tr = t * tr; + } + } +}; + +struct process_translate +{ + using result_type = void; + template + void operator () (TransformType & tr, T0 tx, T1 ty) const + { + if (ty) tr = agg::trans_affine_translation(tx,*ty) * tr; + else tr = agg::trans_affine_translation(tx,0.0) * tr; + } +}; + +struct process_scale +{ + using result_type = void; + template + void operator () (TransformType & tr, T0 sx, T1 sy) const + { + if (sy) tr = agg::trans_affine_scaling(sx,*sy) * tr; + else tr = agg::trans_affine_scaling(sx,sx) * tr; + } +}; + + +struct process_skew +{ + using result_type = void; + + template + void operator () (TransformType & tr, T0 skew_x, T1 skew_y) const + { + tr = agg::trans_affine_skewing(deg2rad(skew_x),deg2rad(skew_y)) * tr; + } +}; + +template +svg_transform_grammar::svg_transform_grammar() + : svg_transform_grammar::base_type(start) +{ + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + qi::_5_type _5; + qi::_6_type _6; + qi::_a_type _a; + qi::_b_type _b; + qi::_c_type _c; + qi::_r1_type _r1; + qi::lit_type lit; + qi::double_type double_; + qi::no_case_type no_case; + + // actions + function matrix_action; + function rotate_action; + function translate_action; + function scale_action; + function skew_action; + + start = +transform_(_r1) ; + + transform_ = matrix(_r1) | rotate(_r1) | translate(_r1) | scale(_r1) | rotate(_r1) | skewX(_r1) | skewY (_r1) ; + + matrix = no_case[lit("matrix")] >> lit('(') + >> (double_ >> -lit(',') + >> double_ >> -lit(',') + >> double_ >> -lit(',') + >> double_ >> -lit(',') + >> double_ >> -lit(',') + >> double_)[matrix_action(_r1, _1, _2, _3, _4, _5, _6)] >> lit(')'); + + translate = no_case[lit("translate")] + >> lit('(') >> (double_ >> -lit(',') >> -double_)[translate_action(_r1, _1, _2)] >> lit(')'); + + scale = no_case[lit("scale")] + >> lit('(') >> (double_ >> -lit(',') >> -double_)[scale_action(_r1, _1, _2)] >> lit(')'); + + rotate = no_case[lit("rotate")] + >> lit('(') + >> double_[_a = _1] >> -lit(',') + >> -(double_ [_b = _1] >> -lit(',') >> double_[_c = _1]) + >> lit(')') [ rotate_action(_r1, _a,_b,_c)]; + + skewX = no_case[lit("skewX")] >> lit('(') >> double_ [ skew_action(_r1, _1, 0.0)] >> lit(')'); + + skewY = no_case[lit("skewY")] >> lit('(') >> double_ [ skew_action(_r1, 0.0, _1)] >> lit(')'); + +} + +}} diff -Nru mapnik-3.0.9+ds/include/mapnik/symbolizer_base.hpp mapnik-3.0.13+ds/include/mapnik/symbolizer_base.hpp --- mapnik-3.0.9+ds/include/mapnik/symbolizer_base.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/symbolizer_base.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -58,7 +58,7 @@ feature_impl const& feature, attributes const& vars, transform_type const& trans_expr, - double scale_factor=1.0); + double scale_factor); struct enumeration_wrapper { @@ -98,24 +98,19 @@ struct strict_value : value_base_type { - // default ctor - strict_value() - : value_base_type() {} - // copy ctor - strict_value(const char* val) - : value_base_type(val) {} + strict_value() = default; - template - strict_value(T const& obj) - : value_base_type(typename detail::mapnik_value_type::type(obj)) - {} - // move ctor - template - strict_value(T && obj) noexcept - : value_base_type(std::move(obj)) {} + strict_value(const char* val) noexcept(false) + : value_base_type(std::string(val)) {} + template > + strict_value(T && obj) + noexcept(std::is_nothrow_constructible::value) + : value_base_type(U(std::forward(obj))) + {} }; -} + +} // namespace detail struct MAPNIK_DECL symbolizer_base { diff -Nru mapnik-3.0.9+ds/include/mapnik/symbolizer_default_values.hpp mapnik-3.0.13+ds/include/mapnik/symbolizer_default_values.hpp --- mapnik-3.0.9+ds/include/mapnik/symbolizer_default_values.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/symbolizer_default_values.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,7 +24,12 @@ #define MAPNIK_SYMBOLIZER_DEFAULT_VALUES_HPP #include +#include +#include +#include +#include #include +#include #include diff -Nru mapnik-3.0.9+ds/include/mapnik/symbolizer.hpp mapnik-3.0.13+ds/include/mapnik/symbolizer.hpp --- mapnik-3.0.9+ds/include/mapnik/symbolizer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/symbolizer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -51,8 +51,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { @@ -317,12 +319,8 @@ mapnik::value_type val = util::apply_visitor(mapnik::evaluate(feature,vars), expr); if (val.is_null()) return dash_array(); dash_array dash; - std::vector buf; std::string str = val.to_string(); - if (util::parse_dasharray(str,buf)) - { - util::add_dashes(buf,dash); - } + util::parse_dasharray(str,dash); return dash; } }; diff -Nru mapnik-3.0.9+ds/include/mapnik/symbolizer_utils.hpp mapnik-3.0.13+ds/include/mapnik/symbolizer_utils.hpp --- mapnik-3.0.9+ds/include/mapnik/symbolizer_utils.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/symbolizer_utils.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -404,9 +404,8 @@ boost::optional str = node.get_opt_attr(name); if (str) { - std::vector buf; dash_array dash; - if (util::parse_dasharray(*str,buf) && util::add_dashes(buf,dash)) + if (util::parse_dasharray(*str,dash)) { put(sym,key,dash); } diff -Nru mapnik-3.0.9+ds/include/mapnik/text/face.hpp mapnik-3.0.13+ds/include/mapnik/text/face.hpp --- mapnik-3.0.9+ds/include/mapnik/text/face.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/face.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,11 +23,13 @@ #define MAPNIK_FACE_HPP //mapnik -#include #include +#include #include -// freetype2 +#pragma GCC diagnostic push +#include + extern "C" { #include @@ -35,8 +37,9 @@ #include FT_STROKER_H } +#pragma GCC diagnostic pop + //stl -#include #include #include #include diff -Nru mapnik-3.0.9+ds/include/mapnik/text/font_feature_settings.hpp mapnik-3.0.13+ds/include/mapnik/text/font_feature_settings.hpp --- mapnik-3.0.9+ds/include/mapnik/text/font_feature_settings.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/font_feature_settings.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -31,8 +31,11 @@ #include #include #include -// harfbuzz + +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // EqualityComparable inline bool operator==(hb_feature_t const& lhs, hb_feature_t const& rhs) @@ -86,7 +89,10 @@ constexpr unsigned int font_feature_range_global_start = 0u; static const unsigned int font_feature_range_global_end = std::numeric_limits::max(); +#pragma GCC diagnostic push +#include constexpr hb_feature_t font_feature_liga_off = { HB_TAG('l', 'i', 'g', 'a'), 0, font_feature_range_global_start, font_feature_range_global_end }; +#pragma GCC diagnostic pop } // mapnik namespace diff -Nru mapnik-3.0.9+ds/include/mapnik/text/formatting/layout.hpp mapnik-3.0.13+ds/include/mapnik/text/formatting/layout.hpp --- mapnik-3.0.9+ds/include/mapnik/text/formatting/layout.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/formatting/layout.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,7 +26,10 @@ #include #include +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { namespace formatting { diff -Nru mapnik-3.0.9+ds/include/mapnik/text/glyph_positions.hpp mapnik-3.0.13+ds/include/mapnik/text/glyph_positions.hpp --- mapnik-3.0.9+ds/include/mapnik/text/glyph_positions.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/glyph_positions.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -19,8 +19,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ -#ifndef MAPNIK_PLACEMENTS_LIST_HPP -#define MAPNIK_PLACEMENTS_LIST_HPP + +#ifndef MAPNIK_TEXT_GLYPH_POSITIONS_HPP +#define MAPNIK_TEXT_GLYPH_POSITIONS_HPP + //mapnik #include #include @@ -28,8 +30,10 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_trans_affine.h" +#pragma GCC diagnostic pop //stl #include @@ -79,7 +83,7 @@ pixel_position const& get_base_point() const; void set_base_point(pixel_position const& base_point); void set_marker(marker_info_ptr marker, pixel_position const& marker_pos); - marker_info_ptr get_marker() const; + marker_info_ptr const& get_marker() const; pixel_position const& marker_pos() const; private: std::vector data_; @@ -88,8 +92,46 @@ pixel_position marker_pos_; box2d bbox_; }; + using glyph_positions_ptr = std::unique_ptr; using placements_list = std::list; -} -#endif // PLACEMENTS_LIST_HPP + +struct scoped_glyph_positions_offset +{ + scoped_glyph_positions_offset(glyph_positions & glyphs, pixel_position const& offset) + : glyphs_(glyphs) + , base_point_(glyphs.get_base_point()) + , marker_pos_(glyphs.marker_pos()) + { + // move the glyphs to the correct offset + glyphs_.set_base_point(base_point_ + offset); + + // update the position of any marker + if (auto const& marker_info = glyphs_.get_marker()) + { + glyphs_.set_marker(marker_info, marker_pos_ + offset); + } + } + + ~scoped_glyph_positions_offset() + { + // set the base_point back how it was + glyphs_.set_base_point(base_point_); + + // restore marker as well, if there is any + if (auto const& marker_info = glyphs_.get_marker()) + { + glyphs_.set_marker(marker_info, marker_pos_); + } + } + +private: + glyph_positions & glyphs_; + pixel_position base_point_; + pixel_position marker_pos_; +}; + +} // namespace mapnik + +#endif // MAPNIK_TEXT_GLYPH_POSITIONS_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/text/harfbuzz_shaper.hpp mapnik-3.0.13+ds/include/mapnik/text/harfbuzz_shaper.hpp --- mapnik-3.0.9+ds/include/mapnik/text/harfbuzz_shaper.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/harfbuzz_shaper.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -36,12 +36,12 @@ #include #include -// harfbuzz +#pragma GCC diagnostic push +#include #include #include - -// icu #include +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/text/icu_shaper.hpp mapnik-3.0.13+ds/include/mapnik/text/icu_shaper.hpp --- mapnik-3.0.9+ds/include/mapnik/text/icu_shaper.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/icu_shaper.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -36,11 +36,12 @@ // stl #include -// icu +#pragma GCC diagnostic push +#include #include #include #include - +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/text/itemizer.hpp mapnik-3.0.13+ds/include/mapnik/text/itemizer.hpp --- mapnik-3.0.9+ds/include/mapnik/text/itemizer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/itemizer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -34,10 +34,12 @@ #include #include -// ICU +#pragma GCC diagnostic push +#include #include #include #include +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/text/placement_finder.hpp mapnik-3.0.13+ds/include/mapnik/text/placement_finder.hpp --- mapnik-3.0.9+ds/include/mapnik/text/placement_finder.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/placement_finder.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -67,8 +67,6 @@ bool single_line_placement(vertex_cache &pp, text_upright_e orientation); // Moves dx pixels but makes sure not to fall of the end. void path_move_dx(vertex_cache & pp, double dx); - // Normalize angle in range [-pi, +pi]. - static double normalize_angle(double angle); // Adjusts user defined spacing to place an integer number of labels. double get_spacing(double path_length, double layout_width) const; // Checks for collision. @@ -78,7 +76,6 @@ // Maps upright==auto, left-only and right-only to left,right to simplify processing. // angle = angle of at start of line (to estimate best option for upright==auto) text_upright_e simplify_upright(text_upright_e upright, double angle) const; - box2d get_bbox(text_layout const& layout, glyph_info const& glyph, pixel_position const& pos, rotation const& rot); feature_impl const& feature_; attributes const& attr_; DetectorType & detector_; diff -Nru mapnik-3.0.9+ds/include/mapnik/text/properties_util.hpp mapnik-3.0.13+ds/include/mapnik/text/properties_util.hpp --- mapnik-3.0.9+ds/include/mapnik/text/properties_util.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/properties_util.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,11 +26,14 @@ #include #include #include -#include + #include -// boost +#pragma GCC diagnostic push +#include +#include #include +#pragma GCC diagnostic pop namespace mapnik { namespace detail { diff -Nru mapnik-3.0.9+ds/include/mapnik/text/renderer.hpp mapnik-3.0.13+ds/include/mapnik/text/renderer.hpp --- mapnik-3.0.9+ds/include/mapnik/text/renderer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/renderer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,7 +28,10 @@ #include #include #include -// agg + +#pragma GCC diagnostic push +#include + #include // freetype2 @@ -39,6 +42,8 @@ #include FT_STROKER_H } +#pragma GCC diagnostic pop + namespace mapnik { @@ -58,8 +63,35 @@ composite_mode_e halo_comp_op = src_over, double scale_factor = 1.0, stroker_ptr stroker = stroker_ptr()); + + void set_comp_op(composite_mode_e comp_op) + { + comp_op_ = comp_op; + } + + void set_halo_comp_op(composite_mode_e halo_comp_op) + { + halo_comp_op_ = halo_comp_op; + } + + void set_halo_rasterizer(halo_rasterizer_e rasterizer) + { + rasterizer_ = rasterizer; + } + + void set_scale_factor(double scale_factor) + { + scale_factor_ = scale_factor; + } + + void set_stroker(stroker_ptr stroker) + { + stroker_ = stroker; + } + void set_transform(agg::trans_affine const& transform); void set_halo_transform(agg::trans_affine const& halo_transform); + protected: using glyph_vector = std::vector; void prepare_glyphs(glyph_positions const& positions); diff -Nru mapnik-3.0.9+ds/include/mapnik/text/scrptrun.hpp mapnik-3.0.13+ds/include/mapnik/text/scrptrun.hpp --- mapnik-3.0.9+ds/include/mapnik/text/scrptrun.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/scrptrun.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -17,9 +17,12 @@ #ifndef __SCRPTRUN_H #define __SCRPTRUN_H +#pragma GCC diagnostic push +#include #include #include #include +#pragma GCC diagnostic pop struct ScriptRecord { @@ -102,7 +105,7 @@ inline ScriptRun::ScriptRun() { - reset(NULL, 0, 0); + reset(nullptr, 0, 0); } inline ScriptRun::ScriptRun(const UChar chars[], int32_t length) diff -Nru mapnik-3.0.9+ds/include/mapnik/text/symbolizer_helpers.hpp mapnik-3.0.13+ds/include/mapnik/text/symbolizer_helpers.hpp --- mapnik-3.0.9+ds/include/mapnik/text/symbolizer_helpers.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/symbolizer_helpers.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -59,7 +59,7 @@ }; -using vertex_converter_type = vertex_converter; +using vertex_converter_type = vertex_converter; class base_symbolizer_helper { @@ -158,6 +158,10 @@ void init_marker() const; }; -} //namespace +namespace geometry { +MAPNIK_DECL mapnik::box2d envelope(mapnik::base_symbolizer_helper::geometry_cref const& geom); +} + +} //namespace mapnik #endif // SYMBOLIZER_HELPERS_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/text/text_properties.hpp mapnik-3.0.13+ds/include/mapnik/text/text_properties.hpp --- mapnik-3.0.9+ds/include/mapnik/text/text_properties.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/text/text_properties.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -36,9 +36,11 @@ // stl #include -// boost +#pragma GCC diagnostic push +#include #include #include +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/include/mapnik/tiff_io.hpp mapnik-3.0.13+ds/include/mapnik/tiff_io.hpp --- mapnik-3.0.9+ds/include/mapnik/tiff_io.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/tiff_io.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,6 +28,9 @@ #include #include +#pragma GCC diagnostic push +#include + extern "C" { #include @@ -35,6 +38,9 @@ #define RealTIFFClose TIFFClose } +#pragma GCC diagnostic pop + + //std #include diff -Nru mapnik-3.0.9+ds/include/mapnik/transform_expression_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/transform_expression_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/transform_expression_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/transform_expression_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -45,7 +45,6 @@ qi::_3_type _3; qi::_6_type _6; qi::_val_type _val; - qi::char_type char_; qi::double_type double_; qi::lit_type lit; qi::no_case_type no_case; @@ -57,8 +56,7 @@ // the order provided. The individual transform definitions are // separated by whitespace and/or a comma. - qi::no_skip_type no_skip; - start = transform_ % no_skip[char_(", ")] ; + start = transform_ % *lit(',') ; transform_ = matrix | translate | scale | rotate | skewX | skewY ; diff -Nru mapnik-3.0.9+ds/include/mapnik/transform_expression.hpp mapnik-3.0.13+ds/include/mapnik/transform_expression.hpp --- mapnik-3.0.9+ds/include/mapnik/transform_expression.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/transform_expression.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,11 +30,13 @@ #include #include #include -// boost + +#pragma GCC diagnostic push +#include #include -// fusion #include #include +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/include/mapnik/transform_path_adapter.hpp mapnik-3.0.13+ds/include/mapnik/transform_path_adapter.hpp --- mapnik-3.0.9+ds/include/mapnik/transform_path_adapter.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/transform_path_adapter.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -56,16 +56,16 @@ using size_type = std::size_t; using value_type = typename select_value_type::type; - transform_path_adapter(Transform const& t, - Geometry & geom, + transform_path_adapter(Transform const& _t, + Geometry & _geom, proj_transform const& prj_trans) - : t_(&t), - geom_(geom), + : t_(&_t), + geom_(_geom), prj_trans_(&prj_trans) {} - explicit transform_path_adapter(Geometry & geom) + explicit transform_path_adapter(Geometry & _geom) : t_(0), - geom_(geom), + geom_(_geom), prj_trans_(0) {} void set_proj_trans(proj_transform const& prj_trans) diff -Nru mapnik-3.0.9+ds/include/mapnik/transform_processor.hpp mapnik-3.0.13+ds/include/mapnik/transform_processor.hpp --- mapnik-3.0.9+ds/include/mapnik/transform_processor.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/transform_processor.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,8 +29,11 @@ #include #include #include -// agg + +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl #include @@ -111,11 +114,11 @@ vars_(v), scale_factor_(scale_factor) {} - void operator() (identity_node const&) + void operator() (identity_node const&) const { } - void operator() (matrix_node const& node) + void operator() (matrix_node const& node) const { double a = eval(node.a_); // scale x; double b = eval(node.b_); @@ -126,21 +129,21 @@ transform_.multiply(agg::trans_affine(a, b, c, d, e, f)); } - void operator() (translate_node const& node) + void operator() (translate_node const& node) const { double tx = eval(node.tx_) * scale_factor_; double ty = eval(node.ty_, 0.0) * scale_factor_; transform_.translate(tx, ty); } - void operator() (scale_node const& node) + void operator() (scale_node const& node) const { double sx = eval(node.sx_); double sy = eval(node.sy_, sx); transform_.scale(sx, sy); } - void operator() (rotate_node const& node) + void operator() (rotate_node const& node) const { double angle = deg2rad(eval(node.angle_)); double cx = eval(node.cx_, 0.0); @@ -150,7 +153,7 @@ transform_.translate(cx, cy); } - void operator() (skewX_node const& node) + void operator() (skewX_node const& node) const { auto degrees = std::fmod(eval(node.angle_),90.0); if (degrees < -89.0) degrees = -89.0; @@ -159,7 +162,7 @@ transform_.multiply(agg::trans_affine_skewing(angle, 0.0)); } - void operator() (skewY_node const& node) + void operator() (skewY_node const& node) const { auto degrees = std::fmod(eval(node.angle_),90.0); if (degrees < -89.0) degrees = -89.0; diff -Nru mapnik-3.0.9+ds/include/mapnik/unicode.hpp mapnik-3.0.13+ds/include/mapnik/unicode.hpp --- mapnik-3.0.9+ds/include/mapnik/unicode.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/unicode.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -45,6 +45,10 @@ private: UConverter * conv_; }; + +// convinience method +void MAPNIK_DECL to_utf8(mapnik::value_unicode_string const& input, std::string & target); + } #endif // MAPNIK_UNICODE_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/util/char_array_buffer.hpp mapnik-3.0.13+ds/include/mapnik/util/char_array_buffer.hpp --- mapnik-3.0.9+ds/include/mapnik/util/char_array_buffer.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/char_array_buffer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,87 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_UTIL_CHAR_ARRAY_BUFFER_HPP +#define MAPNIK_UTIL_CHAR_ARRAY_BUFFER_HPP + +#include + +namespace mapnik { namespace util { + +// ref https://artofcode.wordpress.com/2010/12/12/deriving-from-stdstreambuf/ + +class char_array_buffer : public std::streambuf +{ +public: + char_array_buffer(char const* data, std::size_t size) + : begin_(data), end_(data + size), current_(data) {} + +private: + int_type underflow() + { + if (current_ == end_) + { + return traits_type::eof(); + } + return traits_type::to_int_type(*current_); + } + + int_type uflow() + { + if (current_ == end_) + { + return traits_type::eof(); + } + return traits_type::to_int_type(*current_++); + } + + int_type pbackfail(int_type ch) + { + if (current_ == begin_ || (ch != traits_type::eof() && ch != current_[-1])) + { + return traits_type::eof(); + } + return traits_type::to_int_type(*--current_); + } + + std::streamsize showmanyc() + { + return end_ - current_; + } + + pos_type seekoff(off_type off, std::ios_base::seekdir dir, + std::ios_base::openmode which = std::ios_base::in | std::ios_base::out ) + { + if (dir == std::ios_base::beg) current_ = std::min(begin_ + off, end_); + else if (dir == std::ios_base::cur) current_ = std::min(current_ + off, end_); + else current_ = std::max(end_ - off, begin_); // dir == std::ios_base::end + return pos_type(off_type(current_ - begin_)); + } + char const * const begin_; + char const * const end_; + char const * current_; +}; + +}} + + +#endif // MAPNIK_UTIL_CHAR_ARRAY_BUFFER_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/util/const_rendering_buffer.hpp mapnik-3.0.13+ds/include/mapnik/util/const_rendering_buffer.hpp --- mapnik-3.0.9+ds/include/mapnik/util/const_rendering_buffer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/const_rendering_buffer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,7 +25,10 @@ #include +#pragma GCC diagnostic push +#include #include "agg_basics.h" +#pragma GCC diagnostic pop #include diff -Nru mapnik-3.0.9+ds/include/mapnik/util/dasharray_parser.hpp mapnik-3.0.13+ds/include/mapnik/util/dasharray_parser.hpp --- mapnik-3.0.9+ds/include/mapnik/util/dasharray_parser.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/dasharray_parser.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,32 +23,13 @@ #ifndef MAPNIK_UTIL_DASHARRAY_PARSER_HPP #define MAPNIK_UTIL_DASHARRAY_PARSER_HPP +#include #include #include namespace mapnik { namespace util { -bool parse_dasharray(std::string const& value, std::vector& dasharray); - -inline bool add_dashes(std::vector & buf, std::vector > & dash) -{ - if (buf.empty()) return false; - size_t size = buf.size(); - if (size % 2 == 1) - { - buf.insert(buf.end(),buf.begin(),buf.end()); - } - std::vector::const_iterator pos = buf.begin(); - while (pos != buf.end()) - { - if (*pos > 0.0 || *(pos+1) > 0.0) // avoid both dash and gap eq 0.0 - { - dash.emplace_back(*pos,*(pos + 1)); - } - pos +=2; - } - return !buf.empty(); -} +bool parse_dasharray(std::string const& value, dash_array & dash); }} diff -Nru mapnik-3.0.9+ds/include/mapnik/util/file_io.hpp mapnik-3.0.13+ds/include/mapnik/util/file_io.hpp --- mapnik-3.0.9+ds/include/mapnik/util/file_io.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/file_io.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -58,11 +58,16 @@ } } - inline bool open() const + inline bool is_open() const { return file_ ? true : false; } + explicit operator bool() const + { + return this->is_open(); + } + inline std::FILE * get() const { return file_.get(); diff -Nru mapnik-3.0.9+ds/include/mapnik/util/geometry_to_ds_type.hpp mapnik-3.0.13+ds/include/mapnik/util/geometry_to_ds_type.hpp --- mapnik-3.0.9+ds/include/mapnik/util/geometry_to_ds_type.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/geometry_to_ds_type.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,8 +28,13 @@ #include #include #include -// boost + +#pragma GCC diagnostic push +#include #include +#include +#include +#pragma GCC diagnostic pop namespace mapnik { namespace util { diff -Nru mapnik-3.0.9+ds/include/mapnik/util/geometry_to_geojson.hpp mapnik-3.0.13+ds/include/mapnik/util/geometry_to_geojson.hpp --- mapnik-3.0.9+ds/include/mapnik/util/geometry_to_geojson.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/geometry_to_geojson.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,18 +24,13 @@ #define MAPNIK_GEOMETRY_TO_GEOJSON_HPP // mapnik +#include -#include +#include namespace mapnik { namespace util { -inline bool to_geojson(std::string & json, mapnik::geometry::geometry const& geom) -{ - using sink_type = std::back_insert_iterator; - static const mapnik::json::geometry_generator_grammar > grammar; - sink_type sink(json); - return boost::spirit::karma::generate(sink, grammar, geom); -} +bool to_geojson(std::string & json, mapnik::geometry::geometry const& geom); }} diff -Nru mapnik-3.0.9+ds/include/mapnik/util/is_clockwise.hpp mapnik-3.0.13+ds/include/mapnik/util/is_clockwise.hpp --- mapnik-3.0.9+ds/include/mapnik/util/is_clockwise.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/is_clockwise.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,6 +23,8 @@ #ifndef MAPNIK_UTIL_IS_CLOCKWISE_HPP #define MAPNIK_UTIL_IS_CLOCKWISE_HPP +#include + namespace mapnik { namespace util { template @@ -30,11 +32,18 @@ { double area = 0.0; std::size_t num_points = ring.size(); + assert(num_points > 2); + double orig_x = ring[0].x; + double orig_y = ring[0].y; for (std::size_t i = 0; i < num_points; ++i) { auto const& p0 = ring[i]; auto const& p1 = ring[(i + 1) % num_points]; - area += p0.x * p1.y - p0.y * p1.x; + double x0 = p0.x - orig_x; + double y0 = p0.y - orig_y; + double x1 = p1.x - orig_x; + double y1 = p1.y - orig_y; + area += x0 * y1 - x1 * y0; } return (area < 0.0) ? true : false; } diff -Nru mapnik-3.0.9+ds/include/mapnik/util/noncopyable.hpp mapnik-3.0.13+ds/include/mapnik/util/noncopyable.hpp --- mapnik-3.0.9+ds/include/mapnik/util/noncopyable.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/noncopyable.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,6 +28,15 @@ namespace non_copyable_ { +class movable +{ +protected: + constexpr movable() = default; + ~movable() = default; + movable( movable && ) = default; + movable& operator=(movable && ) = default; +}; + class noncopyable { protected: @@ -36,8 +45,10 @@ noncopyable( noncopyable const& ) = delete; noncopyable& operator=(noncopyable const& ) = delete; }; + } +using movable = non_copyable_::movable; using noncopyable = non_copyable_::noncopyable; }} diff -Nru mapnik-3.0.9+ds/include/mapnik/util/path_iterator.hpp mapnik-3.0.13+ds/include/mapnik/util/path_iterator.hpp --- mapnik-3.0.9+ds/include/mapnik/util/path_iterator.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/path_iterator.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,8 +26,11 @@ // mapnik #include #include -// boost + +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/include/mapnik/util/recursive_wrapper.hpp mapnik-3.0.13+ds/include/mapnik/util/recursive_wrapper.hpp --- mapnik-3.0.9+ds/include/mapnik/util/recursive_wrapper.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/recursive_wrapper.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,150 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2015 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 - * - *****************************************************************************/ - - -#ifndef MAPNIK_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP -#define MAPNIK_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP - -#include - -namespace mapnik { namespace util { - -template -class recursive_wrapper -{ -public: - using type = T; -private: - - T* p_; - -public: - - ~recursive_wrapper(); - recursive_wrapper(); - - recursive_wrapper(recursive_wrapper const& operand); - recursive_wrapper(T const& operand); - recursive_wrapper(recursive_wrapper&& operand); - recursive_wrapper(T&& operand); - -private: - - void assign(const T& rhs); - -public: - - inline recursive_wrapper& operator=(recursive_wrapper const& rhs) - { - assign( rhs.get() ); - return *this; - } - - inline recursive_wrapper& operator=(T const& rhs) - { - assign( rhs ); - return *this; - } - - inline void swap(recursive_wrapper& operand) noexcept - { - T* temp = operand.p_; - operand.p_ = p_; - p_ = temp; - } - - - recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept - { - swap(rhs); - return *this; - } - - recursive_wrapper& operator=(T&& rhs) - { - get() = std::move(rhs); - return *this; - } - - -public: - - T& get() { return *get_pointer(); } - const T& get() const { return *get_pointer(); } - T* get_pointer() { return p_; } - const T* get_pointer() const { return p_; } - operator T const&() const { return this->get(); } - operator T&() { return this->get(); } -}; - -template -recursive_wrapper::~recursive_wrapper() -{ - delete p_; -} - -template -recursive_wrapper::recursive_wrapper() - : p_(new T) -{ -} - -template -recursive_wrapper::recursive_wrapper(recursive_wrapper const& operand) - : p_(new T( operand.get() )) -{ -} - -template -recursive_wrapper::recursive_wrapper(T const& operand) - : p_(new T(operand)) -{ -} - -template -recursive_wrapper::recursive_wrapper(recursive_wrapper&& operand) - : p_(operand.p_) -{ - operand.p_ = nullptr; -} - -template -recursive_wrapper::recursive_wrapper(T&& operand) - : p_(new T( std::move(operand) )) -{ -} - -template -void recursive_wrapper::assign(const T& rhs) -{ - this->get() = rhs; -} - -template -inline void swap(recursive_wrapper& lhs, recursive_wrapper& rhs) noexcept -{ - lhs.swap(rhs); -} - -}} - -#endif // MAPNIK_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP diff -Nru mapnik-3.0.9+ds/include/mapnik/util/spatial_index.hpp mapnik-3.0.13+ds/include/mapnik/util/spatial_index.hpp --- mapnik-3.0.9+ds/include/mapnik/util/spatial_index.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/spatial_index.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,55 +30,68 @@ #include // stl #include +#include using mapnik::box2d; using mapnik::query; namespace mapnik { namespace util { -template + +template +bool check_spatial_index(InputStream& in) +{ + char header[17]; // mapnik-index + std::memset(header, 0, 17); + in.read(header,16); + return (std::strncmp(header, "mapnik-index",12) == 0); +} + +template > class spatial_index { + using bbox_type = BBox; public: static void query(Filter const& filter, InputStream& in,std::vector& pos); - static box2d bounding_box( InputStream& in ); + static bbox_type bounding_box( InputStream& in ); static void query_first_n(Filter const& filter, InputStream & in, std::vector& pos, std::size_t count); private: - spatial_index(); ~spatial_index(); spatial_index(spatial_index const&); spatial_index& operator=(spatial_index const&); static int read_ndr_integer(InputStream& in); - static void read_envelope(InputStream& in, box2d& envelope); + static void read_envelope(InputStream& in, bbox_type& envelope); static void query_node(Filter const& filter, InputStream& in, std::vector & results); static void query_first_n_impl(Filter const& filter, InputStream& in, std::vector & results, std::size_t count); }; -template -box2d spatial_index::bounding_box(InputStream& in) +template +BBox spatial_index::bounding_box(InputStream& in) { static_assert(std::is_standard_layout::value, "Values stored in quad-tree must be standard layout type"); + if (!check_spatial_index(in)) throw std::runtime_error("Invalid index file (regenerate with shapeindex)"); in.seekg(16 + 4, std::ios::beg); - box2d box; + typename spatial_index::bbox_type box; read_envelope(in, box); in.seekg(0, std::ios::beg); return box; } -template -void spatial_index::query(Filter const& filter, InputStream& in, std::vector& results) +template +void spatial_index::query(Filter const& filter, InputStream& in, std::vector& results) { - static_assert(std::is_standard_layout::value, "Values stored in quad-tree must be standard layout types"); + static_assert(std::is_standard_layout::value, "Values stored in quad-tree must be standard layout type"); + if (!check_spatial_index(in)) throw std::runtime_error("Invalid index file (regenerate with shapeindex)"); in.seekg(16, std::ios::beg); query_node(filter, in, results); } -template -void spatial_index::query_node(Filter const& filter, InputStream& in, std::vector& results) +template +void spatial_index::query_node(Filter const& filter, InputStream& in, std::vector& results) { int offset = read_ndr_integer(in); - box2d node_ext; + typename spatial_index::bbox_type node_ext; read_envelope(in, node_ext); int num_shapes = read_ndr_integer(in); if (!filter.pass(node_ext)) @@ -101,20 +114,21 @@ } } -template -void spatial_index::query_first_n(Filter const& filter, InputStream& in, std::vector& results, std::size_t count) +template +void spatial_index::query_first_n(Filter const& filter, InputStream& in, std::vector& results, std::size_t count) { - static_assert(std::is_standard_layout::value, "Values stored in quad-tree must be standard layout types"); + static_assert(std::is_standard_layout::value, "Values stored in quad-tree must be standard layout type"); + if (!check_spatial_index(in)) throw std::runtime_error("Invalid index file (regenerate with shapeindex)"); in.seekg(16, std::ios::beg); query_first_n_impl(filter, in, results, count); } -template -void spatial_index::query_first_n_impl(Filter const& filter, InputStream& in, std::vector& results, std::size_t count) +template +void spatial_index::query_first_n_impl(Filter const& filter, InputStream& in, std::vector& results, std::size_t count) { if (results.size() == count) return; int offset = read_ndr_integer(in); - box2d node_ext; + typename spatial_index::bbox_type node_ext; read_envelope(in, node_ext); int num_shapes = read_ndr_integer(in); if (!filter.pass(node_ext)) @@ -136,16 +150,16 @@ } } -template -int spatial_index::read_ndr_integer(InputStream& in) +template +int spatial_index::read_ndr_integer(InputStream& in) { char b[4]; in.read(b, 4); return (b[0] & 0xff) | (b[1] & 0xff) << 8 | (b[2] & 0xff) << 16 | (b[3] & 0xff) << 24; } -template -void spatial_index::read_envelope(InputStream& in, box2d& envelope) +template +void spatial_index::read_envelope(InputStream& in, BBox& envelope) { in.read(reinterpret_cast(&envelope), sizeof(envelope)); } diff -Nru mapnik-3.0.9+ds/include/mapnik/util/variant.hpp mapnik-3.0.13+ds/include/mapnik/util/variant.hpp --- mapnik-3.0.9+ds/include/mapnik/util/variant.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/variant.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,889 +24,53 @@ #define MAPNIK_UTIL_VARIANT_HPP #include - -#include // swap -#include -#include -#include // runtime_error -#include // operator new -#include // size_t -#include -#include - -#include "recursive_wrapper.hpp" - -#include // spirit support - -#ifdef _MSC_VER - // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx - #ifdef NDEBUG - #define VARIANT_INLINE __forceinline - #else - #define VARIANT_INLINE __declspec(noinline) - #endif -#else - #ifdef NDEBUG - #define VARIANT_INLINE inline __attribute__((always_inline)) - #else - #define VARIANT_INLINE __attribute__((noinline)) - #endif -#endif - -#define VARIANT_MAJOR_VERSION 0 -#define VARIANT_MINOR_VERSION 1 -#define VARIANT_PATCH_VERSION 0 - -// translates to 100 -#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION) +#include namespace mapnik { namespace util { -// static visitor -template -struct static_visitor -{ - using result_type = R; -protected: - static_visitor() {} - ~static_visitor() {} -}; - -namespace detail { - -static constexpr std::size_t invalid_value = std::size_t(-1); - -template -struct direct_type; - -template -struct direct_type -{ - static constexpr std::size_t index = std::is_same::value - ? sizeof...(Types) : direct_type::index; -}; - -template -struct direct_type -{ - static constexpr std::size_t index = invalid_value; -}; - -template -struct convertible_type; - -template -struct convertible_type -{ - static constexpr std::size_t index = std::is_convertible::value - ? sizeof...(Types) : convertible_type::index; -}; - -template -struct convertible_type -{ - static constexpr std::size_t index = invalid_value; -}; - -template -struct value_traits -{ - static constexpr std::size_t direct_index = direct_type::index; - static constexpr std::size_t index = - (direct_index == invalid_value) ? convertible_type::index : direct_index; -}; - -// check if T is in Types... -template -struct has_type; - -template -struct has_type -{ - static constexpr bool value = std::is_same::value - || has_type::value; -}; - -template -struct has_type : std::false_type {}; -// - -template -struct is_valid_type; - -template -struct is_valid_type -{ - static constexpr bool value = std::is_convertible::value - || is_valid_type::value; -}; - template -struct is_valid_type : std::false_type {}; - -template -struct select_type -{ - static_assert(N < sizeof...(Types), "index out of bounds"); -}; - -template -struct select_type -{ - using type = typename select_type::type; -}; - -template -struct select_type<0, T, Types...> -{ - using type = T; -}; - - -template -struct enable_if_type { using type = R; }; - -template -struct result_of_unary_visit -{ - using type = typename std::result_of::type; -}; - -template -struct result_of_unary_visit::type > -{ - using type = typename F::result_type; -}; - -template -struct result_of_binary_visit -{ - using type = typename std::result_of::type; -}; - - -template -struct result_of_binary_visit::type > -{ - using type = typename F::result_type; -}; - - -} // namespace detail - - -template -struct static_max; - -template -struct static_max -{ - static const std::size_t value = arg; -}; - -template -struct static_max -{ - static const std::size_t value = arg1 >= arg2 ? static_max::value : - static_max::value; -}; +using recursive_wrapper = typename mapbox::util::recursive_wrapper; template -struct variant_helper; - -template -struct variant_helper -{ - VARIANT_INLINE static void destroy(const std::size_t id, void * data) - { - if (id == sizeof...(Types)) - { - reinterpret_cast(data)->~T(); - } - else - { - variant_helper::destroy(id, data); - } - } - - VARIANT_INLINE static void move(const std::size_t old_id, void * old_value, void * new_value) - { - if (old_id == sizeof...(Types)) - { - new (new_value) T(std::move(*reinterpret_cast(old_value))); - //std::memcpy(new_value, old_value, sizeof(T)); - // ^^ DANGER: this should only be considered for relocatable types e.g built-in types - // Also, I don't see any measurable performance benefit just yet - } - else - { - variant_helper::move(old_id, old_value, new_value); - } - } - - VARIANT_INLINE static void copy(const std::size_t old_id, const void * old_value, void * new_value) - { - if (old_id == sizeof...(Types)) - { - new (new_value) T(*reinterpret_cast(old_value)); - } - else - { - variant_helper::copy(old_id, old_value, new_value); - } - } - VARIANT_INLINE static void direct_swap(const std::size_t id, void * lhs, void * rhs) - { - using std::swap; //enable ADL - if (id == sizeof...(Types)) - { - // both lhs and rhs hold T - swap(*reinterpret_cast(lhs), *reinterpret_cast(rhs)); - } - else - { - variant_helper::direct_swap(id, lhs, rhs); - } - } -}; - -template<> struct variant_helper<> -{ - VARIANT_INLINE static void destroy(const std::size_t, void *) {} - VARIANT_INLINE static void move(const std::size_t, void *, void *) {} - VARIANT_INLINE static void copy(const std::size_t, const void *, void *) {} - VARIANT_INLINE static void direct_swap(const std::size_t, void *, void *) {} -}; - -namespace detail { - -template -struct unwrapper -{ - T const& operator() (T const& obj) const - { - return obj; - } - - T& operator() (T & obj) const - { - return obj; - } -}; - - -template -struct unwrapper> -{ - auto operator() (recursive_wrapper const& obj) const - -> typename recursive_wrapper::type const& - { - return obj.get(); - } - - auto operator() (recursive_wrapper & obj) const - -> typename recursive_wrapper::type & - { - return obj.get(); - } -}; - -template -struct unwrapper> -{ - auto operator() (std::reference_wrapper const& obj) const - -> typename recursive_wrapper::type const& - { - return obj.get(); - } -}; - -template -struct dispatcher; - -template -struct dispatcher -{ - using result_type = R; - VARIANT_INLINE static result_type apply_const(V const& v, F f) - { - if (v.get_type_index() == sizeof...(Types)) - { - return f(unwrapper()(v. template get())); - } - else - { - return dispatcher::apply_const(v, f); - } - } - - VARIANT_INLINE static result_type apply(V & v, F f) - { - if (v.get_type_index() == sizeof...(Types)) - { - return f(unwrapper()(v. template get())); - } - else - { - return dispatcher::apply(v, f); - } - } -}; - -template -struct dispatcher -{ - using result_type = R; - VARIANT_INLINE static result_type apply_const(V const&, F) - { - throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); - } - - VARIANT_INLINE static result_type apply(V &, F) - { - throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); - } -}; - - -template -struct binary_dispatcher_rhs; - -template -struct binary_dispatcher_rhs -{ - using result_type = R; - VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) - { - if (rhs.get_type_index() == sizeof...(Types)) // call binary functor - { - return f(unwrapper()(lhs. template get()), - unwrapper()(rhs. template get())); - } - else - { - return binary_dispatcher_rhs::apply_const(lhs, rhs, f); - } - } - - VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) - { - if (rhs.get_type_index() == sizeof...(Types)) // call binary functor - { - return f(unwrapper()(lhs. template get()), - unwrapper()(rhs. template get())); - } - else - { - return binary_dispatcher_rhs::apply(lhs, rhs, f); - } - } - -}; - -template -struct binary_dispatcher_rhs -{ - using result_type = R; - VARIANT_INLINE static result_type apply_const(V const&, V const&, F) - { - throw std::runtime_error("binary dispatch: FAIL"); - } - VARIANT_INLINE static result_type apply(V &, V &, F) - { - throw std::runtime_error("binary dispatch: FAIL"); - } -}; - - -template -struct binary_dispatcher_lhs; - -template -struct binary_dispatcher_lhs -{ - using result_type = R; - VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) - { - if (lhs.get_type_index() == sizeof...(Types)) // call binary functor - { - return f(lhs. template get(), rhs. template get()); - } - else - { - return binary_dispatcher_lhs::apply_const(lhs, rhs, f); - } - } - - VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) - { - if (lhs.get_type_index() == sizeof...(Types)) // call binary functor - { - return f(lhs. template get(), rhs. template get()); - } - else - { - return binary_dispatcher_lhs::apply(lhs, rhs, f); - } - } - -}; - -template -struct binary_dispatcher_lhs -{ - using result_type = R; - VARIANT_INLINE static result_type apply_const(V const&, V const&, F) - { - throw std::runtime_error("binary dispatch: FAIL"); - } - - VARIANT_INLINE static result_type apply(V &, V &, F) - { - throw std::runtime_error("binary dispatch: FAIL"); - } -}; - -template -struct binary_dispatcher; - -template -struct binary_dispatcher -{ - using result_type = R; - VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f) - { - if (v0.get_type_index() == sizeof...(Types)) - { - if (v0.get_type_index() == v1.get_type_index()) - { - return f(v0. template get(), v1. template get()); // call binary functor - } - else - { - return binary_dispatcher_rhs::apply_const(v0, v1, f); - } - } - else if (v1.get_type_index() == sizeof...(Types)) - { - return binary_dispatcher_lhs::apply_const(v0, v1, f); - } - return binary_dispatcher::apply_const(v0, v1, f); - } - - VARIANT_INLINE static result_type apply(V & v0, V & v1, F f) - { - if (v0.get_type_index() == sizeof...(Types)) - { - if (v0.get_type_index() == v1.get_type_index()) - { - return f(v0. template get(), v1. template get()); // call binary functor - } - else - { - return binary_dispatcher_rhs::apply(v0, v1, f); - } - } - else if (v1.get_type_index() == sizeof...(Types)) - { - return binary_dispatcher_lhs::apply(v0, v1, f); - } - return binary_dispatcher::apply(v0, v1, f); - } -}; - -template -struct binary_dispatcher -{ - using result_type = R; - VARIANT_INLINE static result_type apply_const(V const&, V const&, F) - { - throw std::runtime_error("binary dispatch: FAIL"); - } - - VARIANT_INLINE static result_type apply(V &, V &, F) - { - throw std::runtime_error("binary dispatch: FAIL"); - } -}; - -// comparator functors -struct equal_comp -{ - template - bool operator()(T const& lhs, T const& rhs) const - { - return lhs == rhs; - } -}; - -struct less_comp -{ - template - bool operator()(T const& lhs, T const& rhs) const - { - return lhs < rhs; - } -}; - -template -class comparer -{ -public: - explicit comparer(Variant const& lhs) noexcept - : lhs_(lhs) {} - comparer& operator=(comparer const&) = delete; - // visitor - template - bool operator()(T const& rhs_content) const - { - T const& lhs_content = lhs_.template get(); - return Comp()(lhs_content, rhs_content); - } -private: - Variant const& lhs_; -}; - - -} // namespace detail - -struct no_init {}; - -template -class variant -{ -private: - - static const std::size_t data_size = static_max::value; - static const std::size_t data_align = static_max::value; - - using data_type = typename std::aligned_storage::type; - using helper_type = variant_helper; - - std::size_t type_index; - data_type data; - -public: - - // tell spirit that this is an adapted variant - struct adapted_variant_tag; - using types = boost::mpl::vector; - - VARIANT_INLINE variant() - : type_index(sizeof...(Types) - 1) - { - new (&data) typename detail::select_type<0, Types...>::type(); - } - - VARIANT_INLINE variant(no_init) - : type_index(detail::invalid_value) {} - - // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers - template ::type, Types...>::value>::type> - VARIANT_INLINE variant(T && val) noexcept - : type_index(detail::value_traits::type, Types...>::index) - { - constexpr std::size_t index = sizeof...(Types) - detail::value_traits::type, Types...>::index - 1; - using target_type = typename detail::select_type::type; - new (&data) target_type(std::forward(val)); // nothrow - } - - VARIANT_INLINE variant(variant const& old) - : type_index(old.type_index) - { - helper_type::copy(old.type_index, &old.data, &data); - } - - VARIANT_INLINE variant(variant&& old) noexcept - : type_index(old.type_index) - { - helper_type::move(old.type_index, &old.data, &data); - } - -private: - VARIANT_INLINE void copy_assign(variant const& rhs) - { - helper_type::destroy(type_index, &data); - type_index = detail::invalid_value; - helper_type::copy(rhs.type_index, &rhs.data, &data); - type_index = rhs.type_index; - } - - VARIANT_INLINE void move_assign(variant && rhs) - { - helper_type::destroy(type_index, &data); - type_index = detail::invalid_value; - helper_type::move(rhs.type_index, &rhs.data, &data); - type_index = rhs.type_index; - } - -public: - VARIANT_INLINE variant& operator=(variant && other) - { - move_assign(std::move(other)); - return *this; - } - - VARIANT_INLINE variant& operator=(variant const& other) - { - copy_assign(other); - return *this; - } - - // conversions - // move-assign - template - VARIANT_INLINE variant& operator=(T && rhs) noexcept - { - variant temp(std::forward(rhs)); - move_assign(std::move(temp)); - return *this; - } - - // copy-assign - template - VARIANT_INLINE variant& operator=(T const& rhs) - { - variant temp(rhs); - copy_assign(temp); - return *this; - } - - template - VARIANT_INLINE bool is() const - { - static_assert(detail::has_type::value, "invalid type in T in `is()` for this variant"); - return (type_index == detail::direct_type::index); - } - - VARIANT_INLINE bool valid() const - { - return (type_index != detail::invalid_value); - } - - template - VARIANT_INLINE void set(Args&&... args) - { - helper_type::destroy(type_index, &data); - new (&data) T(std::forward(args)...); - type_index = detail::direct_type::index; - } - - // get() - template::index != detail::invalid_value) - >::type* = nullptr> - VARIANT_INLINE T& get() - { - if (type_index == detail::direct_type::index) - { - return *reinterpret_cast(&data); - } - else - { - throw std::runtime_error("in get()"); - } - } - - template ::index != detail::invalid_value) - >::type* = nullptr> - VARIANT_INLINE T const& get() const - { - if (type_index == detail::direct_type::index) - { - return *reinterpret_cast(&data); - } - else - { - throw std::runtime_error("in get()"); - } - } - - // get() - T stored as recursive_wrapper - template , Types...>::index != detail::invalid_value) - >::type* = nullptr> - VARIANT_INLINE T& get() - { - if (type_index == detail::direct_type, Types...>::index) - { - return (*reinterpret_cast*>(&data)).get(); - } - else - { - throw std::runtime_error("in get()"); - } - } - - template , Types...>::index != detail::invalid_value) - >::type* = nullptr> - VARIANT_INLINE T const& get() const - { - if (type_index == detail::direct_type, Types...>::index) - { - return (*reinterpret_cast const*>(&data)).get(); - } - else - { - throw std::runtime_error("in get()"); - } - } - - // get() - T stored as std::reference_wrapper - template , Types...>::index != detail::invalid_value) - >::type* = nullptr> - VARIANT_INLINE T& get() - { - if (type_index == detail::direct_type, Types...>::index) - { - return (*reinterpret_cast*>(&data)).get(); - } - else - { - throw std::runtime_error("in get()"); - } - } - - template , Types...>::index != detail::invalid_value) - >::type* = nullptr> - VARIANT_INLINE T const& get() const - { - if (type_index == detail::direct_type, Types...>::index) - { - return (*reinterpret_cast const*>(&data)).get(); - } - else - { - throw std::runtime_error("in get()"); - } - } - - VARIANT_INLINE std::size_t get_type_index() const - { - return type_index; - } - - VARIANT_INLINE int which() const noexcept - { - return static_cast(sizeof...(Types) - type_index - 1); - } - // visitor - // unary - template - auto VARIANT_INLINE - static visit(V const& v, F f) - -> decltype(detail::dispatcher::type>::type, Types...>::apply_const(v, f)) - { - using R = typename detail::result_of_unary_visit::type>::type; - return detail::dispatcher::apply_const(v, f); - } - // non-const - template - auto VARIANT_INLINE - static visit(V & v, F f) - -> decltype(detail::dispatcher::type>::type, Types...>::apply(v, f)) - { - using R = typename detail::result_of_unary_visit::type>::type; - return detail::dispatcher::apply(v, f); - } - - // binary - // const - template - auto VARIANT_INLINE - static binary_visit(V const& v0, V const& v1, F f) - -> decltype(detail::binary_dispatcher::type>::type, Types...>::apply_const(v0, v1, f)) - { - using R = typename detail::result_of_binary_visit::type>::type; - return detail::binary_dispatcher::apply_const(v0, v1, f); - } - // non-const - template - auto VARIANT_INLINE - static binary_visit(V& v0, V& v1, F f) - -> decltype(detail::binary_dispatcher::type>::type, Types...>::apply(v0, v1, f)) - { - using R = typename detail::result_of_binary_visit::type>::type; - return detail::binary_dispatcher::apply(v0, v1, f); - } - - ~variant() noexcept - { - helper_type::destroy(type_index, &data); - } - - // comparison operators - // equality - VARIANT_INLINE bool operator==(variant const& rhs) const - { - if (this->get_type_index() != rhs.get_type_index()) - return false; - detail::comparer visitor(*this); - return visit(rhs, visitor); - } - // less than - VARIANT_INLINE bool operator<(variant const& rhs) const - { - if (this->get_type_index() != rhs.get_type_index()) - { - return this->get_type_index() < rhs.get_type_index(); - // ^^ borrowed from boost::variant - } - detail::comparer visitor(*this); - return visit(rhs, visitor); - } -}; +using variant = typename mapbox::util::variant; // unary visitor interface - // const -template -auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f)) +template +auto VARIANT_INLINE static apply_visitor(F && f, V const& v) -> decltype(V::visit(v, std::forward(f))) { - return V::visit(v, f); + return V::visit(v, std::forward(f)); } // non-const -template -auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f)) +template +auto VARIANT_INLINE static apply_visitor(F && f, V & v) -> decltype(V::visit(v, std::forward(f))) { - return V::visit(v, f); + return V::visit(v, std::forward(f)); } // binary visitor interface // const -template -auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f)) +template +auto VARIANT_INLINE static apply_visitor(F && f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward(f))) { - return V::binary_visit(v0, v1, f); + return V::binary_visit(v0, v1, std::forward(f)); } + // non-const -template -auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f)) +template +auto VARIANT_INLINE static apply_visitor(F && f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, std::forward(f))) { - return V::binary_visit(v0, v1, f); + return V::binary_visit(v0, v1, std::forward(f)); } // getter interface -template +template ResultType & get(T & var) { return var.template get(); } -template +template ResultType const& get(T const& var) { return var.template get(); diff -Nru mapnik-3.0.9+ds/include/mapnik/util/variant_io.hpp mapnik-3.0.13+ds/include/mapnik/util/variant_io.hpp --- mapnik-3.0.9+ds/include/mapnik/util/variant_io.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/util/variant_io.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,7 +24,7 @@ #define MAPNIK_UTIL_VARIANT_IO_HPP -namespace mapnik { namespace util { +namespace mapbox { namespace util { namespace detail { @@ -65,7 +65,7 @@ operator<< (std::basic_ostream& out, variant const& rhs) { detail::printer> visitor(out); - apply_visitor(visitor, rhs); + mapnik::util::apply_visitor(visitor, rhs); return out; } diff -Nru mapnik-3.0.9+ds/include/mapnik/value_hash.hpp mapnik-3.0.13+ds/include/mapnik/value_hash.hpp --- mapnik-3.0.9+ds/include/mapnik/value_hash.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/value_hash.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,21 +26,16 @@ // mapnik #include #include - // stl #include -// icu +#pragma GCC diagnostic push +#include #include -namespace mapnik { namespace detail { +#pragma GCC diagnostic pop -template -inline void hash_combine(std::size_t & seed, T const& v) -{ - std::hash hasher; - seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); -} +namespace mapnik { namespace detail { struct value_hasher { @@ -67,9 +62,7 @@ template std::size_t mapnik_hash_value(T const& val) { - std::size_t seed = util::apply_visitor(detail::value_hasher(), val); - detail::hash_combine(seed, val.get_type_index()); - return seed; + return util::apply_visitor(detail::value_hasher(), val); } } // namespace mapnik diff -Nru mapnik-3.0.9+ds/include/mapnik/value.hpp mapnik-3.0.13+ds/include/mapnik/value.hpp --- mapnik-3.0.9+ds/include/mapnik/value.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/value.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,991 +24,74 @@ #define MAPNIK_VALUE_HPP // mapnik +#include #include #include -#include #include -// stl -#include -#include -#include - -#include -#include -#include - -// icu -#include -#include -namespace mapnik { +namespace mapnik { -inline void to_utf8(mapnik::value_unicode_string const& input, std::string & target) -{ - if (input.isEmpty()) return; - - const int BUF_SIZE = 256; - char buf [BUF_SIZE]; - int len; - - UErrorCode err = U_ZERO_ERROR; - u_strToUTF8(buf, BUF_SIZE, &len, input.getBuffer(), input.length(), &err); - if (err == U_BUFFER_OVERFLOW_ERROR || err == U_STRING_NOT_TERMINATED_WARNING ) - { - const std::unique_ptr buf_ptr(new char [len+1]); - err = U_ZERO_ERROR; - u_strToUTF8(buf_ptr.get() , len + 1, &len, input.getBuffer(), input.length(), &err); - target.assign(buf_ptr.get() , static_cast(len)); - } - else - { - target.assign(buf, static_cast(len)); - } -} - -using value_base = util::variant; - -namespace impl { - -struct equals -{ - bool operator() (value_integer lhs, value_double rhs) const - { - return static_cast(lhs) == rhs; - } - - bool operator() (value_bool lhs, value_double rhs) const - { - return static_cast(lhs) == rhs; - } - - bool operator() (value_double lhs, value_integer rhs) const - { - return lhs == static_cast(rhs); - } - - bool operator() (value_bool lhs, value_integer rhs) const - { - return static_cast(lhs) == rhs; - } - - bool operator() (value_integer lhs, value_bool rhs) const - { - return lhs == static_cast(rhs); - } - - bool operator() (value_double lhs, value_bool rhs) const - { - return lhs == static_cast(rhs); - } - - bool operator() (value_unicode_string const& lhs, - value_unicode_string const& rhs) const - { - return (lhs == rhs) ? true: false; - } - - template - bool operator() (T lhs, T rhs) const - { - return lhs == rhs; - } - - template - bool operator() (T const&, U const&) const - { - return false; - } -}; - -struct not_equals -{ - template - bool operator() (const T &, const U &) const - { - return true; - } - - template - bool operator() (T lhs, T rhs) const - { - return lhs != rhs; - } - - bool operator() (value_bool lhs, value_double rhs) const - { - return static_cast(lhs) != rhs; - } - - bool operator() (value_bool lhs, value_integer rhs) const - { - return static_cast(lhs) != rhs; - } - - bool operator() (value_integer lhs, value_double rhs) const - { - return static_cast(lhs) != rhs; - } - - bool operator() (value_double lhs, value_integer rhs) const - { - return lhs != static_cast(rhs); - } - - bool operator() (value_integer lhs, value_bool rhs) const - { - return lhs != static_cast(rhs); - } - - bool operator() (value_double lhs, value_bool rhs) const - { - return lhs != static_cast(rhs); - } - - bool operator() (value_unicode_string const& lhs, - value_unicode_string const& rhs) const - { - return (lhs != rhs)? true : false; - } - - // back compatibility shim to equate empty string with null for != test - // https://github.com/mapnik/mapnik/issues/1859 - // TODO - consider removing entire specialization at Mapnik 3.x - bool operator() (value_null, value_unicode_string const& rhs) const - { - if (rhs.isEmpty()) return false; - return true; - } - -}; - -struct greater_than -{ - template - bool operator()(const T &, const U &) const - { - return false; - } - - template - bool operator()(T lhs, T rhs) const - { - return lhs > rhs; - } - - bool operator() (value_bool lhs, value_double rhs) const - { - return static_cast(lhs) > rhs; - } - - bool operator() (value_double lhs, value_bool rhs) const - { - return lhs > static_cast(rhs); - } - - bool operator() (value_bool lhs, value_integer rhs) const - { - return static_cast(lhs) > rhs; - } - - bool operator() (value_integer lhs, value_bool rhs) const - { - return lhs > static_cast(rhs); - } - - bool operator() (value_integer lhs, value_double rhs) const - { - return static_cast(lhs) > rhs; - } - - bool operator() (value_double lhs, value_integer rhs) const - { - return static_cast(lhs) > rhs; - } - - bool operator() (value_unicode_string const& lhs, value_unicode_string const& rhs) const - { - return (lhs > rhs) ? true : false ; - } - - bool operator() (value_null, value_null) const - { - return false; - } -}; - -struct greater_or_equal -{ - template - bool operator()(const T &, const U &) const - { - return false; - } - - template - bool operator() (T lhs, T rhs) const - { - return lhs >= rhs; - } - - bool operator() (value_bool lhs, value_double rhs) const - { - return static_cast(lhs) >= rhs; - } - - bool operator() (value_double lhs, value_bool rhs) const - { - return lhs >= static_cast(rhs); - } - - bool operator() (value_bool lhs, value_integer rhs) const - { - return static_cast(lhs) >= rhs; - } - - bool operator() (value_integer lhs, value_bool rhs) const - { - return lhs >= static_cast(rhs); - } - - bool operator() (value_integer lhs, value_double rhs) const - { - return static_cast(lhs) >= rhs; - } - - bool operator() (value_double lhs, value_integer rhs) const - { - return lhs >= static_cast(rhs); - } - - bool operator() (value_unicode_string const& lhs, value_unicode_string const& rhs) const - { - return ( lhs >= rhs ) ? true : false ; - } - - bool operator() (value_null, value_null) const - { - return false; - } -}; - -struct less_than -{ - template - bool operator()(const T &, const U &) const - { - return false; - } - - template - bool operator()(T lhs, T rhs) const - { - return lhs < rhs; - } - - bool operator() (value_bool lhs, value_double rhs) const - { - return static_cast(lhs) < rhs; - } - - bool operator() (value_double lhs, value_bool rhs) const - { - return lhs < static_cast(rhs); - } - - bool operator() (value_bool lhs, value_integer rhs) const - { - return static_cast(lhs) < rhs; - } - - bool operator() (value_integer lhs, value_bool rhs) const - { - return lhs < static_cast(rhs); - } - - bool operator() (value_integer lhs, value_double rhs) const - { - return static_cast(lhs) < rhs; - } - - bool operator() (value_double lhs, value_integer rhs) const - { - return lhs < static_cast(rhs); - } - - bool operator()(value_unicode_string const& lhs, - value_unicode_string const& rhs ) const - { - return (lhs < rhs) ? true : false ; - } - - bool operator() (value_null, value_null) const - { - return false; - } -}; - -struct less_or_equal -{ - template - bool operator()(const T &, const U &) const - { - return false; - } - - template - bool operator()(T lhs, T rhs) const - { - return lhs <= rhs; - } - - bool operator() (value_bool lhs, value_double rhs) const - { - return static_cast(lhs) <= rhs; - } - - bool operator() (value_double lhs, value_bool rhs) const - { - return lhs <= static_cast(rhs); - } - - bool operator() (value_bool lhs, value_integer rhs) const - { - return static_cast(lhs) <= rhs; - } - - bool operator() (value_integer lhs, value_bool rhs) const - { - return lhs <= static_cast(rhs); - } - - bool operator() (value_integer lhs, value_double rhs) const - { - return static_cast(lhs) <= rhs; - } - - bool operator() (value_double lhs, value_integer rhs) const - { - return lhs <= static_cast(rhs); - } - - bool operator()(value_unicode_string const& lhs, - value_unicode_string const& rhs ) const - { - return (lhs <= rhs) ? true : false ; - } - - bool operator() (value_null, value_null) const - { - return false; - } -}; - -template -struct add -{ - using value_type = V; - value_type operator() (value_unicode_string const& lhs , - value_unicode_string const& rhs ) const - { - return lhs + rhs; - } - - value_type operator() (value_double lhs, value_integer rhs) const - { - return lhs + rhs; - } - - value_type operator() (value_integer lhs, value_double rhs) const - { - return lhs + rhs; - } - - value_type operator() (value_unicode_string const& lhs, value_null) const - { - return lhs; - } - - value_type operator() (value_null, value_unicode_string const& rhs) const - { - return rhs; - } - - template - value_type operator() (value_unicode_string const& lhs, R const& rhs) const - { - std::string val; - if (util::to_string(val,rhs)) - return lhs + value_unicode_string(val.c_str()); - return lhs; - } - - template - value_type operator() (L const& lhs , value_unicode_string const& rhs) const - { - std::string val; - if (util::to_string(val,lhs)) - return value_unicode_string(val.c_str()) + rhs; - return rhs; - } - - template - value_type operator() (T lhs, T rhs) const - { - return lhs + rhs ; - } - - template - value_type operator() (T1 const& lhs, T2 const&) const - { - return lhs; - } - - value_type operator() (value_bool lhs, value_bool rhs) const - { - return value_integer(lhs + rhs); - } -}; - -template -struct sub -{ - using value_type = V; - template - value_type operator() (T1 const& lhs, T2 const&) const - { - return lhs; - } - - template - value_type operator() (T lhs, T rhs) const - { - return lhs - rhs ; - } - - value_type operator() (value_unicode_string const&, - value_unicode_string const&) const - { - return value_type(); - } - - value_type operator() (value_double lhs, value_integer rhs) const - { - return lhs - rhs; - } - - value_type operator() (value_integer lhs, value_double rhs) const - { - return lhs - rhs; - } - - value_type operator() (value_bool lhs, value_bool rhs) const - { - return value_integer(lhs - rhs); - } -}; - -template -struct mult -{ - using value_type = V; - template - value_type operator() (T1 const& lhs , T2 const& ) const - { - return lhs; - } - template - value_type operator() (T lhs, T rhs) const - { - return lhs * rhs; - } - - value_type operator() (value_unicode_string const&, - value_unicode_string const&) const - { - return value_type(); - } - - value_type operator() (value_double lhs, value_integer rhs) const - { - return lhs * rhs; - } - - value_type operator() (value_integer lhs, value_double rhs) const - { - return lhs * rhs; - } - - value_type operator() (value_bool, value_bool) const - { - return value_integer(0); - } -}; - -template -struct div -{ - using value_type = V; - template - value_type operator() (T1 const& lhs, T2 const&) const - { - return lhs; - } - - template - value_type operator() (T lhs, T rhs) const - { - if (rhs == 0) return value_type(); - return lhs / rhs; - } - - value_type operator() (value_bool, value_bool) const - { - return false; - } - - value_type operator() (value_unicode_string const&, - value_unicode_string const&) const - { - return value_type(); - } - - value_type operator() (value_double lhs, value_integer rhs) const - { - if (rhs == 0) return value_type(); - return lhs / rhs; - } - - value_type operator() (value_integer lhs, value_double rhs) const - { - if (rhs == 0) return value_type(); - return lhs / rhs; - } -}; - -template -struct mod -{ - using value_type = V; - template - value_type operator() (T1 const& lhs, T2 const&) const - { - return lhs; - } - - template - value_type operator() (T lhs, T rhs) const - { - return lhs % rhs; - } - - value_type operator() (value_unicode_string const&, - value_unicode_string const&) const - { - return value_type(); - } - - value_type operator() (value_bool, - value_bool) const - { - return false; - } - - value_type operator() (value_double lhs, value_integer rhs) const - { - return std::fmod(lhs, static_cast(rhs)); - } - - value_type operator() (value_integer lhs, value_double rhs) const - { - return std::fmod(static_cast(lhs), rhs); - } - - value_type operator() (value_double lhs, value_double rhs) const - { - return std::fmod(lhs, rhs); - } -}; - -template -struct negate -{ - using value_type = V; - - template - value_type operator() (T val) const - { - return -val; - } - - value_type operator() (value_null val) const - { - return val; - } - - value_type operator() (value_bool val) const - { - return val ? value_integer(-1) : value_integer(0); - } - - value_type operator() (value_unicode_string const&) const - { - return value_type(); - } -}; - -// converters -template -struct convert {}; - -template <> -struct convert -{ - value_bool operator() (value_bool val) const - { - return val; - } - - value_bool operator() (value_unicode_string const& ustr) const - { - return !ustr.isEmpty(); - } - - value_bool operator() (value_null const&) const - { - return false; - } - - template - value_bool operator() (T val) const - { - return val > 0 ? true : false; - } -}; - -template <> -struct convert -{ - value_double operator() (value_double val) const - { - return val; - } - - value_double operator() (value_integer val) const - { - return static_cast(val); - } - - value_double operator() (value_bool val) const - { - return static_cast(val); - } - - value_double operator() (std::string const& val) const - { - value_double result; - if (util::string2double(val,result)) - return result; - return 0; - } - - value_double operator() (value_unicode_string const& val) const - { - std::string utf8; - to_utf8(val,utf8); - return operator()(utf8); - } - - value_double operator() (value_null const&) const - { - return 0.0; - } -}; - -template <> -struct convert -{ - value_integer operator() (value_integer val) const - { - return val; - } - - value_integer operator() (value_double val) const - { - return static_cast(rint(val)); - } - - value_integer operator() (value_bool val) const - { - return static_cast(val); - } - - value_integer operator() (std::string const& val) const - { - value_integer result; - if (util::string2int(val,result)) - return result; - return value_integer(0); - } - - value_integer operator() (value_unicode_string const& val) const - { - std::string utf8; - to_utf8(val,utf8); - return operator()(utf8); - } - - value_integer operator() (value_null const&) const - { - return value_integer(0); - } -}; - -template <> -struct convert -{ - template - std::string operator() (T val) const - { - std::string str; - util::to_string(str, val); - return str; - } - - // specializations - std::string operator() (value_unicode_string const& val) const - { - std::string utf8; - to_utf8(val,utf8); - return utf8; - } - - std::string operator() (value_double val) const - { - std::string str; - util::to_string(str, val); // TODO set precision(16) - return str; - } - - std::string operator() (value_bool val) const - { - return val ? "true": "false"; - } - - std::string operator() (value_null const&) const - { - return ""; - } -}; - -struct to_unicode -{ - - template - value_unicode_string operator() (T val) const - { - std::string str; - util::to_string(str,val); - return value_unicode_string(str.c_str()); - } - - // specializations - value_unicode_string const& operator() (value_unicode_string const& val) const - { - return val; - } - - value_unicode_string operator() (value_double val) const - { - std::string str; - util::to_string(str,val); - return value_unicode_string(str.c_str()); - } - - value_unicode_string operator() (value_bool val) const - { - if (val) { - std::string str("true"); - return value_unicode_string(str.c_str()); - } - std::string str("false"); - return value_unicode_string(str.c_str()); - } - - value_unicode_string operator() (value_null const&) const - { - return value_unicode_string(""); - } -}; - -struct to_expression_string -{ - explicit to_expression_string(char quote = '\'') - : quote_(quote) {} - - std::string operator() (value_unicode_string const& val) const - { - std::string utf8; - to_utf8(val,utf8); - return quote_ + utf8 + quote_; - } - - std::string operator() (value_integer val) const - { - std::string output; - util::to_string(output,val); - return output; - } - - std::string operator() (value_double val) const - { - std::string output; - util::to_string(output,val); // TODO precision(16) - return output; - } - - std::string operator() (value_bool val) const - { - return val ? "true":"false"; - } - - std::string operator() (value_null const&) const - { - return "null"; - } - - const char quote_; -}; - -} // namespace impl +using value_base = util::variant; namespace value_adl_barrier { -class value : public value_base +class MAPNIK_DECL value : public value_base { - friend const value operator+(value const&,value const&); - friend const value operator-(value const&,value const&); - friend const value operator*(value const&,value const&); - friend const value operator/(value const&,value const&); - friend const value operator%(value const&,value const&); + friend MAPNIK_DECL value operator+(value const&,value const&); + friend MAPNIK_DECL value operator-(value const&,value const&); + friend MAPNIK_DECL value operator*(value const&,value const&); + friend MAPNIK_DECL value operator/(value const&,value const&); + friend MAPNIK_DECL value operator%(value const&,value const&); public: - value () noexcept //-- comment out for VC++11 - : value_base(value_null()) {} - - value (value const& other) = default; - - value( value && other) noexcept = default; + value() = default; - template - value ( T const& val) - : value_base(typename detail::mapnik_value_type::type(val)) {} - - template - value ( T && val) - : value_base(typename detail::mapnik_value_type::type(val)) {} - - value & operator=( value const& other) = default; - - bool operator==(value const& other) const - { - return util::apply_visitor(impl::equals(),*this,other); - } - - bool operator!=(value const& other) const - { - return util::apply_visitor(impl::not_equals(),*this,other); - } - - bool operator>(value const& other) const - { - return util::apply_visitor(impl::greater_than(),*this,other); - } - - bool operator>=(value const& other) const - { - return util::apply_visitor(impl::greater_or_equal(),*this,other); - } + // Conversion from type T is done via a temporary value or reference + // of type U, which is determined by mapnik_value_type_t. + // + // CAVEAT: We don't check `noexcept(conversion from T to U)`. + // But since the type U is either value_bool, value_integer, + // value_double or T &&, this conversion SHOULD NEVER throw. + template > + value(T && val) + noexcept(std::is_nothrow_constructible::value) + : value_base(U(std::forward(val))) {} + + template > + value& operator=(T && val) + noexcept(std::is_nothrow_assignable::value) + { + value_base::operator=(U(std::forward(val))); + return *this; + } + + bool operator==(value const& other) const; + bool operator!=(value const& other) const; + bool operator>(value const& other) const; + bool operator>=(value const& other) const; + bool operator<(value const& other) const; + bool operator<=(value const& other) const; - bool operator<(value const& other) const - { - return util::apply_visitor(impl::less_than(),*this,other); - } - - bool operator<=(value const& other) const - { - return util::apply_visitor(impl::less_or_equal(),*this,other); - } - - value operator- () const - { - return util::apply_visitor(impl::negate(), *this); - } + value operator-() const; bool is_null() const; - template - T convert() const - { - return util::apply_visitor(impl::convert(),*this); - } - - value_bool to_bool() const - { - return util::apply_visitor(impl::convert(),*this); - } - - std::string to_expression_string(char quote = '\'') const - { - return util::apply_visitor(impl::to_expression_string(quote),*this); - } - - std::string to_string() const - { - return util::apply_visitor(impl::convert(),*this); - } - - value_unicode_string to_unicode() const - { - return util::apply_visitor(impl::to_unicode(),*this); - } - - value_double to_double() const - { - return util::apply_visitor(impl::convert(),*this); - } + template T convert() const; - value_integer to_int() const - { - return util::apply_visitor(impl::convert(),*this); - } + value_bool to_bool() const; + std::string to_expression_string(char quote = '\'') const; + std::string to_string() const; + value_unicode_string to_unicode() const; + value_double to_double() const; + value_integer to_int() const; }; -inline const value operator+(value const& p1,value const& p2) -{ - return value(util::apply_visitor(impl::add(),p1, p2)); -} - -inline const value operator-(value const& p1,value const& p2) -{ - return value(util::apply_visitor(impl::sub(),p1, p2)); -} - -inline const value operator*(value const& p1,value const& p2) -{ - return value(util::apply_visitor(impl::mult(),p1, p2)); -} - -inline const value operator/(value const& p1,value const& p2) -{ - return value(util::apply_visitor(impl::div(),p1, p2)); -} - -inline const value operator%(value const& p1,value const& p2) -{ - return value(util::apply_visitor(impl::mod(),p1, p2)); -} +MAPNIK_DECL value operator+(value const& p1,value const& p2); +MAPNIK_DECL value operator-(value const& p1,value const& p2); +MAPNIK_DECL value operator*(value const& p1,value const& p2); +MAPNIK_DECL value operator/(value const& p1,value const& p2); +MAPNIK_DECL value operator%(value const& p1,value const& p2); template inline std::basic_ostream& @@ -1027,36 +110,28 @@ } // namespace value_adl_barrier -using value_adl_barrier::value; +using value = value_adl_barrier::value; namespace detail { - struct is_null_visitor { - bool operator() (value const& val) const + bool operator()(value const& val) const { return val.is_null(); } - bool operator() (value_null const&) const + bool operator()(value_null const&) const { return true; } template - bool operator() (T const&) const + bool operator()(T const&) const { return false; } }; - } // namespace detail - -inline bool value::is_null() const -{ - return util::apply_visitor(mapnik::detail::is_null_visitor(), *this); -} - } // namespace mapnik // support for std::unordered_xxx @@ -1064,6 +139,7 @@ { #pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wmismatched-tags" template <> diff -Nru mapnik-3.0.9+ds/include/mapnik/value_types.hpp mapnik-3.0.13+ds/include/mapnik/value_types.hpp --- mapnik-3.0.9+ds/include/mapnik/value_types.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/value_types.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,13 +25,16 @@ // mapnik #include +#include #include -// icu + +#pragma GCC diagnostic push +#include #include // for U_NAMESPACE_QUALIFIER +#pragma GCC diagnostic pop // stl -#include #include #include @@ -80,6 +83,26 @@ return true; } + bool operator>(value_null) const + { + return false; + } + + bool operator>=(value_null) const + { + return true; + } + + bool operator<(value_null) const + { + return false; + } + + bool operator<=(value_null) const + { + return true; + } + template value_null operator+ (T const&) const { @@ -129,83 +152,23 @@ namespace detail { -// to mapnik::value_type conversions traits -template -struct is_value_bool -{ - constexpr static bool value = std::is_same::value; -}; -template -struct is_value_integer -{ - constexpr static bool value = std::is_integral::value && !std::is_same::value; -}; - -template -struct is_value_double -{ - constexpr static bool value = std::is_floating_point::value; -}; - -template -struct is_value_unicode_string -{ - constexpr static bool value = std::is_same::value; -}; - -template -struct is_value_string -{ - constexpr static bool value = std::is_same::value; -}; - -template -struct is_value_null -{ - constexpr static bool value = std::is_same::value; -}; - -template -struct mapnik_value_type -{ - using type = T; -}; - -// value_null -template -struct mapnik_value_type::value>::type> -{ - using type = mapnik::value_null; -}; - -// value_bool -template -struct mapnik_value_type::value>::type> -{ - using type = mapnik::value_bool; -}; - -// value_integer -template -struct mapnik_value_type::value>::type> -{ - using type = mapnik::value_integer; -}; - -// value_double -template -struct mapnik_value_type::value>::type> -{ - using type = mapnik::value_double; -}; - -// value_unicode_string -template -struct mapnik_value_type::value>::type> -{ - using type = mapnik::value_unicode_string const&; -}; +// Helper metafunction for mapnik::value construction and assignment. +// Returns: +// value_bool if T is bool +// value_integer if T is an integral type (except bool) +// value_double if T is a floating-point type +// T && otherwise + +template > +using mapnik_value_type_t = + conditional_t< + std::is_same::value, value_bool, + conditional_t< + std::is_integral
::value, value_integer, + conditional_t< + std::is_floating_point
::value, value_double, + T && >>>; } // namespace detail diff -Nru mapnik-3.0.9+ds/include/mapnik/version.hpp mapnik-3.0.13+ds/include/mapnik/version.hpp --- mapnik-3.0.9+ds/include/mapnik/version.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/version.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,17 +23,14 @@ #ifndef MAPNIK_VERSION_HPP #define MAPNIK_VERSION_HPP +#include + #define MAPNIK_MAJOR_VERSION 3 #define MAPNIK_MINOR_VERSION 0 -#define MAPNIK_PATCH_VERSION 9 +#define MAPNIK_PATCH_VERSION 13 #define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION) -#ifndef MAPNIK_STRINGIFY -#define MAPNIK_STRINGIFY(n) MAPNIK_STRINGIFY_HELPER(n) -#define MAPNIK_STRINGIFY_HELPER(n) #n -#endif - #define MAPNIK_VERSION_STRING MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \ MAPNIK_STRINGIFY(MAPNIK_MINOR_VERSION) "." \ MAPNIK_STRINGIFY(MAPNIK_PATCH_VERSION) diff -Nru mapnik-3.0.9+ds/include/mapnik/vertex_adapters.hpp mapnik-3.0.13+ds/include/mapnik/vertex_adapters.hpp --- mapnik-3.0.9+ds/include/mapnik/vertex_adapters.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/vertex_adapters.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -32,34 +32,12 @@ template struct point_vertex_adapter { - using value_type = typename point::value_type; - - point_vertex_adapter(point const& pt) - : pt_(pt), - first_(true) {} - - unsigned vertex(value_type * x, value_type * y) const - { - if (first_) - { - *x = pt_.x; - *y = pt_.y; - first_ = false; - return mapnik::SEG_MOVETO; - } - return mapnik::SEG_END; - } - - void rewind(unsigned) const - { - first_ = true; - } - - inline geometry_types type () const - { - return geometry_types::Point; - } + using coord_type = typename point::coord_type; + point_vertex_adapter(point const& pt); + unsigned vertex(coord_type * x, coord_type * y) const; + void rewind(unsigned) const; + geometry_types type () const; point const& pt_; mutable bool first_; }; @@ -67,111 +45,24 @@ template struct line_string_vertex_adapter { - using value_type = typename point::value_type; - line_string_vertex_adapter(line_string const& line) - : line_(line), - current_index_(0), - end_index_(line.size()) - {} - - unsigned vertex(value_type * x, value_type * y) const - { - if (current_index_ != end_index_) - { - point const& coord = line_[current_index_++]; - *x = coord.x; - *y = coord.y; - if (current_index_ == 1) - { - return mapnik::SEG_MOVETO; - } - else - { - return mapnik::SEG_LINETO; - } - } - return mapnik::SEG_END; - } - - void rewind(unsigned) const - { - current_index_ = 0; - } - - inline geometry_types type () const - { - return geometry_types::LineString; - } - + using coord_type = typename point::coord_type; + line_string_vertex_adapter(line_string const& line); + unsigned vertex(coord_type * x, coord_type * y) const; + void rewind(unsigned) const; + geometry_types type () const; line_string const& line_; mutable std::size_t current_index_; - const std::size_t end_index_; - + const std::size_t end_index_; }; template struct polygon_vertex_adapter { - using value_type = typename point::value_type; - polygon_vertex_adapter(polygon const& poly) - : poly_(poly), - rings_itr_(0), - rings_end_(poly_.interior_rings.size() + 1), - current_index_(0), - end_index_((rings_itr_ < rings_end_) ? poly_.exterior_ring.size() : 0), - start_loop_(true) {} - - void rewind(unsigned) const - { - rings_itr_ = 0; - rings_end_ = poly_.interior_rings.size() + 1; - current_index_ = 0; - end_index_ = (rings_itr_ < rings_end_) ? poly_.exterior_ring.size() : 0; - start_loop_ = true; - } - - unsigned vertex(value_type * x, value_type * y) const - { - if (rings_itr_ == rings_end_) - { - return mapnik::SEG_END; - } - if (current_index_ < end_index_) - { - point const& coord = (rings_itr_ == 0) ? - poly_.exterior_ring[current_index_++] : poly_.interior_rings[rings_itr_- 1][current_index_++]; - *x = coord.x; - *y = coord.y; - if (start_loop_) - { - start_loop_= false; - return mapnik::SEG_MOVETO; - } - if (current_index_ == end_index_) - { - *x = 0; - *y = 0; - return mapnik::SEG_CLOSE; - } - return mapnik::SEG_LINETO; - } - else if (++rings_itr_ != rings_end_) - { - current_index_ = 0; - end_index_ = poly_.interior_rings[rings_itr_ - 1].size(); - point const& coord = poly_.interior_rings[rings_itr_ - 1][current_index_++]; - *x = coord.x; - *y = coord.y; - return mapnik::SEG_MOVETO; - } - return mapnik::SEG_END; - } - - inline geometry_types type () const - { - return geometry_types::Polygon; - } - + using coord_type = typename point::coord_type; + polygon_vertex_adapter(polygon const& poly); + void rewind(unsigned) const; + unsigned vertex(coord_type * x, coord_type * y) const; + geometry_types type () const; private: polygon const& poly_; mutable std::size_t rings_itr_; @@ -184,48 +75,11 @@ template struct ring_vertex_adapter { - using value_type = typename point::value_type; - ring_vertex_adapter(linear_ring const& ring) - : ring_(ring), - current_index_(0), - end_index_(ring_.size()), - start_loop_(true) {} - - void rewind(unsigned) const - { - current_index_ = 0; - end_index_ = ring_.size(); - start_loop_ = true; - } - - unsigned vertex(value_type * x, value_type * y) const - { - if (current_index_ < end_index_) - { - auto const& coord = ring_[current_index_++]; - *x = coord.x; - *y = coord.y; - if (start_loop_) - { - start_loop_= false; - return mapnik::SEG_MOVETO; - } - if (current_index_ == end_index_) - { - *x = 0; - *y = 0; - return mapnik::SEG_CLOSE; - } - return mapnik::SEG_LINETO; - } - return mapnik::SEG_END; - } - - inline geometry_types type () const - { - return geometry_types::Polygon; - } - + using coord_type = typename point::coord_type; + ring_vertex_adapter(linear_ring const& ring); + void rewind(unsigned) const; + unsigned vertex(coord_type * x, coord_type * y) const; + geometry_types type () const; private: linear_ring const& ring_; mutable std::size_t current_index_; @@ -233,6 +87,11 @@ mutable bool start_loop_; }; +extern template struct MAPNIK_DECL point_vertex_adapter; +extern template struct MAPNIK_DECL line_string_vertex_adapter; +extern template struct MAPNIK_DECL polygon_vertex_adapter; +extern template struct MAPNIK_DECL ring_vertex_adapter; + template struct vertex_adapter_traits {}; diff -Nru mapnik-3.0.9+ds/include/mapnik/vertex_cache.hpp mapnik-3.0.13+ds/include/mapnik/vertex_cache.hpp --- mapnik-3.0.9+ds/include/mapnik/vertex_cache.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/vertex_cache.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,8 +28,10 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_basics.h" +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/include/mapnik/vertex_converters.hpp mapnik-3.0.13+ds/include/mapnik/vertex_converters.hpp --- mapnik-3.0.9+ds/include/mapnik/vertex_converters.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/vertex_converters.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -37,7 +37,8 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_math_stroke.h" #include "agg_trans_affine.h" #include "agg_conv_clip_polygon.h" @@ -46,6 +47,7 @@ #include "agg_conv_stroke.h" #include "agg_conv_dash.h" #include "agg_conv_transform.h" +#pragma GCC diagnostic pop // stl #include @@ -275,7 +277,7 @@ struct converters_helper; template -struct converters_helper +struct converters_helper { template static void set(Dispatcher & disp, std::size_t state) diff -Nru mapnik-3.0.9+ds/include/mapnik/vertex.hpp mapnik-3.0.13+ds/include/mapnik/vertex.hpp --- mapnik-3.0.9+ds/include/mapnik/vertex.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/vertex.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -61,29 +61,12 @@ vertex(coord_type x_,coord_type y_,unsigned cmd_) : x(x_),y(y_),cmd(cmd_) {} - vertex(vertex && rhs) noexcept - : x(std::move(rhs.x)), - y(std::move(rhs.y)), - cmd(std::move(rhs.cmd)) {} - - vertex(vertex const& rhs) - : x(rhs.x), - y(rhs.y), - cmd(rhs.cmd) {} - template vertex(vertex const& rhs) : x(coord_type(rhs.x)), y(coord_type(rhs.y)), cmd(rhs.cmd) {} - - vertex& operator=(vertex rhs) - { - swap(rhs); - return *this; - } - template vertex& operator=(vertex const& rhs) { diff -Nru mapnik-3.0.9+ds/include/mapnik/vertex_processor.hpp mapnik-3.0.13+ds/include/mapnik/vertex_processor.hpp --- mapnik-3.0.9+ds/include/mapnik/vertex_processor.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/vertex_processor.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -35,38 +35,38 @@ : proc_(proc) {} template - void operator() (Geometry const& geom) + void operator() (Geometry const& geom) const { util::apply_visitor(*this, geom); } - void operator() (geometry_empty const&) + void operator() (geometry_empty const&) const { // no-op } - + template - void operator() (point const& pt) + void operator() (point const& pt) const { point_vertex_adapter va(pt); proc_(va); } template - void operator() (line_string const& line) + void operator() (line_string const& line) const { line_string_vertex_adapter va(line); proc_(va); } template - void operator() (polygon const& poly) + void operator() (polygon const& poly) const { polygon_vertex_adapter va(poly); proc_(va); } template - void operator() (multi_point const& multi_pt) + void operator() (multi_point const& multi_pt) const { for (auto const& pt : multi_pt) { @@ -76,7 +76,7 @@ } template - void operator() (multi_line_string const& multi_line) + void operator() (multi_line_string const& multi_line) const { for (auto const& line : multi_line) { @@ -86,7 +86,7 @@ } template - void operator() (multi_polygon const& multi_poly) + void operator() (multi_polygon const& multi_poly) const { for ( auto const& poly : multi_poly) { @@ -96,7 +96,7 @@ } template - void operator() (geometry_collection const& collection) + void operator() (geometry_collection const& collection) const { for (auto const& geom : collection) { diff -Nru mapnik-3.0.9+ds/include/mapnik/view_transform.hpp mapnik-3.0.13+ds/include/mapnik/view_transform.hpp --- mapnik-3.0.9+ds/include/mapnik/view_transform.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/view_transform.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -44,15 +44,15 @@ int offset_; public: - view_transform(int width, int height, box2d const& extent, - double offset_x = 0.0, double offset_y = 0.0) - : width_(width), - height_(height), - extent_(extent), + view_transform(int _width, int _height, box2d const& _extent, + double _offset_x = 0.0, double _offset_y = 0.0) + : width_(_width), + height_(_height), + extent_(_extent), sx_(extent_.width() > 0 ? static_cast(width_) / extent_.width() : 1.0), sy_(extent_.height() > 0 ? static_cast(height_) / extent_.height() : 1.0), - offset_x_(offset_x), - offset_y_(offset_y), + offset_x_(_offset_x), + offset_y_(_offset_y), offset_(0) {} view_transform(view_transform const&) = default; @@ -62,9 +62,9 @@ return offset_; } - inline void set_offset(int offset) + inline void set_offset(int _offset) { - offset_ = offset; + offset_ = _offset; } inline double offset_x() const diff -Nru mapnik-3.0.9+ds/include/mapnik/warning_ignore_agg.hpp mapnik-3.0.13+ds/include/mapnik/warning_ignore_agg.hpp --- mapnik-3.0.9+ds/include/mapnik/warning_ignore_agg.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/warning_ignore_agg.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,32 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + * + *****************************************************************************/ + + +#pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc +#pragma GCC diagnostic ignored "-Wpragmas" // gcc +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wpadded" +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wshadow" + diff -Nru mapnik-3.0.9+ds/include/mapnik/warning_ignore.hpp mapnik-3.0.13+ds/include/mapnik/warning_ignore.hpp --- mapnik-3.0.9+ds/include/mapnik/warning_ignore.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/warning_ignore.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -22,15 +22,35 @@ #pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc -#pragma GCC diagnostic ignored "-Wno-unknown-pragmas" // clang -#pragma GCC diagnostic ignored "-Wno-pragmas" // gcc -#pragma GCC diagnostic ignored "-Wno-unsequenced" +#pragma GCC diagnostic ignored "-Wpragmas" // gcc +#pragma GCC diagnostic ignored "-W#pragma-messages" +#pragma GCC diagnostic ignored "-Wunsequenced" #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wredeclared-class-member" -#pragma GCC diagnostic ignored "-Wunused-local-typedef" +#pragma GCC diagnostic ignored "-Wunused-local-typedef" +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" // gcc5 #pragma GCC diagnostic ignored "-Wshadow" #pragma GCC diagnostic ignored "-Wc++11-narrowing" #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic ignored "-Wsign-compare" -#pragma GCC diagnostic ignored "-Wconversion" \ No newline at end of file +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" +#pragma GCC diagnostic ignored "-Wdisabled-macro-expansion" +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wdocumentation" +#pragma GCC diagnostic ignored "-Wdocumentation-unknown-command" +#pragma GCC diagnostic ignored "-Wundef" +#pragma GCC diagnostic ignored "-Wdeprecated" +#pragma GCC diagnostic ignored "-Wpadded" +#pragma GCC diagnostic ignored "-Wc++98-compat" +#pragma GCC diagnostic ignored "-Wreserved-id-macro" +#pragma GCC diagnostic ignored "-Wweak-vtables" +#pragma GCC diagnostic ignored "-Wextra-semi" +#pragma GCC diagnostic ignored "-Wglobal-constructors" +#pragma GCC diagnostic ignored "-Wheader-hygiene" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#pragma GCC diagnostic ignored "-Wmissing-noreturn" +#pragma GCC diagnostic ignored "-Wcovered-switch-default" +#pragma GCC diagnostic ignored "-Wfloat-equal" diff -Nru mapnik-3.0.9+ds/include/mapnik/well_known_srs.hpp mapnik-3.0.13+ds/include/mapnik/well_known_srs.hpp --- mapnik-3.0.9+ds/include/mapnik/well_known_srs.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/well_known_srs.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,8 +28,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl #include @@ -63,7 +65,8 @@ static inline bool lonlat2merc(double * x, double * y , int point_count) { - for(int i=0; i 180) x[i] = 180; else if (x[i] < -180) x[i] = -180; if (y[i] > MAX_LATITUDE) y[i] = MAX_LATITUDE; diff -Nru mapnik-3.0.9+ds/include/mapnik/wkb.hpp mapnik-3.0.13+ds/include/mapnik/wkb.hpp --- mapnik-3.0.9+ds/include/mapnik/wkb.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/wkb.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,6 +24,7 @@ #define MAPNIK_WKB_HPP // mapnik +#include #include #include @@ -59,9 +60,11 @@ { public: - static mapnik::geometry::geometry from_wkb(const char* wkb, - std::size_t size, - wkbFormat format = wkbGeneric); + static geometry::geometry from_wkb(char const* wkb, + std::size_t size, + wkbFormat format = wkbGeneric); + + static geometry::geometry from_twkb(char const* twkb, std::size_t size); }; } diff -Nru mapnik-3.0.9+ds/include/mapnik/wkt/wkt_generator_grammar.hpp mapnik-3.0.13+ds/include/mapnik/wkt/wkt_generator_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/wkt/wkt_generator_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/wkt/wkt_generator_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,7 +27,6 @@ #include #include #include -#include #pragma GCC diagnostic push #include @@ -105,7 +104,7 @@ struct wkt_generator_grammar : karma::grammar { - using coord_type = typename Geometry::value_type; + using coord_type = typename Geometry::coord_type; wkt_generator_grammar(); // rules karma::rule geometry; diff -Nru mapnik-3.0.9+ds/include/mapnik/wkt/wkt_generator_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/wkt/wkt_generator_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/wkt/wkt_generator_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/wkt/wkt_generator_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -20,11 +20,15 @@ * *****************************************************************************/ -#include +// mapnik #include #include -// boost +#include + +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { namespace wkt { diff -Nru mapnik-3.0.9+ds/include/mapnik/wkt/wkt_grammar.hpp mapnik-3.0.13+ds/include/mapnik/wkt/wkt_grammar.hpp --- mapnik-3.0.9+ds/include/mapnik/wkt/wkt_grammar.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/wkt/wkt_grammar.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,9 +24,8 @@ #define MAPNIK_WKT_GRAMMAR_HPP // mapnik +#include #include -#include - #pragma GCC diagnostic push #include #include diff -Nru mapnik-3.0.9+ds/include/mapnik/wkt/wkt_grammar_impl.hpp mapnik-3.0.13+ds/include/mapnik/wkt/wkt_grammar_impl.hpp --- mapnik-3.0.9+ds/include/mapnik/wkt/wkt_grammar_impl.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/wkt/wkt_grammar_impl.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -20,14 +20,18 @@ * *****************************************************************************/ -#include #include +#include + +#pragma GCC diagnostic push +#include #include #include #include #include #include #include +#pragma GCC diagnostic pop namespace mapnik { namespace wkt { diff -Nru mapnik-3.0.9+ds/include/mapnik/xml_attribute_cast.hpp mapnik-3.0.13+ds/include/mapnik/xml_attribute_cast.hpp --- mapnik-3.0.9+ds/include/mapnik/xml_attribute_cast.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/xml_attribute_cast.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -55,7 +55,7 @@ { static inline boost::optional xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& /*source*/) { - std::string err_msg("No conversion from std::string to"); + std::string err_msg("No conversion from std::string to "); err_msg += std::string(typeid(T).name()); throw std::runtime_error(err_msg); } @@ -74,6 +74,19 @@ } }; +// specialization for mapnik::value_bool +template <> +struct do_xml_attribute_cast +{ + static inline boost::optional xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source) + { + bool result; + if (mapnik::util::string2bool(source, result)) + return boost::optional(result); + return boost::optional(); + } +}; + // specialization for int template <> struct do_xml_attribute_cast diff -Nru mapnik-3.0.9+ds/include/mapnik/xml_node.hpp mapnik-3.0.13+ds/include/mapnik/xml_node.hpp --- mapnik-3.0.9+ds/include/mapnik/xml_node.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/include/mapnik/xml_node.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,8 +26,10 @@ //mapnik #include // for MAPNIK_DECL -//boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop //stl #include diff -Nru mapnik-3.0.9+ds/INSTALL.md mapnik-3.0.13+ds/INSTALL.md --- mapnik-3.0.9+ds/INSTALL.md 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/INSTALL.md 2017-02-08 13:06:42.000000000 +0000 @@ -2,6 +2,13 @@ Mapnik runs on Linux, OS X, Windows, and BSD systems. +First clone mapnik from github and initialize submodules + +```bash +git clone https://github.com/mapnik/mapnik.git +git submodule update --init +``` + To configure and build Mapnik do: ```bash @@ -35,7 +42,6 @@ Then to run the tests locally (without needing to install): - git submodule update --init make test Install like: @@ -92,7 +98,7 @@ * PostgreSQL (for PostGIS plugin support) - libpq - PostreSQL libraries - pg_config - PostgreSQL installation capabilities - * libgdal - GDAL/OGR input (For gdal and ogr plugin support) + * libgdal - GDAL/OGR input (For gdal and ogr plugin support) (>= GDAL 2.0.2 for thread safety - https://github.com/mapnik/mapnik/issues/3339) * libsqlite3 - SQLite input (needs RTree support builtin) (sqlite plugin support) Instructions for installing many of these dependencies on diff -Nru mapnik-3.0.9+ds/localize.sh mapnik-3.0.13+ds/localize.sh --- mapnik-3.0.9+ds/localize.sh 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/localize.sh 2017-02-08 13:06:42.000000000 +0000 @@ -1,15 +1,18 @@ #!/bin/bash + # TODO - use rpath to avoid needing this to run tests locally + export CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -if [ $(uname -s) = 'Darwin' ]; then - export DYLD_LIBRARY_PATH="${CURRENT_DIR}/src/":${DYLD_LIBRARY_PATH} -else - export LD_LIBRARY_PATH="${CURRENT_DIR}/src/":${LD_LIBRARY_PATH} +if [[ $(uname -s) == 'Darwin' ]]; then + export DYLD_LIBRARY_PATH="${CURRENT_DIR}/src/":${DYLD_LIBRARY_PATH:-""} +elif [[ $(uname -s) == 'Linux' ]]; then + export LD_LIBRARY_PATH="${CURRENT_DIR}/src/":${LD_LIBRARY_PATH:-""} fi export PATH=$(pwd)/utils/mapnik-render/:${PATH} export PATH=$(pwd)/utils/mapnik-index/:${PATH} export PATH=$(pwd)/utils/mapnik-config/:${PATH} +export PATH=$(pwd)/utils/shapeindex/:${PATH} # mapnik-settings.env is an optional file to store # environment variables that should be used before diff -Nru mapnik-3.0.9+ds/Makefile mapnik-3.0.13+ds/Makefile --- mapnik-3.0.9+ds/Makefile 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/Makefile 2017-02-08 13:06:42.000000000 +0000 @@ -7,29 +7,20 @@ JOBS:=1 endif +ifeq ($(HEAVY_JOBS),) + HEAVY_JOBS:=1 +endif + all: mapnik install: $(PYTHON) scons/scons.py -j$(JOBS) --config=cache --implicit-cache --max-drift=1 install release: - export MAPNIK_VERSION=$(shell ./utils/mapnik-config/mapnik-config --version) && \ - export TARBALL_NAME="mapnik-v$${MAPNIK_VERSION}" && \ - cd /tmp/ && \ - rm -rf $${TARBALL_NAME} && \ - git clone --depth 1 --branch v$${MAPNIK_VERSION} git@github.com:mapnik/mapnik.git $${TARBALL_NAME} && \ - cd $${TARBALL_NAME} && \ - git checkout "tags/v$${MAPNIK_VERSION}" && \ - git submodule update --depth 1 --init && \ - rm -rf test/data/.git && \ - rm -rf test/data/.gitignore && \ - rm -rf test/data-visual/.git && \ - rm -rf test/data-visual/.gitignore && \ - rm -rf .git && \ - rm -rf .gitignore && \ - cd ../ && \ - tar cjf $${TARBALL_NAME}.tar.bz2 $${TARBALL_NAME}/ && \ - aws s3 cp --acl public-read $${TARBALL_NAME}.tar.bz2 s3://mapnik/dist/v$${MAPNIK_VERSION}/ + ./scripts/publish_release.sh + +test-release: + ./scripts/test_release.sh python: if [ ! -d ./bindings/python ]; then git clone git@github.com:mapnik/python-mapnik.git --recursive ./bindings/python; else (cd bindings/python && git pull && git submodule update --init); fi; @@ -37,22 +28,28 @@ python bindings/python/test/visual.py -q src/json/libmapnik-json.a: - # we first build memory intensive files with -j1 - $(PYTHON) scons/scons.py -j1 \ + # we first build memory intensive files with -j$(HEAVY_JOBS) + $(PYTHON) scons/scons.py -j$(HEAVY_JOBS) \ --config=cache --implicit-cache --max-drift=1 \ - src/renderer_common/process_group_symbolizer.os \ + src/renderer_common/render_group_symbolizer.os \ + src/renderer_common/render_markers_symbolizer.os \ + src/renderer_common/render_thunk_extractor.os \ src/json/libmapnik-json.a \ src/wkt/libmapnik-wkt.a \ src/css_color_grammar.os \ src/expression_grammar.os \ src/transform_expression_grammar.os \ - src/image_filter_types.os \ - src/agg/process_markers_symbolizer.os \ - src/agg/process_group_symbolizer.os \ - src/grid/process_markers_symbolizer.os \ - src/grid/process_group_symbolizer.os \ - src/cairo/process_markers_symbolizer.os \ - src/cairo/process_group_symbolizer.os \ + src/image_filter_grammar.os \ + src/marker_helpers.os \ + src/svg/svg_transform_parser.os \ + src/agg/process_line_symbolizer.os \ + plugins/input/geojson/geojson_datasource.os \ + utils/mapnik-index/process_geojson_file.o \ + src/svg/svg_path_parser.os \ + src/svg/svg_parser.os \ + src/svg/svg_points_parser.os \ + src/svg/svg_transform_parser.os \ + mapnik: src/json/libmapnik-json.a # then install the rest with -j$(JOBS) @@ -70,6 +67,8 @@ @find ./src/ -name "*.so" -exec rm {} \; @find ./ -name "*.o" -exec rm {} \; @find ./src/ -name "*.a" -exec rm {} \; + @find ./ -name "*.gcda" -exec rm {} \; + @find ./ -name "*.gcno" -exec rm {} \; distclean: if test -e "config.py"; then mv "config.py" "config.py.backup"; fi @@ -82,10 +81,13 @@ uninstall: @$(PYTHON) scons/scons.py -j$(JOBS) --config=cache --implicit-cache --max-drift=1 uninstall +test/data-visual: + ./scripts/ensure_test_data.sh + test/data: - git submodule update --init + ./scripts/ensure_test_data.sh -test: ./test/data +test: ./test/data test/data-visual @./test/run check: test diff -Nru mapnik-3.0.9+ds/mason_latest.sh mapnik-3.0.13+ds/mason_latest.sh --- mapnik-3.0.9+ds/mason_latest.sh 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/mason_latest.sh 2017-02-08 13:06:42.000000000 +0000 @@ -4,7 +4,11 @@ MASON_VERSION=latest MASON_LIB_FILE=lib/libmapnik-wkt.a -. ${MASON_DIR:-~/.mason}/mason.sh +# warning: may break when https://github.com/mapbox/mason/issues/141 lands +# hence we are pinned for now to older mason in bootstrap.sh +. ./.mason/mason.sh + +set -eu function mason_load_source { export MASON_BUILD_PATH=$(pwd) @@ -13,30 +17,47 @@ function mason_compile { HERE=$(pwd) make install - if [[ `uname` == 'Darwin' ]]; then - install_name_tool -id @loader_path/libmapnik.dylib ${MASON_PREFIX}"/lib/libmapnik.dylib"; + # this is to adapt to when mapnik is not installed in MASON_PREFIX + # originally (to make it easier to publish locally as a stopgap) + MAPNIK_PREFIX=$(mapnik-config --prefix) + if [[ ${MAPNIK_PREFIX} != ${MASON_PREFIX} ]]; then + mkdir -p ${MASON_PREFIX}/lib + mkdir -p ${MASON_PREFIX}/include + mkdir -p ${MASON_PREFIX}/bin + cp -r ${MAPNIK_PREFIX}/lib/*mapnik* ${MASON_PREFIX}/lib/ + cp -r ${MAPNIK_PREFIX}/include/mapnik ${MASON_PREFIX}/include/ + cp -r ${MAPNIK_PREFIX}/bin/mapnik* ${MASON_PREFIX}/bin/ + cp -r ${MAPNIK_PREFIX}/bin/shapeindex ${MASON_PREFIX}/bin/ + fi + if [[ $(uname -s) == 'Darwin' ]]; then + install_name_tool -id @loader_path/lib/libmapnik.dylib ${MASON_PREFIX}"/lib/libmapnik.dylib"; PLUGINDIR=${MASON_PREFIX}"/lib/mapnik/input/*.input"; for f in $PLUGINDIR; do echo $f; - echo `basename $f`; - install_name_tool -id plugins/input/`basename $f` $f; - install_name_tool -change ${MASON_PREFIX}"/lib/libmapnik.dylib" @loader_path/../../libmapnik.dylib $f; + echo $(basename $f); + install_name_tool -id plugins/input/$(basename $f) $f; + install_name_tool -change "${MAPNIK_PREFIX}/lib/libmapnik.dylib" @loader_path/../../lib/libmapnik.dylib $f; + done; + BINDIR=${MASON_PREFIX}"/bin/*"; + for f in $BINDIR; do + echo $f; + echo $(basename $f); + if [[ $(file $f) =~ 'Mach-O' ]]; then + install_name_tool -id bin/$(basename $f) $f; + install_name_tool -change "${MAPNIK_PREFIX}/lib/libmapnik.dylib" @loader_path/../lib/libmapnik.dylib $f; + fi done; fi; python -c "data=open('$MASON_PREFIX/bin/mapnik-config','r').read();open('$MASON_PREFIX/bin/mapnik-config','w').write(data.replace('$HERE','.'))" - mkdir -p ${MASON_PREFIX}/share/icu - cp -r $GDAL_DATA ${MASON_PREFIX}/share/ - cp -r $PROJ_LIB ${MASON_PREFIX}/share/ - cp -r $ICU_DATA/*dat ${MASON_PREFIX}/share/icu/ find ${MASON_PREFIX} -name "*.pyc" -exec rm {} \; } function mason_cflags { - "" + : } function mason_ldflags { - "" + : } function mason_clean { diff -Nru mapnik-3.0.9+ds/plugins/input/csv/build.py mapnik-3.0.13+ds/plugins/input/csv/build.py --- mapnik-3.0.9+ds/plugins/input/csv/build.py 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/build.py 2017-02-08 13:06:42.000000000 +0000 @@ -39,6 +39,7 @@ plugin_sources = Split( """ + %(PLUGIN_NAME)s_utils.cpp %(PLUGIN_NAME)s_datasource.cpp %(PLUGIN_NAME)s_featureset.cpp %(PLUGIN_NAME)s_inline_featureset.cpp diff -Nru mapnik-3.0.9+ds/plugins/input/csv/csv_datasource.cpp mapnik-3.0.13+ds/plugins/input/csv/csv_datasource.cpp --- mapnik-3.0.9+ds/plugins/input/csv/csv_datasource.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/csv_datasource.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -21,6 +21,7 @@ *****************************************************************************/ #include "csv_utils.hpp" +#include "csv_getline.hpp" #include "csv_datasource.hpp" #include "csv_featureset.hpp" #include "csv_inline_featureset.hpp" @@ -36,9 +37,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #if defined(MAPNIK_MEMORY_MAPPED_FILE) @@ -65,21 +69,13 @@ csv_datasource::csv_datasource(parameters const& params) : datasource(params), desc_(csv_datasource::name(), *params.get("encoding", "utf-8")), - extent_(), - filename_(), - row_limit_(*params.get("row_limit", 0)), - inline_string_(), - separator_(0), - quote_(0), - headers_(), - manual_headers_(mapnik::util::trim_copy(*params.get("headers", ""))), - strict_(*params.get("strict", false)), ctx_(std::make_shared()), - extent_initialized_(false), - tree_(nullptr), - locator_(), - has_disk_index_(false) + tree_(nullptr) { + row_limit_ = *params.get("row_limit", 0); + manual_headers_ = mapnik::util::trim_copy(*params.get("headers", "")); + strict_ = *params.get("strict", false); + auto quote_param = params.get("quote"); if (quote_param) { @@ -170,288 +166,89 @@ csv_datasource::~csv_datasource() {} -template -void csv_datasource::parse_csv(T & stream) +void csv_datasource::parse_csv(std::istream & csv_file) { - auto file_length = detail::file_length(stream); - // set back to start - stream.seekg(0, std::ios::beg); - char newline; - bool has_newline; - char detected_quote; - std::tie(newline, has_newline, detected_quote) = detail::autodect_newline_and_quote(stream, file_length); - if (quote_ == 0) quote_ = detected_quote; - // set back to start - stream.seekg(0, std::ios::beg); - std::string csv_line; - csv_utils::getline_csv(stream, csv_line, newline, quote_); - if (separator_ == 0) - { - separator_ = detail::detect_separator(csv_line); - } - - MAPNIK_LOG_DEBUG(csv) << "csv_datasource: separator: '" << separator_ - << "' quote: '" << quote_ << "'"; - stream.seekg(0, std::ios::beg); - - int line_number = 0; - if (!manual_headers_.empty()) - { - std::size_t index = 0; - auto headers = csv_utils::parse_line(manual_headers_, separator_, quote_); - for (auto const& header : headers) - { - detail::locate_geometry_column(header, index++, locator_); - headers_.push_back(header); - } - } - else // parse first line as headers - { - while (csv_utils::getline_csv(stream, csv_line, newline, quote_)) - { - try - { - auto headers = csv_utils::parse_line(csv_line, separator_, quote_); - // skip blank lines - std::string val; - if (headers.size() > 0 && headers[0].empty()) ++line_number; - else - { - std::size_t index = 0; - for (auto const& header : headers) - { - val = mapnik::util::trim_copy(header); - if (val.empty()) - { - if (strict_) - { - std::ostringstream s; - s << "CSV Plugin: expected a column header at line "; - s << line_number << ", column " << index; - s << " - ensure this row contains valid header fields: '"; - s << csv_line; - throw mapnik::datasource_exception(s.str()); - } - else - { - // create a placeholder for the empty header - std::ostringstream s; - s << "_" << index; - headers_.push_back(s.str()); - } - } - else - { - detail::locate_geometry_column(val, index, locator_); - headers_.push_back(val); - } - ++index; - } - ++line_number; - break; - } - } - catch (std::exception const& ex) - { - std::string s("CSV Plugin: error parsing headers: "); - s += ex.what(); - throw mapnik::datasource_exception(s); - } - } - } - - std::size_t num_headers = headers_.size(); - if (!detail::valid(locator_, num_headers)) - { - std::string str("CSV Plugin: could not detect column(s) with the name(s) of wkt, geojson, x/y, or "); - str += "latitude/longitude in:\n"; - str += csv_line; - str += "\n - this is required for reading geometry data"; - throw mapnik::datasource_exception(str); - } - - mapnik::value_integer feature_count = 0; - bool extent_started = false; + std::vector boxes; + csv_utils::csv_file_parser::parse_csv_and_boxes(csv_file, boxes); std::for_each(headers_.begin(), headers_.end(), [ & ](std::string const& header){ ctx_->push(header); }); - mapnik::transcoder tr(desc_.get_encoding()); - - auto pos = stream.tellg(); - // handle rare case of a single line of data and user-provided headers - // where a lack of a newline will mean that csv_utils::getline_csv returns false - bool is_first_row = false; - - if (!has_newline) + if (!has_disk_index_) { - stream.setstate(std::ios::failbit); - pos = 0; - if (!csv_line.empty()) - { - is_first_row = true; - } + // bulk insert initialise r-tree + tree_ = std::make_unique(boxes); } +} - std::vector boxes; - while (is_first_row || csv_utils::getline_csv(stream, csv_line, newline, quote_)) +void csv_datasource::add_feature(mapnik::value_integer index, + mapnik::csv_line const & values) +{ + if (index != 1) return; + + for (std::size_t i = 0; i < values.size(); ++i) { - ++line_number; - if ((row_limit_ > 0) && (line_number > row_limit_)) - { - MAPNIK_LOG_DEBUG(csv) << "csv_datasource: row limit hit, exiting at feature: " << feature_count; - break; - } - auto record_offset = pos; - auto record_size = csv_line.length(); - pos = stream.tellg(); - is_first_row = false; + std::string const& header = headers_.at(i); + std::string value = mapnik::util::trim_copy(values[i]); + int value_length = value.length(); + if (locator_.index == i && (locator_.type == csv_utils::geometry_column_locator::WKT + || locator_.type == csv_utils::geometry_column_locator::GEOJSON)) continue; + + // First we detect likely strings, + // then try parsing likely numbers, + // then try converting to bool, + // finally falling back to string type. - // skip blank lines - if (record_size <= 10) + // An empty string or a string of "null" will be parsed + // as a string rather than a true null value. + // Likely strings are either empty values, very long values + // or values with leading zeros like 001 (which are not safe + // to assume are numbers) + + bool matched = false; + bool has_dot = value.find(".") != std::string::npos; + if (value.empty() || (value_length > 20) || (value_length > 1 && !has_dot && value[0] == '0')) { - std::string trimmed = csv_line; - boost::trim_if(trimmed,boost::algorithm::is_any_of("\",'\r\n ")); - if (trimmed.empty()) - { - MAPNIK_LOG_DEBUG(csv) << "csv_datasource: empty row encountered at line: " << line_number; - continue; - } + matched = true; + desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::String)); } - - try + else if (csv_utils::is_likely_number(value)) { - auto values = csv_utils::parse_line(csv_line, separator_, quote_); - unsigned num_fields = values.size(); - if (num_fields > num_headers || num_fields < num_headers) + bool has_e = value.find("e") != std::string::npos; + if (has_dot || has_e) { - std::ostringstream s; - s << "CSV Plugin: # of columns(" - << num_fields << ") > # of headers(" - << num_headers << ") parsed for row " << line_number; - throw mapnik::datasource_exception(s.str()); - } - - auto geom = detail::extract_geometry(values, locator_); - if (!geom.is()) - { - auto box = mapnik::geometry::envelope(geom); - boxes.emplace_back(std::move(box), make_pair(record_offset, record_size)); - if (!extent_initialized_) + double float_val = 0.0; + if (mapnik::util::string2double(value,float_val)) { - if (!extent_started) - { - extent_started = true; - extent_ = mapnik::geometry::envelope(geom); - } - else - { - extent_.expand_to_include(mapnik::geometry::envelope(geom)); - } + matched = true; + desc_.add_descriptor(mapnik::attribute_descriptor(header,mapnik::Double)); } - if (++feature_count != 1) continue; - auto beg = values.begin(); - for (std::size_t i = 0; i < num_headers; ++i) - { - std::string const& header = headers_.at(i); - std::string value = mapnik::util::trim_copy(*beg++); - int value_length = value.length(); - if (locator_.index == i && (locator_.type == detail::geometry_column_locator::WKT - || locator_.type == detail::geometry_column_locator::GEOJSON)) continue; - - // First we detect likely strings, - // then try parsing likely numbers, - // then try converting to bool, - // finally falling back to string type. - - // An empty string or a string of "null" will be parsed - // as a string rather than a true null value. - // Likely strings are either empty values, very long values - // or values with leading zeros like 001 (which are not safe - // to assume are numbers) - - bool matched = false; - bool has_dot = value.find(".") != std::string::npos; - if (value.empty() || (value_length > 20) || (value_length > 1 && !has_dot && value[0] == '0')) - { - matched = true; - desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::String)); - } - else if (csv_utils::is_likely_number(value)) - { - bool has_e = value.find("e") != std::string::npos; - if (has_dot || has_e) - { - double float_val = 0.0; - if (mapnik::util::string2double(value,float_val)) - { - matched = true; - desc_.add_descriptor(mapnik::attribute_descriptor(header,mapnik::Double)); - } - } - else - { - mapnik::value_integer int_val = 0; - if (mapnik::util::string2int(value,int_val)) - { - matched = true; - desc_.add_descriptor(mapnik::attribute_descriptor(header,mapnik::Integer)); - } - } - } - if (!matched) - { - // NOTE: we don't use mapnik::util::string2bool - // here because we don't want to treat 'on' and 'off' - // as booleans, only 'true' and 'false' - if (csv_utils::ignore_case_equal(value, "true") || csv_utils::ignore_case_equal(value, "false")) - { - desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::Boolean)); - } - else // fallback to normal string - { - desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::String)); - } - } - } - } - else - { - std::ostringstream s; - s << "CSV Plugin: expected geometry column: could not parse row " - << line_number << " " - << values.at(locator_.index) << "'"; - throw mapnik::datasource_exception(s.str()); } - } - catch (mapnik::datasource_exception const& ex ) - { - if (strict_) throw ex; else { - MAPNIK_LOG_ERROR(csv) << ex.what() << " at line: " << line_number; + mapnik::value_integer int_val = 0; + if (mapnik::util::string2int(value,int_val)) + { + matched = true; + desc_.add_descriptor(mapnik::attribute_descriptor(header,mapnik::Integer)); + } } } - catch (std::exception const& ex) + if (!matched) { - std::ostringstream s; - s << "CSV Plugin: unexpected error parsing line: " << line_number - << " - found " << headers_.size() << " with values like: " << csv_line << "\n" - << " and got error like: " << ex.what(); - if (strict_) + // NOTE: we don't use mapnik::util::string2bool + // here because we don't want to treat 'on' and 'off' + // as booleans, only 'true' and 'false' + if (csv_utils::ignore_case_equal(value, "true") || csv_utils::ignore_case_equal(value, "false")) { - throw mapnik::datasource_exception(s.str()); + desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::Boolean)); } - else + else // fallback to normal string { - MAPNIK_LOG_ERROR(csv) << s.str(); + desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::String)); } } - // return early if *.index is present - if (has_disk_index_) return; } - // bulk insert initialise r-tree - tree_ = std::make_unique(boxes); } const char * csv_datasource::name() @@ -474,8 +271,8 @@ return desc_; } -template -boost::optional csv_datasource::get_geometry_type_impl(T & stream) const +boost::optional +csv_datasource::get_geometry_type_impl(std::istream & stream) const { boost::optional result; if (tree_) @@ -496,7 +293,7 @@ try { auto values = csv_utils::parse_line(str, separator_, quote_); - auto geom = detail::extract_geometry(values, locator_); + auto geom = csv_utils::extract_geometry(values, locator_); result = mapnik::util::to_ds_type(geom); if (result) { @@ -539,7 +336,7 @@ try { auto values = csv_utils::parse_line(str, separator_, quote_); - auto geom = detail::extract_geometry(values, locator_); + auto geom = csv_utils::extract_geometry(values, locator_); result = mapnik::util::to_ds_type(geom); if (result) { @@ -634,7 +431,7 @@ return std::make_shared(filename_, filter, locator_, separator_, quote_, headers_, ctx_); } } - return mapnik::featureset_ptr(); + return mapnik::make_invalid_featureset(); } mapnik::featureset_ptr csv_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const diff -Nru mapnik-3.0.9+ds/plugins/input/csv/csv_datasource.hpp mapnik-3.0.13+ds/plugins/input/csv/csv_datasource.hpp --- mapnik-3.0.9+ds/plugins/input/csv/csv_datasource.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/csv_datasource.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -32,6 +32,7 @@ #include #include #include +#include "csv_utils.hpp" #pragma GCC diagnostic push #include @@ -41,8 +42,8 @@ #pragma GCC diagnostic pop // stl +#include #include -#include #include template @@ -67,7 +68,8 @@ }; }}}}} -class csv_datasource : public mapnik::datasource +class csv_datasource : public mapnik::datasource, + private csv_utils::csv_file_parser { public: using box_type = mapnik::box2d; @@ -84,26 +86,15 @@ mapnik::layer_descriptor get_descriptor() const; boost::optional get_geometry_type() const; private: - template - void parse_csv(T & stream); - template - boost::optional get_geometry_type_impl(T & stream) const; + void parse_csv(std::istream & ); + virtual void add_feature(mapnik::value_integer index, mapnik::csv_line const & values); + boost::optional get_geometry_type_impl(std::istream & ) const; mapnik::layer_descriptor desc_; - mapnik::box2d extent_; std::string filename_; - mapnik::value_integer row_limit_; std::string inline_string_; - char separator_; - char quote_; - std::vector headers_; - std::string manual_headers_; - bool strict_; mapnik::context_ptr ctx_; - bool extent_initialized_; std::unique_ptr tree_; - detail::geometry_column_locator locator_; - bool has_disk_index_; }; #endif // MAPNIK_CSV_DATASOURCE_HPP diff -Nru mapnik-3.0.9+ds/plugins/input/csv/csv_featureset.cpp mapnik-3.0.13+ds/plugins/input/csv/csv_featureset.cpp --- mapnik-3.0.9+ds/plugins/input/csv/csv_featureset.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/csv_featureset.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -31,7 +31,7 @@ #include #include -csv_featureset::csv_featureset(std::string const& filename, detail::geometry_column_locator const& locator, char separator, char quote, +csv_featureset::csv_featureset(std::string const& filename, locator_type const& locator, char separator, char quote, std::vector const& headers, mapnik::context_ptr const& ctx, array_type && index_array) : #if defined(MAPNIK_MEMORY_MAPPED_FILE) @@ -72,12 +72,12 @@ mapnik::feature_ptr csv_featureset::parse_feature(char const* beg, char const* end) { auto values = csv_utils::parse_line(beg, end, separator_, quote_, headers_.size()); - auto geom = detail::extract_geometry(values, locator_); + auto geom = csv_utils::extract_geometry(values, locator_); if (!geom.is()) { mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_, ++feature_id_)); feature->set_geometry(std::move(geom)); - detail::process_properties(*feature, headers_, values, locator_, tr_); + csv_utils::process_properties(*feature, headers_, values, locator_, tr_); return feature; } return mapnik::feature_ptr(); diff -Nru mapnik-3.0.9+ds/plugins/input/csv/csv_featureset.hpp mapnik-3.0.13+ds/plugins/input/csv/csv_featureset.hpp --- mapnik-3.0.9+ds/plugins/input/csv/csv_featureset.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/csv_featureset.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,7 +28,6 @@ #include "csv_utils.hpp" #include "csv_datasource.hpp" #include -#include #if defined(MAPNIK_MEMORY_MAPPED_FILE) #pragma GCC diagnostic push @@ -41,7 +40,7 @@ class csv_featureset : public mapnik::Featureset { - using locator_type = detail::geometry_column_locator; + using locator_type = csv_utils::geometry_column_locator; public: using array_type = std::deque; csv_featureset(std::string const& filename, @@ -70,7 +69,7 @@ array_type::const_iterator index_end_; mapnik::context_ptr ctx_; mapnik::value_integer feature_id_ = 0; - detail::geometry_column_locator const& locator_; + locator_type const& locator_; mapnik::transcoder tr_; }; diff -Nru mapnik-3.0.9+ds/plugins/input/csv/csv_getline.hpp mapnik-3.0.13+ds/plugins/input/csv/csv_getline.hpp --- mapnik-3.0.9+ds/plugins/input/csv/csv_getline.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/csv_getline.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,72 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_CSV_GETLINE_HPP +#define MAPNIK_CSV_GETLINE_HPP + +#include +#include +#include + +namespace csv_utils +{ + +template +std::basic_istream& getline_csv(std::istream& is, std::basic_string& s, CharT delim, CharT quote) +{ + typename std::basic_string::size_type nread = 0; + typename std::basic_istream::sentry sentry(is, true); + if (sentry) + { + std::basic_streambuf* buf = is.rdbuf(); + s.clear(); + bool has_quote = false; + while (nread < s.max_size()) + { + int c1 = buf->sbumpc(); + if (Traits::eq_int_type(c1, Traits::eof())) + { + is.setstate(std::ios_base::eofbit); + break; + } + else + { + ++nread; + CharT c = Traits::to_char_type(c1); + if (Traits::eq(c, quote)) + has_quote = !has_quote; + if (!Traits::eq(c, delim) || has_quote) + s.push_back(c); + else + break;// Character is extracted but not appended. + } + } + } + if (nread == 0 || nread >= s.max_size()) + is.setstate(std::ios_base::failbit); + + return is; +} + +} + +#endif // MAPNIK_CSV_GETLINE_HPP diff -Nru mapnik-3.0.9+ds/plugins/input/csv/csv_index_featureset.cpp mapnik-3.0.13+ds/plugins/input/csv/csv_index_featureset.cpp --- mapnik-3.0.9+ds/plugins/input/csv/csv_index_featureset.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/csv_index_featureset.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -37,7 +37,7 @@ csv_index_featureset::csv_index_featureset(std::string const& filename, mapnik::filter_in_box const& filter, - detail::geometry_column_locator const& locator, + locator_type const& locator, char separator, char quote, std::vector const& headers, @@ -89,12 +89,12 @@ mapnik::feature_ptr csv_index_featureset::parse_feature(char const* beg, char const* end) { auto values = csv_utils::parse_line(beg, end, separator_, quote_, headers_.size()); - auto geom = detail::extract_geometry(values, locator_); + auto geom = csv_utils::extract_geometry(values, locator_); if (!geom.is()) { mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_, ++feature_id_)); feature->set_geometry(std::move(geom)); - detail::process_properties(*feature, headers_, values, locator_, tr_); + csv_utils::process_properties(*feature, headers_, values, locator_, tr_); return feature; } return mapnik::feature_ptr(); diff -Nru mapnik-3.0.9+ds/plugins/input/csv/csv_index_featureset.hpp mapnik-3.0.13+ds/plugins/input/csv/csv_index_featureset.hpp --- mapnik-3.0.9+ds/plugins/input/csv/csv_index_featureset.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/csv_index_featureset.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -41,7 +41,7 @@ class csv_index_featureset : public mapnik::Featureset { using value_type = std::pair; - using locator_type = detail::geometry_column_locator; + using locator_type = csv_utils::geometry_column_locator; public: csv_index_featureset(std::string const& filename, @@ -60,7 +60,7 @@ std::vector headers_; mapnik::context_ptr ctx_; mapnik::value_integer feature_id_ = 0; - detail::geometry_column_locator const& locator_; + locator_type const& locator_; mapnik::transcoder tr_; #if defined (MAPNIK_MEMORY_MAPPED_FILE) using file_source_type = boost::interprocess::ibufferstream; diff -Nru mapnik-3.0.9+ds/plugins/input/csv/csv_inline_featureset.cpp mapnik-3.0.13+ds/plugins/input/csv/csv_inline_featureset.cpp --- mapnik-3.0.9+ds/plugins/input/csv/csv_inline_featureset.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/csv_inline_featureset.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -33,7 +33,7 @@ #include csv_inline_featureset::csv_inline_featureset(std::string const& inline_string, - detail::geometry_column_locator const& locator, + locator_type const& locator, char separator, char quote, std::vector const& headers, @@ -54,13 +54,15 @@ mapnik::feature_ptr csv_inline_featureset::parse_feature(std::string const& str) { - auto values = csv_utils::parse_line(str, separator_, quote_); - auto geom = detail::extract_geometry(values, locator_); + auto const* start = str.data(); + auto const* end = start + str.size(); + auto values = csv_utils::parse_line(start, end, separator_, quote_, headers_.size()); + auto geom = csv_utils::extract_geometry(values, locator_); if (!geom.is()) { mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_, ++feature_id_)); feature->set_geometry(std::move(geom)); - detail::process_properties(*feature, headers_, values, locator_, tr_); + csv_utils::process_properties(*feature, headers_, values, locator_, tr_); return feature; } return mapnik::feature_ptr(); diff -Nru mapnik-3.0.9+ds/plugins/input/csv/csv_inline_featureset.hpp mapnik-3.0.13+ds/plugins/input/csv/csv_inline_featureset.hpp --- mapnik-3.0.9+ds/plugins/input/csv/csv_inline_featureset.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/csv_inline_featureset.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,11 +28,10 @@ #include "csv_utils.hpp" #include "csv_datasource.hpp" #include -#include class csv_inline_featureset : public mapnik::Featureset { - using locator_type = detail::geometry_column_locator; + using locator_type = csv_utils::geometry_column_locator; public: using array_type = std::deque; csv_inline_featureset(std::string const& inline_string, @@ -55,7 +54,7 @@ array_type::const_iterator index_end_; mapnik::context_ptr ctx_; mapnik::value_integer feature_id_ = 0; - detail::geometry_column_locator const& locator_; + locator_type const& locator_; mapnik::transcoder tr_; }; diff -Nru mapnik-3.0.9+ds/plugins/input/csv/csv_utils.cpp mapnik-3.0.13+ds/plugins/input/csv/csv_utils.cpp --- mapnik-3.0.9+ds/plugins/input/csv/csv_utils.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/csv_utils.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,509 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + * + *****************************************************************************/ + +// mapnik +#include +#include +#include +#include +#include +#include +#include +#include +// csv grammar +#include +// +#include "csv_getline.hpp" +#include "csv_utils.hpp" + +#include +#include +#include +#include + +namespace csv_utils { +namespace detail { + +std::size_t file_length(std::istream & stream) +{ + stream.seekg(0, std::ios::end); + return stream.tellg(); +} + +std::tuple autodetect_csv_flavour(std::istream & stream, std::size_t file_length) +{ + // autodetect newlines/quotes/separators + char newline = '\n'; // default + bool has_newline = false; + bool has_single_quote = false; + char quote = '"'; // default + char separator = ','; // default + // local counters + int num_commas = 0; + int num_tabs = 0; + int num_pipes = 0; + int num_semicolons = 0; + + static std::size_t const max_size = 4000; + std::size_t size = std::min(file_length, max_size); + std::vector buffer; + buffer.resize(size); + stream.read(buffer.data(), size); + for (auto c : buffer) + { + switch (c) + { + case '\r': + newline = '\r'; + has_newline = true; + break; + case '\n': + has_newline = true; + break; + case '\'': + if (!has_single_quote) + { + quote = c; + has_single_quote = true; + } + break; + case ',': + if (!has_newline) ++num_commas; + break; + case '\t': + if (!has_newline) ++num_tabs; + break; + case '|': + if (!has_newline) ++num_pipes; + break; + case ';': + if (!has_newline) ++num_semicolons; + break; + } + } + // detect separator + if (num_tabs > 0 && num_tabs > num_commas) + { + separator = '\t'; + MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected tab separator"; + } + else // pipes/semicolons + { + if (num_pipes > num_commas) + { + separator = '|'; + MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected '|' separator"; + } + else if (num_semicolons > num_commas) + { + separator = ';'; + MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected ';' separator"; + } + } + + if (has_newline && has_single_quote) + { + std::istringstream ss(std::string(buffer.begin(), buffer.end())); + std::size_t num_columns = 0; + for (std::string line; csv_utils::getline_csv(ss, line, newline, quote); ) + { + if (size < file_length && ss.eof()) + { + // we can't be sure that last line + // is not truncated so skip it + break; + } + if (line.size() == 0 || (line.size() == 1 && line[0] == char(0xa))) continue; // empty lines are not interesting + auto num_quotes = std::count(line.begin(), line.end(), quote); + if (num_quotes % 2 != 0) + { + quote = '"'; + break; + } + auto columns = csv_utils::parse_line(line, separator, quote); + if (num_columns > 0 && num_columns != columns.size()) + { + quote = '"'; + break; + } + num_columns = columns.size(); + } + } + return std::make_tuple(newline, has_newline, separator, quote); +} + +void locate_geometry_column(std::string const& header, std::size_t index, geometry_column_locator & locator) +{ + std::string lower_val(header); + std::transform(lower_val.begin(), lower_val.end(), lower_val.begin(), ::tolower); + if (lower_val == "wkt" || (lower_val.find("geom") != std::string::npos)) + { + locator.type = geometry_column_locator::WKT; + locator.index = index; + } + else if (lower_val == "geojson") + { + locator.type = geometry_column_locator::GEOJSON; + locator.index = index; + } + else if (lower_val == "x" || lower_val == "lon" + || lower_val == "lng" || lower_val == "long" + || (lower_val.find("longitude") != std::string::npos)) + { + locator.index = index; + locator.type = geometry_column_locator::LON_LAT; + } + + else if (lower_val == "y" + || lower_val == "lat" + || (lower_val.find("latitude") != std::string::npos)) + { + locator.index2 = index; + locator.type = geometry_column_locator::LON_LAT; + } +} + +bool valid(geometry_column_locator const& locator, std::size_t max_size) +{ + if (locator.type == geometry_column_locator::UNKNOWN) return false; + if (locator.index >= max_size) return false; + if (locator.type == geometry_column_locator::LON_LAT && locator.index2 >= max_size) return false; + return true; +} + +} // namespace detail + +static const mapnik::csv_line_grammar line_g; +static const mapnik::csv_white_space_skipper skipper{}; + +mapnik::csv_line parse_line(char const* start, char const* end, char separator, char quote, std::size_t num_columns) +{ + mapnik::csv_line values; + if (num_columns > 0) values.reserve(num_columns); + if (!boost::spirit::qi::phrase_parse(start, end, (line_g)(separator, quote), skipper, values)) + { + throw mapnik::datasource_exception("Failed to parse CSV line:\n" + std::string(start, end)); + } + return values; +} + +mapnik::csv_line parse_line(std::string const& line_str, char separator, char quote) +{ + auto start = line_str.c_str(); + auto end = start + line_str.length(); + return parse_line(start, end, separator, quote, 0); +} + + +bool is_likely_number(std::string const& value) +{ + return (std::strspn( value.c_str(), "e-.+0123456789" ) == value.size()); +} + +struct ignore_case_equal_pred +{ + bool operator () (unsigned char a, unsigned char b) const + { + return std::tolower(a) == std::tolower(b); + } +}; + +bool ignore_case_equal(std::string const& s0, std::string const& s1) +{ + return std::equal(s0.begin(), s0.end(), + s1.begin(), ignore_case_equal_pred()); +} + +void csv_file_parser::add_feature(mapnik::value_integer, mapnik::csv_line const & ) +{ + // no-op by default +} + +template +void csv_file_parser::parse_csv_and_boxes(std::istream & csv_file, T & boxes) +{ + using boxes_type = T; + using box_type = typename boxes_type::value_type::first_type; + + auto file_length = detail::file_length(csv_file); + // set back to start + csv_file.seekg(0, std::ios::beg); + char newline; + bool has_newline; + char detected_quote; + char detected_separator; + std::tie(newline, has_newline, detected_separator, detected_quote) = detail::autodetect_csv_flavour(csv_file, file_length); + if (quote_ == 0) quote_ = detected_quote; + if (separator_ == 0) separator_ = detected_separator; + + // set back to start + MAPNIK_LOG_DEBUG(csv) << "csv_datasource: separator: '" << separator_ + << "' quote: '" << quote_ << "'"; + + // rewind stream + csv_file.seekg(0, std::ios::beg); + // + std::string csv_line; + csv_utils::getline_csv(csv_file, csv_line, newline, quote_); + csv_file.seekg(0, std::ios::beg); + int line_number = 0; + if (!manual_headers_.empty()) + { + std::size_t index = 0; + auto headers = csv_utils::parse_line(manual_headers_, separator_, quote_); + headers_.reserve(headers.size()); + for (auto const& header : headers) + { + detail::locate_geometry_column(header, index++, locator_); + headers_.push_back(header); + } + } + else // parse first line as headers + { + while (csv_utils::getline_csv(csv_file, csv_line, newline, quote_)) + { + try + { + auto headers = csv_utils::parse_line(csv_line, separator_, quote_); + // skip blank lines + if (headers.size() == 1 && headers[0].empty()) + { + ++line_number; + } + else + { + std::size_t index = 0; + headers_.reserve(headers.size()); + for (auto & header : headers) + { + mapnik::util::trim(header); + if (header.empty()) + { + if (strict_) + { + std::ostringstream s; + s << "CSV Plugin: expected a column header at line "; + s << line_number << ", column " << index; + s << " - expected fields: '"; + s << csv_line; + throw mapnik::datasource_exception(s.str()); + } + else + { + // create a placeholder for the empty header + std::ostringstream s; + s << "_" << index; + headers_.push_back(s.str()); + } + } + else + { + detail::locate_geometry_column(header, index, locator_); + headers_.push_back(header); + } + ++index; + } + ++line_number; + break; + } + } + catch (std::exception const& ex) + { + std::string s("CSV Plugin: error parsing headers: "); + s += ex.what(); + throw mapnik::datasource_exception(s); + } + } + } + + std::size_t num_headers = headers_.size(); + if (!detail::valid(locator_, num_headers)) + { + std::string str("CSV Plugin: could not detect column(s) with the name(s) of wkt, geojson, x/y, or "); + str += "latitude/longitude in:\n"; + str += csv_line; + throw mapnik::datasource_exception(str); + } + + mapnik::value_integer feature_count = 0; + auto pos = csv_file.tellg(); + // handle rare case of a single line of data and user-provided headers + // where a lack of a newline will mean that csv_utils::getline_csv returns false + bool is_first_row = false; + + if (!has_newline) + { + csv_file.setstate(std::ios::failbit); + pos = 0; + if (!csv_line.empty()) + { + is_first_row = true; + } + } + + while (is_first_row || csv_utils::getline_csv(csv_file, csv_line, newline, quote_)) + { + ++line_number; + if ((row_limit_ > 0) && (line_number > row_limit_)) + { + MAPNIK_LOG_DEBUG(csv) << "csv_datasource: row limit hit, exiting at feature: " << feature_count; + break; + } + auto record_offset = pos; + auto record_size = csv_line.length(); + pos = csv_file.tellg(); + is_first_row = false; + + // skip blank lines + if (record_size <= 10) + { + std::string trimmed = csv_line; + boost::trim_if(trimmed, boost::algorithm::is_any_of("\",'\r\n ")); + if (trimmed.empty()) + { + MAPNIK_LOG_DEBUG(csv) << "csv_datasource: empty row encountered at line: " << line_number; + continue; + } + } + + try + { + auto const* line_start = csv_line.data(); + auto const* line_end = line_start + csv_line.size(); + auto values = csv_utils::parse_line(line_start, line_end, separator_, quote_, num_headers); + unsigned num_fields = values.size(); + if (num_fields != num_headers) + { + std::ostringstream s; + s << "CSV Plugin: # of columns(" << num_fields << ")"; + if (num_fields > num_headers) + { + s << " > "; + } + else + { + s << " < "; + } + s << "# of headers(" << num_headers << ") parsed"; + throw mapnik::datasource_exception(s.str()); + } + + auto geom = extract_geometry(values, locator_); + if (!geom.is()) + { + auto box = mapnik::geometry::envelope(geom); + if (!extent_initialized_) + { + if (extent_.valid()) + extent_.expand_to_include(box); + else + extent_ = box; + } + boxes.emplace_back(box_type(box), make_pair(record_offset, record_size)); + add_feature(++feature_count, values); + } + else + { + std::ostringstream s; + s << "CSV Plugin: expected geometry column: could not parse row " + << line_number << " " + << values.at(locator_.index) << "'"; + throw mapnik::datasource_exception(s.str()); + } + } + catch (mapnik::datasource_exception const& ex ) + { + if (strict_) throw ex; + else + { + MAPNIK_LOG_ERROR(csv) << ex.what() << " at line: " << line_number; + } + } + catch (std::exception const& ex) + { + std::ostringstream s; + s << "CSV Plugin: unexpected error parsing line: " << line_number + << " - found " << headers_.size() << " with values like: " << csv_line << "\n" + << " and got error like: " << ex.what(); + if (strict_) + { + throw mapnik::datasource_exception(s.str()); + } + else + { + MAPNIK_LOG_ERROR(csv) << s.str(); + } + } + // return early if *.index is present + if (has_disk_index_) return; + } +} + + +mapnik::geometry::geometry extract_geometry(std::vector const& row, geometry_column_locator const& locator) +{ + mapnik::geometry::geometry geom; + if (locator.type == geometry_column_locator::WKT) + { + auto wkt_value = row.at(locator.index); + if (mapnik::from_wkt(wkt_value, geom)) + { + // correct orientations .. + mapnik::geometry::correct(geom); + } + else + { + throw mapnik::datasource_exception("Failed to parse WKT: '" + wkt_value + "'"); + } + } + else if (locator.type == geometry_column_locator::GEOJSON) + { + + auto json_value = row.at(locator.index); + if (!mapnik::json::from_geojson(json_value, geom)) + { + throw mapnik::datasource_exception("Failed to parse GeoJSON: '" + json_value + "'"); + } + } + else if (locator.type == geometry_column_locator::LON_LAT) + { + double x, y; + auto long_value = row.at(locator.index); + auto lat_value = row.at(locator.index2); + if (!mapnik::util::string2double(long_value,x)) + { + throw mapnik::datasource_exception("Failed to parse Longitude: '" + long_value + "'"); + } + if (!mapnik::util::string2double(lat_value,y)) + { + throw mapnik::datasource_exception("Failed to parse Latitude: '" + lat_value + "'"); + } + geom = mapnik::geometry::point(x,y); + } + return geom; +} + +template void csv_file_parser::parse_csv_and_boxes(std::istream & csv_file, std::vector, std::pair>> & boxes); + +template void csv_file_parser::parse_csv_and_boxes(std::istream & csv_file, std::vector, std::pair>> & boxes); + +} // namespace csv_utils diff -Nru mapnik-3.0.9+ds/plugins/input/csv/csv_utils.hpp mapnik-3.0.13+ds/plugins/input/csv/csv_utils.hpp --- mapnik-3.0.9+ds/plugins/input/csv/csv_utils.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/csv/csv_utils.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,188 +24,26 @@ #define MAPNIK_CSV_UTILS_DATASOURCE_HPP // mapnik -#include +#include #include -#include -#include -#include +#include #include -#include #include -#include - -#pragma GCC diagnostic push -#include -#include -#pragma GCC diagnostic pop +#include +// std +#include #include -#include -#include - -namespace csv_utils -{ +#include -static const mapnik::csv_line_grammar line_g; -static const mapnik::csv_white_space_skipper skipper; +namespace csv_utils { -template -static mapnik::csv_line parse_line(Iterator start, Iterator end, char separator, char quote, std::size_t num_columns) -{ - mapnik::csv_line values; - if (num_columns > 0) values.reserve(num_columns); - if (!boost::spirit::qi::phrase_parse(start, end, (line_g)(separator, quote), skipper, values)) - { - throw mapnik::datasource_exception("Failed to parse CSV line:\n" + std::string(start, end)); - } - return values; -} - -static inline mapnik::csv_line parse_line(std::string const& line_str, char separator, char quote) -{ - auto start = line_str.c_str(); - auto end = start + line_str.length(); - return parse_line(start, end, separator, quote, 0); -} - -static inline bool is_likely_number(std::string const& value) -{ - return (std::strspn( value.c_str(), "e-.+0123456789" ) == value.size()); -} +mapnik::csv_line parse_line(char const* start, char const* end, char separator, char quote, std::size_t num_columns); +mapnik::csv_line parse_line(std::string const& line_str, char separator, char quote); -struct ignore_case_equal_pred -{ - bool operator () (unsigned char a, unsigned char b) const - { - return std::tolower(a) == std::tolower(b); - } -}; - -inline bool ignore_case_equal(std::string const& s0, std::string const& s1) -{ - return std::equal(s0.begin(), s0.end(), - s1.begin(), ignore_case_equal_pred()); -} - -template -std::basic_istream& getline_csv(std::istream& is, std::basic_string& s, CharT delim, CharT quote) -{ - typename std::basic_string::size_type nread = 0; - typename std::basic_istream::sentry sentry(is, true); - if (sentry) - { - std::basic_streambuf* buf = is.rdbuf(); - s.clear(); - bool has_quote = false; - while (nread < s.max_size()) - { - int c1 = buf->sbumpc(); - if (Traits::eq_int_type(c1, Traits::eof())) - { - is.setstate(std::ios_base::eofbit); - break; - } - else - { - ++nread; - CharT c = Traits::to_char_type(c1); - if (Traits::eq(c, quote)) - has_quote = !has_quote; - if (!Traits::eq(c, delim) || has_quote) - s.push_back(c); - else - break;// Character is extracted but not appended. - } - } - } - if (nread == 0 || nread >= s.max_size()) - is.setstate(std::ios_base::failbit); - - return is; -} - -} - - -namespace detail { - -template -std::size_t file_length(T & stream) -{ - stream.seekg(0, std::ios::end); - return stream.tellg(); -} - -static inline char detect_separator(std::string const& str) -{ - char separator = ','; // default - int num_commas = std::count(str.begin(), str.end(), ','); - // detect tabs - int num_tabs = std::count(str.begin(), str.end(), '\t'); - if (num_tabs > 0) - { - if (num_tabs > num_commas) - { - separator = '\t'; - MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected tab separator"; - } - } - else // pipes - { - int num_pipes = std::count(str.begin(), str.end(), '|'); - if (num_pipes > num_commas) - { - separator = '|'; - MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected '|' separator"; - } - else // semicolons - { - int num_semicolons = std::count(str.begin(), str.end(), ';'); - if (num_semicolons > num_commas) - { - separator = ';'; - MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected ';' separator"; - } - } - } - return separator; -} - -template -std::tuple autodect_newline_and_quote(T & stream, std::size_t file_length) -{ - // autodetect newlines - char newline = '\n'; - bool has_newline = false; - bool has_quote = false; - char quote = '"'; - static std::size_t const max_size = 4000; - std::size_t size = std::min(file_length, max_size); - for (std::size_t lidx = 0; lidx < size; ++lidx) - { - char c = static_cast(stream.get()); - switch (c) - { - case '\r': - newline = '\r'; - has_newline = true; - break; - case '\n': - has_newline = true; - break; - case '\'': - case '"': - if (!has_quote) - { - quote = c; - has_quote = true; - } - break; - } - } - return std::make_tuple(newline, has_newline, quote); -} +bool is_likely_number(std::string const& value); +bool ignore_case_equal(std::string const& s0, std::string const& s1); struct geometry_column_locator { @@ -217,87 +55,8 @@ std::size_t index2; }; -static inline void locate_geometry_column(std::string const& header, std::size_t index, geometry_column_locator & locator) -{ - std::string lower_val(header); - std::transform(lower_val.begin(), lower_val.end(), lower_val.begin(), ::tolower); - if (lower_val == "wkt" || (lower_val.find("geom") != std::string::npos)) - { - locator.type = geometry_column_locator::WKT; - locator.index = index; - } - else if (lower_val == "geojson") - { - locator.type = geometry_column_locator::GEOJSON; - locator.index = index; - } - else if (lower_val == "x" || lower_val == "lon" - || lower_val == "lng" || lower_val == "long" - || (lower_val.find("longitude") != std::string::npos)) - { - locator.index = index; - locator.type = geometry_column_locator::LON_LAT; - } - - else if (lower_val == "y" - || lower_val == "lat" - || (lower_val.find("latitude") != std::string::npos)) - { - locator.index2 = index; - locator.type = geometry_column_locator::LON_LAT; - } -} - -static inline bool valid(geometry_column_locator const& locator, std::size_t max_size) -{ - if (locator.type == geometry_column_locator::UNKNOWN) return false; - if (locator.index >= max_size) return false; - if (locator.type == geometry_column_locator::LON_LAT && locator.index2 >= max_size) return false; - return true; -} -static inline mapnik::geometry::geometry extract_geometry(std::vector const& row, geometry_column_locator const& locator) -{ - mapnik::geometry::geometry geom; - if (locator.type == geometry_column_locator::WKT) - { - auto wkt_value = row.at(locator.index); - if (mapnik::from_wkt(wkt_value, geom)) - { - // correct orientations .. - mapnik::geometry::correct(geom); - } - else - { - throw mapnik::datasource_exception("Failed to parse WKT: '" + wkt_value + "'"); - } - } - else if (locator.type == geometry_column_locator::GEOJSON) - { - - auto json_value = row.at(locator.index); - if (!mapnik::json::from_geojson(json_value, geom)) - { - throw mapnik::datasource_exception("Failed to parse GeoJSON: '" + json_value + "'"); - } - } - else if (locator.type == geometry_column_locator::LON_LAT) - { - double x, y; - auto long_value = row.at(locator.index); - auto lat_value = row.at(locator.index2); - if (!mapnik::util::string2double(long_value,x)) - { - throw mapnik::datasource_exception("Failed to parse Longitude: '" + long_value + "'"); - } - if (!mapnik::util::string2double(lat_value,y)) - { - throw mapnik::datasource_exception("Failed to parse Latitude: '" + lat_value + "'"); - } - geom = mapnik::geometry::point(x,y); - } - return geom; -} +mapnik::geometry::geometry extract_geometry(std::vector const& row, geometry_column_locator const& locator); template void process_properties(Feature & feature, Headers const& headers, Values const& values, Locator const& locator, Transcoder const& tr) @@ -316,8 +75,8 @@ std::string value = mapnik::util::trim_copy(*val_beg++); int value_length = value.length(); - if (locator.index == i && (locator.type == detail::geometry_column_locator::WKT - || locator.type == detail::geometry_column_locator::GEOJSON) ) continue; + if (locator.index == i && (locator.type == geometry_column_locator::WKT + || locator.type == geometry_column_locator::GEOJSON) ) continue; bool matched = false; @@ -369,7 +128,25 @@ } } +struct csv_file_parser +{ + template + void parse_csv_and_boxes(std::istream & csv_file, T & boxes); + + virtual void add_feature(mapnik::value_integer index, mapnik::csv_line const & values); + + std::vector headers_; + std::string manual_headers_; + geometry_column_locator locator_; + mapnik::box2d extent_; + mapnik::value_integer row_limit_ = 0; + char separator_ = '\0'; + char quote_ = '\0'; + bool strict_ = false; + bool extent_initialized_ = false; + bool has_disk_index_ = false; +}; -}// ns detail +} // namespace csv_utils #endif // MAPNIK_CSV_UTILS_DATASOURCE_HPP diff -Nru mapnik-3.0.9+ds/plugins/input/gdal/gdal_datasource.cpp mapnik-3.0.13+ds/plugins/input/gdal/gdal_datasource.cpp --- mapnik-3.0.9+ds/plugins/input/gdal/gdal_datasource.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/gdal/gdal_datasource.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -44,10 +44,19 @@ using mapnik::layer_descriptor; using mapnik::datasource_exception; +static std::once_flag once_flag; + +extern "C" MAPNIK_EXP void on_plugin_load() +{ + // initialize gdal formats + std::call_once(once_flag,[](){ + GDALAllRegister(); + }); +} gdal_datasource::gdal_datasource(parameters const& params) : datasource(params), - dataset_(nullptr), + dataset_(nullptr, &GDALClose), desc_(gdal_datasource::name(), "utf-8"), nodata_value_(params.get("nodata")), nodata_tolerance_(*params.get("nodata_tolerance",1e-12)) @@ -58,8 +67,6 @@ mapnik::progress_timer __stats__(std::clog, "gdal_datasource::init"); #endif - GDALAllRegister(); - boost::optional file = params.get("file"); if (! file) throw datasource_exception("missing parameter"); @@ -79,12 +86,14 @@ #if GDAL_VERSION_NUM >= 1600 if (shared_dataset_) { - dataset_ = reinterpret_cast(GDALOpenShared((dataset_name_).c_str(), GA_ReadOnly)); + auto ds = GDALOpenShared(dataset_name_.c_str(), GA_ReadOnly); + dataset_.reset(static_cast(ds)); } else #endif { - dataset_ = reinterpret_cast(GDALOpen((dataset_name_).c_str(), GA_ReadOnly)); + auto ds = GDALOpen(dataset_name_.c_str(), GA_ReadOnly); + dataset_.reset(static_cast(ds)); } if (! dataset_) @@ -92,7 +101,7 @@ throw datasource_exception(CPLGetLastErrorMsg()); } - MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: opened Dataset=" << dataset_; + MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: opened Dataset=" << dataset_.get(); nbands_ = dataset_->GetRasterCount(); width_ = dataset_->GetRasterXSize(); @@ -182,8 +191,7 @@ gdal_datasource::~gdal_datasource() { - MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Closing Dataset=" << dataset_; - GDALClose(dataset_); + MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Closing Dataset=" << dataset_.get(); } datasource::datasource_t gdal_datasource::type() const @@ -217,12 +225,9 @@ mapnik::progress_timer __stats__(std::clog, "gdal_datasource::features"); #endif - gdal_query gq = q; - - // TODO - move to std::make_shared, but must reduce # of args to <= 9 - return featureset_ptr(new gdal_featureset(*dataset_, + return std::make_shared(*dataset_, band_, - gq, + gdal_query(q), extent_, width_, height_, @@ -230,7 +235,7 @@ dx_, dy_, nodata_value_, - nodata_tolerance_)); + nodata_tolerance_); } featureset_ptr gdal_datasource::features_at_point(coord2d const& pt, double tol) const @@ -239,12 +244,9 @@ mapnik::progress_timer __stats__(std::clog, "gdal_datasource::features_at_point"); #endif - gdal_query gq = pt; - - // TODO - move to std::make_shared, but must reduce # of args to <= 9 - return featureset_ptr(new gdal_featureset(*dataset_, + return std::make_shared(*dataset_, band_, - gq, + gdal_query(pt), extent_, width_, height_, @@ -252,5 +254,5 @@ dx_, dy_, nodata_value_, - nodata_tolerance_)); + nodata_tolerance_); } diff -Nru mapnik-3.0.9+ds/plugins/input/gdal/gdal_datasource.hpp mapnik-3.0.13+ds/plugins/input/gdal/gdal_datasource.hpp --- mapnik-3.0.9+ds/plugins/input/gdal/gdal_datasource.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/gdal/gdal_datasource.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -55,8 +55,7 @@ boost::optional get_geometry_type() const; mapnik::layer_descriptor get_descriptor() const; private: - GDALDataset* open_dataset() const; - GDALDataset* dataset_; + std::unique_ptr dataset_; mapnik::box2d extent_; std::string dataset_name_; int band_; diff -Nru mapnik-3.0.9+ds/plugins/input/gdal/gdal_featureset.cpp mapnik-3.0.13+ds/plugins/input/gdal/gdal_featureset.cpp --- mapnik-3.0.9+ds/plugins/input/gdal/gdal_featureset.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/gdal/gdal_featureset.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -21,7 +21,7 @@ *****************************************************************************/ // mapnik -#include +#include #include #include #include @@ -29,7 +29,6 @@ #include #include #include -#include // stl #include @@ -39,14 +38,47 @@ #include "gdal_featureset.hpp" #include -using mapnik::query; -using mapnik::coord2d; using mapnik::box2d; using mapnik::feature_ptr; using mapnik::view_transform; using mapnik::datasource_exception; using mapnik::feature_factory; +#ifdef MAPNIK_LOG +namespace { + +void get_overview_meta(GDALRasterBand* band) +{ + int band_overviews = band->GetOverviewCount(); + if (band_overviews > 0) + { + MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: " << band_overviews << " overviews found!"; + + for (int b = 0; b < band_overviews; b++) + { + GDALRasterBand * overview = band->GetOverview(b); + MAPNIK_LOG_DEBUG(gdal) << "Overview= " << b + << " Width=" << overview->GetXSize() + << " Height=" << overview->GetYSize(); + } + } + else + { + MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: No overviews found!"; + } + + int bsx,bsy; + double scale; + band->GetBlockSize(&bsx, &bsy); + scale = band->GetScale(); + + MAPNIK_LOG_DEBUG(gdal) << "Block=" << bsx << "x" << bsy + << " Scale=" << scale + << " Type=" << GDALGetDataTypeName(band->GetRasterDataType()) + << "Color=" << GDALGetColorInterpretationName(band->GetColorInterpretation()); +} +} // anonymous ns +#endif gdal_featureset::gdal_featureset(GDALDataset& dataset, int band, gdal_query q, @@ -77,8 +109,6 @@ gdal_featureset::~gdal_featureset() { - MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Closing Dataset=" << &dataset_; - } feature_ptr gdal_featureset::next() @@ -408,15 +438,15 @@ if( red->GetBand() == 1 && green->GetBand() == 2 && blue->GetBand() == 3 ) { int nBandsToRead = 3; - if( alpha != NULL && alpha->GetBand() == 4 && !raster_has_nodata ) + if( alpha != nullptr && alpha->GetBand() == 4 && !raster_has_nodata ) { nBandsToRead = 4; - alpha = NULL; // to avoid reading it again afterwards + alpha = nullptr; // to avoid reading it again afterwards } raster_io_error = dataset_.RasterIO(GF_Read, x_off, y_off, width, height, image.bytes(), image.width(), image.height(), GDT_Byte, - nBandsToRead, NULL, + nBandsToRead, nullptr, 4, 4 * image.width(), 1); if (raster_io_error == CE_Failure) { throw datasource_exception(CPLGetLastErrorMsg()); @@ -556,6 +586,32 @@ MAPNIK_LOG_WARN(gdal) << "warning: nodata value (" << raster_nodata << ") used to set transparency instead of alpha band"; } } + else if( dataset_.GetRasterCount() > 0 && dataset_.GetRasterBand(1) ) + { + // Check if we have a non-alpha mask band (for example a TIFF internal mask) + int flags = dataset_.GetRasterBand(1)->GetMaskFlags(); + GDALRasterBand* mask = 0; + if (flags == GMF_PER_DATASET) + { + mask = dataset_.GetRasterBand(1)->GetMaskBand(); + } + if (mask) + { + MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: found and processing mask band..."; + if (!raster_has_nodata) + { + raster_io_error = mask->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 3, + image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); + if (raster_io_error == CE_Failure) { + throw datasource_exception(CPLGetLastErrorMsg()); + } + } + else + { + MAPNIK_LOG_WARN(gdal) << "warning: nodata value (" << raster_nodata << ") used to set transparency instead of mask band"; + } + } + } mapnik::raster_ptr raster = std::make_shared(intersect, image, filter_factor); // set nodata value to be used in raster colorizer if (nodata_value_) raster->set_nodata(*nodata_value_); @@ -625,36 +681,3 @@ } return feature_ptr(); } - -#ifdef MAPNIK_LOG -void gdal_featureset::get_overview_meta(GDALRasterBand* band) -{ - int band_overviews = band->GetOverviewCount(); - if (band_overviews > 0) - { - MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: " << band_overviews << " overviews found!"; - - for (int b = 0; b < band_overviews; b++) - { - GDALRasterBand * overview = band->GetOverview(b); - MAPNIK_LOG_DEBUG(gdal) << "Overview= " << b - << " Width=" << overview->GetXSize() - << " Height=" << overview->GetYSize(); - } - } - else - { - MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: No overviews found!"; - } - - int bsx,bsy; - double scale; - band->GetBlockSize(&bsx, &bsy); - scale = band->GetScale(); - - MAPNIK_LOG_DEBUG(gdal) << "Block=" << bsx << "x" << bsy - << " Scale=" << scale - << " Type=" << GDALGetDataTypeName(band->GetRasterDataType()) - << "Color=" << GDALGetColorInterpretationName(band->GetColorInterpretation()); -} -#endif diff -Nru mapnik-3.0.9+ds/plugins/input/gdal/gdal_featureset.hpp mapnik-3.0.13+ds/plugins/input/gdal/gdal_featureset.hpp --- mapnik-3.0.9+ds/plugins/input/gdal/gdal_featureset.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/gdal/gdal_featureset.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,13 +24,12 @@ #define GDAL_FEATURESET_HPP // mapnik -#include +#include +#include #include // boost #include -#include "gdal_datasource.hpp" - class GDALDataset; class GDALRasterBand; @@ -74,11 +73,6 @@ private: mapnik::feature_ptr get_feature(mapnik::query const& q); mapnik::feature_ptr get_feature_at_point(mapnik::coord2d const& p); - -#ifdef MAPNIK_LOG - void get_overview_meta(GDALRasterBand * band); -#endif - GDALDataset & dataset_; mapnik::context_ptr ctx_; int band_; diff -Nru mapnik-3.0.9+ds/plugins/input/geojson/geojson_datasource.cpp mapnik-3.0.13+ds/plugins/input/geojson/geojson_datasource.cpp --- mapnik-3.0.9+ds/plugins/input/geojson/geojson_datasource.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/geojson/geojson_datasource.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -108,22 +108,19 @@ }; geojson_datasource::geojson_datasource(parameters const& params) - : datasource(params), - type_(datasource::Vector), - desc_(geojson_datasource::name(), - *params.get("encoding","utf-8")), - filename_(), - inline_string_(), - extent_(), - features_(), - tree_(nullptr) + : datasource(params), + type_(datasource::Vector), + desc_(geojson_datasource::name(), + *params.get("encoding","utf-8")), + filename_(), + from_inline_string_(false), + extent_(), + features_(), + tree_(nullptr), + num_features_to_query_(std::max(mapnik::value_integer(1), *params.get("num_features_to_query", 5))) { boost::optional inline_string = params.get("inline"); - if (inline_string) - { - inline_string_ = *inline_string; - } - else + if (!inline_string) { boost::optional file = params.get("file"); if (!file) throw mapnik::datasource_exception("GeoJSON Plugin: missing parameter"); @@ -136,10 +133,11 @@ has_disk_index_ = mapnik::util::exists(filename_ + ".index"); } - if (!inline_string_.empty()) + if (inline_string) { - char const* start = inline_string_.c_str(); - char const* end = start + inline_string_.size(); + from_inline_string_ = true; + char const* start = inline_string->c_str(); + char const* end = start + inline_string->size(); parse_geojson(start, end); } else if (has_disk_index_) @@ -151,7 +149,7 @@ cache_features_ = *params.get("cache_features", true); #if !defined(MAPNIK_MEMORY_MAPPED_FILE) mapnik::util::file file(filename_); - if (!file.open()) + if (!file) { throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'"); } @@ -161,14 +159,6 @@ std::fread(&file_buffer[0], file.size(), 1, file.get()); char const* start = file_buffer.c_str(); char const* end = start + file_buffer.length(); - if (cache_features_) - { - parse_geojson(start, end); - } - else - { - initialise_index(start, end); - } #else boost::optional mapped_region = mapnik::mapped_memory_cache::instance().find(filename_, false); @@ -179,6 +169,7 @@ char const* start = reinterpret_cast((*mapped_region)->get_address()); char const* end = start + (*mapped_region)->get_size(); +#endif if (cache_features_) { parse_geojson(start, end); @@ -187,17 +178,32 @@ { initialise_index(start, end); } -#endif } } namespace { +using box_type = box2d; +using boxes_type = std::vector>>; using base_iterator_type = char const*; const mapnik::transcoder geojson_datasource_static_tr("utf8"); const mapnik::json::feature_collection_grammar geojson_datasource_static_fc_grammar(geojson_datasource_static_tr); const mapnik::json::feature_grammar_callback geojson_datasource_static_feature_callback_grammar(geojson_datasource_static_tr); const mapnik::json::feature_grammar geojson_datasource_static_feature_grammar(geojson_datasource_static_tr); -const mapnik::json::extract_bounding_box_grammar geojson_datasource_static_bbox_grammar; +const mapnik::json::extract_bounding_box_grammar geojson_datasource_static_bbox_grammar; +} + +void geojson_datasource::initialise_descriptor(mapnik::feature_ptr const& feature) +{ + for ( auto const& kv : *feature) + { + auto const& name = std::get<0>(kv); + if (!desc_.has_name(name)) + { + desc_.add_descriptor(mapnik::attribute_descriptor(name, + mapnik::util::apply_visitor(attr_value_converter(), + std::get<1>(kv)))); + } + } } void geojson_datasource::initialise_disk_index(std::string const& filename) @@ -213,11 +219,11 @@ std::vector positions; mapnik::util::spatial_index::query_first_n(filter, index, positions, 5); + std::ifstream>::query_first_n(filter, index, positions, num_features_to_query_); mapnik::util::file file(filename_); - if (!file.open()) throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'"); - + if (!file) throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'"); + mapnik::context_ptr ctx = std::make_shared(); for (auto const& pos : positions) { std::fseek(file.get(), pos.first, SEEK_SET); @@ -226,8 +232,7 @@ std::fread(record.data(), pos.second, 1, file.get()); auto const* start = record.data(); auto const* end = start + record.size(); - mapnik::context_ptr ctx = std::make_shared(); - mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,1)); + mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx, -1)); using namespace boost::spirit; standard::space_type space; if (!boost::spirit::qi::phrase_parse(start, end, @@ -236,23 +241,15 @@ { throw std::runtime_error("Failed to parse geojson feature"); } - for ( auto const& kv : *feature) - { - auto const& name = std::get<0>(kv); - if (!desc_.has_name(name)) - { - desc_.add_descriptor(mapnik::attribute_descriptor(name, - mapnik::util::apply_visitor(attr_value_converter(), - std::get<1>(kv)))); - } - } + initialise_descriptor(feature); } + desc_.order_by_name(); } template void geojson_datasource::initialise_index(Iterator start, Iterator end) { - mapnik::json::boxes_type boxes; + boxes_type boxes; boost::spirit::standard::space_type space; Iterator itr = start; if (!boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_bbox_grammar)(boost::phoenix::ref(boxes)) , space)) @@ -264,11 +261,11 @@ std::size_t start_id = 1; mapnik::json::default_feature_callback callback(features_); bool result = boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_feature_callback_grammar) - (boost::phoenix::ref(ctx), boost::phoenix::ref(start_id), boost::phoenix::ref(callback)), - space); + (boost::phoenix::ref(ctx), boost::phoenix::ref(start_id), boost::phoenix::ref(callback)), + space); if (!result || itr != end) { - if (!inline_string_.empty()) throw mapnik::datasource_exception("geojson_datasource: Failed to parse GeoJSON file from in-memory string"); + if (from_inline_string_) throw mapnik::datasource_exception("geojson_datasource: Failed to parse GeoJSON file from in-memory string"); else throw mapnik::datasource_exception("geojson_datasource: Failed to parse GeoJSON file '" + filename_ + "'"); } @@ -285,20 +282,18 @@ if (geometry_index == 0) { extent_ = box; - for ( auto const& kv : *f) - { - desc_.add_descriptor(mapnik::attribute_descriptor(std::get<0>(kv), - mapnik::util::apply_visitor(attr_value_converter(), - std::get<1>(kv)))); - } } else { extent_.expand_to_include(box); } values.emplace_back(box, std::make_pair(geometry_index,0)); + + } + if (geometry_index++ < num_features_to_query_) + { + initialise_descriptor(f); } - ++geometry_index; } // packing algorithm tree_ = std::make_unique(values); @@ -308,18 +303,20 @@ // bulk insert initialise r-tree tree_ = std::make_unique(boxes); // calculate total extent + std::size_t feature_count = 0; + mapnik::context_ptr ctx = std::make_shared(); for (auto const& item : boxes) { auto const& box = std::get<0>(item); auto const& geometry_index = std::get<1>(item); - if (!extent_.valid()) + if (!extent_.valid()) extent_ = box; + else extent_.expand_to_include(box); + if (feature_count++ < num_features_to_query_) { - extent_ = box; - // parse first feature to extract attributes schema. + // parse first N features to extract attributes schema. // NOTE: this doesn't yield correct answer for geoJSON in general, just an indication Iterator itr2 = start + geometry_index.first; Iterator end2 = itr2 + geometry_index.second; - mapnik::context_ptr ctx = std::make_shared(); mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,-1)); // temp feature if (!boost::spirit::qi::phrase_parse(itr2, end2, (geojson_datasource_static_feature_grammar)(boost::phoenix::ref(*feature)), space) @@ -327,19 +324,12 @@ { throw std::runtime_error("Failed to parse geojson feature"); } - for ( auto const& kv : *feature) - { - desc_.add_descriptor(mapnik::attribute_descriptor(std::get<0>(kv), - mapnik::util::apply_visitor(attr_value_converter(), - std::get<1>(kv)))); - } - } - else - { - extent_.expand_to_include(box); + + initialise_descriptor(feature); } } } + desc_.order_by_name(); } template @@ -356,7 +346,7 @@ try { bool result = boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_fc_grammar) - (boost::phoenix::ref(ctx),boost::phoenix::ref(start_id), boost::phoenix::ref(callback)), + (boost::phoenix::ref(ctx), boost::phoenix::ref(start_id), boost::phoenix::ref(callback)), space); if (!result || itr != end) { @@ -367,7 +357,7 @@ space); if (!result || itr != end) { - if (!inline_string_.empty()) throw mapnik::datasource_exception("geojson_datasource: Failed parse GeoJSON file from in-memory string"); + if (from_inline_string_) throw mapnik::datasource_exception("geojson_datasource: Failed parse GeoJSON file from in-memory string"); else throw mapnik::datasource_exception("geojson_datasource: Failed parse GeoJSON file '" + filename_ + "'"); } } @@ -381,7 +371,7 @@ space); if (!result || itr != end) { - if (!inline_string_.empty()) throw mapnik::datasource_exception("geojson_datasource: Failed parse GeoJSON file from in-memory string"); + if (from_inline_string_) throw mapnik::datasource_exception("geojson_datasource: Failed parse GeoJSON file from in-memory string"); else throw mapnik::datasource_exception("geojson_datasource: Failed parse GeoJSON file '" + filename_ + "'"); } } @@ -399,12 +389,7 @@ if (geometry_index == 0) { extent_ = box; - for ( auto const& kv : *f) - { - desc_.add_descriptor(mapnik::attribute_descriptor(std::get<0>(kv), - mapnik::util::apply_visitor(attr_value_converter(), - std::get<1>(kv)))); - } + } else { @@ -412,6 +397,10 @@ } values.emplace_back(box, std::make_pair(geometry_index,0)); } + if (geometry_index < num_features_to_query_) + { + initialise_descriptor(f); + } ++geometry_index; } // packing algorithm @@ -419,7 +408,7 @@ } -geojson_datasource::~geojson_datasource() { } +geojson_datasource::~geojson_datasource() {} const char * geojson_datasource::name() { @@ -454,12 +443,12 @@ std::vector positions; mapnik::util::spatial_index::query_first_n(filter, index, positions, 5); + std::ifstream>::query_first_n(filter, index, positions, num_features_to_query_); mapnik::util::file file(filename_); - if (!file.open()) throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'"); - + if (!file) throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'"); + mapnik::context_ptr ctx = std::make_shared(); for (auto const& pos : positions) { std::fseek(file.get(), pos.first, SEEK_SET); @@ -468,7 +457,6 @@ std::fread(record.data(), pos.second, 1, file.get()); auto const* start = record.data(); auto const* end = start + record.size(); - mapnik::context_ptr ctx = std::make_shared(); mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx, -1)); // temp feature using namespace boost::spirit; standard::space_type space; @@ -493,8 +481,8 @@ } else if (cache_features_) { - unsigned num_features = features_.size(); - for (unsigned i = 0; i < num_features && i < 5; ++i) + std::size_t num_features = features_.size(); + for (std::size_t i = 0; i < num_features && i < num_features_to_query_; ++i) { result = mapnik::util::to_ds_type(features_[i]->get_geometry()); if (result) @@ -512,14 +500,14 @@ else { mapnik::util::file file(filename_); - if (!file.open()) + if (!file) { throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'"); } auto itr = tree_->qbegin(boost::geometry::index::intersects(extent_)); auto end = tree_->qend(); mapnik::context_ptr ctx = std::make_shared(); - for (std::size_t count = 0; itr !=end && count < 5; ++itr,++count) + for (std::size_t count = 0; itr !=end && count < num_features_to_query_; ++itr,++count) { geojson_datasource::item_type const& item = *itr; std::size_t file_offset = item.second.first; @@ -589,8 +577,8 @@ } } - // otherwise return an empty featureset pointer - return mapnik::featureset_ptr(); + // otherwise return an empty featureset + return mapnik::make_invalid_featureset(); } mapnik::featureset_ptr geojson_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const diff -Nru mapnik-3.0.9+ds/plugins/input/geojson/geojson_datasource.hpp mapnik-3.0.13+ds/plugins/input/geojson/geojson_datasource.hpp --- mapnik-3.0.9+ds/plugins/input/geojson/geojson_datasource.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/geojson/geojson_datasource.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -94,15 +94,17 @@ void initialise_index(Iterator start, Iterator end); void initialise_disk_index(std::string const& filename); private: + void initialise_descriptor(mapnik::feature_ptr const&); mapnik::datasource::datasource_t type_; mapnik::layer_descriptor desc_; std::string filename_; - std::string inline_string_; + bool from_inline_string_; mapnik::box2d extent_; std::vector features_; std::unique_ptr tree_; bool cache_features_ = true; bool has_disk_index_ = false; + const std::size_t num_features_to_query_; }; diff -Nru mapnik-3.0.9+ds/plugins/input/geojson/geojson_index_featureset.cpp mapnik-3.0.13+ds/plugins/input/geojson/geojson_index_featureset.cpp --- mapnik-3.0.9+ds/plugins/input/geojson/geojson_index_featureset.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/geojson/geojson_index_featureset.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,7 +24,6 @@ #include "geojson_index_featureset.hpp" #include #include -#include #include #include #include diff -Nru mapnik-3.0.9+ds/plugins/input/geojson/geojson_memory_index_featureset.cpp mapnik-3.0.13+ds/plugins/input/geojson/geojson_memory_index_featureset.cpp --- mapnik-3.0.9+ds/plugins/input/geojson/geojson_memory_index_featureset.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/geojson/geojson_memory_index_featureset.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,7 +23,6 @@ // mapnik #include #include -#include #include #include #include diff -Nru mapnik-3.0.9+ds/plugins/input/ogr/ogr_converter.cpp mapnik-3.0.13+ds/plugins/input/ogr/ogr_converter.cpp --- mapnik-3.0.9+ds/plugins/input/ogr/ogr_converter.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/ogr/ogr_converter.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,9 +25,12 @@ #include // ogr +#pragma GCC diagnostic push +#include #include "ogr_converter.hpp" #include #include +#pragma GCC diagnostic pop mapnik::geometry::geometry ogr_converter::convert_geometry(OGRGeometry* ogr_geom) { diff -Nru mapnik-3.0.9+ds/plugins/input/ogr/ogr_datasource.cpp mapnik-3.0.13+ds/plugins/input/ogr/ogr_datasource.cpp --- mapnik-3.0.9+ds/plugins/input/ogr/ogr_datasource.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/ogr/ogr_datasource.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -59,6 +59,16 @@ using mapnik::filter_in_box; using mapnik::filter_at_point; +static std::once_flag once_flag; + +extern "C" MAPNIK_EXP void on_plugin_load() +{ + // initialize ogr formats + // NOTE: in GDAL >= 2.0 this is the same as GDALAllRegister() + std::call_once(once_flag,[](){ + OGRRegisterAll(); + }); +} ogr_datasource::ogr_datasource(parameters const& params) : datasource(params), @@ -87,10 +97,6 @@ mapnik::progress_timer __stats__(std::clog, "ogr_datasource::init"); #endif - // initialize ogr formats - // NOTE: in GDAL >= 2.0 this is the same as GDALAllRegister() - OGRRegisterAll(); - boost::optional file = params.get("file"); boost::optional string = params.get("string"); if (!string) string = params.get("inline"); @@ -371,7 +377,7 @@ } mapnik::parameters & extra_params = desc_.get_extra_parameters(); OGRSpatialReference * srs_ref = layer->GetSpatialRef(); - char * srs_output = NULL; + char * srs_output = nullptr; if (srs_ref && srs_ref->exportToProj4( &srs_output ) == OGRERR_NONE ) { extra_params["proj4"] = mapnik::util::trim_copy(srs_output); } @@ -554,7 +560,7 @@ } } - return featureset_ptr(); + return mapnik::make_invalid_featureset(); } featureset_ptr ogr_datasource::features_at_point(coord2d const& pt, double tol) const @@ -597,5 +603,5 @@ } } - return featureset_ptr(); + return mapnik::make_invalid_featureset(); } diff -Nru mapnik-3.0.9+ds/plugins/input/pgraster/build.py mapnik-3.0.13+ds/plugins/input/pgraster/build.py --- mapnik-3.0.9+ds/plugins/input/pgraster/build.py 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/pgraster/build.py 2017-02-08 13:06:42.000000000 +0000 @@ -60,8 +60,7 @@ SHLIBPREFIX='', SHLIBSUFFIX='.input', source=plugin_sources, - LIBS=libraries, - LINKFLAGS=env['CUSTOM_LDFLAGS']) + LIBS=libraries) # if the plugin links to libmapnik ensure it is built first Depends(TARGET, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME'])) diff -Nru mapnik-3.0.9+ds/plugins/input/pgraster/pgraster_datasource.cpp mapnik-3.0.13+ds/plugins/input/pgraster/pgraster_datasource.cpp --- mapnik-3.0.9+ds/plugins/input/pgraster/pgraster_datasource.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/pgraster/pgraster_datasource.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -257,7 +257,7 @@ if (srid_ == 0) { const char* srid_c = rs->getValue("srid"); - if (srid_c != NULL) + if (srid_c != nullptr) { int result = 0; const char * end = srid_c + std::strlen(srid_c); @@ -274,7 +274,7 @@ } else { - MAPNIK_LOG_DEBUG(pgraster) << "pgraster_datasource: no response from metadata query " << s.str(); + MAPNIK_LOG_DEBUG(pgraster) << "pgraster_datasource: no response from metadata query " << s.str(); } rs->close(); } @@ -297,7 +297,7 @@ if (rs->next()) { const char* srid_c = rs->getValue("srid"); - if (srid_c != NULL) + if (srid_c != nullptr) { int result = 0; const char * end = srid_c + std::strlen(srid_c); @@ -627,10 +627,10 @@ b << "ST_SetSRID("; } - b << "'BOX3D("; + b << "'BOX("; b << std::setprecision(16); b << env.minx() << " " << env.miny() << ","; - b << env.maxx() << " " << env.maxy() << ")'::box3d"; + b << env.maxx() << " " << env.maxy() << ")'::box2d"; if (srid_ > 0) { @@ -878,9 +878,10 @@ std::string table_with_bbox; std::string col = geometryColumn_; - if ( use_overviews_ ) { - std::string sch = schema_; - std::string tab = mapnik::sql_utils::unquote_double(raster_table_); + if ( use_overviews_ && !overviews_.empty()) { + std::string sch = overviews_[0].schema; + std::string tab = overviews_[0].table; + col = overviews_[0].column; const double scale = std::min(px_gw, px_gh); std::vector::const_reverse_iterator i; for (i=overviews_.rbegin(); i!=overviews_.rend(); ++i) { @@ -997,7 +998,7 @@ } - return featureset_ptr(); + return mapnik::make_invalid_featureset(); } @@ -1010,7 +1011,7 @@ if (pool) { shared_ptr conn = pool->borrowObject(); - if (!conn) return featureset_ptr(); + if (!conn) return mapnik::make_invalid_featureset(); if (conn->isOK()) { @@ -1081,7 +1082,7 @@ } } - return featureset_ptr(); + return mapnik::make_invalid_featureset(); } box2d pgraster_datasource::envelope() const diff -Nru mapnik-3.0.9+ds/plugins/input/pgraster/pgraster_wkb_reader.cpp mapnik-3.0.13+ds/plugins/input/pgraster/pgraster_wkb_reader.cpp --- mapnik-3.0.9+ds/plugins/input/pgraster/pgraster_wkb_reader.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/pgraster/pgraster_wkb_reader.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -66,7 +66,7 @@ /* int16_t read_int16(const uint8_t** from, uint8_t littleEndian) { - assert(NULL != from); + assert(nullptr != from); return read_uint16(from, littleEndian); } @@ -183,17 +183,16 @@ { mapnik::image_gray32f image(width, height); float* data = image.data(); - double val; - val = reader(); // nodata value, need to read anyway + double nodataval = reader(); for (int y=0; y(bbox, image, 1.0); - if ( hasnodata ) raster->set_nodata(val); + if ( hasnodata ) raster->set_nodata(nodataval); return raster; } @@ -270,15 +269,13 @@ image.set(0xffffffff); - int val; - int nodataval; uint8_t * data = image.bytes(); int ps = 4; // sizeof(image::pixel_type) int off; - nodataval = reader(); // nodata value, need to read anyway + int nodataval = reader(); for (int y=0; y 255 ) val = 255; @@ -298,7 +295,7 @@ } } mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0); - if ( hasnodata ) raster->set_nodata(val); + if ( hasnodata ) raster->set_nodata(nodataval); return raster; } diff -Nru mapnik-3.0.9+ds/plugins/input/postgis/build.py mapnik-3.0.13+ds/plugins/input/postgis/build.py --- mapnik-3.0.9+ds/plugins/input/postgis/build.py 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/postgis/build.py 2017-02-08 13:06:42.000000000 +0000 @@ -54,7 +54,9 @@ libraries.append('boost_system%s' % env['BOOST_APPEND']) libraries.append('boost_regex%s' % env['BOOST_APPEND']) libraries.insert(0,env['MAPNIK_NAME']) + libraries.append('icui18n') libraries.append(env['ICU_LIB_NAME']) + libraries.append('icudata') TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME, SHLIBPREFIX='', diff -Nru mapnik-3.0.9+ds/plugins/input/postgis/postgis_datasource.cpp mapnik-3.0.13+ds/plugins/input/postgis/postgis_datasource.cpp --- mapnik-3.0.9+ds/plugins/input/postgis/postgis_datasource.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/postgis/postgis_datasource.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -88,6 +88,17 @@ extent_from_subquery_(*params.get("extent_from_subquery", false)), max_async_connections_(*params_.get("max_async_connection", 1)), asynchronous_request_(false), + twkb_encoding_(false), + twkb_rounding_adjustment_(*params_.get("twkb_rounding_adjustment", 0.0)), + simplify_snap_ratio_(*params_.get("simplify_snap_ratio", 1.0/40.0)), + // 1/20 of pixel seems to be a good compromise to avoid + // drop of collapsed polygons. + // See https://github.com/mapnik/mapnik/issues/1639 + // See http://trac.osgeo.org/postgis/ticket/2093 + simplify_dp_ratio_(*params_.get("simplify_dp_ratio", 1.0/20.0)), + simplify_prefilter_(*params_.get("simplify_prefilter", 0.0)), + simplify_dp_preserve_(false), + simplify_clip_resolution_(*params_.get("simplify_clip_resolution", 0.0)), // TODO - use for known tokens too: "(@\\w+|!\\w+!)" pattern_(boost::regex("(@\\w+)",boost::regex::normal | boost::regbase::icase)), // params below are for testing purposes only and may be removed at any time @@ -130,6 +141,12 @@ boost::optional simplify_opt = params.get("simplify_geometries", false); simplify_geometries_ = simplify_opt && *simplify_opt; + boost::optional twkb_opt = params.get("twkb_encoding", false); + twkb_encoding_ = twkb_opt && *twkb_opt; + + boost::optional simplify_preserve_opt = params.get("simplify_dp_preserve", false); + simplify_dp_preserve_ = simplify_preserve_opt && *simplify_preserve_opt; + ConnectionManager::instance().registerPool(creator_, *initial_size, pool_max_size_); CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id()); if (pool) @@ -462,7 +479,7 @@ // Finally, add unique metadata to layer descriptor mapnik::parameters & extra_params = desc_.get_extra_parameters(); // explicitly make copies of values due to https://github.com/mapnik/mapnik/issues/2651 - extra_params["srid"] = srid_; + extra_params["srid"] = mapnik::value_integer(srid_); if (!key_field_.empty()) { extra_params["key_field"] = key_field_; @@ -794,25 +811,91 @@ const double px_gw = 1.0 / std::get<0>(q.resolution()); const double px_gh = 1.0 / std::get<1>(q.resolution()); + const double px_sz = std::min(px_gw, px_gh); - s << "SELECT ST_AsBinary("; + if (twkb_encoding_) + { + // This will only work against PostGIS 2.2, or a back-patched version + // that has (a) a ST_Simplify with a "preserve collapsed" flag and + // (b) a ST_RemoveRepeatedPoints with a tolerance parameter and + // (c) a ST_AsTWKB implementation - if (simplify_geometries_) { - s << "ST_Simplify("; - } + // What number of decimals of rounding does the pixel size imply? + const int twkb_rounding = -1 * std::lround(log10(px_sz) + twkb_rounding_adjustment_) + 1; + // And what's that in map units? + const double twkb_tolerance = pow(10.0, -1.0 * twkb_rounding); - s << "\"" << geometryColumn_ << "\""; + s << "SELECT ST_AsTWKB("; + s << "ST_Simplify("; + s << "ST_RemoveRepeatedPoints("; - if (simplify_geometries_) { - // 1/20 of pixel seems to be a good compromise to avoid - // drop of collapsed polygons. - // See https://github.com/mapnik/mapnik/issues/1639 - const double tolerance = std::min(px_gw, px_gh) / 20.0; - s << ", " << tolerance << ")"; + if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz) + { + s << "ST_ClipByBox2D("; + } + s << "\"" << geometryColumn_ << "\""; + + // ! ST_ClipByBox2D() + if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz) + { + s << "," << sql_bbox(box) << ")"; + } + + // ! ST_RemoveRepeatedPoints() + s << "," << twkb_tolerance << ")"; + // ! ST_Simplify(), with parameter to keep collapsed geometries + s << "," << twkb_tolerance << ",true)"; + // ! ST_TWKB() + s << "," << twkb_rounding << ") AS geom"; } + else + { + s << "SELECT ST_AsBinary("; + if (simplify_geometries_) + { + s << "ST_Simplify("; + } + if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz) + { + s << "ST_ClipByBox2D("; + } + if (simplify_geometries_ && simplify_snap_ratio_ > 0.0) + { + s<< "ST_SnapToGrid("; + } + + // Geometry column! + s << "\"" << geometryColumn_ << "\""; - s << ") AS geom"; + // ! ST_SnapToGrid() + if (simplify_geometries_ && simplify_snap_ratio_ > 0.0) + { + const double tolerance = px_sz * simplify_snap_ratio_; + s << "," << tolerance << ")"; + } + // ! ST_ClipByBox2D() + if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz) + { + s << "," << sql_bbox(box) << ")"; + } + + // ! ST_Simplify() + if (simplify_geometries_) + { + const double tolerance = px_sz * simplify_dp_ratio_; + s << ", " << tolerance; + // Add parameter to ST_Simplify to keep collapsed geometries + if (simplify_dp_preserve_) + { + s << ", true"; + } + s << ")"; + } + + // ! ST_AsBinary() + s << ") AS geom"; + } mapnik::context_ptr ctx = std::make_shared(); std::set const& props = q.property_names(); std::set::const_iterator pos = props.begin(); @@ -854,11 +937,12 @@ } std::shared_ptr rs = get_resultset(conn, s.str(), pool, proc_ctx); - return std::make_shared(rs, ctx, desc_.get_encoding(), !key_field_.empty(), key_field_as_attribute_); + return std::make_shared(rs, ctx, desc_.get_encoding(), !key_field_.empty(), + key_field_as_attribute_, twkb_encoding_); } - return featureset_ptr(); + return mapnik::make_invalid_featureset(); } @@ -871,7 +955,7 @@ if (pool) { shared_ptr conn = pool->borrowObject(); - if (!conn) return featureset_ptr(); + if (!conn) return mapnik::make_invalid_featureset(); if (conn->isOK()) { @@ -941,11 +1025,12 @@ } std::shared_ptr rs = get_resultset(conn, s.str(), pool); - return std::make_shared(rs, ctx, desc_.get_encoding(), !key_field_.empty(), key_field_as_attribute_); + return std::make_shared(rs, ctx, desc_.get_encoding(), !key_field_.empty(), + key_field_as_attribute_, twkb_encoding_); } } - return featureset_ptr(); + return mapnik::make_invalid_featureset(); } box2d postgis_datasource::envelope() const diff -Nru mapnik-3.0.9+ds/plugins/input/postgis/postgis_datasource.hpp mapnik-3.0.13+ds/plugins/input/postgis/postgis_datasource.hpp --- mapnik-3.0.9+ds/plugins/input/postgis/postgis_datasource.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/postgis/postgis_datasource.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -119,6 +119,13 @@ bool estimate_extent_; int max_async_connections_; bool asynchronous_request_; + bool twkb_encoding_; + mapnik::value_double twkb_rounding_adjustment_; + mapnik::value_double simplify_snap_ratio_; + mapnik::value_double simplify_dp_ratio_; + mapnik::value_double simplify_prefilter_; + bool simplify_dp_preserve_; + mapnik::value_double simplify_clip_resolution_; boost::regex pattern_; int intersect_min_scale_; int intersect_max_scale_; diff -Nru mapnik-3.0.9+ds/plugins/input/postgis/postgis_featureset.cpp mapnik-3.0.13+ds/plugins/input/postgis/postgis_featureset.cpp --- mapnik-3.0.9+ds/plugins/input/postgis/postgis_featureset.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/postgis/postgis_featureset.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -49,14 +49,16 @@ context_ptr const& ctx, std::string const& encoding, bool key_field, - bool key_field_as_attribute) + bool key_field_as_attribute, + bool twkb_encoding) : rs_(rs), ctx_(ctx), tr_(new transcoder(encoding)), totalGeomSize_(0), feature_id_(1), key_field_(key_field), - key_field_as_attribute_(key_field_as_attribute) + key_field_as_attribute_(key_field_as_attribute), + twkb_encoding_(twkb_encoding) { } @@ -123,8 +125,14 @@ int size = rs_->getFieldLength(0); const char *data = rs_->getValue(0); - mapnik::geometry::geometry geometry = geometry_utils::from_wkb(data, size); - feature->set_geometry(std::move(geometry)); + if (twkb_encoding_ ) + { + feature->set_geometry(geometry_utils::from_twkb(data, size)); + } + else + { + feature->set_geometry(geometry_utils::from_wkb(data, size)); + } totalGeomSize_ += size; unsigned num_attrs = ctx_->size() + 1; diff -Nru mapnik-3.0.9+ds/plugins/input/postgis/postgis_featureset.hpp mapnik-3.0.13+ds/plugins/input/postgis/postgis_featureset.hpp --- mapnik-3.0.9+ds/plugins/input/postgis/postgis_featureset.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/postgis/postgis_featureset.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -44,7 +44,8 @@ context_ptr const& ctx, std::string const& encoding, bool key_field, - bool key_field_as_attribute); + bool key_field_as_attribute, + bool twkb_encoding); feature_ptr next(); ~postgis_featureset(); @@ -56,6 +57,7 @@ mapnik::value_integer feature_id_; bool key_field_; bool key_field_as_attribute_; + bool twkb_encoding_; }; #endif // POSTGIS_FEATURESET_HPP diff -Nru mapnik-3.0.9+ds/plugins/input/raster/raster_datasource.cpp mapnik-3.0.13+ds/plugins/input/raster/raster_datasource.cpp --- mapnik-3.0.9+ds/plugins/input/raster/raster_datasource.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/raster/raster_datasource.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -224,5 +224,5 @@ { MAPNIK_LOG_WARN(raster) << "raster_datasource: feature_at_point not supported"; - return featureset_ptr(); + return mapnik::make_invalid_featureset(); } diff -Nru mapnik-3.0.9+ds/plugins/input/shape/shape_datasource.cpp mapnik-3.0.13+ds/plugins/input/shape/shape_datasource.cpp --- mapnik-3.0.9+ds/plugins/input/shape/shape_datasource.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/shape/shape_datasource.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -98,11 +98,11 @@ mapnik::progress_timer __stats2__(std::clog, "shape_datasource::init(get_column_description)"); #endif - std::unique_ptr shape_ref = std::make_unique(shape_name_); - init(*shape_ref); - for (int i=0;idbf().num_fields();++i) + shape_io shape(shape_name_); + init(shape); + for (int i = 0; i < shape.dbf().num_fields(); ++i) { - field_descriptor const& fd = shape_ref->dbf().descriptor(i); + field_descriptor const& fd = shape.dbf().descriptor(i); std::string fld_name=fd.name_; switch (fd.type_) { diff -Nru mapnik-3.0.9+ds/plugins/input/shape/shapefile.hpp mapnik-3.0.13+ds/plugins/input/shape/shapefile.hpp --- mapnik-3.0.9+ds/plugins/input/shape/shapefile.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/shape/shapefile.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -105,6 +105,11 @@ pos += n; } + void set_pos(unsigned pos_) + { + pos = pos_; + } + int read_ndr_integer() { std::int32_t val; diff -Nru mapnik-3.0.9+ds/plugins/input/shape/shape_index_featureset.cpp mapnik-3.0.13+ds/plugins/input/shape/shape_index_featureset.cpp --- mapnik-3.0.9+ds/plugins/input/shape/shape_index_featureset.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/shape/shape_index_featureset.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -52,6 +52,9 @@ ctx_(std::make_shared()), shape_ptr_(std::move(shape_ptr)), tr_(new mapnik::transcoder(encoding)), + offsets_(), + itr_(), + attr_ids_(), row_limit_(row_limit), count_(0), feature_bbox_() @@ -63,12 +66,13 @@ if (index) { #if defined(MAPNIK_MEMORY_MAPPED_FILE) - mapnik::util::spatial_index::query(filter, index->file(), offsets_); + mapnik::util::spatial_index::query(filter, index->file(), offsets_); #else - mapnik::util::spatial_index::query(filter, index->file(), offsets_); + mapnik::util::spatial_index::query(filter, index->file(), offsets_); #endif } - std::sort(offsets_.begin(), offsets_.end()); + std::sort(offsets_.begin(), offsets_.end(), [](mapnik::detail::node const& n0, mapnik::detail::node const& n1) + {return n0.offset != n1.offset ? n0.offset < n1.offset : n0.start < n1.start;}); MAPNIK_LOG_DEBUG(shape) << "shape_index_featureset: Query size=" << offsets_.size(); itr_ = offsets_.begin(); } @@ -83,7 +87,14 @@ while ( itr_ != offsets_.end()) { - shape_ptr_->move_to(*itr_++); + int offset = itr_->offset; + shape_ptr_->move_to(offset); + std::vector> parts; + while (itr_ != offsets_.end() && itr_->offset == offset) + { + if (itr_->start!= -1) parts.emplace_back(itr_->start, itr_->end); + ++itr_; + } mapnik::value_integer feature_id = shape_ptr_->id(); shape_file::record_type record(shape_ptr_->reclength_ * 2); shape_ptr_->shp().read_record(record); @@ -124,7 +135,8 @@ { shape_io::read_bbox(record, feature_bbox_); if (!filter_.pass(feature_bbox_)) continue; - feature->set_geometry(shape_io::read_polyline(record)); + if (parts.size() < 2) feature->set_geometry(shape_io::read_polyline(record)); + else feature->set_geometry(shape_io::read_polyline_parts(record, parts)); break; } case shape_io::shape_polygon: @@ -133,7 +145,8 @@ { shape_io::read_bbox(record, feature_bbox_); if (!filter_.pass(feature_bbox_)) continue; - feature->set_geometry(shape_io::read_polygon(record)); + if (parts.size() < 2) feature->set_geometry(shape_io::read_polygon(record)); + else feature->set_geometry(shape_io::read_polygon_parts(record, parts)); break; } default : diff -Nru mapnik-3.0.9+ds/plugins/input/shape/shape_index_featureset.hpp mapnik-3.0.13+ds/plugins/input/shape/shape_index_featureset.hpp --- mapnik-3.0.9+ds/plugins/input/shape/shape_index_featureset.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/shape/shape_index_featureset.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -45,6 +45,21 @@ using mapnik::feature_ptr; using mapnik::context_ptr; +namespace mapnik { namespace detail +{ +struct node +{ + node() = default; + node(int offset_, int start_, int end_) + : offset(offset_), + start(start_), + end(end_) {} + int offset; + int start; + int end; +}; +}} // ns + template class shape_index_featureset : public Featureset { @@ -63,8 +78,8 @@ context_ptr ctx_; std::unique_ptr shape_ptr_; const std::unique_ptr tr_; - std::vector offsets_; - std::vector::iterator itr_; + std::vector offsets_; + std::vector::iterator itr_; std::vector attr_ids_; mapnik::value_integer row_limit_; mutable int count_; diff -Nru mapnik-3.0.9+ds/plugins/input/shape/shape_io.cpp mapnik-3.0.13+ds/plugins/input/shape/shape_io.cpp --- mapnik-3.0.9+ds/plugins/input/shape/shape_io.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/shape/shape_io.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -125,6 +125,7 @@ std::for_each(parts.begin(), parts.end(), [&](int & part) { part = record.read_ndr_integer();}); int start, end; mapnik::geometry::multi_line_string multi_line; + multi_line.reserve(num_parts); for (int k = 0; k < num_parts; ++k) { start = parts[k]; @@ -152,6 +153,34 @@ return geom; } +mapnik::geometry::geometry shape_io::read_polyline_parts(shape_file::record_type & record, std::vector> const& parts) +{ + mapnik::geometry::geometry geom; // default empty + int total_num_parts = record.read_ndr_integer(); + int num_parts = parts.size(); + mapnik::geometry::multi_line_string multi_line; + multi_line.reserve(num_parts); + for (int k = 0; k < num_parts; ++k) + { + int start = parts[k].first; + int end = parts[k].second; + unsigned pos = 4 + 32 + 8 + 4 * total_num_parts + start * 16; + record.set_pos(pos); + + mapnik::geometry::line_string line; + line.reserve(end - start); + for (int j = start; j < end; ++j) + { + double x = record.read_double(); + double y = record.read_double(); + line.emplace_back(x, y); + } + multi_line.push_back(std::move(line)); + } + geom = std::move(multi_line); + return geom; +} + mapnik::geometry::geometry shape_io::read_polygon(shape_file::record_type & record) { @@ -174,6 +203,56 @@ mapnik::geometry::linear_ring ring; ring.reserve(end - start); for (int j = start; j < end; ++j) + { + double x = record.read_double(); + double y = record.read_double(); + ring.emplace_back(x, y); + } + if (k == 0) + { + poly.set_exterior_ring(std::move(ring)); + } + else if (mapnik::util::is_clockwise(ring)) + { + multi_poly.emplace_back(std::move(poly)); + poly.interior_rings.clear(); + poly.set_exterior_ring(std::move(ring)); + } + else + { + poly.add_hole(std::move(ring)); + } + } + + if (multi_poly.size() > 0) // multi + { + multi_poly.emplace_back(std::move(poly)); + geom = std::move(multi_poly); + } + else + { + geom = std::move(poly); + } + mapnik::geometry::correct(geom); + return geom; +} + +mapnik::geometry::geometry shape_io::read_polygon_parts(shape_file::record_type & record, std::vector> const& parts) +{ + mapnik::geometry::geometry geom; // default empty + int total_num_parts = record.read_ndr_integer(); + mapnik::geometry::polygon poly; + mapnik::geometry::multi_polygon multi_poly; + int num_parts = parts.size(); + for (int k = 0; k < num_parts; ++k) + { + int start = parts[k].first; + int end = parts[k].second; + unsigned pos = 4 + 32 + 8 + 4 * total_num_parts + start * 16; + record.set_pos(pos); + mapnik::geometry::linear_ring ring; + ring.reserve(end - start); + for (int j = start; j < end; ++j) { double x = record.read_double(); double y = record.read_double(); diff -Nru mapnik-3.0.9+ds/plugins/input/shape/shape_io.hpp mapnik-3.0.13+ds/plugins/input/shape/shape_io.hpp --- mapnik-3.0.9+ds/plugins/input/shape/shape_io.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/shape/shape_io.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,16 +23,16 @@ #ifndef SHAPE_IO_HPP #define SHAPE_IO_HPP +// stl +#include +#include // mapnik #include #include - +#include // boost #include - -// stl -#include - +// #include "dbfile.hpp" #include "shapefile.hpp" @@ -72,7 +72,13 @@ inline bool has_index() const { - return (index_ && index_->is_open()); + if (index_ && index_->is_open()) + { + bool status = mapnik::util::check_spatial_index(index_->file()); + index_->seek(0);// rewind + return status; + } + return false; } inline int id() const { return id_;} @@ -80,6 +86,8 @@ static void read_bbox(shape_file::record_type & record, mapnik::box2d & bbox); static mapnik::geometry::geometry read_polyline(shape_file::record_type & record); static mapnik::geometry::geometry read_polygon(shape_file::record_type & record); + static mapnik::geometry::geometry read_polyline_parts(shape_file::record_type & record,std::vector> const& parts); + static mapnik::geometry::geometry read_polygon_parts(shape_file::record_type & record, std::vector> const& parts); shapeType type_; shape_file shp_; diff -Nru mapnik-3.0.9+ds/plugins/input/sqlite/sqlite_datasource.cpp mapnik-3.0.13+ds/plugins/input/sqlite/sqlite_datasource.cpp --- mapnik-3.0.9+ds/plugins/input/sqlite/sqlite_datasource.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/sqlite/sqlite_datasource.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -551,7 +551,7 @@ using_subquery_); } - return featureset_ptr(); + return mapnik::make_invalid_featureset(); } featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt, double tol) const @@ -631,5 +631,5 @@ using_subquery_); } - return featureset_ptr(); + return mapnik::make_invalid_featureset(); } diff -Nru mapnik-3.0.9+ds/plugins/input/topojson/topojson_datasource.cpp mapnik-3.0.13+ds/plugins/input/topojson/topojson_datasource.cpp --- mapnik-3.0.9+ds/plugins/input/topojson/topojson_datasource.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/topojson/topojson_datasource.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -66,18 +66,9 @@ { return mapnik::Boolean; } - - mapnik::eAttributeType operator() (std::string const& /*val*/) const - { - return mapnik::String; - } - - mapnik::eAttributeType operator() (mapnik::value_unicode_string const& /*val*/) const - { - return mapnik::String; - } - - mapnik::eAttributeType operator() (mapnik::value_null const& /*val*/) const + // string, object, array + template + mapnik::eAttributeType operator() (T const& /*val*/) const { return mapnik::String; } @@ -109,6 +100,11 @@ { return static_cast(mapnik::datasource_geometry_t::Polygon); } + template + int operator() (T const& ) const + { + return 0; + } }; struct collect_attributes_visitor @@ -117,6 +113,9 @@ collect_attributes_visitor(mapnik::layer_descriptor & desc): desc_(desc) {} + // no-op + void operator() (mapnik::topojson::empty) {} + // template void operator() (GeomType const& g) { @@ -161,32 +160,34 @@ } if (!inline_string_.empty()) { - parse_topojson(inline_string_); + parse_topojson(inline_string_.c_str()); } else { mapnik::util::file file(filename_); - if (!file.open()) + if (!file) { throw mapnik::datasource_exception("TopoJSON Plugin: could not open: '" + filename_ + "'"); } std::string file_buffer; file_buffer.resize(file.size()); std::fread(&file_buffer[0], file.size(), 1, file.get()); - parse_topojson(file_buffer); + parse_topojson(file_buffer.c_str()); } } namespace { -using base_iterator_type = std::string::const_iterator; -const mapnik::topojson::topojson_grammar g; +using iterator_type = const char*; +const mapnik::topojson::topojson_grammar g; } template void topojson_datasource::parse_topojson(T const& buffer) { boost::spirit::standard::space_type space; - bool result = boost::spirit::qi::phrase_parse(buffer.begin(), buffer.end(), g, space, topo_); + auto itr = buffer; + auto end = buffer + std::strlen(buffer); + bool result = boost::spirit::qi::phrase_parse(itr, end, g, space, topo_); if (!result) { throw mapnik::datasource_exception("topojson_datasource: Failed parse TopoJSON file '" + filename_ + "'"); @@ -285,7 +286,7 @@ } } // otherwise return an empty featureset pointer - return mapnik::featureset_ptr(); + return mapnik::make_invalid_featureset(); } mapnik::featureset_ptr topojson_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const diff -Nru mapnik-3.0.9+ds/plugins/input/topojson/topojson_featureset.cpp mapnik-3.0.13+ds/plugins/input/topojson/topojson_featureset.cpp --- mapnik-3.0.9+ds/plugins/input/topojson/topojson_featureset.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/plugins/input/topojson/topojson_featureset.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -21,13 +21,8 @@ *****************************************************************************/ // mapnik -#include -#include #include -#include -#include -#include - +#include // stl #include #include @@ -40,334 +35,6 @@ #include "topojson_featureset.hpp" -namespace mapnik { namespace topojson { - -struct attribute_value_visitor - -{ -public: - attribute_value_visitor(mapnik::transcoder const& tr) - : tr_(tr) {} - - mapnik::value operator()(std::string const& val) const - { - return mapnik::value(tr_.transcode(val.c_str())); - } - - template - mapnik::value operator()(T const& val) const - { - return mapnik::value(val); - } - - mapnik::transcoder const& tr_; -}; - -template -void assign_properties(mapnik::feature_impl & feature, T const& geom, mapnik::transcoder const& tr) -{ - if ( geom.props) - { - for (auto const& p : *geom.props) - { - feature.put_new(std::get<0>(p), mapnik::util::apply_visitor(attribute_value_visitor(tr),std::get<1>(p))); - } - } -} - -template -struct feature_generator -{ - feature_generator(Context & ctx, mapnik::transcoder const& tr, topology const& topo, std::size_t feature_id) - : ctx_(ctx), - tr_(tr), - topo_(topo), - num_arcs_(topo.arcs.size()), - feature_id_(feature_id) {} - - feature_ptr operator() (point const& pt) const - { - mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); - double x = pt.coord.x; - double y = pt.coord.y; - if (topo_.tr) - { - x = x * (*topo_.tr).scale_x + (*topo_.tr).translate_x; - y = y * (*topo_.tr).scale_y + (*topo_.tr).translate_y; - } - mapnik::geometry::point point(x, y); - feature->set_geometry(std::move(point)); - assign_properties(*feature, pt, tr_); - return feature; - } - - feature_ptr operator() (multi_point const& multi_pt) const - { - mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); - mapnik::geometry::multi_point multi_point; - multi_point.reserve(multi_pt.points.size()); - for (auto const& pt : multi_pt.points) - { - double x = pt.x; - double y = pt.y; - if (topo_.tr) - { - x = x * (*topo_.tr).scale_x + (*topo_.tr).translate_x; - y = y * (*topo_.tr).scale_y + (*topo_.tr).translate_y; - } - multi_point.add_coord(x, y); - } - feature->set_geometry(std::move(multi_point)); - assign_properties(*feature, multi_pt, tr_); - return feature; - } - - feature_ptr operator() (linestring const& line) const - { - mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); - if (num_arcs_ > 0) - { - index_type index = line.ring; - index_type arc_index = index < 0 ? std::abs(index) - 1 : index; - if (arc_index >= 0 && arc_index < static_cast(num_arcs_)) - { - auto const& arcs = topo_.arcs[arc_index]; - double px = 0, py = 0; - mapnik::geometry::line_string line_string; - line_string.reserve(arcs.coordinates.size()); - - for (auto pt : arcs.coordinates) - { - double x = pt.x; - double y = pt.y; - if (topo_.tr) - { - x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x; - y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y; - } - line_string.add_coord(x,y); - } - feature->set_geometry(std::move(line_string)); - assign_properties(*feature, line, tr_); - } - } - return feature; - } - - feature_ptr operator() (multi_linestring const& multi_line) const - { - mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); - if (num_arcs_ > 0) - { - mapnik::geometry::multi_line_string multi_line_string; - bool hit = false; - multi_line_string.reserve(multi_line.rings.size()); - for (auto const& index : multi_line.rings) - { - index_type arc_index = index < 0 ? std::abs(index) - 1 : index; - if (arc_index >= 0 && arc_index < static_cast(num_arcs_)) - { - hit = true; - double px = 0, py = 0; - mapnik::geometry::line_string line_string; - auto const& arcs = topo_.arcs[arc_index]; - line_string.reserve(arcs.coordinates.size()); - for (auto pt : arcs.coordinates) - { - double x = pt.x; - double y = pt.y; - if (topo_.tr) - { - x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x; - y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y; - } - line_string.add_coord(x, y); - } - multi_line_string.push_back(std::move(line_string)); - } - } - if (hit) - { - feature->set_geometry(std::move(multi_line_string)); - assign_properties(*feature, multi_line, tr_); - } - } - return feature; - } - - feature_ptr operator() (polygon const& poly) const - { - mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); - if (num_arcs_ > 0) - { - std::vector processed_coords; - mapnik::geometry::polygon polygon; - if (poly.rings.size() > 1) polygon.interior_rings.reserve(poly.rings.size() - 1); - bool first = true; - bool hit = false; - for (auto const& ring : poly.rings) - { - mapnik::geometry::linear_ring linear_ring; - for (auto const& index : ring) - { - double px = 0, py = 0; - bool reverse = index < 0; - index_type arc_index = reverse ? std::abs(index) - 1 : index; - if (arc_index >= 0 && arc_index < static_cast(num_arcs_)) - { - hit = true; - auto const& arcs = topo_.arcs[arc_index]; - auto const& coords = arcs.coordinates; - processed_coords.clear(); - processed_coords.reserve(coords.size()); - for (auto const& pt : coords ) - { - double x = pt.x; - double y = pt.y; - - if (topo_.tr) - { - transform const& tr = *topo_.tr; - x = (px += x) * tr.scale_x + tr.translate_x; - y = (py += y) * tr.scale_y + tr.translate_y; - } - processed_coords.emplace_back(coordinate{x,y}); - } - - if (reverse) - { - for (auto const& c : processed_coords | boost::adaptors::reversed) - { - linear_ring.emplace_back(c.x, c.y); - } - } - else - { - for (auto const& c : processed_coords) - { - linear_ring.emplace_back(c.x, c.y); - } - } - } - } - if (first) - { - first = false; - polygon.set_exterior_ring(std::move(linear_ring)); - } - else - { - polygon.add_hole(std::move(linear_ring)); - } - } - if (hit) - { - mapnik::geometry::correct(polygon); - feature->set_geometry(std::move(polygon)); - assign_properties(*feature, poly, tr_); - } - } - return feature; - } - - feature_ptr operator() (multi_polygon const& multi_poly) const - { - mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); - if (num_arcs_ > 0) - { - std::vector processed_coords; - mapnik::geometry::multi_polygon multi_polygon; - multi_polygon.reserve(multi_poly.polygons.size()); - bool hit = false; - for (auto const& poly : multi_poly.polygons) - { - bool first = true; - mapnik::geometry::polygon polygon; - if (poly.size() > 1) polygon.interior_rings.reserve(poly.size() - 1); - - for (auto const& ring : poly) - { - mapnik::geometry::linear_ring linear_ring; - for (auto const& index : ring) - { - double px = 0, py = 0; - bool reverse = index < 0; - index_type arc_index = reverse ? std::abs(index) - 1 : index; - if (arc_index >= 0 && arc_index < static_cast(num_arcs_)) - { - hit = true; - auto const& arcs = topo_.arcs[arc_index]; - auto const& coords = arcs.coordinates; - processed_coords.clear(); - processed_coords.reserve(coords.size()); - for (auto const& pt : coords ) - { - double x = pt.x; - double y = pt.y; - - if (topo_.tr) - { - x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x; - y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y; - } - processed_coords.emplace_back(coordinate{x,y}); - } - - using namespace boost::adaptors; - - if (reverse) - { - for (auto const& c : (processed_coords | reversed)) - { - linear_ring.add_coord(c.x, c.y); - } - } - else - { - for (auto const& c : processed_coords) - { - linear_ring.add_coord(c.x, c.y); - } - } - } - } - if (first) - { - first = false; - polygon.set_exterior_ring(std::move(linear_ring)); - } - else - { - polygon.add_hole(std::move(linear_ring)); - } - } - multi_polygon.push_back(std::move(polygon)); - } - if (hit) - { - mapnik::geometry::correct(multi_polygon); - feature->set_geometry(std::move(multi_polygon)); - assign_properties(*feature, multi_poly, tr_); - } - } - return feature; - } - - template - feature_ptr operator() (T const& ) const - { - return feature_ptr(); - } - - Context & ctx_; - mapnik::transcoder const& tr_; - topology const& topo_; - std::size_t num_arcs_; - std::size_t feature_id_; -}; - -}} - topojson_featureset::topojson_featureset(mapnik::topojson::topology const& topo, mapnik::transcoder const& tr, array_type && index_array) diff -Nru mapnik-3.0.9+ds/README.md mapnik-3.0.13+ds/README.md --- mapnik-3.0.9+ds/README.md 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/README.md 2017-02-08 13:06:42.000000000 +0000 @@ -8,8 +8,8 @@ _/ ``` -[![Build Status Linux](https://secure.travis-ci.org/mapnik/mapnik.png)](http://travis-ci.org/mapnik/mapnik) -[![Build status Windows](https://ci.appveyor.com/api/projects/status/hc9l7okdjtucfqqn?svg=true)](https://ci.appveyor.com/project/Mapbox/mapnik) +[![Build Status Linux](https://api.travis-ci.org/mapnik/mapnik.svg?branch=master)](http://travis-ci.org/mapnik/mapnik) +[![Build Status Windows](https://ci.appveyor.com/api/projects/status/hc9l7okdjtucfqqn?branch=master&svg=true)](https://ci.appveyor.com/project/Mapbox/mapnik) [![Coverage Status](https://coveralls.io/repos/mapnik/mapnik/badge.svg?branch=master&service=github)](https://coveralls.io/github/mapnik/mapnik?branch=master) Mapnik is an open source toolkit for developing mapping applications. At the core is a C++ shared library providing algorithms and patterns for spatial data access and visualization. @@ -20,7 +20,7 @@ # Installation -See [INSTALL.md](https://github.com/mapnik/mapnik/blob/master/INSTALL.md) for installation instructions and the [Install](https://github.com/mapnik/mapnik/wiki/Mapnik-Installation) page on the wiki for guides. +See [INSTALL.md](INSTALL.md) for installation instructions and the [Install](https://github.com/mapnik/mapnik/wiki/Mapnik-Installation) page on the wiki for guides. # Code of Conduct @@ -28,4 +28,4 @@ # License -Mapnik software is free and is released under the LGPL ([GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl.html_)). Please see [COPYING](https://github.com/mapnik/mapnik/blob/master/COPYING) for more information. +Mapnik software is free and is released under the LGPL ([GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl.html)). Please see [COPYING](https://github.com/mapnik/mapnik/blob/master/COPYING) for more information. diff -Nru mapnik-3.0.9+ds/SConstruct mapnik-3.0.13+ds/SConstruct --- mapnik-3.0.9+ds/SConstruct 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/SConstruct 2017-02-08 13:06:42.000000000 +0000 @@ -293,7 +293,9 @@ EnumVariable('OPTIMIZATION','Set compiler optimization level','3', ['0','1','2','3','4','s']), # Note: setting DEBUG=True will override any custom OPTIMIZATION level BoolVariable('DEBUG', 'Compile a debug version of Mapnik', 'False'), + BoolVariable('COVERAGE', 'Compile a libmapnik and plugins with --coverage', 'False'), BoolVariable('DEBUG_UNDEFINED', 'Compile a version of Mapnik using clang/llvm undefined behavior asserts', 'False'), + BoolVariable('DEBUG_SANITIZE', 'Compile a version of Mapnik using clang/llvm address sanitation', 'False'), ListVariable('INPUT_PLUGINS','Input drivers to include',DEFAULT_PLUGINS,PLUGINS.keys()), ('WARNING_CXXFLAGS', 'Compiler flags you can set to reduce warning levels which are placed after -Wall.', ''), @@ -302,6 +304,7 @@ ('CONFIG', "The path to the python file in which to save user configuration options. Currently : '%s'" % SCONS_LOCAL_CONFIG,SCONS_LOCAL_CONFIG), BoolVariable('USE_CONFIG', "Use SCons user '%s' file (will also write variables after successful configuration)", 'True'), BoolVariable('NO_ATEXIT', 'Will prevent Singletons from being deleted atexit of main thread', 'False'), + BoolVariable('NO_DLCLOSE', 'Will prevent plugins from being unloaded', 'False'), # http://www.scons.org/wiki/GoFastButton # http://stackoverflow.com/questions/1318863/how-to-optimize-an-scons-script BoolVariable('FAST', "Make SCons faster at the cost of less precise dependency tracking", 'False'), @@ -316,7 +319,6 @@ ('PATH_REMOVE', 'A path prefix to exclude from all known command and compile paths (create multiple excludes separated by :)', ''), ('PATH_REPLACE', 'Two path prefixes (divided with a :) to search/replace from all known command and compile paths', ''), ('MAPNIK_NAME', 'Name of library', 'mapnik'), - BoolVariable('MAPNIK_BUNDLED_SHARE_DIRECTORY', 'For portable packaging: instruct mapnik-config to report relative paths to bundled GDAL_DATA, PROJ_LIB, and ICU_DATA','False'), # Boost variables # default is '/usr/include', see FindBoost method below @@ -702,11 +704,7 @@ BOOST_INCLUDE_DIR = None BOOST_APPEND = None env['BOOST_APPEND'] = str() - - if env['THREADING'] == 'multi': - search_lib = 'libboost_thread' - else: - search_lib = 'libboost_filesystem' + search_lib = 'libboost_filesystem' # note: must call normpath to strip trailing slash otherwise dirname # does not remove 'lib' and 'include' @@ -1138,6 +1136,9 @@ else: mode = 'release mode' + if env['COVERAGE']: + mode += ' (with coverage)' + env['PLATFORM'] = platform.uname()[0] color_print(4,"Configuring on %s in *%s*..." % (env['PLATFORM'],mode)) @@ -1354,7 +1355,7 @@ # test for C++11 support, which is required if not env['HOST'] and not conf.supports_cxx11(): - color_print(1,"C++ compiler does not support C++11 standard (-std=c++11), which is required. Please upgrade your compiler to at least g++ 4.7 (ideally 4.8)") + color_print(1,"C++ compiler does not support C++11 standard (-std=c++11), which is required. Please upgrade your compiler") Exit(1) if not env['HOST']: @@ -1406,15 +1407,6 @@ ['program_options', 'boost/program_options.hpp', False] ] - if env['THREADING'] == 'multi': - BOOST_LIBSHEADERS.append(['thread', 'boost/thread/mutex.hpp', True]) - # on solaris the configure checks for boost_thread - # require the -pthreads flag to be able to check for - # threading support, so we add as a global library instead - # of attaching to cxxflags after configure - if env['PLATFORM'] == 'SunOS': - env.Append(CXXFLAGS = '-pthreads') - # if requested, sort LIBPATH and CPPPATH before running CheckLibWithHeader tests if env['PRIORITIZE_LINKING']: conf.prioritize_paths(silent=True) @@ -1446,12 +1438,13 @@ # just turn it off like this, but seems the only available work- # around. See https://svn.boost.org/trac/boost/ticket/6779 for more # details. - boost_version = [int(x) for x in env.get('BOOST_LIB_VERSION_FROM_HEADER').split('_')] - if not conf.CheckBoostScopedEnum(): - if boost_version < [1, 51]: - env.Append(CXXFLAGS = '-DBOOST_NO_SCOPED_ENUMS') - elif boost_version < [1, 57]: - env.Append(CXXFLAGS = '-DBOOST_NO_CXX11_SCOPED_ENUMS') + if not env['HOST']: + boost_version = [int(x) for x in env.get('BOOST_LIB_VERSION_FROM_HEADER').split('_')] + if not conf.CheckBoostScopedEnum(): + if boost_version < [1, 51]: + env.Append(CXXFLAGS = '-DBOOST_NO_SCOPED_ENUMS') + elif boost_version < [1, 57]: + env.Append(CXXFLAGS = '-DBOOST_NO_CXX11_SCOPED_ENUMS') if not env['HOST'] and env['ICU_LIB_NAME'] not in env['MISSING_DEPS']: # http://lists.boost.org/Archives/boost/2009/03/150076.php @@ -1604,6 +1597,7 @@ # prepend to make sure we link locally env.Prepend(CPPPATH = '#deps/agg/include') env.Prepend(LIBPATH = '#deps/agg') + env.Prepend(CPPPATH = '#deps/mapbox/variant/include') # prepend deps dir for auxillary headers env.Prepend(CPPPATH = '#deps') @@ -1629,7 +1623,7 @@ env["CAIRO_ALL_LIBS"] = ['cairo'] if env['RUNTIME_LINK'] == 'static': env["CAIRO_ALL_LIBS"].extend( - ['pixman-1','expat'] + ['pixman-1'] ) # todo - run actual checkLib? env['HAS_CAIRO'] = True @@ -1726,6 +1720,9 @@ if env['NO_ATEXIT']: env.Append(CPPDEFINES = '-DMAPNIK_NO_ATEXIT') + if env['NO_DLCLOSE'] or env['COVERAGE']: + env.Append(CPPDEFINES = '-DMAPNIK_NO_DLCLOSE') + # Mac OSX (Darwin) special settings if env['PLATFORM'] == 'Darwin': pthread = '' @@ -1785,17 +1782,24 @@ # Common flags for g++/clang++ CXX compiler. # TODO: clean up code more to make -Wextra -Wsign-compare -Wsign-conversion -Wconversion viable - common_cxx_flags = '-Wall %s %s -ftemplate-depth-300 -Wsign-compare -Wshadow ' % (env['WARNING_CXXFLAGS'], pthread) + # -Wfloat-equal -Wold-style-cast -Wexit-time-destructors -Wglobal-constructors -Wreserved-id-macro -Wheader-hygiene -Wmissing-noreturn + common_cxx_flags = '-fvisibility=hidden -fvisibility-inlines-hidden -Wall %s %s -ftemplate-depth-300 -Wsign-compare -Wshadow ' % (env['WARNING_CXXFLAGS'], pthread) + + if 'clang++' in env['CXX']: + common_cxx_flags += ' -Wno-unsequenced -Wtautological-compare -Wheader-hygiene ' if env['DEBUG']: env.Append(CXXFLAGS = common_cxx_flags + '-O0') else: - # TODO - add back -fvisibility-inlines-hidden - # https://github.com/mapnik/mapnik/issues/1863 env.Append(CXXFLAGS = common_cxx_flags + '-O%s' % (env['OPTIMIZATION'])) if env['DEBUG_UNDEFINED']: env.Append(CXXFLAGS = '-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error -ftrapv -fwrapv') + if env['DEBUG_SANITIZE']: + env.Append(CXXFLAGS = ['-fsanitize=address']) + env.Append(LINKFLAGS = ['-fsanitize=address']) + + # if requested, sort LIBPATH and CPPPATH one last time before saving... if env['PRIORITIZE_LINKING']: conf.prioritize_paths(silent=True) @@ -1884,6 +1888,10 @@ plugin_base = env.Clone() + if env['COVERAGE']: + plugin_base.Append(LINKFLAGS='--coverage') + plugin_base.Append(CXXFLAGS='--coverage') + Export('plugin_base') if env['FAST']: diff -Nru mapnik-3.0.9+ds/scripts/appveyor-system-info.ps1 mapnik-3.0.13+ds/scripts/appveyor-system-info.ps1 --- mapnik-3.0.9+ds/scripts/appveyor-system-info.ps1 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/scripts/appveyor-system-info.ps1 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,84 @@ +$PSVersionTable +$PSVersionTable.PSVersion + +$comp_name = $env:COMPUTERNAME +$user_name = $env:USERNAME +Write-Host $comp_name $user_name + +$on_appveyor = $false +if($comp_name -like 'APPVYR*' -And $user_name -eq "appveyor"){ + $on_appveyor = $true +} + + +$SystemManaged = Get-WmiObject -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile} +$total_physicalmem = gwmi Win32_ComputerSystem | % {[Math]::round($_.TotalPhysicalMemory/1MB,0)} +$physical_mem = get-ciminstance -class 'cim_physicalmemory' | % { $_.Capacity/1024/1024} + +$PF =gwmi Win32_PageFileUsage +$PageFileLocation = $PF.Name; +$PageFileSize = $PF.AllocatedBaseSize + +Write-Host "physical memory : "$physical_mem +Write-Host "total physical memory : "$total_physicalmem +Write-Host "page file system managed : "$SystemManaged +Write-Host "page file location : "$PageFileLocation +Write-Host "page file size : "$PageFileSize +Write-Host "InitialSize : "${CurrentPageFile}.InitialSize +Write-Host "MaximumSize : "$CurrentPageFile.MaximumSize + +if($on_appveyor -eq $true){ + + Write-Host !!!!!!! on AppVeyor: changing page file settings !!!!!!!!!! + + $dirs = ( + "C:\qt", + "C:\Users\appveyor\AppData\Local\Microsoft\Web Platform Installer", + "C:\Program Files\Microsoft SQL Server", + "C:\ProgramData\Package Cache" + ) + Foreach($dir in $dirs){ + if(Test-Path $dir) { + Write-Host found $dir + Remove-Item $dir -Force -Recurse + } else { + Write-Host not found $dir + } + } + + #disable automatically managed page file settings + $c = Get-WmiObject Win32_computersystem -EnableAllPrivileges + if($c.AutomaticManagedPagefile){ + Write-Host disabling managed page file settings + $c.AutomaticManagedPagefile = $false + $c.Put() | Out-Null + } + + $new_page_size=18000 + $CurrentPageFile = Get-WmiObject -Class Win32_PageFileSetting + if($CurrentPageFile.InitialSize -ne $new_page_size){ + Write-Host "setting new page file size to $new_page_size" + $CurrentPageFile.InitialSize=$new_page_size + $CurrentPageFile.MaximumSize=$new_page_size + $CurrentPageFile.Put() | Out-Null + } + + Write-Host "new ------------ " + Write-Host "system managed:" (Get-WmiObject -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile}) + Write-Host "page file size:" (gwmi Win32_PageFileUsage).AllocatedBaseSize + Write-Host "InitialSize: "${CurrentPageFile}.InitialSize + Write-Host "MaximumSize: "$CurrentPageFile.MaximumSize +} else { + Write-Host not on AppVeyor, leaving page file as is +} + +#list drives +Get-WmiObject -Class Win32_LogicalDisk | + Where-Object {$_.DriveType -ne 5} | + Sort-Object -Property Name | + Select-Object Name, VolumeName, FileSystem, Description, VolumeDirty, ` + @{"Label"="DiskSize(GB)";"Expression"={"{0:N}" -f ($_.Size/1GB) -as [float]}}, ` + @{"Label"="FreeSpace(GB)";"Expression"={"{0:N}" -f ($_.FreeSpace/1GB) -as [float]}}, ` + @{"Label"="%Free";"Expression"={"{0:N}" -f ($_.FreeSpace/$_.Size*100) -as [float]}} | + Format-Table -AutoSize + diff -Nru mapnik-3.0.9+ds/scripts/build-appveyor.bat mapnik-3.0.13+ds/scripts/build-appveyor.bat --- mapnik-3.0.9+ds/scripts/build-appveyor.bat 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/scripts/build-appveyor.bat 2017-02-08 13:06:42.000000000 +0000 @@ -5,12 +5,13 @@ ECHO =========== %~f0 =========== ECHO NUMBER_OF_PROCESSORS^: %NUMBER_OF_PROCESSORS% -ECHO RAM [MB]^: -powershell "get-ciminstance -class 'cim_physicalmemory' | %% { $_.Capacity/1024/1024}" +powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted -Force +IF %ERRORLEVEL% NEQ 0 GOTO ERROR +powershell .\scripts\appveyor-system-info.ps1 IF %ERRORLEVEL% NEQ 0 GOTO ERROR ::only build on AppVeyor, if explicitly stated -ECHO APPVEYOR_REPO_COMMIT_MESSAGE^: %APPVEYOR_REPO_COMMIT_MESSAGE% +ECHO APPVEYOR_REPO_COMMIT_MESSAGE^: "%APPVEYOR_REPO_COMMIT_MESSAGE%" ::SET BUILD_ON_APPVEYOR=0 ::for /F "tokens=1 usebackq" %%i in (`powershell .\scripts\parse-commit-message.ps1 '[build appveyor]'`) DO SET BUILD_ON_APPVEYOR=%%i ::IF %BUILD_ON_APPVEYOR% EQU 0 ECHO not building, commit with [build appveyor] && GOTO DONE @@ -21,13 +22,26 @@ SET BUILD_TYPE=%configuration% SET BUILDPLATFORM=%platform% SET TOOLS_VERSION=%msvs_toolset%.0 +ECHO ICU_VERSION^: %ICU_VERSION% IF DEFINED APPVEYOR (ECHO on AppVeyor) ELSE (ECHO NOT on AppVeyor) ECHO ======== SET PATH=C:\Python27;%PATH% SET PATH=C:\Program Files\7-Zip;%PATH% -:: *nix style find command: -SET PATH=C:\Program Files (x86)\Git\bin;%PATH% + +::update submodules (variant + test data) +git submodule update --init +IF %ERRORLEVEL% NEQ 0 GOTO ERROR + + +::python bindings, including test data +IF NOT EXIST bindings\python git clone --recursive https://github.com/mapnik/python-mapnik.git bindings/python +IF %ERRORLEVEL% NEQ 0 GOTO ERROR + +CD bindings\python & IF %ERRORLEVEL% NEQ 0 GOTO ERROR +git fetch & IF %ERRORLEVEL% NEQ 0 GOTO ERROR +git pull & IF %ERRORLEVEL% NEQ 0 GOTO ERROR +CD ..\.. & IF %ERRORLEVEL% NEQ 0 GOTO ERROR ::cloning mapnik-gyp if EXIST mapnik-gyp ECHO mapnik-gyp already cloned && GOTO MAPNIK_GYP_ALREADY_HERE @@ -48,6 +62,16 @@ IF EXIST mapnik-sdk (ECHO already extracted) ELSE (7z -y x deps.7z | %windir%\system32\FIND "ing archive") IF %ERRORLEVEL% NEQ 0 GOTO ERROR + +ECHO looking for boost and icu versions in SDK ... +FOR /F "tokens=1,2 usebackq" %%i in (`powershell %APPVEYOR_BUILD_FOLDER%\scripts\get-boost-icu-version-from-sdk.ps1`) DO SET %%i=%%j +IF %ERRORLEVEL% NEQ 0 GOTO ERROR + +ECHO BOOST_VERSION found in SDK^: %BOOST_VERSION% +ECHO ICU_VERSION found in SDK^: %ICU_VERSION% +ECHO ICU_VERSION2 found in SDK^: %ICU_VERSION2% + + CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 IF %ERRORLEVEL% NEQ 0 GOTO ERROR diff -Nru mapnik-3.0.9+ds/scripts/build-local.bat mapnik-3.0.13+ds/scripts/build-local.bat --- mapnik-3.0.9+ds/scripts/build-local.bat 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/scripts/build-local.bat 2017-02-08 13:06:42.000000000 +0000 @@ -8,14 +8,32 @@ SET APPVEYOR=true ::comment this to get complete AppVeyor behaviour SET LOCAL_BUILD_DONT_SKIP_TESTS=true - -SET MAPNIK_GIT=3.0.5 -SET BOOST_VERSION=59 SET FASTBUILD=1 + +:: OVERRIDE PARAMETERS >>>>>>>> +:NEXT-ARG + +IF '%1'=='' GOTO ARGS-DONE +ECHO setting %1 +SET %1 +SHIFT +GOTO NEXT-ARG + +:ARGS-DONE +::<<<<< OVERRIDE PARAMETERS + + SET configuration=Release SET msvs_toolset=14 SET platform=x64 SET APPVEYOR_BUILD_FOLDER=%CD% + +ECHO pulling test data +CALL git submodule update --init +IF %ERRORLEVEL% NEQ 0 GOTO ERROR +ECHO pulling test data, DONE + +SET TIME_START_LOCAL_BUILD=%TIME% CALL scripts\build-appveyor.bat IF %ERRORLEVEL% NEQ 0 GOTO ERROR @@ -28,5 +46,7 @@ :DONE ECHO =========== DONE %~f0 =========== +ECHO build started^: %TIME_START_LOCAL_BUILD% +ECHO build finished^: %TIME% EXIT /b %EL% diff -Nru mapnik-3.0.9+ds/scripts/ensure_test_data.sh mapnik-3.0.13+ds/scripts/ensure_test_data.sh --- mapnik-3.0.9+ds/scripts/ensure_test_data.sh 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/scripts/ensure_test_data.sh 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -eu +set -o pipefail + +if [[ -f RELEASE_VERSION.md ]]; then + VERSION=$(cat RELEASE_VERSION.md) + if [[ ! -d ./test/data ]]; then + echo "Downloading unit test data from https://github.com/mapnik/test-data/archive/${VERSION}.tar.gz" + mkdir -p test/data/ + curl -f -L -s https://github.com/mapnik/test-data/archive/${VERSION}.tar.gz | tar zxf - --strip-components=1 -C test/data/ + fi + if [[ ! -d ./test/data-visual ]]; then + echo "Downloading visual test data from https://github.com/mapnik/test-data-visual/archive/${VERSION}.tar.gz" + mkdir -p test/data-visual/ + curl -f -L -s https://github.com/mapnik/test-data-visual/archive/${VERSION}.tar.gz | tar zxf - --strip-components=1 -C test/data-visual/ + fi +elif [[ -d .git ]]; then + git submodule update --init test/ +else + echo "Expected either git clone directory (with .git) or release tarball with `RELEASE_VERSION.md` in root" + exit 1 +fi \ No newline at end of file diff -Nru mapnik-3.0.9+ds/scripts/get-boost-icu-version-from-sdk.ps1 mapnik-3.0.13+ds/scripts/get-boost-icu-version-from-sdk.ps1 --- mapnik-3.0.9+ds/scripts/get-boost-icu-version-from-sdk.ps1 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/scripts/get-boost-icu-version-from-sdk.ps1 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,21 @@ +$ErrorActionPreference = 'Stop' +$boost_version='0' +$icu_version='0' +$libdir=$PSScriptRoot+"\..\mapnik-gyp\mapnik-sdk\lib" + +#get boost and icu versions directly from the files in the SDK + +#boost_python-vc140-mt-1_61.dll +$boost_version=(Get-ChildItem $libdir -Filter *boost*.dll)[0].BaseName.split("_")[-1] + +#icuin56.dll +$icu_version=(Get-ChildItem $libdir -Filter icuin*.dll)[0].BaseName.split("icuin")[-1] + +Write-Host "BOOST_VERSION" $boost_version +Write-Host "ICU_VERSION" $icu_version".1" +Write-Host "ICU_VERSION2" $icu_version"_1" + +trap { + "Error: $_" + exit 1 +} diff -Nru mapnik-3.0.9+ds/scripts/msbuild-force-mp-and-buildinparallel.props mapnik-3.0.13+ds/scripts/msbuild-force-mp-and-buildinparallel.props --- mapnik-3.0.9+ds/scripts/msbuild-force-mp-and-buildinparallel.props 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/scripts/msbuild-force-mp-and-buildinparallel.props 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,9 @@ + + + + + true + true + + + \ No newline at end of file diff -Nru mapnik-3.0.9+ds/scripts/publish_release.sh mapnik-3.0.13+ds/scripts/publish_release.sh --- mapnik-3.0.9+ds/scripts/publish_release.sh 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/scripts/publish_release.sh 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,136 @@ +#!/bin/bash + +set -eu +set -o pipefail + +: ' + +Usage: + + git tag v3.0.12-rc7 -a -m "Tagging v3.0.12-rc7" + ./scripts/publish_release.sh + +Note: before running this script you need to tag a new release or release candidate. + +This script: + + - confirms that the current git checkout is a valid tag + - Downloads a fresh checkout to a /tmp directory + - Updates the submodules + - Confirms that the test-data and test-data-visual is also tagged, otherwise tags them + - Removes the test-data and test-data-visual since they are large and can be downloaded dynamically for released code + - Creates a tarball and uploads to a DRAFT "github release" + +After using this script: + + - Go to https://github.com/mapnik/mapnik/releases and confirm that the draft release looks good, then publish it. + +' + +function step { >&2 echo -e "\033[1m\033[36m* $1\033[0m"; } +function step_error { >&2 echo -e "\033[1m\033[31m$1\033[0m"; } + +if [[ ${GITHUB_TOKEN_MAPNIK_PUBLIC_REPO:-false} == false ]]; then + step_error "Please set GITHUB_TOKEN_MAPNIK_PUBLIC_REPO to a github token with 'public_repo' scope (create one at https://github.com/settings/tokens)" + exit 1 +fi + +export MAPNIK_VERSION=$(git describe) +if [[ $(git tag -l) =~ $MAPNIK_VERSION ]]; then + step "Success: found $MAPNIK_VERSION (result of git describe) in tags, continuing" +else + step_error "error: $MAPNIK_VERSION (result of git describe) not in "git tag -l" output, aborting" + step_error "You must create a valid annotated tag first, before running this ./scripts/publish_release.sh" + exit 1 +fi + +# alternatively set this to `git@github.com:mapnik/mapnik.git` to pull public tag +export ROOT_GIT_CLONE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd ../ && pwd )" + +export TARBALL_NAME="mapnik-${MAPNIK_VERSION}" +cd /tmp/ +rm -rf ${TARBALL_NAME} +step "Cloning ${MAPNIK_VERSION}" +git clone --depth 1 --branch ${MAPNIK_VERSION} ${ROOT_GIT_CLONE} ${TARBALL_NAME} +cd ${TARBALL_NAME} +step "Checking out ${MAPNIK_VERSION}" +git checkout "tags/${MAPNIK_VERSION}" + +step "checking submodules" +step "vendorizing and cleaning up mapbox variant" +git submodule update --init deps/mapbox/variant +rm -rf deps/mapbox/variant/.git +rm -f deps/mapbox/variant/*yml +rm -f deps/mapbox/variant/Jamroot + +function check_and_tag() { + REPO_DIR=$1 + REPO_NAME=$2 + cmd="curl --fail -I https://github.com/mapnik/${REPO_NAME}/releases/tag/${MAPNIK_VERSION}" + if [[ $(${cmd}) ]]; then + step "test data already tagged, no need to initialize submodule" + else + step "tagging test data" + git submodule update --depth 100 --init ${REPO_DIR} + cd ${REPO_DIR}/ + git remote set-url origin git@github.com:mapnik/${REPO_NAME} + git tag ${MAPNIK_VERSION} -a -m "tagging for ${MAPNIK_VERSION}" + git push --tags + cd ../../ + step "removing test data submodule" + rm -rf ${REPO_DIR}/ + fi + +} + +# test data +check_and_tag test/data test-data +# test data visual +check_and_tag test/data-visual test-data-visual + +step "removing .git and .gitignore" +rm -rf .git +rm -rf .gitignore +export TARBALL_COMPRESSED=${TARBALL_NAME}.tar.bz2 +echo ${MAPNIK_VERSION} > RELEASE_VERSION.md +step "creating tarball of ${TARBALL_COMPRESSED}" +cd ../ +tar cjf ${TARBALL_COMPRESSED} ${TARBALL_NAME}/ +step "uploading to github" +# https://developer.github.com/v3/repos/releases/#create-a-release +IS_PRERELEASE=false +if [[ ${MAPNIK_VERSION} =~ 'rc' ]] || [[ ${MAPNIK_VERSION} =~ 'alpha' ]]; then + IS_PRERELEASE=true +fi +IS_DRAFT=true +step "creating a draft release" + +export CHANGELOG_REF=$(python -c "print '${MAPNIK_VERSION}'.replace('.','').replace('v','').split('-')[0]") +export RELEASE_NOTES="Mapnik ${MAPNIK_VERSION}\r\n\r\n[Changelog](https://github.com/mapnik/mapnik/blob/${MAPNIK_VERSION}/CHANGELOG.md#${CHANGELOG_REF})" +step "release notes: $RELEASE_NOTES" + +# create draft release +curl --data "{\"tag_name\": \"${MAPNIK_VERSION}\",\"target_commitish\": \"master\",\"name\": \"${MAPNIK_VERSION}\",\"body\": \"${RELEASE_NOTES}\",\"draft\": ${IS_DRAFT},\"prerelease\": ${IS_PRERELEASE}}" \ +https://api.github.com/repos/mapnik/mapnik/releases?access_token=${GITHUB_TOKEN_MAPNIK_PUBLIC_REPO} \ +> create_response.json +cat create_response.json +# parse out upload url and form it up to post tarball +UPLOAD_URL=$(python -c "import json;print json.load(open('create_response.json'))['upload_url'].replace('{?name,label}','?name=${TARBALL_COMPRESSED}')") +HTML_URL=$(python -c "import json;print json.load(open('create_response.json'))['html_url']") + +step "upload url: $UPLOAD_URL" + +# upload source tarball +curl ${UPLOAD_URL} \ +-X POST \ +-H "Authorization: token ${GITHUB_TOKEN_MAPNIK_PUBLIC_REPO}" \ +-H "Content-Type:application/octet-stream" \ +--data-binary @${TARBALL_COMPRESSED} + +echo +step "Success: view your new draft release at ${HTML_URL}" +open ${HTML_URL} +echo + +#step "uploading $(realpath ${TARBALL_COMPRESSED}) to s3://mapnik/dist/${MAPNIK_VERSION}/" +#aws s3 cp --acl public-read ${TARBALL_COMPRESSED} s3://mapnik/dist/${MAPNIK_VERSION}/ diff -Nru mapnik-3.0.9+ds/scripts/test_release.sh mapnik-3.0.13+ds/scripts/test_release.sh --- mapnik-3.0.9+ds/scripts/test_release.sh 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/scripts/test_release.sh 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,65 @@ +#!/bin/bash + +set -eu +set -o pipefail + +: ' + +Note: before running this script you need to tag and publish a new release (it can be a draft) + +Usage: + + ./scripts/test_release.sh + +This script: + + - Downloads the latest release tarball from github + - Builds it and runs tests + +' + +function step { >&2 echo -e "\033[1m\033[36m* $1\033[0m"; } +function step_error { >&2 echo -e "\033[1m\033[31m$1\033[0m"; } + +if [[ ${GITHUB_TOKEN_MAPNIK_PUBLIC_REPO:-false} == false ]]; then + step_error "Please set GITHUB_TOKEN_MAPNIK_PUBLIC_REPO to a github token with 'public_repo' scope (create one at https://github.com/settings/tokens)" + exit 1 +fi + +export MAPNIK_VERSION="$(git describe)" +if [[ $(git tag -l) =~ ${MAPNIK_VERSION} ]]; then + step "Success: found $MAPNIK_VERSION (result of git describe) in tags, continuing" +else + step_error "error: $MAPNIK_VERSION (result of git describe) not in "git tag -l" output, aborting" + step_error "You must create a valid annotated tag first, before running this ./scripts/publish_release.sh" + exit 1 +fi + +curl --fail https://api.github.com/repos/mapnik/mapnik/releases -H "Authorization: token ${GITHUB_TOKEN_MAPNIK_PUBLIC_REPO}" > /tmp/mapnik-releases.json +RELEASE_ASSET_NAME=$(python -c "import json;print json.load(open('/tmp/mapnik-releases.json'))[0]['assets'][0]['name']") +if [[ ${RELEASE_ASSET_NAME} == "mapnik-${MAPNIK_VERSION}.tar.bz2" ]]; then + step "Successfully found release asset to test: mapnik-${MAPNIK_VERSION}.tar.bz2" +else + step_error "Error: did not find correct release asset to test: mapnik-${MAPNIK_VERSION}.tar.bz2" + exit 1 +fi + +export RELEASE_ASSET_URL=$(python -c "import json;print json.load(open('/tmp/mapnik-releases.json'))[0]['assets'][0]['url']") +step "Downloading ${RELEASE_ASSET_URL}" +mkdir -p /tmp/build-mapnik-${MAPNIK_VERSION}/ +rm -rf /tmp/build-mapnik-${MAPNIK_VERSION}/* +cd /tmp/build-mapnik-${MAPNIK_VERSION}/ +# note: curl passes the "Authorization" header to redirects such that this breaks aws +# hence we need a two step approach here to downloading rather than depending on -L + +# first a head request to get the download redirect +curl -I -f ${RELEASE_ASSET_URL} -H "Accept: application/octet-stream" -H "Authorization: token ${GITHUB_TOKEN_MAPNIK_PUBLIC_REPO}" > redirect.json +# now download from the github s3 location after stripping bogus newline +export RELEASE_ASSET_S3=$(cat redirect.json | grep location | cut -d' ' -f2 | tr '\r' ' ') +curl --retry 3 -f -S -L "${RELEASE_ASSET_S3}" -o mapnik-${MAPNIK_VERSION}.tar.bz2 +tar xf mapnik-${MAPNIK_VERSION}.tar.bz2 +cd mapnik-${MAPNIK_VERSION} +source bootstrap.sh +./configure CXX="$(pwd)/mason_packages/.link/bin/ccache clang++" +make +make test diff -Nru mapnik-3.0.9+ds/scripts/time-header mapnik-3.0.13+ds/scripts/time-header --- mapnik-3.0.9+ds/scripts/time-header 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/scripts/time-header 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -eu +set -o pipefail + +CXXFLAGS="$(./utils/mapnik-config/mapnik-config --cflags)" +CXX="$(./utils/mapnik-config/mapnik-config --cxx)" +echo "Time taken to compile '$(basename $1)':" +time ${CXX} $1 -I./test -I./deps/agg/include -Ideps -I./deps/mapbox/variant/include -I./include $CXXFLAGS -o /tmp/header.out \ No newline at end of file diff -Nru mapnik-3.0.9+ds/scripts/travis-command-wrapper.py mapnik-3.0.13+ds/scripts/travis-command-wrapper.py --- mapnik-3.0.9+ds/scripts/travis-command-wrapper.py 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/scripts/travis-command-wrapper.py 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,106 @@ +#!/usr/bin/python +# +# Author: Patrick Ohly +# Copyright: Copyright (C) 2015 Intel Corporation +# +# This file is licensed under the MIT license, see COPYING.MIT in +# this source distribution for the terms. + +# Runs a command, pipes its output to stdout, and injects status +# reports at regular time interval. +# +# This ensures that TravisCI does not abort the command just because +# it is silent for more than 10 minutes, as it can happen with bitbake +# when working on a single complex task, like "bitbake linux-yocto". +# +# Piping bitbake stdout has the advantage that bitbake enters +# non-interactive output mode, which it would do when run by TravisCI +# directly. +# +# Finally, the default status messages give some sense of memory +# and disk usage, which is critical in the rather constrained +# TravisCI environments. + +import errno +import optparse +import signal +import subprocess +import sys +import time + +parser = optparse.OptionParser() +parser.add_option("-s", "--status", + help="invoked in a shell when it is time for a status report", + # 200 columns is readable in the TravisCI Web UI without wrapping. + # Depends of course on screen and font size. Resizing top output + # only works (and is needed) on the more recent Trusty TravisCI + # environment. + default="date; free; df -h .; COLUMNS=200 LINES=30 top -w -b -n 1 2>/dev/null || top -n 1; ps x --cols 200 --forest", + metavar="SHELL-CMD") +parser.add_option("-i", "--interval", + help="repeat status at intervals of this amount of seconds, 0 to disable", + default=300, + metavar="SECONDS", type="int") +parser.add_option("-d", "--deadline", + help="stop execution when reaching the given time", + default=time.time, + metavar="SECONDS-SINCE-EPOCH", type="int") + +(options, args) = parser.parse_args() + +def check_deadline(now): + if options.deadline > 0 and options.deadline < now: + print "\n\n*** travis-cmd-wrapper: deadline reached, shutting down ***\n\n" + sys.exit(1) + else: + print "deadline not reached: %s > %s" % (options.deadline,now) + +# Set up status alarm. When we have a deadline, we need to check more often +# and/or sooner. Sending a SIGALRM manually will also trigger a status report +# (not really possible in TravisCI, but may be useful elsewhere). +now = time.time() +next_status = now + options.interval +alarm_interval = max(options.interval, 0) +if options.deadline: + check_deadline(now) + if options.deadline < now + 60: + # Wake up a little too late, to be sure that we trigger the if check. + deadline_alarm_interval = max(int(options.deadline + 2 - now), 1) + elif next_status > 60: + deadline_alarm_interval = 60 + if deadline_alarm_interval < alarm_interval: + alarm_interval = deadline_alarm_interval + +def status(signum, frame): + global next_status + now = time.time() + if options.interval < 0 or now >= next_status: + subprocess.call(options.status, shell=True) + next_status = now + options.interval + check_deadline(now) + if alarm_interval > 0: + signal.alarm(alarm_interval) + +# Run command. +try: + cmd = subprocess.Popen(args, stdout=subprocess.PIPE) + + # Arm timer and handler. + signal.signal(signal.SIGALRM, status) + if alarm_interval > 0: + signal.alarm(alarm_interval) + + while cmd.poll() is None: + try: + line = cmd.stdout.readline() + sys.stdout.write(line) + sys.stdout.flush() + except IOError, ex: + if ex.errno != errno.EINTR: + raise +finally: + # If we go down, so must our child... + if cmd.poll() is None: + cmd.kill() + +exit(1 if cmd.returncode else 0) \ No newline at end of file diff -Nru mapnik-3.0.9+ds/scripts/travis-common.sh mapnik-3.0.13+ds/scripts/travis-common.sh --- mapnik-3.0.9+ds/scripts/travis-common.sh 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/scripts/travis-common.sh 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,120 @@ +#! /bin/bash + +# enabled VALUE +# - if VALUE is empty or falsy, returns 1 (false) +# - otherwise returns 0 (true) +# enabled VALUE COMMAND ... +# - if VALUE is empty or falsy, returns 0 (true) +# - otherwise runs COMMAND and returns its result +enabled () { + local value="$1"; shift + case $value in + ''|'0'|[Ff]alse|[Nn]o) test $# -ne 0;; + *) test $# -eq 0 || "$@";; + esac +} + +# on NAME +# - if NAME == $TRAVIS_OS_NAME, returns 0 (true) +# - otherwise returns 1 (false) +# on NAME COMMAND ... +# - if NAME == $TRAVIS_OS_NAME, runs COMMAND and returns its result +# - otherwise returns 0 (true) +on () { + local name="$1"; shift + case $name in + $TRAVIS_OS_NAME) test $# -eq 0 || "$@";; + *) test $# -ne 0;; + esac +} + +git_submodule_update () { + git submodule update "$@" && return + # failed, search branch and pull request heads for matching commit + git submodule foreach \ + ' + test "$sha1" = "`git rev-parse HEAD`" || + git ls-remote origin "refs/heads/*" "refs/pull/*/head" | + while read hash ref; do + if test "$hash" = "$sha1"; then + git config --add remote.origin.fetch "+$ref:$ref" + break + fi + done + ' + # try again with added fetch refs + git submodule update "$@" +} + +# install and call pip +pip () { + if ! which pip >/dev/null; then + easy_install --user pip && \ + export PATH="$HOME/Library/Python/2.7/bin:$PATH" + fi + command pip "$@" +} + +# commit_message_contains TEXT +# - returns 0 (true) if TEXT is found in commit message +# - case-insensitive, plain-text search, not regex +commit_message_contains () { + git log -1 --pretty='%B' "$TRAVIS_COMMIT" | grep -qiFe "$*" +} + +commit_message_parse () { + if commit_message_contains '[skip tests]'; then + config_override "CPP_TESTS = False" + fi + if commit_message_contains '[skip utils]'; then + config_override "MAPNIK_INDEX = False" + config_override "MAPNIK_RENDER = False" + config_override "PGSQL2SQLITE = False" + config_override "SHAPEINDEX = False" + config_override "SVG2PNG = False" + fi +} + +config_override () { + echo "Appending to config.py:" "$@" + echo "$@" >> ./config.py +} + +configure () { + if enabled ${COVERAGE}; then + ./configure "$@" PREFIX=${PREFIX} PGSQL2SQLITE=False SVG2PNG=False SVG_RENDERER=False \ + COVERAGE=True DEBUG=True + else + ./configure "$@" PREFIX=${PREFIX} + fi + # print final config values, sorted and indented + sort -sk1,1 ./config.py | sed -e 's/^/ /' +} + +coverage () { + ./mason_packages/.link/bin/cpp-coveralls \ + --gcov ${LLVM_COV} \ + --exclude mason_packages \ + --exclude .sconf_temp --exclude benchmark --exclude deps \ + --exclude scons --exclude test --exclude demo --exclude docs \ + --exclude fonts \ + > /dev/null +} + +trigger_downstream() { + body="{ + \"request\": { + \"message\": \"Triggered build: Mapnik core commit ${TRAVIS_COMMIT}\", + \"branch\":\"master\" + } + } + " + + curl -s -X POST \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -H "Travis-API-Version: 3" \ + -H "Authorization: token ${TRAVIS_TRIGGER_TOKEN}" \ + -d "$body" \ + https://api.travis-ci.org/repo/mapnik%2Fpython-mapnik/requests +} diff -Nru mapnik-3.0.9+ds/src/agg/agg_renderer.cpp mapnik-3.0.13+ds/src/agg/agg_renderer.cpp --- mapnik-3.0.9+ds/src/agg/agg_renderer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/agg_renderer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -43,7 +43,9 @@ #include #include #include -// agg + +#pragma GCC diagnostic push +#include #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" #include "agg_color_rgba.h" @@ -53,9 +55,12 @@ #include "agg_span_allocator.h" #include "agg_image_accessors.h" #include "agg_span_image_filter_rgba.h" +#pragma GCC diagnostic pop -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop // stl #include @@ -121,11 +126,11 @@ mode_(mode), opacity_(opacity) {} - void operator() (marker_null const&) {} + void operator() (marker_null const&) const {} - void operator() (marker_svg const&) {} + void operator() (marker_svg const&) const {} - void operator() (marker_rgba8 const& marker) + void operator() (marker_rgba8 const& marker) const { mapnik::image_rgba8 const& bg_image = marker.get_data(); std::size_t w = bg_image.width(); @@ -252,6 +257,7 @@ { util::apply_visitor(visitor, filter_tag); } + radius *= common_.scale_factor_; if (radius > common_.t_.offset()) { common_.t_.set_offset(radius); @@ -304,7 +310,7 @@ if (st.image_filters().size() > 0) { blend_from = true; - mapnik::filter::filter_visitor visitor(*current_buffer_); + mapnik::filter::filter_visitor visitor(*current_buffer_, common_.scale_factor_); for (mapnik::filter::filter_type const& filter_tag : st.image_filters()) { util::apply_visitor(visitor, filter_tag); @@ -329,7 +335,7 @@ if (st.direct_image_filters().size() > 0) { // apply any 'direct' image filters - mapnik::filter::filter_visitor visitor(pixmap_); + mapnik::filter::filter_visitor visitor(pixmap_, common_.scale_factor_); for (mapnik::filter::filter_type const& filter_tag : st.direct_image_filters()) { util::apply_visitor(visitor, filter_tag); @@ -361,9 +367,9 @@ opacity_(opacity), comp_op_(comp_op) {} - void operator() (marker_null const&) {} + void operator() (marker_null const&) const {} - void operator() (marker_svg const& marker) + void operator() (marker_svg const& marker) const { using color_type = agg::rgba8; using order_type = agg::order_rgba; @@ -414,7 +420,7 @@ svg_renderer.render(*ras_ptr_, sl, renb, mtx, opacity_, bbox); } - void operator() (marker_rgba8 const& marker) + void operator() (marker_rgba8 const& marker) const { using color_type = agg::rgba8; using order_type = agg::order_rgba; diff -Nru mapnik-3.0.9+ds/src/agg/process_building_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_building_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_building_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_building_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -33,10 +33,12 @@ #include #include #include + // stl #include -// agg +#pragma GCC diagnostic push +#include #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_color_rgba.h" @@ -45,6 +47,7 @@ #include "agg_scanline_u.h" #include "agg_renderer_scanline.h" #include "agg_conv_stroke.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/agg/process_debug_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_debug_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_debug_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_debug_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -33,7 +33,8 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_color_rgba.h" @@ -41,6 +42,7 @@ #include "agg_scanline_u.h" #include "agg_renderer_scanline.h" #include "agg_conv_stroke.h" +#pragma GCC diagnostic pop namespace mapnik { @@ -165,12 +167,12 @@ }; template -struct render_ring_visitor { - +struct render_ring_visitor +{ render_ring_visitor(RingRenderer & renderer) : renderer_(renderer) {} - void operator()(mapnik::geometry::multi_polygon const& geom) + void operator()(mapnik::geometry::multi_polygon const& geom) const { for (auto const& poly : geom) { @@ -178,7 +180,7 @@ } } - void operator()(mapnik::geometry::polygon const& geom) + void operator()(mapnik::geometry::polygon const& geom) const { agg::rgba8 red(255,0,0,255); agg::rgba8 green(0,255,255,255); @@ -199,7 +201,7 @@ } template - void operator()(GeomType const&) {} + void operator()(GeomType const&) const {} RingRenderer & renderer_; }; diff -Nru mapnik-3.0.9+ds/src/agg/process_dot_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_dot_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_dot_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_dot_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -33,7 +33,8 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_ellipse.h" #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" @@ -41,6 +42,7 @@ #include "agg_renderer_scanline.h" #include "agg_color_rgba.h" #include "agg_renderer_base.h" +#pragma GCC diagnostic pop namespace mapnik { namespace detail { diff -Nru mapnik-3.0.9+ds/src/agg/process_group_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_group_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_group_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_group_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,22 +25,20 @@ #include #include #include -#include #include -#include #include -#include -#include -#include #include -#include #include +#include #include #include #include #include -// agg + +#pragma GCC diagnostic push +#include #include "agg_trans_affine.h" +#pragma GCC diagnostic pop namespace mapnik { @@ -55,7 +53,7 @@ struct thunk_renderer; template <> -struct thunk_renderer +struct thunk_renderer : render_thunk_list_dispatch { using renderer_type = agg_renderer; using buffer_type = renderer_type::buffer_type; @@ -64,12 +62,13 @@ thunk_renderer(renderer_type &ren, std::unique_ptr const& ras_ptr, buffer_type *buf, - renderer_common &common, - pixel_position const &offset) - : ren_(ren), ras_ptr_(ras_ptr), buf_(buf), common_(common), offset_(offset) + renderer_common &common) + : ren_(ren), ras_ptr_(ras_ptr), buf_(buf), common_(common), + tex_(*buf, HALO_RASTERIZER_FULL, src_over, src_over, + common.scale_factor_, common.font_manager_.get_stroker()) {} - void operator()(vector_marker_render_thunk const &thunk) const + virtual void operator()(vector_marker_render_thunk const& thunk) { using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender using buf_type = agg::rendering_buffer; @@ -95,7 +94,7 @@ render_vector_marker(svg_renderer, *ras_ptr_, renb, thunk.src_->bounding_box(), offset_tr, thunk.opacity_, thunk.snap_to_pixels_); } - void operator()(raster_marker_render_thunk const &thunk) const + virtual void operator()(raster_marker_render_thunk const& thunk) { using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender using buf_type = agg::rendering_buffer; @@ -113,32 +112,25 @@ render_raster_marker(renb, *ras_ptr_, thunk.src_, offset_tr, thunk.opacity_, common_.scale_factor_, thunk.snap_to_pixels_); } - void operator()(text_render_thunk const &thunk) const + virtual void operator()(text_render_thunk const& thunk) { - text_renderer_type ren(*buf_, thunk.halo_rasterizer_, thunk.comp_op_, thunk.comp_op_, - common_.scale_factor_, common_.font_manager_.get_stroker()); + tex_.set_comp_op(thunk.comp_op_); + tex_.set_halo_comp_op(thunk.comp_op_); + tex_.set_halo_rasterizer(thunk.halo_rasterizer_); - render_offset_placements( - thunk.placements_, - offset_, - [&] (glyph_positions_ptr const& glyphs) - { - marker_info_ptr mark = glyphs->get_marker(); - if (mark) - { - ren_.render_marker(glyphs->marker_pos(), - *mark->marker_, - mark->transform_, - thunk.opacity_, thunk.comp_op_); - } - ren.render(*glyphs); - }); - } + for (auto const& glyphs : thunk.placements_) + { + scoped_glyph_positions_offset tmp_off(*glyphs, offset_); - template - void operator()(T const &) const - { - throw std::runtime_error("Rendering of this data type is not supported currently by the renderer"); + if (auto const& mark = glyphs->get_marker()) + { + ren_.render_marker(glyphs->marker_pos(), + *mark->marker_, + mark->transform_, + thunk.opacity_, thunk.comp_op_); + } + tex_.render(*glyphs); + } } private: @@ -146,7 +138,7 @@ std::unique_ptr const& ras_ptr_; buffer_type *buf_; renderer_common &common_; - pixel_position offset_; + text_renderer_type tex_; }; template @@ -154,16 +146,11 @@ mapnik::feature_impl & feature, proj_transform const& prj_trans) { + thunk_renderer ren(*this, ras_ptr, current_buffer_, common_); + render_group_symbolizer( sym, feature, common_.vars_, prj_trans, clipping_extent(common_), common_, - [&](render_thunk_list const& thunks, pixel_position const& render_offset) - { - thunk_renderer ren(*this, ras_ptr, current_buffer_, common_, render_offset); - for (render_thunk_ptr const& thunk : thunks) - { - util::apply_visitor(ren, *thunk); - } - }); + ren); } template void agg_renderer::process(group_symbolizer const&, diff -Nru mapnik-3.0.9+ds/src/agg/process_line_pattern_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_line_pattern_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_line_pattern_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_line_pattern_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -37,7 +37,10 @@ #include #include #include -// agg + + +#pragma GCC diagnostic push +#include #include "agg_basics.h" #include "agg_pixfmt_rgba.h" #include "agg_color_rgba.h" @@ -50,6 +53,7 @@ #include "agg_span_allocator.h" #include "agg_span_pattern_rgba.h" #include "agg_renderer_outline_image.h" +#pragma GCC diagnostic pop namespace mapnik { @@ -71,83 +75,26 @@ feature_(feature), prj_trans_(prj_trans) {} - void operator() (marker_null const&) {} + void operator() (marker_null const&) const {} - void operator() (marker_svg const& marker) + void operator() (marker_svg const& marker) const { - using color = agg::rgba8; - using order = agg::order_rgba; - using blender_type = agg::comp_op_adaptor_rgba_pre; - using pattern_filter_type = agg::pattern_filter_bilinear_rgba8; - using pattern_type = agg::line_image_pattern; - using pixfmt_type = agg::pixfmt_custom_blend_rgba; - using renderer_base = agg::renderer_base; - using renderer_type = agg::renderer_outline_image; - using rasterizer_type = agg::rasterizer_outline_aa; - - value_double opacity = get(sym_, feature_, common_.vars_); agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional(sym_, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_); mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; image_rgba8 image(bbox_image.width(), bbox_image.height()); render_pattern(*ras_ptr_, marker, image_tr, 1.0, image); + render(image, marker.width(), marker.height()); + } - value_bool clip = get(sym_, feature_, common_.vars_); - value_double offset = get(sym_, feature_, common_.vars_); - value_double simplify_tolerance = get(sym_, feature_, common_.vars_); - value_double smooth = get(sym_, feature_, common_.vars_); - - agg::rendering_buffer buf(current_buffer_->bytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->row_size()); - pixfmt_type pixf(buf); - pixf.comp_op(static_cast(get(sym_, feature_, common_.vars_))); - renderer_base ren_base(pixf); - agg::pattern_filter_bilinear_rgba8 filter; - - pattern_source source(image, opacity); - pattern_type pattern (filter,source); - renderer_type ren(ren_base, pattern); - double half_stroke = std::max(marker.width()/2.0,marker.height()/2.0); - int rast_clip_padding = static_cast(std::round(half_stroke)); - ren.clip_box(-rast_clip_padding,-rast_clip_padding,common_.width_+rast_clip_padding,common_.height_+rast_clip_padding); - rasterizer_type ras(ren); - - agg::trans_affine tr; - auto transform = get_optional(sym_, keys::geometry_transform); - if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_); - - box2d clip_box = clipping_extent(common_); - if (clip) - { - double padding = (double)(common_.query_extent_.width()/pixmap_.width()); - if (half_stroke > 1) - padding *= half_stroke; - if (std::fabs(offset) > 0) - padding *= std::fabs(offset) * 1.2; - padding *= common_.scale_factor_; - clip_box.pad(padding); - } - using vertex_converter_type = vertex_converter; - - vertex_converter_type converter(clip_box,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); - - if (clip) converter.set(); - converter.set(); //always transform - if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter - if (std::fabs(offset) > 0.0) converter.set(); // parallel offset - converter.set(); // optional affine transform - if (smooth > 0.0) converter.set(); // optional smooth converter - - using apply_vertex_converter_type = detail::apply_vertex_converter; - using vertex_processor_type = geometry::vertex_processor; - apply_vertex_converter_type apply(converter, ras); - mapnik::util::apply_visitor(vertex_processor_type(apply),feature_.get_geometry()); + void operator() (marker_rgba8 const& marker) const + { + render(marker.get_data(), marker.width(), marker.height()); } - void operator() (marker_rgba8 const& marker) +private: + void render(mapnik::image_rgba8 const& marker, double width, double height) const { using color = agg::rgba8; using order = agg::order_rgba; @@ -160,8 +107,6 @@ using rasterizer_type = agg::rasterizer_outline_aa; value_double opacity = get(sym_, feature_, common_.vars_); - mapnik::image_rgba8 const& image = marker.get_data(); - value_bool clip = get(sym_, feature_, common_.vars_); value_double offset = get(sym_, feature_, common_.vars_); value_double simplify_tolerance = get(sym_, feature_, common_.vars_); @@ -174,10 +119,10 @@ renderer_base ren_base(pixf); agg::pattern_filter_bilinear_rgba8 filter; - pattern_source source(image, opacity); + pattern_source source(marker, opacity); pattern_type pattern (filter,source); renderer_type ren(ren_base, pattern); - double half_stroke = std::max(marker.width()/2.0,marker.height()/2.0); + double half_stroke = std::max(width / 2.0, height / 2.0); int rast_clip_padding = static_cast(std::round(half_stroke)); ren.clip_box(-rast_clip_padding,-rast_clip_padding,common_.width_+rast_clip_padding,common_.height_+rast_clip_padding); rasterizer_type ras(ren); @@ -214,10 +159,9 @@ using apply_vertex_converter_type = detail::apply_vertex_converter; using vertex_processor_type = geometry::vertex_processor; apply_vertex_converter_type apply(converter, ras); - mapnik::util::apply_visitor(vertex_processor_type(apply),feature_.get_geometry()); + mapnik::util::apply_visitor(vertex_processor_type(apply), feature_.get_geometry()); } - private: renderer_common & common_; buffer_type & pixmap_; buffer_type * current_buffer_; diff -Nru mapnik-3.0.9+ds/src/agg/process_line_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_line_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_line_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_line_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -32,7 +32,9 @@ #include #include #include -// agg + +#pragma GCC diagnostic push +#include #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" @@ -45,6 +47,7 @@ #include "agg_conv_dash.h" #include "agg_renderer_outline_aa.h" #include "agg_rasterizer_outline_aa.h" +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/src/agg/process_markers_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_markers_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_markers_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_markers_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,23 +24,17 @@ #include #include #include - -#include -#include -#include -#include -#include -#include #include #include #include #include #include #include -#include -#include #include -// agg +#include + +#pragma GCC diagnostic push +#include #include "agg_basics.h" #include "agg_renderer_base.h" #include "agg_renderer_scanline.h" @@ -51,115 +45,64 @@ #include "agg_scanline_u.h" #include "agg_path_storage.h" #include "agg_conv_transform.h" - - -// boost -#include +#pragma GCC diagnostic pop namespace mapnik { namespace detail { -template -struct vector_markers_rasterizer_dispatch : public vector_markers_dispatch +template +struct agg_markers_renderer_context : markers_renderer_context { using renderer_base = typename SvgRenderer::renderer_base; using vertex_source_type = typename SvgRenderer::vertex_source_type; using attribute_source_type = typename SvgRenderer::attribute_source_type; using pixfmt_type = typename renderer_base::pixfmt_type; - using BufferType = typename std::tuple_element<0,RendererContext>::type; - using RasterizerType = typename std::tuple_element<1,RendererContext>::type; - - vector_markers_rasterizer_dispatch(svg_path_ptr const& src, - vertex_source_type & path, - svg_attribute_type const& attrs, - agg::trans_affine const& marker_trans, - symbolizer_base const& sym, - Detector & detector, - double scale_factor, - feature_impl & feature, - attributes const& vars, - bool snap_to_pixels, - RendererContext const& renderer_context) -: vector_markers_dispatch(src, marker_trans, sym, detector, scale_factor, feature, vars), - buf_(std::get<0>(renderer_context)), + agg_markers_renderer_context(symbolizer_base const& sym, + feature_impl const& feature, + attributes const& vars, + BufferType & buf, + RasterizerType & ras) + : buf_(buf), pixf_(buf_), renb_(pixf_), - svg_renderer_(path, attrs), - ras_(std::get<1>(renderer_context)), - snap_to_pixels_(snap_to_pixels) - { - pixf_.comp_op(static_cast(get(sym, feature, vars))); - } - - ~vector_markers_rasterizer_dispatch() {} - - void render_marker(agg::trans_affine const& marker_tr, double opacity) + ras_(ras) { - render_vector_marker(svg_renderer_, ras_, renb_, this->src_->bounding_box(), - marker_tr, opacity, snap_to_pixels_); + auto comp_op = get(sym, feature, vars); + pixf_.comp_op(static_cast(comp_op)); } -private: - BufferType & buf_; - pixfmt_type pixf_; - renderer_base renb_; - SvgRenderer svg_renderer_; - RasterizerType & ras_; - bool snap_to_pixels_; -}; - -template -struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch -{ - using BufferType = typename std::remove_reference::type>::type; - using RasterizerType = typename std::tuple_element<1,RendererContext>::type; - - using color_type = agg::rgba8; - using order_type = agg::order_rgba; - using pixel_type = agg::pixel32_type; - using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender - using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; - using renderer_base = agg::renderer_base; - - raster_markers_rasterizer_dispatch(image_rgba8 const& src, - agg::trans_affine const& marker_trans, - symbolizer_base const& sym, - Detector & detector, - double scale_factor, - feature_impl & feature, - attributes const& vars, - RendererContext const& renderer_context, - bool snap_to_pixels = false) - : raster_markers_dispatch(src, marker_trans, sym, detector, scale_factor, feature, vars), - buf_(std::get<0>(renderer_context)), - pixf_(buf_), - renb_(pixf_), - ras_(std::get<1>(renderer_context)), - snap_to_pixels_(snap_to_pixels) + virtual void render_marker(svg_path_ptr const& src, + svg_path_adapter & path, + svg_attribute_type const& attrs, + markers_dispatch_params const& params, + agg::trans_affine const& marker_tr) { - pixf_.comp_op(static_cast(get(sym, feature, vars))); + SvgRenderer svg_renderer(path, attrs); + render_vector_marker(svg_renderer, ras_, renb_, src->bounding_box(), + marker_tr, params.opacity, params.snap_to_pixels); } - ~raster_markers_rasterizer_dispatch() {} - void render_marker(agg::trans_affine const& marker_tr, double opacity) + virtual void render_marker(image_rgba8 const& src, + markers_dispatch_params const& params, + agg::trans_affine const& marker_tr) { - // In the long term this should be a visitor pattern based on the type of render this->src_ provided that converts - // the destination pixel type required. - render_raster_marker(renb_, ras_, this->src_, marker_tr, opacity, this->scale_factor_, snap_to_pixels_); + // In the long term this should be a visitor pattern based on the type of + // render src provided that converts the destination pixel type required. + render_raster_marker(renb_, ras_, src, marker_tr, params.opacity, + params.scale_factor, params.snap_to_pixels); } private: BufferType & buf_; - pixfmt_comp_type pixf_; + pixfmt_type pixf_; renderer_base renb_; RasterizerType & ras_; - bool snap_to_pixels_; }; -} +} // namespace detail template void agg_renderer::process(markers_symbolizer const& sym, @@ -194,16 +137,16 @@ buf_type render_buffer(current_buffer_->bytes(), current_buffer_->width(), current_buffer_->height(), current_buffer_->row_size()); box2d clip_box = clipping_extent(common_); - auto renderer_context = std::tie(render_buffer,*ras_ptr,pixmap_); - using context_type = decltype(renderer_context); - using vector_dispatch_type = detail::vector_markers_rasterizer_dispatch; - using raster_dispatch_type = detail::raster_markers_rasterizer_dispatch; + using context_type = detail::agg_markers_renderer_context; + context_type renderer_context(sym, feature, common_.vars_, render_buffer, *ras_ptr); - render_markers_symbolizer( + render_markers_symbolizer( sym, feature, prj_trans, common_, clip_box, renderer_context); } template void agg_renderer::process(markers_symbolizer const&, mapnik::feature_impl &, proj_transform const&); -} +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/src/agg/process_point_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_point_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_point_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_point_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,13 +30,14 @@ #include #include #include -#include #include #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_trans_affine.h" +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/src/agg/process_polygon_pattern_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_polygon_pattern_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_polygon_pattern_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_polygon_pattern_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -39,7 +39,9 @@ #include #include #include -// agg + +#pragma GCC diagnostic push +#include #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" @@ -52,6 +54,7 @@ #include "agg_span_pattern_rgba.h" #include "agg_image_accessors.h" #include "agg_conv_clip_polygon.h" +#pragma GCC diagnostic pop namespace mapnik { @@ -75,17 +78,27 @@ feature_(feature), prj_trans_(prj_trans) {} - void operator() (marker_null const&) {} + void operator() (marker_null const&) const {} - void operator() (marker_svg const& marker) + void operator() (marker_svg const& marker) const { agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional(sym_, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_); mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); render_pattern(*ras_ptr_, marker, image_tr, 1.0, image); + render(image); + } + void operator() (marker_rgba8 const& marker) const + { + render(marker.get_data()); + } + +private: + void render(mapnik::image_rgba8 const& image) const + { agg::rendering_buffer buf(current_buffer_->bytes(), current_buffer_->width(), current_buffer_->height(), current_buffer_->row_size()); ras_ptr_->reset(); @@ -144,105 +157,6 @@ using apply_local_alignment = detail::apply_local_alignment; apply_local_alignment apply(common_.t_,prj_trans_, clip_box, x0, y0); util::apply_visitor(geometry::vertex_processor(apply), feature_.get_geometry()); - offset_x = unsigned(current_buffer_->width() - x0); - offset_y = unsigned(current_buffer_->height() - y0); - } - - span_gen_type sg(img_src, offset_x, offset_y); - - agg::span_allocator sa; - renderer_type rp(renb,sa, sg, unsigned(opacity * 255)); - - agg::trans_affine tr; - auto transform = get_optional(sym_, keys::geometry_transform); - if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_); - using vertex_converter_type = vertex_converter; - - vertex_converter_type converter(clip_box,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); - - - if (prj_trans_.equal() && clip) converter.set(); - converter.set(); //always transform - converter.set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter - if (smooth > 0.0) converter.set(); // optional smooth converter - - using apply_vertex_converter_type = detail::apply_vertex_converter; - using vertex_processor_type = geometry::vertex_processor; - apply_vertex_converter_type apply(converter, *ras_ptr_); - mapnik::util::apply_visitor(vertex_processor_type(apply),feature_.get_geometry()); - agg::scanline_u8 sl; - ras_ptr_->filling_rule(agg::fill_even_odd); - agg::render_scanlines(*ras_ptr_, sl, rp); - } - - void operator() (marker_rgba8 const& marker) - { - using color = agg::rgba8; - using order = agg::order_rgba; - using blender_type = agg::comp_op_adaptor_rgba_pre; - using pixfmt_type = agg::pixfmt_custom_blend_rgba; - - using wrap_x_type = agg::wrap_mode_repeat; - using wrap_y_type = agg::wrap_mode_repeat; - using img_source_type = agg::image_accessor_wrap; - - using span_gen_type = agg::span_pattern_rgba; - using ren_base = agg::renderer_base; - - using renderer_type = agg::renderer_scanline_aa_alpha, - span_gen_type>; - mapnik::image_rgba8 const& image = marker.get_data(); - - - agg::rendering_buffer buf(current_buffer_->bytes(), current_buffer_->width(), - current_buffer_->height(), current_buffer_->row_size()); - ras_ptr_->reset(); - value_double gamma = get(sym_, feature_, common_.vars_); - gamma_method_enum gamma_method = get(sym_, feature_, common_.vars_); - if (gamma != gamma_ || gamma_method != gamma_method_) - { - set_gamma_method(ras_ptr_, gamma, gamma_method); - gamma_method_ = gamma_method; - gamma_ = gamma; - } - - value_bool clip = get(sym_, feature_, common_.vars_); - value_double opacity = get(sym_, feature_, common_.vars_); - value_double simplify_tolerance = get(sym_, feature_, common_.vars_); - value_double smooth = get(sym_, feature_, common_.vars_); - - box2d clip_box = clipping_extent(common_); - - - pixfmt_type pixf(buf); - pixf.comp_op(static_cast(get(sym_, feature_, common_.vars_))); - ren_base renb(pixf); - - unsigned w = image.width(); - unsigned h = image.height(); - agg::rendering_buffer pattern_rbuf((agg::int8u*)image.bytes(),w,h,w*4); - agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf); - img_source_type img_src(pixf_pattern); - - pattern_alignment_enum alignment = get(sym_, feature_, common_.vars_); - unsigned offset_x=0; - unsigned offset_y=0; - - if (alignment == LOCAL_ALIGNMENT) - { - double x0 = 0; - double y0 = 0; - using apply_local_alignment = detail::apply_local_alignment; - apply_local_alignment apply(common_.t_,prj_trans_, clip_box, x0, y0); - util::apply_visitor(geometry::vertex_processor(apply), feature_.get_geometry()); offset_x = unsigned(current_buffer_->width() - x0); offset_y = unsigned(current_buffer_->height() - y0); @@ -279,7 +193,6 @@ agg::render_scanlines(*ras_ptr_, sl, rp); } -private: renderer_common & common_; buffer_type * current_buffer_; std::unique_ptr const& ras_ptr_; diff -Nru mapnik-3.0.9+ds/src/agg/process_polygon_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_polygon_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_polygon_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_polygon_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -32,7 +32,9 @@ #include #include #include -// agg + +#pragma GCC diagnostic push +#include #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" @@ -40,6 +42,7 @@ #include "agg_renderer_scanline.h" #include "agg_rasterizer_scanline_aa.h" #include "agg_scanline_u.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/agg/process_raster_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_raster_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_raster_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_raster_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -38,9 +38,11 @@ // stl #include -// agg +#pragma GCC diagnostic push +#include #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/agg/process_text_symbolizer.cpp mapnik-3.0.13+ds/src/agg/process_text_symbolizer.cpp --- mapnik-3.0.9+ds/src/agg/process_text_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/agg/process_text_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -63,7 +63,7 @@ if (halo_transform) { agg::trans_affine halo_affine_transform; - evaluate_transform(halo_affine_transform, feature, common_.vars_, *halo_transform); + evaluate_transform(halo_affine_transform, feature, common_.vars_, *halo_transform, common_.scale_factor_); ren.set_halo_transform(halo_affine_transform); } diff -Nru mapnik-3.0.9+ds/src/box2d.cpp mapnik-3.0.13+ds/src/box2d.cpp --- mapnik-3.0.9+ds/src/box2d.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/box2d.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -2,7 +2,7 @@ * * This file is part of Mapnik (c++ mapping toolkit) * - * Copyright (C) 2015 Artem Pavlenko + * Copyright (C) 2016 Artem Pavlenko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,465 +21,12 @@ *****************************************************************************/ // mapnik -#include -#include +#include -// stl -#include -#include -#include - -#include - -#pragma GCC diagnostic push -#include -#include -#include -#include -#pragma GCC diagnostic pop - -// agg -#include "agg_trans_affine.h" - -BOOST_FUSION_ADAPT_TPL_ADT( - (T), - (mapnik::box2d)(T), - (T, T, obj.minx(), obj.set_minx(mapnik::safe_cast(val))) - (T, T, obj.miny(), obj.set_miny(mapnik::safe_cast(val))) - (T, T, obj.maxx(), obj.set_maxx(mapnik::safe_cast(val))) - (T, T, obj.maxy(), obj.set_maxy(mapnik::safe_cast(val)))) - -namespace mapnik -{ -template -box2d::box2d() - :minx_( std::numeric_limits::max()), - miny_( std::numeric_limits::max()), - maxx_(-std::numeric_limits::max()), - maxy_(-std::numeric_limits::max()) {} - -template -box2d::box2d(T minx,T miny,T maxx,T maxy) -{ - init(minx,miny,maxx,maxy); -} - -template -box2d::box2d(coord const& c0, coord const& c1) -{ - init(c0.x,c0.y,c1.x,c1.y); -} - -template -box2d::box2d(box2d_type const& rhs) - : minx_(rhs.minx_), - miny_(rhs.miny_), - maxx_(rhs.maxx_), - maxy_(rhs.maxy_) {} - -template -box2d::box2d(box2d_type && rhs) - : minx_(std::move(rhs.minx_)), - miny_(std::move(rhs.miny_)), - maxx_(std::move(rhs.maxx_)), - maxy_(std::move(rhs.maxy_)) {} - -template -box2d& box2d::operator=(box2d_type other) -{ - swap(*this, other); - return *this; -} - -template -box2d::box2d(box2d_type const& rhs, agg::trans_affine const& tr) -{ - double x0 = rhs.minx_, y0 = rhs.miny_; - double x1 = rhs.maxx_, y1 = rhs.miny_; - double x2 = rhs.maxx_, y2 = rhs.maxy_; - double x3 = rhs.minx_, y3 = rhs.maxy_; - tr.transform(&x0, &y0); - tr.transform(&x1, &y1); - tr.transform(&x2, &y2); - tr.transform(&x3, &y3); - init(static_cast(x0), static_cast(y0), - static_cast(x2), static_cast(y2)); - expand_to_include(static_cast(x1), static_cast(y1)); - expand_to_include(static_cast(x3), static_cast(y3)); -} - -template -bool box2d::operator==(box2d const& other) const -{ - return minx_==other.minx_ && - miny_==other.miny_ && - maxx_==other.maxx_ && - maxy_==other.maxy_; -} - -template -T box2d::minx() const -{ - return minx_; -} - -template -T box2d::maxx() const -{ - return maxx_; -} - -template -T box2d::miny() const -{ - return miny_; -} - -template -T box2d::maxy() const -{ - return maxy_; -} - -template -void box2d::set_minx(T v) -{ - minx_ = v; -} - -template -void box2d::set_miny(T v) -{ - miny_ = v; -} - -template -void box2d::set_maxx(T v) -{ - maxx_ = v; -} - -template -void box2d::set_maxy(T v) -{ - maxy_ = v; -} - -template -T box2d::width() const -{ - return maxx_-minx_; -} - -template -T box2d::height() const -{ - return maxy_-miny_; -} - -template -void box2d::width(T w) -{ - T cx=center().x; - minx_=static_cast(cx-w*0.5); - maxx_=static_cast(cx+w*0.5); -} - -template -void box2d::height(T h) -{ - T cy=center().y; - miny_=static_cast(cy-h*0.5); - maxy_=static_cast(cy+h*0.5); -} - -template -coord box2d::center() const -{ - return coord(static_cast(0.5*(minx_+maxx_)), - static_cast(0.5*(miny_+maxy_))); -} - -template -void box2d::expand_to_include(coord const& c) -{ - expand_to_include(c.x,c.y); -} - -template -void box2d::expand_to_include(T x,T y) -{ - if (xmaxx_) maxx_=x; - if (ymaxy_) maxy_=y; -} - -template -void box2d::expand_to_include(box2d const& other) -{ - if (other.minx_maxx_) maxx_=other.maxx_; - if (other.miny_maxy_) maxy_=other.maxy_; -} - -template -bool box2d::contains(coord const& c) const -{ - return contains(c.x,c.y); -} - -template -bool box2d::contains(T x,T y) const -{ - return x>=minx_ && x<=maxx_ && y>=miny_ && y<=maxy_; -} - -template -bool box2d::contains(box2d const& other) const -{ - return other.minx_>=minx_ && - other.maxx_<=maxx_ && - other.miny_>=miny_ && - other.maxy_<=maxy_; -} - -template -bool box2d::intersects(coord const& c) const -{ - return intersects(c.x,c.y); -} - -template -bool box2d::intersects(T x,T y) const -{ - return !(x>maxx_ || xmaxy_ || y -bool box2d::intersects(box2d const& other) const -{ - return !(other.minx_>maxx_ || other.maxx_maxy_ || other.maxy_ -box2d box2d::intersect(box2d_type const& other) const -{ - if (intersects(other)) - { - T x0=std::max(minx_,other.minx_); - T y0=std::max(miny_,other.miny_); - T x1=std::min(maxx_,other.maxx_); - T y1=std::min(maxy_,other.maxy_); - return box2d(x0,y0,x1,y1); - } - else - { - return box2d(); - } -} - -template -void box2d::re_center(T cx,T cy) -{ - T dx=cx-center().x; - T dy=cy-center().y; - minx_+=dx; - miny_+=dy; - maxx_+=dx; - maxy_+=dy; -} - -template -void box2d::re_center(coord const& c) -{ - re_center(c.x,c.y); -} - -template -void box2d::init(T x0,T y0,T x1,T y1) -{ - if (x0 -void box2d::clip(box2d_type const& other) -{ - minx_ = std::max(minx_,other.minx()); - miny_ = std::max(miny_,other.miny()); - maxx_ = std::min(maxx_,other.maxx()); - maxy_ = std::min(maxy_,other.maxy()); -} - -template -void box2d::pad(T padding) -{ - minx_ -= padding; - miny_ -= padding; - maxx_ += padding; - maxy_ += padding; -} - - -template -bool box2d::from_string(std::string const& str) -{ - boost::spirit::qi::lit_type lit; - boost::spirit::qi::double_type double_; - boost::spirit::ascii::space_type space; - bool r = boost::spirit::qi::phrase_parse(str.begin(), - str.end(), - double_ >> -lit(',') >> double_ >> -lit(',') - >> double_ >> -lit(',') >> double_, - space, - *this); - return r; -} - -template -bool box2d::valid() const -{ - return (minx_ <= maxx_ && miny_ <= maxy_) ; -} - -template -void box2d::move(T x, T y) -{ - minx_ += x; - maxx_ += x; - miny_ += y; - maxy_ += y; -} - -template -std::string box2d::to_string() const -{ - std::ostringstream s; - s << "box2d(" << std::fixed << std::setprecision(16) - << minx_ << ',' << miny_ << ',' - << maxx_ << ',' << maxy_ << ')'; - return s.str(); -} - - -template -box2d& box2d::operator+=(box2d const& other) -{ - expand_to_include(other); - return *this; -} - -template -box2d box2d::operator+ (T other) const -{ - return box2d(minx_ - other, miny_ - other, maxx_ + other, maxy_ + other); -} - -template -box2d& box2d::operator+= (T other) -{ - minx_ -= other; - miny_ -= other; - maxx_ += other; - maxy_ += other; - return *this; -} - - -template -box2d& box2d::operator*=(T t) -{ - coord c = center(); - T sx = static_cast(0.5 * width() * t); - T sy = static_cast(0.5 * height() * t); - minx_ = c.x - sx; - maxx_ = c.x + sx; - miny_ = c.y - sy; - maxy_ = c.y + sy; - return *this; -} - -template -box2d& box2d::operator/=(T t) -{ - coord c = center(); - T sx = static_cast(0.5 * width() / t); - T sy = static_cast(0.5 * height() / t); - minx_ = c.x - sx; - maxx_ = c.x + sx; - miny_ = c.y - sy; - maxy_ = c.y + sy; - return *this; -} - -template -T box2d::operator[] (int index) const -{ - switch(index) - { - case 0: - return minx_; - case 1: - return miny_; - case 2: - return maxx_; - case 3: - return maxy_; - case -4: - return minx_; - case -3: - return miny_; - case -2: - return maxx_; - case -1: - return maxy_; - default: - throw std::out_of_range("index out of range, max value is 3, min value is -4 "); - } -} - -template -box2d box2d::operator*(agg::trans_affine const& tr) const -{ - return box2d(*this, tr); -} - -template -box2d& box2d::operator*=(agg::trans_affine const& tr) -{ - double x0 = minx_, y0 = miny_; - double x1 = maxx_, y1 = miny_; - double x2 = maxx_, y2 = maxy_; - double x3 = minx_, y3 = maxy_; - tr.transform(&x0, &y0); - tr.transform(&x1, &y1); - tr.transform(&x2, &y2); - tr.transform(&x3, &y3); - init(static_cast(x0), static_cast(y0), - static_cast(x2), static_cast(y2)); - expand_to_include(static_cast(x1), static_cast(y1)); - expand_to_include(static_cast(x3), static_cast(y3)); - return *this; -} +namespace mapnik { template class box2d; +template class box2d; template class box2d; } diff -Nru mapnik-3.0.9+ds/src/build.py mapnik-3.0.13+ds/src/build.py --- mapnik-3.0.9+ds/src/build.py 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/build.py 2017-02-08 13:06:42.000000000 +0000 @@ -62,6 +62,10 @@ lib_env['LIBS'] = [filesystem, regex] +if env['COVERAGE']: + lib_env.Append(LINKFLAGS='--coverage') + lib_env.Append(CXXFLAGS='--coverage') + if env['HAS_CAIRO']: lib_env.Append(LIBS=env['CAIRO_ALL_LIBS']) @@ -154,7 +158,7 @@ well_known_srs.cpp params.cpp image_filter_types.cpp - miniz_png.cpp + image_filter_grammar.cpp color.cpp conversions.cpp image_copy.cpp @@ -201,6 +205,7 @@ rule.cpp save_map.cpp wkb.cpp + twkb.cpp projection.cpp proj_transform.cpp scale_denominator.cpp @@ -221,6 +226,7 @@ warp.cpp css_color_grammar.cpp vertex_cache.cpp + vertex_adapters.cpp text/font_library.cpp text/text_layout.cpp text/text_line.cpp @@ -252,9 +258,12 @@ config_error.cpp color_factory.cpp renderer_common.cpp + renderer_common/render_group_symbolizer.cpp + renderer_common/render_markers_symbolizer.cpp renderer_common/render_pattern.cpp - renderer_common/process_group_symbolizer.cpp + renderer_common/render_thunk_extractor.cpp math.cpp + value.cpp """ ) diff -Nru mapnik-3.0.9+ds/src/cairo/cairo_context.cpp mapnik-3.0.13+ds/src/cairo/cairo_context.cpp --- mapnik-3.0.9+ds/src/cairo/cairo_context.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/cairo/cairo_context.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -304,6 +304,12 @@ check_object_status_and_throw_exception(*this); } +void cairo_context::paint(double opacity) +{ + cairo_paint_with_alpha(cairo_.get(), opacity); + check_object_status_and_throw_exception(*this); +} + void cairo_context::set_pattern(cairo_pattern const& pattern) { cairo_set_source(cairo_.get(), pattern.pattern()); @@ -489,6 +495,18 @@ } +void cairo_context::push_group() +{ + cairo_push_group(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::pop_group() +{ + cairo_pop_group_to_source(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + cairo_face_manager::cairo_face_manager(std::shared_ptr font_library) : font_library_(font_library) { diff -Nru mapnik-3.0.9+ds/src/cairo/cairo_renderer.cpp mapnik-3.0.13+ds/src/cairo/cairo_renderer.cpp --- mapnik-3.0.9+ds/src/cairo/cairo_renderer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/cairo/cairo_renderer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -36,6 +36,7 @@ #include #include #include +#include // agg #include "agg/include/agg_trans_affine.h" // for trans_affine, etc @@ -58,7 +59,8 @@ m_(m), context_(cairo), common_(m, attributes(), offset_x, offset_y, m.width(), m.height(), scale_factor), - face_manager_(common_.shared_font_library_) + face_manager_(common_.shared_font_library_), + style_level_compositing_(false) { setup(m); } @@ -75,7 +77,9 @@ m_(m), context_(cairo), common_(m, req, vars, offset_x, offset_y, req.width(), req.height(), scale_factor), - face_manager_(common_.shared_font_library_) + face_manager_(common_.shared_font_library_), + style_level_compositing_(false) + { setup(m); } @@ -91,7 +95,9 @@ m_(m), context_(cairo), common_(m, attributes(), offset_x, offset_y, m.width(), m.height(), scale_factor, detector), - face_manager_(common_.shared_font_library_) + face_manager_(common_.shared_font_library_), + style_level_compositing_(false) + { setup(m); } @@ -104,10 +110,10 @@ setup_marker_visitor(cairo_context & context, renderer_common const& common) : context_(context), common_(common) {} - void operator() (marker_null const &) {} - void operator() (marker_svg const &) {} + void operator() (marker_null const &) const{} + void operator() (marker_svg const &) const {} - void operator() (marker_rgba8 const& marker) + void operator() (marker_rgba8 const& marker) const { mapnik::image_rgba8 const& bg_image = marker.get_data(); std::size_t w = bg_image.width(); @@ -191,15 +197,30 @@ } template -void cairo_renderer::start_style_processing(feature_type_style const&) +void cairo_renderer::start_style_processing(feature_type_style const & st) { MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer:start style processing"; + + style_level_compositing_ = st.comp_op() || st.get_opacity() < 1; + + if (style_level_compositing_) + { + context_.push_group(); + } } template -void cairo_renderer::end_style_processing(feature_type_style const&) +void cairo_renderer::end_style_processing(feature_type_style const & st) { MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer:end style processing"; + + if (style_level_compositing_) + { + context_.pop_group(); + composite_mode_e comp_op = st.comp_op() ? *st.comp_op() : src_over; + context_.set_operator(comp_op); + context_.paint(st.get_opacity()); + } } struct cairo_render_marker_visitor diff -Nru mapnik-3.0.9+ds/src/cairo/process_group_symbolizer.cpp mapnik-3.0.13+ds/src/cairo/process_group_symbolizer.cpp --- mapnik-3.0.9+ds/src/cairo/process_group_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/cairo/process_group_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,13 +25,12 @@ // mapnik #include #include -#include #include #include #include // mapnik symbolizer generics -#include +#include namespace mapnik { @@ -47,20 +46,19 @@ // to render it, and the boxes themselves should already be // in the detector from the placement_finder. template -struct thunk_renderer +struct thunk_renderer : render_thunk_list_dispatch { using renderer_type = cairo_renderer; thunk_renderer(renderer_type & ren, cairo_context & context, cairo_face_manager & face_manager, - renderer_common & common, - pixel_position const& offset) + renderer_common & common) : ren_(ren), context_(context), face_manager_(face_manager), - common_(common), offset_(offset) + common_(common) {} - void operator()(vector_marker_render_thunk const &thunk) const + virtual void operator()(vector_marker_render_thunk const& thunk) { cairo_save_restore guard(context_); context_.set_operator(thunk.comp_op_); @@ -78,7 +76,7 @@ thunk.opacity_); } - void operator()(raster_marker_render_thunk const& thunk) const + virtual void operator()(raster_marker_render_thunk const& thunk) { cairo_save_restore guard(context_); context_.set_operator(thunk.comp_op_); @@ -88,32 +86,24 @@ context_.add_image(offset_tr, thunk.src_, thunk.opacity_); } - void operator()(text_render_thunk const &thunk) const + virtual void operator()(text_render_thunk const& thunk) { cairo_save_restore guard(context_); context_.set_operator(thunk.comp_op_); - render_offset_placements( - thunk.placements_, - offset_, - [&] (glyph_positions_ptr const& glyphs) - { - marker_info_ptr mark = glyphs->get_marker(); - if (mark) - { - ren_.render_marker(glyphs->marker_pos(), - *mark->marker_, - mark->transform_, - thunk.opacity_, thunk.comp_op_); - } - context_.add_text(*glyphs, face_manager_, src_over, src_over, common_.scale_factor_); - }); - } + for (auto const& glyphs : thunk.placements_) + { + scoped_glyph_positions_offset tmp_off(*glyphs, offset_); - template - void operator()(T0 const &) const - { - throw std::runtime_error("Rendering of this type is not supported by the cairo renderer."); + if (auto const& mark = glyphs->get_marker()) + { + ren_.render_marker(glyphs->marker_pos(), + *mark->marker_, + mark->transform_, + thunk.opacity_, thunk.comp_op_); + } + context_.add_text(*glyphs, face_manager_, src_over, src_over, common_.scale_factor_); + } } private: @@ -121,7 +111,6 @@ cairo_context & context_; cairo_face_manager & face_manager_; renderer_common & common_; - pixel_position offset_; }; } // anonymous namespace @@ -131,16 +120,11 @@ mapnik::feature_impl & feature, proj_transform const& prj_trans) { + thunk_renderer ren(*this, context_, face_manager_, common_); + render_group_symbolizer( sym, feature, common_.vars_, prj_trans, common_.query_extent_, common_, - [&](render_thunk_list const& thunks, pixel_position const& render_offset) - { - thunk_renderer ren(*this, context_, face_manager_, common_, render_offset); - for (render_thunk_ptr const& thunk : thunks) - { - util::apply_visitor(ren, *thunk); - } - }); + ren); } template void cairo_renderer::process(group_symbolizer const&, diff -Nru mapnik-3.0.9+ds/src/cairo/process_line_pattern_symbolizer.cpp mapnik-3.0.13+ds/src/cairo/process_line_pattern_symbolizer.cpp --- mapnik-3.0.9+ds/src/cairo/process_line_pattern_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/cairo/process_line_pattern_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -62,7 +62,7 @@ mapnik::rasterizer ras; agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional(sym_, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_); mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); render_pattern(ras, marker, image_tr, 1.0, image); diff -Nru mapnik-3.0.9+ds/src/cairo/process_markers_symbolizer.cpp mapnik-3.0.13+ds/src/cairo/process_markers_symbolizer.cpp --- mapnik-3.0.9+ds/src/cairo/process_markers_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/cairo/process_markers_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,90 +25,46 @@ // mapnik #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// agg -#include "agg/include/agg_array.h" // for pod_bvector -#include "agg/include/agg_trans_affine.h" // for trans_affine, etc +#include +#include namespace mapnik { -class feature_impl; -class proj_transform; - namespace detail { -template -struct vector_markers_dispatch_cairo : public vector_markers_dispatch +struct cairo_markers_renderer_context : markers_renderer_context { - vector_markers_dispatch_cairo(svg_path_ptr const& src, - svg::svg_path_adapter & path, - svg_attribute_type const& attrs, - agg::trans_affine const& marker_trans, - markers_symbolizer const& sym, - Detector & detector, - double scale_factor, - feature_impl & feature, - mapnik::attributes const& vars, - bool /* snap_to_pixels */, // only used in agg renderer currently - RendererContext const& renderer_context) - : vector_markers_dispatch(src, marker_trans, sym, detector, scale_factor, feature, vars), - path_(path), - attr_(attrs), - ctx_(std::get<0>(renderer_context)) + explicit cairo_markers_renderer_context(cairo_context & ctx) + : ctx_(ctx) {} - void render_marker(agg::trans_affine const& marker_tr, double opacity) + virtual void render_marker(svg_path_ptr const& src, + svg_path_adapter & path, + svg_attribute_type const& attrs, + markers_dispatch_params const& params, + agg::trans_affine const& marker_tr) { render_vector_marker(ctx_, - path_, - attr_, - this->src_->bounding_box(), + path, + attrs, + src->bounding_box(), marker_tr, - opacity); + params.opacity); } -private: - svg::svg_path_adapter & path_; - svg_attribute_type const& attr_; - cairo_context & ctx_; -}; - -template -struct raster_markers_dispatch_cairo : public raster_markers_dispatch -{ - raster_markers_dispatch_cairo(image_rgba8 const& src, - agg::trans_affine const& marker_trans, - markers_symbolizer const& sym, - Detector & detector, - double scale_factor, - feature_impl & feature, - mapnik::attributes const& vars, - RendererContext const& renderer_context) - : raster_markers_dispatch(src, marker_trans, sym, detector, scale_factor, feature, vars), - ctx_(std::get<0>(renderer_context)) {} - - ~raster_markers_dispatch_cairo() {} - - void render_marker(agg::trans_affine const& marker_tr, double opacity) + virtual void render_marker(image_rgba8 const& src, + markers_dispatch_params const& params, + agg::trans_affine const& marker_tr) { - ctx_.add_image(marker_tr, this->src_, opacity); + ctx_.add_image(marker_tr, src, params.opacity); } private: cairo_context & ctx_; }; -} +} // namespace detail template void cairo_renderer::process(markers_symbolizer const& sym, @@ -120,17 +76,10 @@ context_.set_operator(comp_op); box2d clip_box = common_.query_extent_; - auto renderer_context = std::tie(context_); - - using RendererContextType = decltype(renderer_context); - using vector_dispatch_type = detail::vector_markers_dispatch_cairo; + using context_type = detail::cairo_markers_renderer_context; + context_type renderer_context(context_); - using raster_dispatch_type = detail::raster_markers_dispatch_cairo; - - - render_markers_symbolizer( + render_markers_symbolizer( sym, feature, prj_trans, common_, clip_box, renderer_context); } @@ -139,6 +88,6 @@ mapnik::feature_impl &, proj_transform const&); -} +} // namespace mapnik #endif // HAVE_CAIRO diff -Nru mapnik-3.0.9+ds/src/cairo/process_polygon_pattern_symbolizer.cpp mapnik-3.0.13+ds/src/cairo/process_polygon_pattern_symbolizer.cpp --- mapnik-3.0.9+ds/src/cairo/process_polygon_pattern_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/cairo/process_polygon_pattern_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -96,7 +96,7 @@ value_double opacity = get(sym, feature, common_.vars_); agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); + if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform, common_.scale_factor_); cairo_save_restore guard(context_); context_.set_operator(comp_op); @@ -124,8 +124,7 @@ agg::trans_affine tr; auto geom_transform = get_optional(sym, keys::geometry_transform); if (geom_transform) { evaluate_transform(tr, feature, common_.vars_, *geom_transform, common_.scale_factor_); } - using vertex_converter_type = vertex_converter< - clip_poly_tag, + using vertex_converter_type = vertex_converter #include -// agg -#include "agg_color_rgba.h" - #pragma GCC diagnostic push #include #include -#include -#include -#include -#include -#include #pragma GCC diagnostic pop -// stl -#include - namespace mapnik { color::color(std::string const& str, bool premultiplied) @@ -52,22 +41,23 @@ std::string color::to_string() const { namespace karma = boost::spirit::karma; - boost::spirit::karma::_1_type _1; boost::spirit::karma::eps_type eps; boost::spirit::karma::double_type double_; - boost::spirit::karma::string_type kstring; - boost::spirit::karma::uint_generator color_generator; + boost::spirit::karma::uint_generator color_; std::string str; std::back_insert_iterator sink(str); - karma::generate(sink, + karma::generate(sink, eps(alpha() < 255) // begin grammar - kstring[ boost::phoenix::if_(alpha()==255) [_1="rgb("].else_[_1="rgba("]] - << color_generator[_1 = red()] << ',' - << color_generator[_1 = green()] << ',' - << color_generator[_1 = blue()] - << kstring[ boost::phoenix::if_(alpha()==255) [_1 = ')'].else_[_1 =',']] - << eps(alpha()<255) << double_ [_1 = alpha()/255.0] - << ')' + << "rgba(" + << color_(red()) << ',' + << color_(green()) << ',' + << color_(blue()) << ',' + << double_(alpha()/255.0) << ')' + | + "rgb(" + << color_(red()) << ',' + << color_(green()) << ',' + << color_(blue()) << ')' // end grammar ); return str; @@ -76,7 +66,6 @@ std::string color::to_hex_string() const { namespace karma = boost::spirit::karma; - boost::spirit::karma::_1_type _1; boost::spirit::karma::hex_type hex; boost::spirit::karma::eps_type eps; boost::spirit::karma::right_align_type right_align; @@ -85,23 +74,34 @@ karma::generate(sink, // begin grammar '#' - << right_align(2,'0')[hex[_1 = red()]] - << right_align(2,'0')[hex[_1 = green()]] - << right_align(2,'0')[hex[_1 = blue()]] - << eps(alpha() < 255) << right_align(2,'0')[hex [_1 = alpha()]] + << right_align(2,'0')[hex(red())] + << right_align(2,'0')[hex(green())] + << right_align(2,'0')[hex(blue())] + << eps(alpha() < 255) << right_align(2,'0')[hex(alpha())] // end grammar ); return str; } +namespace { + +static std::uint8_t multiply(std::uint8_t c, std::uint8_t a) +{ + std::uint32_t t = c * a + 128; + return std::uint8_t(((t >> 8) + t) >> 8); +} + +} + bool color::premultiply() { if (premultiplied_) return false; - agg::rgba8 pre_c = agg::rgba8(red_,green_,blue_,alpha_); - pre_c.premultiply(); - red_ = pre_c.r; - green_ = pre_c.g; - blue_ = pre_c.b; + if (alpha_ != 255) + { + red_ = multiply(red_, alpha_); + green_ = multiply(green_, alpha_); + blue_ = multiply(blue_, alpha_); + } premultiplied_ = true; return true; } @@ -109,13 +109,23 @@ bool color::demultiply() { if (!premultiplied_) return false; - agg::rgba8 pre_c = agg::rgba8(red_,green_,blue_,alpha_); - pre_c.demultiply(); - red_ = pre_c.r; - green_ = pre_c.g; - blue_ = pre_c.b; + if (alpha_ < 255) + { + if (alpha_ == 0) + { + red_ = green_ = blue_ = 0; + } + else + { + std::uint32_t r = (std::uint32_t(red_) * 255) / alpha_; + std::uint32_t g = (std::uint32_t(green_) * 255) / alpha_; + std::uint32_t b = (std::uint32_t(blue_) * 255) / alpha_; + red_ = (r > 255) ? 255 : r; + green_ = (g > 255) ? 255 : g; + blue_ = (b > 255) ? 255 : b; + } + } premultiplied_ = false; return true; } - } diff -Nru mapnik-3.0.9+ds/src/dasharray_parser.cpp mapnik-3.0.13+ds/src/dasharray_parser.cpp --- mapnik-3.0.9+ds/src/dasharray_parser.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/dasharray_parser.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -36,7 +36,29 @@ namespace util { -bool parse_dasharray(std::string const& value, std::vector& dasharray) +namespace { +inline bool setup_dashes(std::vector & buf, dash_array & dash) +{ + if (buf.empty()) return false; + size_t size = buf.size(); + if (size % 2 == 1) + { + buf.insert(buf.end(),buf.begin(),buf.end()); + } + std::vector::const_iterator pos = buf.begin(); + while (pos != buf.end()) + { + if (*pos > 0.0 || *(pos+1) > 0.0) // avoid both dash and gap eq 0.0 + { + dash.emplace_back(*pos,*(pos + 1)); + } + pos +=2; + } + return !buf.empty(); +} +} + +bool parse_dasharray(std::string const& value, dash_array & dash) { using namespace boost::spirit; qi::double_type double_; @@ -49,18 +71,19 @@ // dasharray ::= (length | percentage) (comma-wsp dasharray)? // no support for 'percentage' as viewport is unknown at load_map // + std::vector buf; auto first = value.begin(); auto last = value.end(); bool r = qi::phrase_parse(first, last, - (double_[boost::phoenix::push_back(boost::phoenix::ref(dasharray), _1)] % + (double_[boost::phoenix::push_back(boost::phoenix::ref(buf), _1)] % no_skip[char_(", ")] | lit("none")), space); - if (first != last) + if (r && first == last) { - return false; + return setup_dashes(buf, dash); } - return r; + return false; } } // end namespace util diff -Nru mapnik-3.0.9+ds/src/datasource_cache.cpp mapnik-3.0.13+ds/src/datasource_cache.cpp --- mapnik-3.0.9+ds/src/datasource_cache.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/datasource_cache.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -65,7 +65,7 @@ datasource_ptr datasource_cache::create(parameters const& params) { boost::optional type = params.get("type"); - if ( ! type) + if (!type) { throw config_error(std::string("Could not create datasource. Required ") + "parameter 'type' is missing"); @@ -88,7 +88,7 @@ #ifdef MAPNIK_THREADSAFE std::lock_guard lock(instance_mutex_); #endif - itr=plugins_.find(*type); + itr = plugins_.find(*type); if (itr == plugins_.end()) { std::string s("Could not create datasource for type: '"); @@ -105,7 +105,7 @@ } } - if (! itr->second->valid()) + if (!itr->second->valid()) { throw std::runtime_error(std::string("Cannot load library: ") + itr->second->get_error()); @@ -117,7 +117,7 @@ #endif create_ds create_datasource = reinterpret_cast(itr->second->get_symbol("create")); - if (! create_datasource) + if (!create_datasource) { throw std::runtime_error(std::string("Cannot load symbols: ") + itr->second->get_error()); diff -Nru mapnik-3.0.9+ds/src/debug.cpp mapnik-3.0.13+ds/src/debug.cpp --- mapnik-3.0.9+ds/src/debug.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/debug.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -22,6 +22,7 @@ // mapnik #include +#include // stl #include @@ -74,14 +75,7 @@ logger::severity_map logger::object_severity_level_ = logger::severity_map(); - -// format - -#define __xstr__(s) __str__(s) -#define __str__(s) #s -std::string logger::format_ = __xstr__(MAPNIK_LOG_FORMAT); -#undef __xstr__ -#undef __str__ +std::string logger::format_ = MAPNIK_STRINGIFY(MAPNIK_LOG_FORMAT); std::string logger::str() { diff -Nru mapnik-3.0.9+ds/src/expression_node.cpp mapnik-3.0.13+ds/src/expression_node.cpp --- mapnik-3.0.9+ds/src/expression_node.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/expression_node.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -37,6 +37,14 @@ namespace mapnik { +#if defined(BOOST_REGEX_HAS_ICU) +static void fromUTF32toUTF8(std::basic_string const& src, std::string & dst) +{ + int32_t len = safe_cast(src.length()); + value_unicode_string::fromUTF32(src.data(), len).toUTF8String(dst); +} +#endif + struct _regex_match_impl : util::noncopyable { #if defined(BOOST_REGEX_HAS_ICU) _regex_match_impl(value_unicode_string const& ustr) : @@ -94,10 +102,7 @@ str_ +=".match('"; auto const& pattern = impl_.get()->pattern_; #if defined(BOOST_REGEX_HAS_ICU) - std::string utf8; - value_unicode_string ustr = value_unicode_string::fromUTF32( &pattern.str()[0], safe_cast(pattern.str().length())); - to_utf8(ustr,utf8); - str_ += utf8; + fromUTF32toUTF8(pattern.str(), str_); #else str_ += pattern.str(); #endif @@ -125,9 +130,9 @@ auto const& pattern = impl_.get()->pattern_; auto const& format = impl_.get()->format_; #if defined(BOOST_REGEX_HAS_ICU) - return boost::u32regex_replace(v.to_unicode(),pattern,format); + return boost::u32regex_replace(v.to_unicode(), pattern, format); #else - std::string repl = boost::regex_replace(v.to_string(),pattern,format); + std::string repl = boost::regex_replace(v.to_string(), pattern, format); transcoder tr_("utf8"); return tr_.transcode(repl.c_str()); #endif @@ -141,13 +146,9 @@ auto const& pattern = impl_.get()->pattern_; auto const& format = impl_.get()->format_; #if defined(BOOST_REGEX_HAS_ICU) - std::string utf8; - value_unicode_string ustr = value_unicode_string::fromUTF32( &pattern.str()[0], safe_cast(pattern.str().length())); - to_utf8(ustr,utf8); - str_ += utf8; + fromUTF32toUTF8(pattern.str(), str_); str_ +="','"; - to_utf8(format ,utf8); - str_ += utf8; + format.toUTF8String(str_); #else str_ += pattern.str(); str_ +="','"; diff -Nru mapnik-3.0.9+ds/src/feature_kv_iterator.cpp mapnik-3.0.13+ds/src/feature_kv_iterator.cpp --- mapnik-3.0.9+ds/src/feature_kv_iterator.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/feature_kv_iterator.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -22,7 +22,11 @@ #include #include + +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/font_engine_freetype.cpp mapnik-3.0.13+ds/src/font_engine_freetype.cpp --- mapnik-3.0.9+ds/src/font_engine_freetype.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/font_engine_freetype.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,18 +27,12 @@ #include #include #include -#include #include #pragma GCC diagnostic push #include #include #include -#pragma GCC diagnostic pop - -// stl -#include -#include // freetype2 extern "C" @@ -48,6 +42,11 @@ #include FT_STROKER_H #include FT_MODULE_H } +#pragma GCC diagnostic pop + +// stl +#include +#include namespace mapnik @@ -76,7 +75,7 @@ if (count <= 0) return 0; FILE * file = static_cast(stream->descriptor.pointer); std::fseek (file , offset , SEEK_SET); - return std::fread ((char*)buffer, 1, count, file); + return std::fread(reinterpret_cast(buffer), 1, count, file); } bool freetype_engine::register_font(std::string const& file_name) @@ -94,7 +93,7 @@ { MAPNIK_LOG_DEBUG(font_engine_freetype) << "registering: " << file_name; mapnik::util::file file(file_name); - if (!file.open()) return false; + if (!file) return false; FT_Face face = 0; FT_Open_Args args; @@ -106,7 +105,7 @@ streamRec.size = file.size(); streamRec.descriptor.pointer = file.get(); streamRec.read = ft_read_cb; - streamRec.close = NULL; + streamRec.close = nullptr; args.flags = FT_OPEN_STREAM; args.stream = &streamRec; int num_faces = 0; @@ -259,7 +258,7 @@ } if (!found_font_file) return false; mapnik::util::file file(itr->second.second); - if (!file.open()) return false; + if (!file) return false; FT_Face face = 0; FT_Open_Args args; FT_StreamRec streamRec; @@ -270,7 +269,7 @@ streamRec.size = file.size(); streamRec.descriptor.pointer = file.get(); streamRec.read = ft_read_cb; - streamRec.close = NULL; + streamRec.close = nullptr; args.flags = FT_OPEN_STREAM; args.stream = &streamRec; // -1 is used to quickly check if the font file appears valid without iterating each face @@ -333,7 +332,7 @@ if (found_font_file) { mapnik::util::file file(itr->second.second); - if (file.open()) + if (file) { #ifdef MAPNIK_THREADSAFE std::lock_guard lock(mutex_); @@ -361,7 +360,7 @@ face_manager::face_manager(font_library & library, freetype_engine::font_file_mapping_type const& font_file_mapping, freetype_engine::font_memory_cache_type const& font_cache) - : face_ptr_cache_(), + : face_cache_(new face_cache()), library_(library), font_file_mapping_(font_file_mapping), font_memory_cache_(font_cache) @@ -376,8 +375,8 @@ face_ptr face_manager::get_face(std::string const& name) { - auto itr = face_ptr_cache_.find(name); - if (itr != face_ptr_cache_.end()) + auto itr = face_cache_->find(name); + if (itr != face_cache_->end()) { return itr->second; } @@ -391,7 +390,7 @@ freetype_engine::get_cache()); if (face) { - face_ptr_cache_.emplace(name,face); + face_cache_->emplace(name, face); } return face; } diff -Nru mapnik-3.0.9+ds/src/fs.cpp mapnik-3.0.13+ds/src/fs.cpp --- mapnik-3.0.9+ds/src/fs.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/fs.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,9 +24,12 @@ #include #include -// boost + +#pragma GCC diagnostic push +#include #include // for absolute, exists, etc #include // for path, operator/ +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/src/geometry_envelope.cpp mapnik-3.0.13+ds/src/geometry_envelope.cpp --- mapnik-3.0.9+ds/src/geometry_envelope.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/geometry_envelope.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,28 +23,21 @@ #include #include #include -namespace mapnik { -namespace geometry { + +namespace mapnik { namespace geometry { template MAPNIK_DECL mapnik::box2d envelope(geometry const& geom); -template MAPNIK_DECL mapnik::box2d envelope(mapnik::base_symbolizer_helper::geometry_cref const& geom); -template MAPNIK_DECL mapnik::box2d envelope(geometry_empty const& geom); +// single template MAPNIK_DECL mapnik::box2d envelope(point const& geom); template MAPNIK_DECL mapnik::box2d envelope(line_string const& geom); template MAPNIK_DECL mapnik::box2d envelope(polygon const& geom); +template MAPNIK_DECL mapnik::box2d envelope(linear_ring const& geom); +// multi template MAPNIK_DECL mapnik::box2d envelope(multi_point const& geom); template MAPNIK_DECL mapnik::box2d envelope(multi_line_string const& geom); template MAPNIK_DECL mapnik::box2d envelope(multi_polygon const& geom); +// collection template MAPNIK_DECL mapnik::box2d envelope(geometry_collection const& geom); -template MAPNIK_DECL mapnik::box2d envelope(geometry const& geom); -template MAPNIK_DECL mapnik::box2d envelope(point const& geom); -template MAPNIK_DECL mapnik::box2d envelope(line_string const& geom); -template MAPNIK_DECL mapnik::box2d envelope(polygon const& geom); -template MAPNIK_DECL mapnik::box2d envelope(multi_point const& geom); -template MAPNIK_DECL mapnik::box2d envelope(multi_line_string const& geom); -template MAPNIK_DECL mapnik::box2d envelope(multi_polygon const& geom); -template MAPNIK_DECL mapnik::box2d envelope(geometry_collection const& geom); - } // end ns geometry } // end ns mapnik diff -Nru mapnik-3.0.9+ds/src/gradient.cpp mapnik-3.0.13+ds/src/gradient.cpp --- mapnik-3.0.9+ds/src/gradient.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/gradient.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,24 +26,6 @@ namespace mapnik { -static const char * gradient_strings[] = { - "no-gradient", - "linear", - "radial", - "" -}; - -IMPLEMENT_ENUM( gradient_e, gradient_strings ) - -static const char * gradient_unit_strings[] = { - "user-space-on-use", - "user-space-on-use-bounding-box", - "object-bounding-box", - "" -}; - -IMPLEMENT_ENUM( gradient_unit_e, gradient_unit_strings ) - gradient::gradient() : transform_(), x1_(0), diff -Nru mapnik-3.0.9+ds/src/grid/grid_renderer.cpp mapnik-3.0.13+ds/src/grid/grid_renderer.cpp --- mapnik-3.0.9+ds/src/grid/grid_renderer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/grid/grid_renderer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -47,11 +47,15 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop -// agg +#pragma GCC diagnostic push +#include #include "agg_trans_affine.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/grid/process_building_symbolizer.cpp mapnik-3.0.13+ds/src/grid/process_building_symbolizer.cpp --- mapnik-3.0.9+ds/src/grid/process_building_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/grid/process_building_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -39,11 +39,13 @@ // stl #include -// agg +#pragma GCC diagnostic push +#include #include "agg_rasterizer_scanline_aa.h" #include "agg_renderer_scanline.h" #include "agg_scanline_bin.h" #include "agg_conv_stroke.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/grid/process_group_symbolizer.cpp mapnik-3.0.13+ds/src/grid/process_group_symbolizer.cpp --- mapnik-3.0.9+ds/src/grid/process_group_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/grid/process_group_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,28 +29,18 @@ #include #include #include -#include -#include -#include #include #include #include #include #include #include -#include -#include -#include -#include -#include -#include - -#include -#include -#include +#include -// agg +#pragma GCC diagnostic push +#include #include "agg_trans_affine.h" +#pragma GCC diagnostic pop namespace mapnik { @@ -61,7 +51,7 @@ * in the detector from the placement_finder. */ template -struct thunk_renderer +struct thunk_renderer : render_thunk_list_dispatch { using renderer_type = grid_renderer; using buffer_type = typename renderer_type::buffer_type; @@ -71,13 +61,13 @@ grid_rasterizer &ras, buffer_type &pixmap, renderer_common &common, - feature_impl &feature, - pixel_position const &offset) + feature_impl &feature) : ren_(ren), ras_(ras), pixmap_(pixmap), - common_(common), feature_(feature), offset_(offset) + common_(common), feature_(feature), + tex_(pixmap, src_over, common.scale_factor_) {} - void operator()(vector_marker_render_thunk const &thunk) const + virtual void operator()(vector_marker_render_thunk const& thunk) { using buf_type = grid_rendering_buffer; using pixfmt_type = typename grid_renderer_base_type::pixfmt_type; @@ -106,7 +96,7 @@ pixmap_.add_feature(feature_); } - void operator()(raster_marker_render_thunk const &thunk) const + virtual void operator()(raster_marker_render_thunk const& thunk) { using buf_type = grid_rendering_buffer; using pixfmt_type = typename grid_renderer_base_type::pixfmt_type; @@ -122,34 +112,28 @@ pixmap_.add_feature(feature_); } - void operator()(text_render_thunk const &thunk) const + virtual void operator()(text_render_thunk const &thunk) { - text_renderer_type ren(pixmap_, thunk.comp_op_, common_.scale_factor_); + tex_.set_comp_op(thunk.comp_op_); + value_integer feature_id = feature_.id(); - render_offset_placements( - thunk.placements_, - offset_, - [&] (glyph_positions_ptr const& glyphs) + for (auto const& glyphs : thunk.placements_) + { + scoped_glyph_positions_offset tmp_off(*glyphs, offset_); + + if (auto const& mark = glyphs->get_marker()) { - marker_info_ptr mark = glyphs->get_marker(); - if (mark) - { - ren_.render_marker(feature_, - glyphs->marker_pos(), - *mark->marker_, - mark->transform_, - thunk.opacity_, thunk.comp_op_); - } - ren.render(*glyphs, feature_id); - }); - pixmap_.add_feature(feature_); - } + ren_.render_marker(feature_, + glyphs->marker_pos(), + *mark->marker_, + mark->transform_, + thunk.opacity_, thunk.comp_op_); + } + tex_.render(*glyphs, feature_id); + } - template - void operator()(T1 const &) const - { - // TODO: warning if unimplemented? + pixmap_.add_feature(feature_); } private: @@ -158,7 +142,7 @@ buffer_type &pixmap_; renderer_common &common_; feature_impl &feature_; - pixel_position offset_; + text_renderer_type tex_; }; template @@ -166,16 +150,11 @@ mapnik::feature_impl & feature, proj_transform const& prj_trans) { + thunk_renderer ren(*this, *ras_ptr, pixmap_, common_, feature); + render_group_symbolizer( sym, feature, common_.vars_, prj_trans, common_.query_extent_, common_, - [&](render_thunk_list const& thunks, pixel_position const& render_offset) - { - thunk_renderer ren(*this, *ras_ptr, pixmap_, common_, feature, render_offset); - for (render_thunk_ptr const& thunk : thunks) - { - util::apply_visitor(ren, *thunk); - } - }); + ren); } template void grid_renderer::process(group_symbolizer const&, diff -Nru mapnik-3.0.9+ds/src/grid/process_line_pattern_symbolizer.cpp mapnik-3.0.13+ds/src/grid/process_line_pattern_symbolizer.cpp --- mapnik-3.0.9+ds/src/grid/process_line_pattern_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/grid/process_line_pattern_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -35,12 +35,15 @@ #include #include #include -// agg + +#pragma GCC diagnostic push +#include #include "agg_rasterizer_scanline_aa.h" #include "agg_renderer_scanline.h" #include "agg_scanline_bin.h" #include "agg_conv_stroke.h" #include "agg_conv_dash.h" +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/src/grid/process_line_symbolizer.cpp mapnik-3.0.13+ds/src/grid/process_line_symbolizer.cpp --- mapnik-3.0.9+ds/src/grid/process_line_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/grid/process_line_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -32,12 +32,15 @@ #include #include #include -// agg + +#pragma GCC diagnostic push +#include #include "agg_rasterizer_scanline_aa.h" #include "agg_renderer_scanline.h" #include "agg_scanline_bin.h" #include "agg_conv_stroke.h" #include "agg_conv_dash.h" +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/src/grid/process_markers_symbolizer.cpp mapnik-3.0.13+ds/src/grid/process_markers_symbolizer.cpp --- mapnik-3.0.9+ds/src/grid/process_markers_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/grid/process_markers_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -44,146 +44,94 @@ */ // mapnik -#include -#include -#include #include #include #include #include #include - -#include -#include -#include -#include -#include #include #include #include #include -#include -#include +#include -// agg +#pragma GCC diagnostic push +#include #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_rasterizer_scanline_aa.h" - -// boost -#include - -// stl -#include -#include +#pragma GCC diagnostic pop namespace mapnik { namespace detail { -template -struct vector_markers_rasterizer_dispatch : public vector_markers_dispatch +template +struct grid_markers_renderer_context : markers_renderer_context { using renderer_base = typename SvgRenderer::renderer_base; using vertex_source_type = typename SvgRenderer::vertex_source_type; using attribute_source_type = typename SvgRenderer::attribute_source_type; using pixfmt_type = typename renderer_base::pixfmt_type; - using BufferType = typename std::tuple_element<0,RendererContext>::type; - using RasterizerType = typename std::tuple_element<1,RendererContext>::type; - using PixMapType = typename std::tuple_element<2,RendererContext>::type; - - vector_markers_rasterizer_dispatch(svg_path_ptr const& src, - vertex_source_type & path, - svg_attribute_type const& attrs, - agg::trans_affine const& marker_trans, - markers_symbolizer const& sym, - Detector & detector, - double scale_factor, - mapnik::feature_impl & feature, - attributes const& vars, - bool snap_to_pixels, - RendererContext const& renderer_context) - : vector_markers_dispatch(src, marker_trans, sym, detector, scale_factor, feature, vars), - buf_(std::get<0>(renderer_context)), + grid_markers_renderer_context(feature_impl const& feature, + BufferType & buf, + RasterizerType & ras, + PixMapType & pixmap) + : feature_(feature), + buf_(buf), pixf_(buf_), renb_(pixf_), - svg_renderer_(path, attrs), - ras_(std::get<1>(renderer_context)), - pixmap_(std::get<2>(renderer_context)), + ras_(ras), + pixmap_(pixmap), placed_(false) {} - void render_marker(agg::trans_affine const& marker_tr, double opacity) + virtual void render_marker(svg_path_ptr const& src, + svg_path_adapter & path, + svg_attribute_type const& attrs, + markers_dispatch_params const& params, + agg::trans_affine const& marker_tr) { + SvgRenderer svg_renderer_(path, attrs); agg::scanline_bin sl_; - svg_renderer_.render_id(ras_, sl_, renb_, this->feature_.id(), marker_tr, opacity, this->src_->bounding_box()); - if (!placed_) - { - pixmap_.add_feature(this->feature_); - placed_ = true; - } + svg_renderer_.render_id(ras_, sl_, renb_, feature_.id(), marker_tr, + params.opacity, src->bounding_box()); + place_feature(); } -private: - BufferType & buf_; - pixfmt_type pixf_; - renderer_base renb_; - SvgRenderer svg_renderer_; - RasterizerType & ras_; - PixMapType & pixmap_; - bool placed_; -}; - -template -struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch -{ - using pixfmt_type = typename RendererBase::pixfmt_type; - using color_type = typename RendererBase::pixfmt_type::color_type; - - using BufferType = typename std::tuple_element<0,RendererContext>::type; - using RasterizerType = typename std::tuple_element<1,RendererContext>::type; - using PixMapType = typename std::tuple_element<2,RendererContext>::type; - - raster_markers_rasterizer_dispatch(image_rgba8 const& src, - agg::trans_affine const& marker_trans, - markers_symbolizer const& sym, - Detector & detector, - double scale_factor, - mapnik::feature_impl & feature, - attributes const& vars, - RendererContext const& renderer_context) - : raster_markers_dispatch(src, marker_trans, sym, detector, scale_factor, feature, vars), - buf_(std::get<0>(renderer_context)), - pixf_(buf_), - renb_(pixf_), - ras_(std::get<1>(renderer_context)), - pixmap_(std::get<2>(renderer_context)), - placed_(false) - {} + virtual void render_marker(image_rgba8 const& src, + markers_dispatch_params const& params, + agg::trans_affine const& marker_tr) + { + // In the long term this should be a visitor pattern based on the type of + // render src provided that converts the destination pixel type required. + render_raster_marker(ScanlineRenderer(renb_), ras_, src, feature_, + marker_tr, params.opacity); + place_feature(); + } - void render_marker(agg::trans_affine const& marker_tr, double opacity) + void place_feature() { - // In the long term this should be a visitor pattern based on the type of render this->src_ provided that converts - // the destination pixel type required. - render_raster_marker(RendererType(renb_), ras_, this->src_, this->feature_, marker_tr, opacity); if (!placed_) { - pixmap_.add_feature(this->feature_); + pixmap_.add_feature(feature_); placed_ = true; } } private: + feature_impl const& feature_; BufferType & buf_; pixfmt_type pixf_; - RendererBase renb_; + renderer_base renb_; RasterizerType & ras_; PixMapType & pixmap_; bool placed_; }; -} +} // namespace detail template void grid_renderer::process(markers_symbolizer const& sym, @@ -193,7 +141,6 @@ using buf_type = grid_rendering_buffer; using pixfmt_type = typename grid_renderer_base_type::pixfmt_type; using renderer_type = agg::renderer_scanline_bin_solid; - using detector_type = label_collision_detector4; using namespace mapnik::svg; using svg_attribute_type = agg::pod_bvector; @@ -206,22 +153,20 @@ ras_ptr->reset(); box2d clip_box = common_.query_extent_; - auto renderer_context = std::tie(render_buf,*ras_ptr,pixmap_); - using context_type = decltype(renderer_context); - using vector_dispatch_type = detail::vector_markers_rasterizer_dispatch; - using raster_dispatch_type = detail::raster_markers_rasterizer_dispatch; - render_markers_symbolizer( - sym, feature, prj_trans, common_, clip_box,renderer_context); + using context_type = detail::grid_markers_renderer_context; + context_type renderer_context(feature, render_buf, *ras_ptr, pixmap_); + + render_markers_symbolizer( + sym, feature, prj_trans, common_, clip_box, renderer_context); } template void grid_renderer::process(markers_symbolizer const&, mapnik::feature_impl &, proj_transform const&); -} +} // namespace mapnik #endif diff -Nru mapnik-3.0.9+ds/src/grid/process_point_symbolizer.cpp mapnik-3.0.13+ds/src/grid/process_point_symbolizer.cpp --- mapnik-3.0.9+ds/src/grid/process_point_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/grid/process_point_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,15 +30,16 @@ #include #include -#include #include #include #include #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_trans_affine.h" +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/src/grid/process_polygon_pattern_symbolizer.cpp mapnik-3.0.13+ds/src/grid/process_polygon_pattern_symbolizer.cpp --- mapnik-3.0.9+ds/src/grid/process_polygon_pattern_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/grid/process_polygon_pattern_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -36,10 +36,12 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_rasterizer_scanline_aa.h" #include "agg_renderer_scanline.h" #include "agg_scanline_bin.h" +#pragma GCC diagnostic pop // stl #include @@ -76,7 +78,12 @@ evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_); } - using vertex_converter_type = vertex_converter; + using vertex_converter_type = vertex_converter; + vertex_converter_type converter(common_.query_extent_,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); if (prj_trans.equal() && clip) converter.set(); diff -Nru mapnik-3.0.9+ds/src/grid/process_polygon_symbolizer.cpp mapnik-3.0.13+ds/src/grid/process_polygon_symbolizer.cpp --- mapnik-3.0.9+ds/src/grid/process_polygon_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/grid/process_polygon_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -34,10 +34,12 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_rasterizer_scanline_aa.h" #include "agg_renderer_scanline.h" #include "agg_scanline_bin.h" +#pragma GCC diagnostic pop // stl #include diff -Nru mapnik-3.0.9+ds/src/grid/process_shield_symbolizer.cpp mapnik-3.0.13+ds/src/grid/process_shield_symbolizer.cpp --- mapnik-3.0.9+ds/src/grid/process_shield_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/grid/process_shield_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -33,8 +33,11 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_trans_affine.h" +#include "agg_gamma_functions.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/grid/process_text_symbolizer.cpp mapnik-3.0.13+ds/src/grid/process_text_symbolizer.cpp --- mapnik-3.0.9+ds/src/grid/process_text_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/grid/process_text_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -60,7 +60,7 @@ if (halo_transform) { agg::trans_affine halo_affine_transform; - evaluate_transform(halo_affine_transform, feature, common_.vars_, *halo_transform); + evaluate_transform(halo_affine_transform, feature, common_.vars_, *halo_transform, common_.scale_factor_); ren.set_halo_transform(halo_affine_transform); } diff -Nru mapnik-3.0.9+ds/src/group/group_layout_manager.cpp mapnik-3.0.13+ds/src/group/group_layout_manager.cpp --- mapnik-3.0.9+ds/src/group/group_layout_manager.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/group/group_layout_manager.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -34,19 +34,21 @@ // This visitor will process offsets for the given layout struct process_layout { + using bound_box = box2d; + // The vector containing the existing, centered item bounding boxes - vector const& member_boxes_; + std::vector const& member_boxes_; // The vector to populate with item offsets - vector & member_offsets_; + std::vector & member_offsets_; // The origin point of the member boxes // i.e. The member boxes are positioned around input_origin, // and the offset values should position them around (0,0) pixel_position const& input_origin_; - process_layout(vector const& member_bboxes, - vector &member_offsets, + process_layout(std::vector const& member_bboxes, + std::vector &member_offsets, pixel_position const& input_origin) : member_boxes_(member_bboxes), member_offsets_(member_offsets), @@ -54,9 +56,12 @@ { } - // arrange group memebers in centered, horizontal row + // arrange group members in centered, horizontal row void operator()(simple_row_layout const& layout) const { + member_offsets_.clear(); + member_offsets_.reserve(member_boxes_.size()); + double total_width = (member_boxes_.size() - 1) * layout.get_item_margin(); for (auto const& box : member_boxes_) { @@ -66,7 +71,7 @@ double x_offset = -(total_width / 2.0); for (auto const& box : member_boxes_) { - member_offsets_.push_back(pixel_position(x_offset - box.minx(), -input_origin_.y)); + member_offsets_.emplace_back(x_offset - box.minx(), -input_origin_.y); x_offset += box.width() + layout.get_item_margin(); } } @@ -85,30 +90,26 @@ return; } - bound_box layout_box; - int middle_ifirst = safe_cast((member_boxes_.size() - 1) >> 1); - int top_i = 0; - int bottom_i = 0; - if (middle_ifirst % 2 == 0) - { - layout_box = make_horiz_pair(0, 0.0, 0, x_margin, layout.get_max_difference()); - top_i = middle_ifirst - 2; - bottom_i = middle_ifirst + 2; - } - else + auto max_diff = layout.get_max_difference(); + auto layout_box = make_horiz_pair(0, 0.0, 0, x_margin, max_diff); + auto y_shift = 0.5 * layout_box.height(); + + for (size_t i = 2; i < member_boxes_.size(); i += 2) { - top_i = middle_ifirst - 1; - bottom_i = middle_ifirst + 1; + auto y = layout_box.maxy() + y_margin; + auto pair_box = make_horiz_pair(i, y, 1, x_margin, max_diff); + layout_box.expand_to_include(pair_box); } - while (bottom_i >= 0 && top_i >= 0 && top_i < static_cast(member_offsets_.size())) + // layout_box.center corresponds to the center of the first row; + // shift offsets so that the whole group is centered vertically + + y_shift -= 0.5 * layout_box.height(); + + for (auto & offset : member_offsets_) { - layout_box.expand_to_include(make_horiz_pair(static_cast(top_i), layout_box.miny() - y_margin, -1, x_margin, layout.get_max_difference())); - layout_box.expand_to_include(make_horiz_pair(static_cast(bottom_i), layout_box.maxy() + y_margin, 1, x_margin, layout.get_max_difference())); - top_i -= 2; - bottom_i += 2; + offset.y += y_shift; } - } private: @@ -141,16 +142,16 @@ // stores corresponding offset, and returns modified bounding box bound_box box_offset_align(size_t i, double x, double y, int x_dir, int y_dir) const { - bound_box const& box = member_boxes_[i]; - pixel_position offset((x_dir == 0 ? x - input_origin_.x : x - (x_dir < 0 ? box.maxx() : box.minx())), - (y_dir == 0 ? y - input_origin_.y : y - (y_dir < 0 ? box.maxy() : box.miny()))); - - member_offsets_[i] = offset; - return bound_box(box.minx() + offset.x, box.miny() + offset.y, box.maxx() + offset.x, box.maxy() + offset.y); + auto box = member_boxes_[i]; + auto & offset = member_offsets_[i]; + offset.x = x - (x_dir == 0 ? input_origin_.x : (x_dir < 0 ? box.maxx() : box.minx())); + offset.y = y - (y_dir == 0 ? input_origin_.y : (y_dir < 0 ? box.maxy() : box.miny())); + box.move(offset.x, offset.y); + return box; } }; -bound_box group_layout_manager::offset_box_at(size_t i) +box2d group_layout_manager::offset_box_at(size_t i) { handle_update(); pixel_position const& offset = member_offsets_.at(i); diff -Nru mapnik-3.0.9+ds/src/image_compositing.cpp mapnik-3.0.13+ds/src/image_compositing.cpp --- mapnik-3.0.9+ds/src/image_compositing.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/image_compositing.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -33,7 +33,8 @@ #include #pragma GCC diagnostic pop -// agg +#pragma GCC diagnostic push +#include #include "agg_rendering_buffer.h" #include "agg_rasterizer_scanline_aa.h" #include "agg_scanline_u.h" @@ -41,7 +42,7 @@ #include "agg_pixfmt_rgba.h" #include "agg_pixfmt_gray.h" #include "agg_color_rgba.h" - +#pragma GCC diagnostic pop namespace mapnik { @@ -190,7 +191,20 @@ dy_(dy) {} template - void operator() (T & dst); + void operator() (T & dst) const + { + throw std::runtime_error("Error: Composite with " + std::string(typeid(dst).name()) + " is not supported"); + } + + void operator()(image_rgba8 & dst) const + { + composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); + } + + void operator() (image_gray32f & dst) const + { + composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); + } private: image_any const& src_; @@ -198,25 +212,8 @@ float opacity_; int dx_; int dy_; -}; -template -void composite_visitor::operator() (T & dst) -{ - throw std::runtime_error("Error: Composite with " + std::string(typeid(dst).name()) + " is not supported"); -} - -template <> -void composite_visitor::operator() (image_rgba8 & dst) -{ - composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); -} - -template <> -void composite_visitor::operator() (image_gray32f & dst) -{ - composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); -} +}; } // end ns diff -Nru mapnik-3.0.9+ds/src/image_copy.cpp mapnik-3.0.13+ds/src/image_copy.cpp --- mapnik-3.0.9+ds/src/image_copy.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/image_copy.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -37,7 +37,7 @@ { using dst_type = typename T0::pixel_type; - T0 operator() (image_null const&) + T0 operator() (image_null const&) const { throw std::runtime_error("Can not cast a null image"); } @@ -48,7 +48,7 @@ } template - T0 operator() (T1 const& src) + T0 operator() (T1 const& src) const { T0 dst(safe_cast(src.width()), safe_cast(src.height()), false); for (std::size_t y = 0; y < dst.height(); ++y) @@ -75,7 +75,7 @@ throw std::runtime_error("Can not cast a null image"); } - T0 operator() (T0 const& src) + T0 operator() (T0 const& src) const { if (offset_ == src.get_offset() && scaling_ == src.get_scaling()) { @@ -91,7 +91,7 @@ } template - T0 operator() (T1 const& src) + T0 operator() (T1 const& src) const { double src_offset = src.get_offset(); double src_scaling = src.get_scaling(); diff -Nru mapnik-3.0.9+ds/src/image.cpp mapnik-3.0.13+ds/src/image.cpp --- mapnik-3.0.9+ds/src/image.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/image.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -88,7 +88,6 @@ } // end ns detail -template class MAPNIK_DECL image; template class MAPNIK_DECL image; template class MAPNIK_DECL image; template class MAPNIK_DECL image; diff -Nru mapnik-3.0.9+ds/src/image_filter_grammar.cpp mapnik-3.0.13+ds/src/image_filter_grammar.cpp --- mapnik-3.0.9+ds/src/image_filter_grammar.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/src/image_filter_grammar.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,29 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 +#include +#include +#include +#include + +template struct mapnik::image_filter_grammar>; diff -Nru mapnik-3.0.9+ds/src/image_filter_types.cpp mapnik-3.0.13+ds/src/image_filter_types.cpp --- mapnik-3.0.9+ds/src/image_filter_types.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/image_filter_types.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -22,7 +22,6 @@ // mapnik #include #include -#include #pragma GCC diagnostic push #include diff -Nru mapnik-3.0.9+ds/src/image_scaling.cpp mapnik-3.0.13+ds/src/image_scaling.cpp --- mapnik-3.0.9+ds/src/image_scaling.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/image_scaling.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,14 +25,14 @@ #include #include -// boost #pragma GCC diagnostic push #include #include #include #pragma GCC diagnostic pop -// agg +#pragma GCC diagnostic push +#include #include "agg_image_accessors.h" #include "agg_pixfmt_rgba.h" #include "agg_pixfmt_gray.h" @@ -47,6 +47,7 @@ #include "agg_span_interpolator_linear.h" #include "agg_trans_affine.h" #include "agg_image_filters.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/image_util.cpp mapnik-3.0.13+ds/src/image_util.cpp --- mapnik-3.0.9+ds/src/image_util.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/image_util.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -38,13 +38,14 @@ #include #ifdef SSE_MATH #include - #endif -// agg +#pragma GCC diagnostic push +#include #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" #include "agg_color_rgba.h" +#pragma GCC diagnostic pop // stl #include @@ -111,7 +112,7 @@ { std::string t = type; std::transform(t.begin(), t.end(), t.begin(), ::tolower); - if (t == "png" || boost::algorithm::starts_with(t, "png")) + if (boost::algorithm::starts_with(t, "png")) { png_saver_pal visitor(stream, t, palette); mapnik::util::apply_visitor(visitor, image); @@ -141,7 +142,7 @@ { std::string t = type; std::transform(t.begin(), t.end(), t.begin(), ::tolower); - if (t == "png" || boost::algorithm::starts_with(t, "png")) + if (boost::algorithm::starts_with(t, "png")) { png_saver_pal visitor(stream, t, palette); visitor(image); @@ -172,7 +173,7 @@ { std::string t = type; std::transform(t.begin(), t.end(), t.begin(), ::tolower); - if (t == "png" || boost::algorithm::starts_with(t, "png")) + if (boost::algorithm::starts_with(t, "png")) { png_saver_pal visitor(stream, t, palette); visitor(image); @@ -200,7 +201,7 @@ { std::string t = type; std::transform(t.begin(), t.end(), t.begin(), ::tolower); - if (t == "png" || boost::algorithm::starts_with(t, "png")) + if (boost::algorithm::starts_with(t, "png")) { png_saver visitor(stream, t); util::apply_visitor(visitor, image); @@ -236,7 +237,7 @@ { std::string t = type; std::transform(t.begin(), t.end(), t.begin(), ::tolower); - if (t == "png" || boost::algorithm::starts_with(t, "png")) + if (boost::algorithm::starts_with(t, "png")) { png_saver visitor(stream, t); visitor(image); @@ -276,7 +277,7 @@ { std::string t = type; std::transform(t.begin(), t.end(), t.begin(), ::tolower); - if (t == "png" || boost::algorithm::starts_with(t, "png")) + if (boost::algorithm::starts_with(t, "png")) { png_saver visitor(stream, t); visitor(image); @@ -2087,7 +2088,7 @@ : os_(os) {} template - void operator() (T const& view) + void operator() (T const& view) const { for (std::size_t i=0;i (image_rgba8 const& image) const; template void jpeg_saver::operator() (image_gray8 const& image) const; template void jpeg_saver::operator() (image_gray8s const& image) const; template void jpeg_saver::operator() (image_gray16 const& image) const; @@ -130,7 +129,6 @@ template void jpeg_saver::operator() (image_gray64 const& image) const; template void jpeg_saver::operator() (image_gray64s const& image) const; template void jpeg_saver::operator() (image_gray64f const& image) const; -template void jpeg_saver::operator() (image_view_rgba8 const& image) const; template void jpeg_saver::operator() (image_view_gray8 const& image) const; template void jpeg_saver::operator() (image_view_gray8s const& image) const; template void jpeg_saver::operator() (image_view_gray16 const& image) const; diff -Nru mapnik-3.0.9+ds/src/image_util_png.cpp mapnik-3.0.13+ds/src/image_util_png.cpp --- mapnik-3.0.9+ds/src/image_util_png.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/image_util_png.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -85,7 +85,7 @@ } else if (key == "e" && val && *val == "miniz") { - opts.use_miniz = true; + throw image_writer_exception("miniz support has been removed from Mapnik"); } else if (key == "c") { @@ -168,7 +168,7 @@ { throw image_writer_exception("invalid gamma parameter: unavailable for true color (non-paletted) images"); } - if ((opts.use_miniz == false) && opts.compression > Z_BEST_COMPRESSION) + if (opts.compression > Z_BEST_COMPRESSION) { throw image_writer_exception("invalid compression value: (only -1 through 9 are valid)"); } @@ -316,7 +316,6 @@ #endif } -template void png_saver::operator() (image_rgba8 const& image) const; template void png_saver::operator() (image_gray8 const& image) const; template void png_saver::operator() (image_gray8s const& image) const; template void png_saver::operator() (image_gray16 const& image) const; @@ -327,7 +326,6 @@ template void png_saver::operator() (image_gray64 const& image) const; template void png_saver::operator() (image_gray64s const& image) const; template void png_saver::operator() (image_gray64f const& image) const; -template void png_saver::operator() (image_view_rgba8 const& image) const; template void png_saver::operator() (image_view_gray8 const& image) const; template void png_saver::operator() (image_view_gray8s const& image) const; template void png_saver::operator() (image_view_gray16 const& image) const; @@ -338,7 +336,6 @@ template void png_saver::operator() (image_view_gray64 const& image) const; template void png_saver::operator() (image_view_gray64s const& image) const; template void png_saver::operator() (image_view_gray64f const& image) const; -template void png_saver_pal::operator() (image_rgba8 const& image) const; template void png_saver_pal::operator() (image_gray8 const& image) const; template void png_saver_pal::operator() (image_gray8s const& image) const; template void png_saver_pal::operator() (image_gray16 const& image) const; @@ -349,7 +346,6 @@ template void png_saver_pal::operator() (image_gray64 const& image) const; template void png_saver_pal::operator() (image_gray64s const& image) const; template void png_saver_pal::operator() (image_gray64f const& image) const; -template void png_saver_pal::operator() (image_view_rgba8 const& image) const; template void png_saver_pal::operator() (image_view_gray8 const& image) const; template void png_saver_pal::operator() (image_view_gray8s const& image) const; template void png_saver_pal::operator() (image_view_gray16 const& image) const; diff -Nru mapnik-3.0.9+ds/src/image_util_webp.cpp mapnik-3.0.13+ds/src/image_util_webp.cpp --- mapnik-3.0.9+ds/src/image_util_webp.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/image_util_webp.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -360,7 +360,6 @@ throw image_writer_exception("Mapnik does not support webp grayscale images"); } -template void webp_saver::operator() (image_rgba8 const& image) const; template void webp_saver::operator() (image_gray8 const& image) const; template void webp_saver::operator() (image_gray8s const& image) const; template void webp_saver::operator() (image_gray16 const& image) const; @@ -371,7 +370,6 @@ template void webp_saver::operator() (image_gray64 const& image) const; template void webp_saver::operator() (image_gray64s const& image) const; template void webp_saver::operator() (image_gray64f const& image) const; -template void webp_saver::operator() (image_view_rgba8 const& image) const; template void webp_saver::operator() (image_view_gray8 const& image) const; template void webp_saver::operator() (image_view_gray8s const& image) const; template void webp_saver::operator() (image_view_gray16 const& image) const; diff -Nru mapnik-3.0.9+ds/src/jpeg_reader.cpp mapnik-3.0.13+ds/src/jpeg_reader.cpp --- mapnik-3.0.9+ds/src/jpeg_reader.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/jpeg_reader.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -22,6 +22,7 @@ // mapnik #include +#include #include // jpeg @@ -30,16 +31,10 @@ #include } -#pragma GCC diagnostic push -#include -#include -#include -#include -#pragma GCC diagnostic pop - // std #include #include +#include namespace mapnik { @@ -49,7 +44,7 @@ { public: using source_type = T; - using input_stream = boost::iostreams::stream; + using input_stream = std::iostream; const static unsigned BUF_SIZE = 4096; private: struct jpeg_stream_wrapper @@ -77,7 +72,7 @@ unsigned width_; unsigned height_; public: - explicit jpeg_reader(std::string const& file_name); + explicit jpeg_reader(std::string const& filename); explicit jpeg_reader(char const* data, size_t size); ~jpeg_reader(); unsigned width() const final; @@ -99,14 +94,14 @@ namespace { -image_reader* create_jpeg_reader(std::string const& file) +image_reader* create_jpeg_reader(std::string const& filename) { - return new jpeg_reader(file); + return new jpeg_reader(filename); } image_reader* create_jpeg_reader2(char const* data, size_t size) { - return new jpeg_reader(data, size); + return new jpeg_reader(data, size); } const bool registered = register_image_reader("jpeg",create_jpeg_reader); @@ -115,20 +110,21 @@ // ctors template -jpeg_reader::jpeg_reader(std::string const& file_name) - : source_(file_name,std::ios_base::in | std::ios_base::binary), - stream_(source_), +jpeg_reader::jpeg_reader(std::string const& filename) + : source_(), + stream_(&source_), width_(0), height_(0) { - if (!stream_) throw image_reader_exception("cannot open image file "+ file_name); + source_.open(filename, std::ios_base::in | std::ios_base::binary); + if (!stream_) throw image_reader_exception("cannot open image file "+ filename); init(); } template jpeg_reader::jpeg_reader(char const* data, size_t size) : source_(data, size), - stream_(source_), + stream_(&source_), width_(0), height_(0) { diff -Nru mapnik-3.0.9+ds/src/json/generic_json.cpp mapnik-3.0.13+ds/src/json/generic_json.cpp --- mapnik-3.0.9+ds/src/json/generic_json.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/src/json/generic_json.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,63 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + +namespace mapnik { namespace json { + +template +generic_json::generic_json() + : generic_json::base_type(value) +{ + qi::lit_type lit; + qi::_val_type _val; + qi::_1_type _1; + using phoenix::construct; + // generic json types + value = object | array | string_ | number + ; + + key_value = string_ > lit(':') > value + ; + + object = lit('{') + > -(key_value % lit(',')) + > lit('}') + ; + + array = lit('[') + > -(value % lit(',')) + > lit(']') + ; + + number = strict_double[_val = double_converter(_1)] + | int__[_val = integer_converter(_1)] + | lit("true") [_val = true] + | lit ("false") [_val = false] + | lit("null")[_val = construct()] + ; +} + +}} + +using iterator_type = char const*; +template struct mapnik::json::generic_json; diff -Nru mapnik-3.0.9+ds/src/json/mapnik_geometry_to_geojson.cpp mapnik-3.0.13+ds/src/json/mapnik_geometry_to_geojson.cpp --- mapnik-3.0.9+ds/src/json/mapnik_geometry_to_geojson.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/src/json/mapnik_geometry_to_geojson.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,37 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + * + *****************************************************************************/ + +// mapnik +#include +#include + +namespace mapnik { namespace util { + +bool to_geojson(std::string & json, mapnik::geometry::geometry const& geom) +{ + using sink_type = std::back_insert_iterator; + static const mapnik::json::geometry_generator_grammar > grammar; + sink_type sink(json); + return boost::spirit::karma::generate(sink, grammar, geom); +} + +}} diff -Nru mapnik-3.0.9+ds/src/json/mapnik_json_geometry_parser.cpp mapnik-3.0.13+ds/src/json/mapnik_json_geometry_parser.cpp --- mapnik-3.0.9+ds/src/json/mapnik_json_geometry_parser.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/src/json/mapnik_json_geometry_parser.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,43 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 +#include + +// boost +#include +#include + +namespace mapnik { namespace json { + +bool from_geojson(std::string const& json, mapnik::geometry::geometry & geom) +{ + using namespace boost::spirit; + static const geometry_grammar g; + standard::space_type space; + char const* start = json.c_str(); + char const* end = start + json.length(); + return qi::phrase_parse(start, end, g, space, geom); +} + +}} diff -Nru mapnik-3.0.9+ds/src/json/mapnik_json_positions_grammar.cpp mapnik-3.0.13+ds/src/json/mapnik_json_positions_grammar.cpp --- mapnik-3.0.9+ds/src/json/mapnik_json_positions_grammar.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/src/json/mapnik_json_positions_grammar.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,27 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 +#include + +using iterator_type = char const*; +template struct mapnik::json::positions_grammar; diff -Nru mapnik-3.0.9+ds/src/json/mapnik_topojson_grammar.cpp mapnik-3.0.13+ds/src/json/mapnik_topojson_grammar.cpp --- mapnik-3.0.9+ds/src/json/mapnik_topojson_grammar.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/json/mapnik_topojson_grammar.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,5 +24,5 @@ #include #include -using iterator_type = std::string::const_iterator; +using iterator_type = char const*; template struct mapnik::topojson::topojson_grammar ; diff -Nru mapnik-3.0.9+ds/src/load_map.cpp mapnik-3.0.13+ds/src/load_map.cpp --- mapnik-3.0.9+ds/src/load_map.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/load_map.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -59,18 +59,22 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include #include #include #include #include +#pragma GCC diagnostic pop // stl #include -// agg +#pragma GCC diagnostic push +#include #include "agg_trans_affine.h" +#pragma GCC diagnostic pop using boost::tokenizer; @@ -196,7 +200,7 @@ { map.set_background(*bgcolor); } - + optional image_filename = map_node.get_opt_attr("background-image"); if (image_filename) { @@ -751,7 +755,7 @@ } catch (...) { - throw config_error("Unknown exception occured attempting to create datasoure for layer '" + lyr.name() + "'"); + throw config_error("Unknown exception occurred attempting to create datasoure for layer '" + lyr.name() + "'"); } } } @@ -887,7 +891,7 @@ { set_symbolizer_property(sym, keys::simplify_tolerance, node); set_symbolizer_property(sym, keys::smooth, node); - set_symbolizer_property(sym, keys::clip, node); + set_symbolizer_property(sym, keys::clip, node); set_symbolizer_property(sym, keys::comp_op, node); set_symbolizer_property(sym, keys::geometry_transform, node); set_symbolizer_property(sym, keys::simplify_algorithm, node); @@ -903,8 +907,8 @@ point_symbolizer sym; parse_symbolizer_base(sym, node); set_symbolizer_property(sym, keys::opacity, node); - set_symbolizer_property(sym, keys::allow_overlap, node); - set_symbolizer_property(sym, keys::ignore_placement, node); + set_symbolizer_property(sym, keys::allow_overlap, node); + set_symbolizer_property(sym, keys::ignore_placement, node); set_symbolizer_property(sym, keys::point_placement_type, node); set_symbolizer_property(sym, keys::image_transform, node); if (file && !file->empty()) @@ -1007,9 +1011,9 @@ set_symbolizer_property(sym, keys::offset, node); set_symbolizer_property(sym, keys::width, node); set_symbolizer_property(sym, keys::height, node); - set_symbolizer_property(sym, keys::allow_overlap, node); - set_symbolizer_property(sym, keys::avoid_edges, node); - set_symbolizer_property(sym, keys::ignore_placement, node); + set_symbolizer_property(sym, keys::allow_overlap, node); + set_symbolizer_property(sym, keys::avoid_edges, node); + set_symbolizer_property(sym, keys::ignore_placement, node); set_symbolizer_property(sym, keys::fill, node); set_symbolizer_property(sym, keys::image_transform, node); set_symbolizer_property(sym, keys::markers_placement_type, node); @@ -1168,7 +1172,7 @@ set_symbolizer_property(sym, keys::shield_dx, node); set_symbolizer_property(sym, keys::shield_dy, node); set_symbolizer_property(sym, keys::opacity, node); - set_symbolizer_property(sym, keys::unlock_image, node); + set_symbolizer_property(sym, keys::unlock_image, node); std::string file = node.get_attr("file"); if (file.empty()) @@ -1339,7 +1343,7 @@ // premultiplied status of image optional premultiplied = node.get_opt_attr("premultiplied"); - if (premultiplied) put(raster_sym, keys::premultiplied, *premultiplied); + if (premultiplied) put(raster_sym, keys::premultiplied, bool(*premultiplied)); bool found_colorizer = false; for ( auto const& css : node) diff -Nru mapnik-3.0.9+ds/src/map.cpp mapnik-3.0.13+ds/src/map.cpp --- mapnik-3.0.9+ds/src/map.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/map.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -307,7 +307,7 @@ continue; } mapnik::util::file file(file_path); - if (file.open()) + if (file) { auto item = font_memory_cache_.emplace(file_path, std::make_pair(file.data(),file.size())); if (item.second) result = true; @@ -695,7 +695,7 @@ { if (!current_extent_.valid()) { - throw std::runtime_error("query_point: map extent is not intialized, you need to set a valid extent before querying"); + throw std::runtime_error("query_point: map extent is not initialized, you need to set a valid extent before querying"); } if (!current_extent_.intersects(x,y)) { @@ -746,7 +746,7 @@ else s << " (map has no layers)"; throw std::out_of_range(s.str()); } - return featureset_ptr(); + return mapnik::make_invalid_featureset(); } featureset_ptr Map::query_map_point(unsigned index, double x, double y) const diff -Nru mapnik-3.0.9+ds/src/mapped_memory_cache.cpp mapnik-3.0.13+ds/src/mapped_memory_cache.cpp --- mapnik-3.0.9+ds/src/mapped_memory_cache.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/mapped_memory_cache.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -37,6 +37,8 @@ namespace mapnik { +template class singleton; + void mapped_memory_cache::clear() { #ifdef MAPNIK_THREADSAFE @@ -58,6 +60,7 @@ #ifdef MAPNIK_THREADSAFE std::lock_guard lock(mutex_); #endif + using iterator_type = std::unordered_map::const_iterator; boost::optional result; iterator_type itr = cache_.find(uri); @@ -76,7 +79,7 @@ result.reset(region); if (update_cache) { - cache_.emplace(uri,*result); + cache_.emplace(uri, *result); } return result; } diff -Nru mapnik-3.0.9+ds/src/marker_cache.cpp mapnik-3.0.13+ds/src/marker_cache.cpp --- mapnik-3.0.9+ds/src/marker_cache.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/marker_cache.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -39,9 +39,11 @@ #include #pragma GCC diagnostic pop -// agg +#pragma GCC diagnostic push +#include #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" +#pragma GCC diagnostic pop namespace mapnik { @@ -118,19 +120,19 @@ struct visitor_create_marker { - marker operator() (image_rgba8 & data) + marker operator() (image_rgba8 & data) const { mapnik::premultiply_alpha(data); return mapnik::marker(mapnik::marker_rgba8(data)); } - marker operator() (image_null &) + marker operator() (image_null &) const { throw std::runtime_error("Can not make marker from null image data type"); } template - marker operator() (T &) + marker operator() (T &) const { throw std::runtime_error("Can not make marker from this data type"); } @@ -265,7 +267,7 @@ } else { - MAPNIK_LOG_ERROR(marker_cache) << "could not intialize reader for: '" << uri << "'"; + MAPNIK_LOG_ERROR(marker_cache) << "could not initialize reader for: '" << uri << "'"; return std::make_shared(mapnik::marker_null()); } } diff -Nru mapnik-3.0.9+ds/src/marker_helpers.cpp mapnik-3.0.13+ds/src/marker_helpers.cpp --- mapnik-3.0.9+ds/src/marker_helpers.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/marker_helpers.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,9 +23,13 @@ // mapnik #include #include +#include +#pragma GCC diagnostic push +#include #include "agg_ellipse.h" #include "agg_color_rgba.h" +#pragma GCC diagnostic pop namespace mapnik { @@ -33,6 +37,7 @@ { double width = 0.0; double height = 0.0; + double half_stroke_width = 0.0; if (has_key(sym,keys::width) && has_key(sym,keys::height)) { width = get(sym, keys::width, feature, vars, 0.0); @@ -46,6 +51,10 @@ { width = height = get(sym, keys::height, feature, vars, 0.0); } + if (has_key(sym,keys::stroke_width)) + { + half_stroke_width = get(sym, keys::stroke_width, feature, vars, 0.0) / 2.0; + } svg::svg_converter_type styled_svg(svg_path, marker_ellipse.attributes()); styled_svg.push_attr(); styled_svg.begin_path(); @@ -55,6 +64,10 @@ styled_svg.pop_attr(); double lox,loy,hix,hiy; styled_svg.bounding_rect(&lox, &loy, &hix, &hiy); + lox -= half_stroke_width; + loy -= half_stroke_width; + hix += half_stroke_width; + hiy += half_stroke_width; styled_svg.set_dimensions(width,height); marker_ellipse.set_dimensions(width,height); marker_ellipse.set_bounding_box(lox,loy,hix,hiy); @@ -158,5 +171,142 @@ } } +template +void apply_markers_single(vertex_converter_type & converter, Processor & proc, + geometry::geometry const& geom, geometry::geometry_types type) +{ + if (type == geometry::geometry_types::Point) + { + geometry::point_vertex_adapter va(geom.get>()); + converter.apply(va, proc); + } + else if (type == geometry::geometry_types::LineString) + { + geometry::line_string_vertex_adapter va(geom.get>()); + converter.apply(va, proc); + } + else if (type == geometry::geometry_types::Polygon) + { + geometry::polygon_vertex_adapter va(geom.get>()); + converter.apply(va, proc); + } + else if (type == geometry::geometry_types::MultiPoint) + { + for (auto const& pt : geom.get>()) + { + geometry::point_vertex_adapter va(pt); + converter.apply(va, proc); + } + } + else if (type == geometry::geometry_types::MultiLineString) + { + for (auto const& line : geom.get>()) + { + geometry::line_string_vertex_adapter va(line); + converter.apply(va, proc); + } + } + else if (type == geometry::geometry_types::MultiPolygon) + { + for (auto const& poly : geom.get>()) + { + geometry::polygon_vertex_adapter va(poly); + converter.apply(va, proc); + } + } +} + +template +void apply_markers_multi(feature_impl const& feature, attributes const& vars, + vertex_converter_type & converter, Processor & proc, symbolizer_base const& sym) +{ + auto const& geom = feature.get_geometry(); + geometry::geometry_types type = geometry::geometry_type(geom); + + if (type == geometry::geometry_types::Point + || + type == geometry::geometry_types::LineString + || + type == geometry::geometry_types::Polygon) + { + apply_markers_single(converter, proc, geom, type); + } + else + { + + marker_multi_policy_enum multi_policy = get(sym, feature, vars); + marker_placement_enum placement = get(sym, feature, vars); + + if (placement == MARKER_POINT_PLACEMENT && + multi_policy == MARKER_WHOLE_MULTI) + { + geometry::point pt; + // test if centroid is contained by bounding box + if (geometry::centroid(geom, pt) && converter.disp_.args_.bbox.contains(pt.x, pt.y)) + { + // unset any clipping since we're now dealing with a point + converter.template unset(); + geometry::point_vertex_adapter va(pt); + converter.apply(va, proc); + } + } + else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) && + multi_policy == MARKER_LARGEST_MULTI) + { + // Only apply to path with largest envelope area + // TODO: consider using true area for polygon types + if (type == geometry::geometry_types::MultiPolygon) + { + geometry::multi_polygon const& multi_poly = mapnik::util::get >(geom); + double maxarea = 0; + geometry::polygon const* largest = 0; + for (geometry::polygon const& poly : multi_poly) + { + box2d bbox = geometry::envelope(poly); + double area = bbox.width() * bbox.height(); + if (area > maxarea) + { + maxarea = area; + largest = &poly; + } + } + if (largest) + { + geometry::polygon_vertex_adapter va(*largest); + converter.apply(va, proc); + } + } + else + { + MAPNIK_LOG_WARN(marker_symbolizer) << "TODO: if you get here -> open an issue"; + } + } + else + { + if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT) + { + MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'"; + } + if (type == geometry::geometry_types::GeometryCollection) + { + for (auto const& g : geom.get>()) + { + apply_markers_single(converter, proc, g, geometry::geometry_type(g)); + } + } + else + { + apply_markers_single(converter, proc, geom, type); + } + } + } +} +template void apply_markers_multi(feature_impl const& feature, attributes const& vars, + vertex_converter_type & converter, vector_dispatch_type & proc, + symbolizer_base const& sym); + +template void apply_markers_multi(feature_impl const& feature, attributes const& vars, + vertex_converter_type & converter, raster_dispatch_type & proc, + symbolizer_base const& sym); } // end namespace mapnik diff -Nru mapnik-3.0.9+ds/src/memory_datasource.cpp mapnik-3.0.13+ds/src/memory_datasource.cpp --- mapnik-3.0.9+ds/src/memory_datasource.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/memory_datasource.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -73,7 +73,8 @@ desc_(memory_datasource::name(), *params.get("encoding","utf-8")), type_(datasource::Vector), - bbox_check_(*params.get("bbox_check", true)) {} + bbox_check_(*params.get("bbox_check", true)), + type_set_(false) {} memory_datasource::~memory_datasource() {} @@ -81,6 +82,30 @@ { // TODO - collect attribute descriptors? //desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer)); + if (feature->get_raster()) + { + // if a feature has a raster_ptr set it must be of raster type. + if (!type_set_) + { + type_ = datasource::Raster; + type_set_ = true; + } + else if (type_ == datasource::Vector) + { + throw std::runtime_error("Can not add a raster feature to a memory datasource that contains vectors"); + } + } + else + { + if (!type_set_) + { + type_set_ = true; + } + else if (type_ == datasource::Raster) + { + throw std::runtime_error("Can not add a vector feature to a memory datasource that contains rasters"); + } + } features_.push_back(feature); dirty_extent_ = true; } @@ -92,12 +117,20 @@ featureset_ptr memory_datasource::features(const query& q) const { + if (features_.empty()) + { + return mapnik::make_invalid_featureset(); + } return std::make_shared(q.get_bbox(),*this,bbox_check_); } featureset_ptr memory_datasource::features_at_point(coord2d const& pt, double tol) const { + if (features_.empty()) + { + return mapnik::make_invalid_featureset(); + } box2d box = box2d(pt.x, pt.y, pt.x, pt.y); box.pad(tol); MAPNIK_LOG_DEBUG(memory_datasource) << "memory_datasource: Box=" << box << ", Point x=" << pt.x << ",y=" << pt.y; @@ -107,6 +140,7 @@ void memory_datasource::set_envelope(box2d const& box) { extent_ = box; + dirty_extent_ = false; } box2d memory_datasource::envelope() const diff -Nru mapnik-3.0.9+ds/src/miniz.c mapnik-3.0.13+ds/src/miniz.c --- mapnik-3.0.9+ds/src/miniz.c 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/miniz.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,4834 +0,0 @@ -/* miniz.c v1.14 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing - See "unlicense" statement at the end of this file. - Rich Geldreich , last updated May 20, 2012 - Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt - - Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define - MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). - - * Change History - 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include (thanks fermtect). - 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files. - Eliminated a bunch of warnings when compiling with GCC 32-bit/64. - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly - "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning). - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64. - Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test. - Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives. - Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.) - Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself). - 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's. - level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson for the feedback/bug report. - 5/28/11 v1.11 - Added statement from unlicense.org - 5/27/11 v1.10 - Substantial compressor optimizations: - Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a - Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86). - Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types. - Refactored the compression code for better readability and maintainability. - Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large - drop in throughput on some files). - 5/15/11 v1.09 - Initial stable release. - - * Low-level Deflate/Inflate implementation notes: - - Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or - greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses - approximately as well as zlib. - - Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function - coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory - block large enough to hold the entire file. - - The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. - - * zlib-style API notes: - - miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in - zlib replacement in many apps: - The z_stream struct, optional memory allocation callbacks - deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound - inflateInit/inflateInit2/inflate/inflateEnd - compress, compress2, compressBound, uncompress - CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. - Supports raw deflate streams or standard zlib streams with adler-32 checking. - - Limitations: - The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. - I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but - there are no guarantees that miniz.c pulls this off perfectly. - - * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by - Alex Evans. Supports 1-4 bytes/pixel images. - - * ZIP archive API notes: - - The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to - get the job done with minimal fuss. There are simple API's to retrieve file information, read files from - existing archives, create new archives, append new files to existing archives, or clone archive data from - one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), - or you can specify custom file read/write callbacks. - - - Archive reading: Just call this function to read a single file from a disk archive: - - void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, - size_t *pSize, mz_uint zip_flags); - - For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central - directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. - - - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: - - int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); - - The locate operation can optionally check file comments too, which (as one example) can be used to identify - multiple versions of the same file in an archive. This function uses a simple linear search through the central - directory, so it's not very fast. - - Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and - retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - - - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data - to disk and builds an exact image of the central directory in memory. The central directory image is written - all at once at the end of the archive file when the archive is finalized. - - The archive writer can optionally align each file's local header and file data to any power of 2 alignment, - which can be useful when the archive will be read from optical media. Also, the writer supports placing - arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still - readable by any ZIP tool. - - - Archive appending: The simple way to add a single file to an archive is to call this function: - - mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, - const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - - The archive will be created if it doesn't already exist, otherwise it'll be appended to. - Note the appending is done in-place and is not an atomic operation, so if something goes wrong - during the operation it's possible the archive could be left without a central directory (although the local - file headers and file data will be fine, so the archive will be recoverable). - - For more complex archive modification scenarios: - 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to - preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the - compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and - you're done. This is safe but requires a bunch of temporary disk space or heap memory. - - 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), - append new files as needed, then finalize the archive which will write an updated central directory to the - original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a - possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - - - ZIP archive support limitations: - No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. - Requires streams capable of seeking. - - * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the - below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. - - * Important: For best perf. be sure to customize the below macros for your target platform: - #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 - #define MINIZ_LITTLE_ENDIAN 1 - #define MINIZ_HAS_64BIT_REGISTERS 1 -*/ - -#ifndef MINIZ_HEADER_INCLUDED -#define MINIZ_HEADER_INCLUDED - -#include - -#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) -#include -#endif - -// Defines to completely disable specific portions of miniz.c: -// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. - -// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. -//#define MINIZ_NO_STDIO - -// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or -// get/set file times. -//#define MINIZ_NO_TIME - -// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. -//#define MINIZ_NO_ARCHIVE_APIS - -// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's. -//#define MINIZ_NO_ARCHIVE_WRITING_APIS - -// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. -//#define MINIZ_NO_ZLIB_APIS - -// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. -//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES - -// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. -// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc -// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user -// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. -//#define MINIZ_NO_MALLOC - -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) -// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. -#define MINIZ_X86_OR_X64_CPU 1 -#endif - -#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU -// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. -#define MINIZ_LITTLE_ENDIAN 1 -#endif - -#if MINIZ_X86_OR_X64_CPU -// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 -#endif - -#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) -// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). -#define MINIZ_HAS_64BIT_REGISTERS 1 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// ------------------- zlib-style API Definitions. - -// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! -typedef unsigned long mz_ulong; - -// mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. -void mz_free(void *p); - -#define MZ_ADLER32_INIT (1) -// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); - -#define MZ_CRC32_INIT (0) -// mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. -mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); - -// Compression strategies. -enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; - -// Method -#define MZ_DEFLATED 8 - -#ifndef MINIZ_NO_ZLIB_APIS - -// Heap allocation callbacks. -// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. -typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); -typedef void (*mz_free_func)(void *opaque, void *address); -typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); - -#define MZ_VERSION "9.1.14" -#define MZ_VERNUM 0x91E0 -#define MZ_VER_MAJOR 9 -#define MZ_VER_MINOR 1 -#define MZ_VER_REVISION 14 -#define MZ_VER_SUBREVISION 0 - -// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). -enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; - -// Return status codes. MZ_PARAM_ERROR is non-standard. -enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; - -// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. -enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; - -// Window bits -#define MZ_DEFAULT_WINDOW_BITS 15 - -struct mz_internal_state; - -// Compression/decompression stream struct. -typedef struct mz_stream_s -{ - const unsigned char *next_in; // pointer to next byte to read - unsigned int avail_in; // number of bytes available at next_in - mz_ulong total_in; // total number of bytes consumed so far - - unsigned char *next_out; // pointer to next byte to write - unsigned int avail_out; // number of bytes that can be written to next_out - mz_ulong total_out; // total number of bytes produced so far - - char *msg; // error msg (unused) - struct mz_internal_state *state; // internal state, allocated by zalloc/zfree - - mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) - mz_free_func zfree; // optional heap free function (defaults to free) - void *opaque; // heap alloc function user pointer - - int data_type; // data_type (unused) - mz_ulong adler; // adler32 of the source or uncompressed data - mz_ulong reserved; // not used -} mz_stream; - -typedef mz_stream *mz_streamp; - -// Returns the version string of miniz.c. -const char *mz_version(void); - -// mz_deflateInit() initializes a compressor with default options: -// Parameters: -// pStream must point to an initialized mz_stream struct. -// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. -// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. -// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) -// Return values: -// MZ_OK on success. -// MZ_STREAM_ERROR if the stream is bogus. -// MZ_PARAM_ERROR if the input parameters are bogus. -// MZ_MEM_ERROR on out of memory. -int mz_deflateInit(mz_streamp pStream, int level); - -// mz_deflateInit2() is like mz_deflate(), except with more control: -// Additional parameters: -// method must be MZ_DEFLATED -// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) -// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); - -// Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). -int mz_deflateReset(mz_streamp pStream); - -// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. -// Parameters: -// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. -// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. -// Return values: -// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). -// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. -// MZ_STREAM_ERROR if the stream is bogus. -// MZ_PARAM_ERROR if one of the parameters is invalid. -// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) -int mz_deflate(mz_streamp pStream, int flush); - -// mz_deflateEnd() deinitializes a compressor: -// Return values: -// MZ_OK on success. -// MZ_STREAM_ERROR if the stream is bogus. -int mz_deflateEnd(mz_streamp pStream); - -// mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. -mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); - -// Single-call compression functions mz_compress() and mz_compress2(): -// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); - -// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). -mz_ulong mz_compressBound(mz_ulong source_len); - -// Initializes a decompressor. -int mz_inflateInit(mz_streamp pStream); - -// mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: -// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). -int mz_inflateInit2(mz_streamp pStream, int window_bits); - -// Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. -// Parameters: -// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. -// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. -// On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). -// MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. -// Return values: -// MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. -// MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. -// MZ_STREAM_ERROR if the stream is bogus. -// MZ_DATA_ERROR if the deflate stream is invalid. -// MZ_PARAM_ERROR if one of the parameters is invalid. -// MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again -// with more input data, or with more room in the output buffer (except when using single call decompression, described above). -int mz_inflate(mz_streamp pStream, int flush); - -// Deinitializes a decompressor. -int mz_inflateEnd(mz_streamp pStream); - -// Single-call decompression. -// Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); - -// Returns a string description of the specified error code, or NULL if the error code is invalid. -const char *mz_error(int err); - -// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. -// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. -#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES - typedef unsigned char Byte; - typedef unsigned int uInt; - typedef mz_ulong uLong; - typedef Byte Bytef; - typedef uInt uIntf; - typedef char charf; - typedef int intf; - typedef void *voidpf; - typedef uLong uLongf; - typedef void *voidp; - typedef void *const voidpc; - #define Z_NULL 0 - #define Z_NO_FLUSH MZ_NO_FLUSH - #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH - #define Z_SYNC_FLUSH MZ_SYNC_FLUSH - #define Z_FULL_FLUSH MZ_FULL_FLUSH - #define Z_FINISH MZ_FINISH - #define Z_BLOCK MZ_BLOCK - #define Z_OK MZ_OK - #define Z_STREAM_END MZ_STREAM_END - #define Z_NEED_DICT MZ_NEED_DICT - #define Z_ERRNO MZ_ERRNO - #define Z_STREAM_ERROR MZ_STREAM_ERROR - #define Z_DATA_ERROR MZ_DATA_ERROR - #define Z_MEM_ERROR MZ_MEM_ERROR - #define Z_BUF_ERROR MZ_BUF_ERROR - #define Z_VERSION_ERROR MZ_VERSION_ERROR - #define Z_PARAM_ERROR MZ_PARAM_ERROR - #define Z_NO_COMPRESSION MZ_NO_COMPRESSION - #define Z_BEST_SPEED MZ_BEST_SPEED - #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION - #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION - #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY - #define Z_FILTERED MZ_FILTERED - #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY - #define Z_RLE MZ_RLE - #define Z_FIXED MZ_FIXED - #define Z_DEFLATED MZ_DEFLATED - #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS - #define alloc_func mz_alloc_func - #define free_func mz_free_func - #define internal_state mz_internal_state - #define z_stream mz_stream - #define deflateInit mz_deflateInit - #define deflateInit2 mz_deflateInit2 - #define deflateReset mz_deflateReset - #define deflate mz_deflate - #define deflateEnd mz_deflateEnd - #define deflateBound mz_deflateBound - #define compress mz_compress - #define compress2 mz_compress2 - #define compressBound mz_compressBound - #define inflateInit mz_inflateInit - #define inflateInit2 mz_inflateInit2 - #define inflate mz_inflate - #define inflateEnd mz_inflateEnd - #define uncompress mz_uncompress - #define crc32 mz_crc32 - #define adler32 mz_adler32 - #define MAX_WBITS 15 - #define MAX_MEM_LEVEL 9 - #define zError mz_error - #define ZLIB_VERSION MZ_VERSION - #define ZLIB_VERNUM MZ_VERNUM - #define ZLIB_VER_MAJOR MZ_VER_MAJOR - #define ZLIB_VER_MINOR MZ_VER_MINOR - #define ZLIB_VER_REVISION MZ_VER_REVISION - #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION - #define zlibVersion mz_version - #define zlib_version mz_version() -#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES - -#endif // MINIZ_NO_ZLIB_APIS - -// ------------------- Types and macros - -typedef unsigned char mz_uint8; -typedef signed short mz_int16; -typedef unsigned short mz_uint16; -typedef unsigned int mz_uint32; -typedef unsigned int mz_uint; -typedef long long mz_int64; -typedef unsigned long long mz_uint64; -typedef int mz_bool; - -#define MZ_FALSE (0) -#define MZ_TRUE (1) - -// Works around MSVC's spammy "warning C4127: conditional expression is constant" message. -#ifdef _MSC_VER - #define MZ_MACRO_END while (0, 0) -#else - #define MZ_MACRO_END while (0) -#endif - -// ------------------- ZIP archive reading/writing - -#ifndef MINIZ_NO_ARCHIVE_APIS - -enum -{ - MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024, - MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, - MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 -}; - -typedef struct -{ - mz_uint32 m_file_index; - mz_uint32 m_central_dir_ofs; - mz_uint16 m_version_made_by; - mz_uint16 m_version_needed; - mz_uint16 m_bit_flag; - mz_uint16 m_method; -#ifndef MINIZ_NO_TIME - time_t m_time; -#endif - mz_uint32 m_crc32; - mz_uint64 m_comp_size; - mz_uint64 m_uncomp_size; - mz_uint16 m_internal_attr; - mz_uint32 m_external_attr; - mz_uint64 m_local_header_ofs; - mz_uint32 m_comment_size; - char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; - char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; -} mz_zip_archive_file_stat; - -typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); -typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); - -struct mz_zip_internal_state_tag; -typedef struct mz_zip_internal_state_tag mz_zip_internal_state; - -typedef enum -{ - MZ_ZIP_MODE_INVALID = 0, - MZ_ZIP_MODE_READING = 1, - MZ_ZIP_MODE_WRITING = 2, - MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 -} mz_zip_mode; - -typedef struct -{ - mz_uint64 m_archive_size; - mz_uint64 m_central_directory_file_ofs; - mz_uint m_total_files; - mz_zip_mode m_zip_mode; - - mz_uint m_file_offset_alignment; - - mz_alloc_func m_pAlloc; - mz_free_func m_pFree; - mz_realloc_func m_pRealloc; - void *m_pAlloc_opaque; - - mz_file_read_func m_pRead; - mz_file_write_func m_pWrite; - void *m_pIO_opaque; - - mz_zip_internal_state *m_pState; - -} mz_zip_archive; - -typedef enum -{ - MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, - MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, - MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, - MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 -} mz_zip_flags; - -// ZIP archive reading - -// Inits a ZIP archive reader. -// These functions read and validate the archive's central directory. -mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags); -mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags); - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); -#endif - -// Returns the total number of files in the archive. -mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); - -// Returns detailed information about an archive file entry. -mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); - -// Determines if an archive file entry is a directory entry. -mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); -mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); - -// Retrieves the filename of an archive file entry. -// Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. -mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); - -// Attempts to locates a file in the archive's central directory. -// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH -// Returns -1 if the file cannot be found. -int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); - -// Extracts a archive file to a memory buffer using no memory allocation. -mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); - -// Extracts a archive file to a memory buffer. -mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); - -// Extracts a archive file to a dynamically allocated heap buffer. -void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); -void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); - -// Extracts a archive file using a callback function to output the file's data. -mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); - -#ifndef MINIZ_NO_STDIO -// Extracts a archive file to a disk file and sets its last accessed and modified times. -// This function only extracts files, not archive directory records. -mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); -#endif - -// Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. -mz_bool mz_zip_reader_end(mz_zip_archive *pZip); - -// ZIP archive writing - -#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -// Inits a ZIP archive writer. -mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); -mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); -#endif - -// Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. -// For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. -// For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). -// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. -// Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before -// the archive is finalized the file's central directory will be hosed. -mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); - -// Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. -// To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer. -// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); -mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); - -#ifndef MINIZ_NO_STDIO -// Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. -// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); -#endif - -// Adds a file to an archive by fully cloning the data from another archive. -// This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields. -mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index); - -// Finalizes the archive by writing the central directory records followed by the end of central directory record. -// After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). -// An archive must be manually finalized by calling this function for it to be valid. -mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); -mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize); - -// Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. -// Note for the archive to be valid, it must have been finalized before ending. -mz_bool mz_zip_writer_end(mz_zip_archive *pZip); - -// Misc. high-level helper functions: - -// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. -// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - -// Reads a single file from an archive into a heap block. -// Returns NULL on failure. -void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); - -#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -#endif // #ifndef MINIZ_NO_ARCHIVE_APIS - -// ------------------- Low-level Decompression API Definitions - -// Decompression flags used by tinfl_decompress(). -// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. -// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. -// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). -// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. -enum -{ - TINFL_FLAG_PARSE_ZLIB_HEADER = 1, - TINFL_FLAG_HAS_MORE_INPUT = 2, - TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, - TINFL_FLAG_COMPUTE_ADLER32 = 8 -}; - -// High level decompression functions: -// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). -// On entry: -// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. -// On return: -// Function returns a pointer to the decompressed data, or NULL on failure. -// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. -// The caller must call mz_free() on the returned block when it's no longer needed. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. -// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. -#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. -// Returns 1 on success or 0 on failure. -typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; - -// Max size of LZ dictionary. -#define TINFL_LZ_DICT_SIZE 32768 - -// Return status. -typedef enum -{ - TINFL_STATUS_BAD_PARAM = -3, - TINFL_STATUS_ADLER32_MISMATCH = -2, - TINFL_STATUS_FAILED = -1, - TINFL_STATUS_DONE = 0, - TINFL_STATUS_NEEDS_MORE_INPUT = 1, - TINFL_STATUS_HAS_MORE_OUTPUT = 2 -} tinfl_status; - -// Initializes the decompressor to its initial state. -#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END -#define tinfl_get_adler32(r) (r)->m_check_adler32 - -// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. -// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); - -// Internal/private bits follow. -enum -{ - TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, - TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS -}; - -typedef struct -{ - mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; - mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; -} tinfl_huff_table; - -#if MINIZ_HAS_64BIT_REGISTERS - #define TINFL_USE_64BIT_BITBUF 1 -#endif - -#if TINFL_USE_64BIT_BITBUF - typedef mz_uint64 tinfl_bit_buf_t; - #define TINFL_BITBUF_SIZE (64) -#else - typedef mz_uint32 tinfl_bit_buf_t; - #define TINFL_BITBUF_SIZE (32) -#endif - -struct tinfl_decompressor_tag -{ - mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; - tinfl_bit_buf_t m_bit_buf; - size_t m_dist_from_out_buf_start; - tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; - mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; -}; - -// ------------------- Low-level Compression API Definitions - -// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). -#define TDEFL_LESS_MEMORY 0 - -// tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): -// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). -enum -{ - TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF -}; - -// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. -// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). -// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. -// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). -// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) -// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. -// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. -// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. -enum -{ - TDEFL_WRITE_ZLIB_HEADER = 0x01000, - TDEFL_COMPUTE_ADLER32 = 0x02000, - TDEFL_GREEDY_PARSING_FLAG = 0x04000, - TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, - TDEFL_RLE_MATCHES = 0x10000, - TDEFL_FILTER_MATCHES = 0x20000, - TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, - TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 -}; - -// High level compression functions: -// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). -// On entry: -// pSrc_buf, src_buf_len: Pointer and size of source block to compress. -// flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. -// On return: -// Function returns a pointer to the compressed data, or NULL on failure. -// *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. -// The caller must free() the returned block when it's no longer needed. -void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); - -// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. -// Returns 0 on failure. -size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); - -// Compresses an image to a compressed PNG file in memory. -// On entry: -// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. -// The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. -// On return: -// Function returns a pointer to the compressed data, or NULL on failure. -// *pLen_out will be set to the size of the PNG image file. -// The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); - -// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. -typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, size_t len, void *pUser); - -// tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. -mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; - -// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). -#if TDEFL_LESS_MEMORY -enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; -#else -enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; -#endif - -// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. -typedef enum -{ - TDEFL_STATUS_BAD_PARAM = -2, - TDEFL_STATUS_PUT_BUF_FAILED = -1, - TDEFL_STATUS_OKAY = 0, - TDEFL_STATUS_DONE = 1, -} tdefl_status; - -// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums -typedef enum -{ - TDEFL_NO_FLUSH = 0, - TDEFL_SYNC_FLUSH = 2, - TDEFL_FULL_FLUSH = 3, - TDEFL_FINISH = 4 -} tdefl_flush; - -// tdefl's compression state structure. -struct tdefl_compressor -{ - tdefl_put_buf_func_ptr m_pPut_buf_func; - void *m_pPut_buf_user; - mz_uint m_flags, m_max_probes[2]; - int m_greedy_parsing; - mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; - mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; - mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; - mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; - tdefl_status m_prev_return_status; - const void *m_pIn_buf; - void *m_pOut_buf; - size_t *m_pIn_buf_size, *m_pOut_buf_size; - tdefl_flush m_flush; - const mz_uint8 *m_pSrc; - size_t m_src_buf_left, m_out_buf_ofs; - mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; - mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; - mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; - mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; - mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; - mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; -}; - -// Initializes the compressor. -// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. -// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. -// If pBut_buf_func is NULL the user should always call the tdefl_compress() API. -// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); - -// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); - -// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. -// tdefl_compress_buffer() always consumes the entire input buffer. -tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); - -tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); -mz_uint32 tdefl_get_adler32(tdefl_compressor *d); - -// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros. -#ifndef MINIZ_NO_ZLIB_APIS -// Create tdefl_compress() flags given zlib-style compression parameters. -// level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) -// window_bits may be -15 (raw deflate) or 15 (zlib) -// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); -#endif // #ifndef MINIZ_NO_ZLIB_APIS - -#ifdef __cplusplus -} -#endif - -#endif // MINIZ_HEADER_INCLUDED - -// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) - -#ifndef MINIZ_HEADER_FILE_ONLY - -typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1]; -typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1]; -typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; - -#include -#include - -#define MZ_ASSERT(x) assert(x) - -#ifdef MINIZ_NO_MALLOC - #define MZ_MALLOC(x) NULL - #define MZ_FREE(x) (void)x, ((void)0) - #define MZ_REALLOC(p, x) NULL -#else - #define MZ_MALLOC(x) malloc(x) - #define MZ_FREE(x) free(x) - #define MZ_REALLOC(p, x) realloc(p, x) -#endif - -#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) -#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) -#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) - #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) -#else - #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) - #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) -#endif - -#ifdef _MSC_VER - #define MZ_FORCEINLINE __forceinline -#elif defined(__GNUC__) - #define MZ_FORCEINLINE inline __attribute__((__always_inline__)) -#else - #define MZ_FORCEINLINE inline -#endif - -#ifdef __cplusplus - extern "C" { -#endif - -// ------------------- zlib-style API's - -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) -{ - mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; - if (!ptr) return MZ_ADLER32_INIT; - while (buf_len) { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; - } - for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; - } - return (s2 << 16) + s1; -} - -// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ -mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -{ - static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; - mz_uint32 crcu32 = (mz_uint32)crc; - if (!ptr) return MZ_CRC32_INIT; - crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } - return ~crcu32; -} - -void mz_free(void *p) -{ - MZ_FREE(p); -} - -#ifndef MINIZ_NO_ZLIB_APIS - -static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } -static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } -//static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } - -const char *mz_version(void) -{ - return MZ_VERSION; -} - -int mz_deflateInit(mz_streamp pStream, int level) -{ - return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); -} - -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) -{ - tdefl_compressor *pComp; - mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); - - if (!pStream) return MZ_STREAM_ERROR; - if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; - - pStream->data_type = 0; - pStream->adler = MZ_ADLER32_INIT; - pStream->msg = NULL; - pStream->reserved = 0; - pStream->total_in = 0; - pStream->total_out = 0; - if (!pStream->zalloc) pStream->zalloc = def_alloc_func; - if (!pStream->zfree) pStream->zfree = def_free_func; - - pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); - if (!pComp) - return MZ_MEM_ERROR; - - pStream->state = (struct mz_internal_state *)pComp; - - if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) - { - mz_deflateEnd(pStream); - return MZ_PARAM_ERROR; - } - - return MZ_OK; -} - -int mz_deflateReset(mz_streamp pStream) -{ - if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; - pStream->total_in = pStream->total_out = 0; - tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); - return MZ_OK; -} - -int mz_deflate(mz_streamp pStream, int flush) -{ - size_t in_bytes, out_bytes; - mz_ulong orig_total_in, orig_total_out; - int mz_status = MZ_OK; - - if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; - if (!pStream->avail_out) return MZ_BUF_ERROR; - - if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; - - if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) - return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; - - orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; - for ( ; ; ) - { - tdefl_status defl_status; - in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; - - defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); - - pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; - pStream->total_out += (mz_uint)out_bytes; - - if (defl_status < 0) - { - mz_status = MZ_STREAM_ERROR; - break; - } - else if (defl_status == TDEFL_STATUS_DONE) - { - mz_status = MZ_STREAM_END; - break; - } - else if (!pStream->avail_out) - break; - else if ((!pStream->avail_in) && (flush != MZ_FINISH)) - { - if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) - break; - return MZ_BUF_ERROR; // Can't make forward progress without some input. - } - } - return mz_status; -} - -int mz_deflateEnd(mz_streamp pStream) -{ - if (!pStream) return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; -} - -mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) -{ - (void)pStream; - // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) - return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); -} - -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) -{ - int status; - mz_stream stream; - memset(&stream, 0, sizeof(stream)); - - // In case mz_ulong is 64-bits (argh I hate longs). - if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; - - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; - - status = mz_deflateInit(&stream, level); - if (status != MZ_OK) return status; - - status = mz_deflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_deflateEnd(&stream); - return (status == MZ_OK) ? MZ_BUF_ERROR : status; - } - - *pDest_len = stream.total_out; - return mz_deflateEnd(&stream); -} - -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ - return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); -} - -mz_ulong mz_compressBound(mz_ulong source_len) -{ - return mz_deflateBound(NULL, source_len); -} - -typedef struct -{ - tinfl_decompressor m_decomp; - mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; - mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; - tinfl_status m_last_status; -} inflate_state; - -int mz_inflateInit2(mz_streamp pStream, int window_bits) -{ - inflate_state *pDecomp; - if (!pStream) return MZ_STREAM_ERROR; - if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; - - pStream->data_type = 0; - pStream->adler = 0; - pStream->msg = NULL; - pStream->total_in = 0; - pStream->total_out = 0; - pStream->reserved = 0; - if (!pStream->zalloc) pStream->zalloc = def_alloc_func; - if (!pStream->zfree) pStream->zfree = def_free_func; - - pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); - if (!pDecomp) return MZ_MEM_ERROR; - - pStream->state = (struct mz_internal_state *)pDecomp; - - tinfl_init(&pDecomp->m_decomp); - pDecomp->m_dict_ofs = 0; - pDecomp->m_dict_avail = 0; - pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; - pDecomp->m_first_call = 1; - pDecomp->m_has_flushed = 0; - pDecomp->m_window_bits = window_bits; - - return MZ_OK; -} - -int mz_inflateInit(mz_streamp pStream) -{ - return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); -} - -int mz_inflate(mz_streamp pStream, int flush) -{ - inflate_state* pState; - mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; - size_t in_bytes, out_bytes, orig_avail_in; - tinfl_status status; - - if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; - if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; - if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; - - pState = (inflate_state*)pStream->state; - if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; - orig_avail_in = pStream->avail_in; - - first_call = pState->m_first_call; pState->m_first_call = 0; - if (pState->m_last_status < 0) return MZ_DATA_ERROR; - - if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; - pState->m_has_flushed |= (flush == MZ_FINISH); - - if ((flush == MZ_FINISH) && (first_call)) - { - // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. - decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); - pState->m_last_status = status; - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; - pStream->adler = tinfl_get_adler32(&pState->m_decomp); - pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; - - if (status < 0) - return MZ_DATA_ERROR; - else if (status != TINFL_STATUS_DONE) - { - pState->m_last_status = TINFL_STATUS_FAILED; - return MZ_BUF_ERROR; - } - return MZ_STREAM_END; - } - // flush != MZ_FINISH then we must assume there's more input. - if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; - - if (pState->m_dict_avail) - { - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; - pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; - } - - for ( ; ; ) - { - in_bytes = pStream->avail_in; - out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; - - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); - pState->m_last_status = status; - - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); - - pState->m_dict_avail = (mz_uint)out_bytes; - - n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); - memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; - pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - - if (status < 0) - return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). - else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) - return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. - else if (flush == MZ_FINISH) - { - // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. - if (status == TINFL_STATUS_DONE) - return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; - // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. - else if (!pStream->avail_out) - return MZ_BUF_ERROR; - } - else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) - break; - } - - return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; -} - -int mz_inflateEnd(mz_streamp pStream) -{ - if (!pStream) - return MZ_STREAM_ERROR; - if (pStream->state) - { - pStream->zfree(pStream->opaque, pStream->state); - pStream->state = NULL; - } - return MZ_OK; -} - -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ - mz_stream stream; - int status; - memset(&stream, 0, sizeof(stream)); - - // In case mz_ulong is 64-bits (argh I hate longs). - if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; - - stream.next_in = pSource; - stream.avail_in = (mz_uint32)source_len; - stream.next_out = pDest; - stream.avail_out = (mz_uint32)*pDest_len; - - status = mz_inflateInit(&stream); - if (status != MZ_OK) - return status; - - status = mz_inflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { - mz_inflateEnd(&stream); - return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; - } - *pDest_len = stream.total_out; - - return mz_inflateEnd(&stream); -} - -const char *mz_error(int err) -{ - static struct { int m_err; const char *m_pDesc; } s_error_descs[] = - { - { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, - { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } - }; - mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; - return NULL; -} - -#endif //MINIZ_NO_ZLIB_APIS - -// ------------------- Low-level Decompression (completely independent from all compression API's) - -#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) -#define TINFL_MEMSET(p, c, l) memset(p, c, l) - -#define TINFL_CR_BEGIN switch(r->m_state) { case 0: -#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END -#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END -#define TINFL_CR_FINISH } - -// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never -// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. -#define TINFL_GET_BYTE(state_index, c) do { \ - if (pIn_buf_cur >= pIn_buf_end) { \ - for ( ; ; ) { \ - if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ - TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ - if (pIn_buf_cur < pIn_buf_end) { \ - c = *pIn_buf_cur++; \ - break; \ - } \ - } else { \ - c = 0; \ - break; \ - } \ - } \ - } else c = *pIn_buf_cur++; } MZ_MACRO_END - -#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) -#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END -#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END - -// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. -// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a -// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the -// bit buffer contains >=15 bits (deflate's max. Huffman code size). -#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ - do { \ - temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ - if (temp >= 0) { \ - code_len = temp >> 9; \ - if ((code_len) && (num_bits >= code_len)) \ - break; \ - } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ - } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ - } while (num_bits < 15); - -// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read -// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully -// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. -// The slow path is only executed at the very end of the input buffer. -#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ - int temp; mz_uint code_len, c; \ - if (num_bits < 15) { \ - if ((pIn_buf_end - pIn_buf_cur) < 2) { \ - TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ - } else { \ - bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ - } \ - } \ - if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ - code_len = temp >> 9, temp &= 511; \ - else { \ - code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ - } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END - -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) -{ - static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; - static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - static const int s_min_table_sizes[3] = { 257, 1, 4 }; - - tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; - const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; - size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; - - // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). - if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } - - num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; - TINFL_CR_BEGIN - - bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); - counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); - if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); - if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } - } - - do - { - TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; - if (r->m_type == 0) - { - TINFL_SKIP_BITS(5, num_bits & 7); - for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } - if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } - while ((counter) && (num_bits)) - { - TINFL_GET_BITS(51, dist, 8); - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (mz_uint8)dist; - counter--; - } - while (counter) - { - size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } - while (pIn_buf_cur >= pIn_buf_end) - { - if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) - { - TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); - } - else - { - TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); - } - } - n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); - TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; - } - } - else if (r->m_type == 3) - { - TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); - } - else - { - if (r->m_type == 1) - { - mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; - r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); - for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; - } - else - { - for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } - MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } - r->m_table_sizes[2] = 19; - } - for ( ; (int)r->m_type >= 0; r->m_type--) - { - int tree_next, tree_cur; tinfl_huff_table *pTable; - mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); - for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; - used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; - for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } - if ((65536 != total) && (used_syms > 1)) - { - TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); - } - for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) - { - mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; - cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); - if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } - if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } - rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); - for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) - { - tree_cur -= ((rev_code >>= 1) & 1); - if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; - } - tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; - } - if (r->m_type == 2) - { - for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) - { - mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } - if ((dist == 16) && (!counter)) - { - TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); - } - num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; - TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; - } - if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) - { - TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); - } - TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); - } - } - for ( ; ; ) - { - mz_uint8 *pSrc; - for ( ; ; ) - { - if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) - { - TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); - if (counter >= 256) - break; - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (mz_uint8)counter; - } - else - { - int sym2; mz_uint code_len; -#if TINFL_USE_64BIT_BITBUF - if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } -#else - if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - counter = sym2; bit_buf >>= code_len; num_bits -= code_len; - if (counter & 256) - break; - -#if !TINFL_USE_64BIT_BITBUF - if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); - } - bit_buf >>= code_len; num_bits -= code_len; - - pOut_buf_cur[0] = (mz_uint8)counter; - if (sym2 & 256) - { - pOut_buf_cur++; - counter = sym2; - break; - } - pOut_buf_cur[1] = (mz_uint8)sym2; - pOut_buf_cur += 2; - } - } - if ((counter &= 511) == 256) break; - - num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } - - TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); - num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } - - dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; - if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - { - TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); - } - - pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); - - if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) - { - while (counter--) - { - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; - } - continue; - } -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES - else if ((counter >= 9) && (counter <= dist)) - { - const mz_uint8 *pSrc_end = pSrc + (counter & ~7); - do - { - ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; - ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; - pOut_buf_cur += 8; - } while ((pSrc += 8) < pSrc_end); - if ((counter &= 7) < 3) - { - if (counter) - { - pOut_buf_cur[0] = pSrc[0]; - if (counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - continue; - } - } -#endif - do - { - pOut_buf_cur[0] = pSrc[0]; - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur[2] = pSrc[2]; - pOut_buf_cur += 3; pSrc += 3; - } while ((int)(counter -= 3) > 2); - if ((int)counter > 0) - { - pOut_buf_cur[0] = pSrc[0]; - if ((int)counter > 1) - pOut_buf_cur[1] = pSrc[1]; - pOut_buf_cur += counter; - } - } - } - } while (!(r->m_final & 1)); - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } - } - TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); - TINFL_CR_FINISH - -common_exit: - r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; - *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; - if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) - { - const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; - mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; - } - for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; - } - r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; - } - return status; -} - -// Higher level helper functions. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -{ - tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; - *pOut_len = 0; - tinfl_init(&decomp); - for ( ; ; ) - { - size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, - (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - src_buf_ofs += src_buf_size; - *pOut_len += dst_buf_size; - if (status == TINFL_STATUS_DONE) break; - new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; - pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); - if (!pNew_buf) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; - } - pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; - } - return pBuf; -} - -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -{ - tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); - status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; -} - -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - int result = 0; - tinfl_decompressor decomp; - mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; - if (!pDict) - return TINFL_STATUS_FAILED; - tinfl_init(&decomp); - for ( ; ; ) - { - size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, - (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); - in_buf_ofs += in_buf_size; - if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) - break; - if (status != TINFL_STATUS_HAS_MORE_OUTPUT) - { - result = (status == TINFL_STATUS_DONE); - break; - } - dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); - } - MZ_FREE(pDict); - *pIn_buf_size = in_buf_ofs; - return result; -} - -// ------------------- Low-level Compression (independent from all decompression API's) - -// Purposely making these tables static for faster init and thread safety. -static const mz_uint16 s_tdefl_len_sym[256] = { - 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272, - 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276, - 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278, - 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280, - 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281, - 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282, - 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, - 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 }; - -static const mz_uint8 s_tdefl_len_extra[256] = { - 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 }; - -static const mz_uint8 s_tdefl_small_dist_sym[512] = { - 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, - 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, - 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14, - 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, - 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, - 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 }; - -static const mz_uint8 s_tdefl_small_dist_extra[512] = { - 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7 }; - -static const mz_uint8 s_tdefl_large_dist_sym[128] = { - 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26, - 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 }; - -static const mz_uint8 s_tdefl_large_dist_extra[128] = { - 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, - 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, - 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 }; - -// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. -typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; -static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) -{ - mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); - for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } - while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; - for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) - { - const mz_uint32* pHist = &hist[pass << 8]; - mz_uint offsets[256], cur_ofs = 0; - for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } - for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; - { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } - } - return pCur_syms; -} - -// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. -static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) -{ - int root, leaf, next, avbl, used, dpth; - if (n==0) return; else if (n==1) { A[0].m_key = 1; return; } - A[0].m_key += A[1].m_key; root = 0; leaf = 2; - for (next=1; next < n-1; next++) - { - if (leaf>=n || A[root].m_key=n || (root=0; next--) A[next].m_key = A[A[next].m_key].m_key+1; - avbl = 1; used = dpth = 0; root = n-2; next = n-1; - while (avbl>0) - { - while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; } - while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } - avbl = 2*used; dpth++; used = 0; - } -} - -// Limits canonical Huffman code table's max code size. -enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; -static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) -{ - int i; mz_uint32 total = 0; if (code_list_len <= 1) return; - for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; - for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); - while (total != (1UL << max_code_size)) - { - pNum_codes[max_code_size]--; - for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } - total--; - } -} - -static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) -{ - int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); - if (static_table) - { - for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; - } - else - { - tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; - int num_used_syms = 0; - const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; - for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } - - pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); - - for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; - - tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); - - MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); - for (i = 1, j = num_used_syms; i <= code_size_limit; i++) - for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); - } - - next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); - - for (i = 0; i < table_len; i++) - { - mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; - code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); - d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; - } -} - -#define TDEFL_PUT_BITS(b, l) do { \ - mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \ - d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \ - while (d->m_bits_in >= 8) { \ - if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ - *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ - d->m_bit_buffer >>= 8; \ - d->m_bits_in -= 8; \ - } \ -} MZ_MACRO_END - -#define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \ - if (rle_repeat_count < 3) { \ - d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ - while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ - } else { \ - d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ -} rle_repeat_count = 0; } } - -#define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \ - if (rle_z_count < 3) { \ - d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ - } else if (rle_z_count <= 10) { \ - d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ - } else { \ - d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ -} rle_z_count = 0; } } - -static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - -static void tdefl_start_dynamic_block(tdefl_compressor *d) -{ - int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; - mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; - - d->m_huff_count[0][256] = 1; - - tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); - tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); - - for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; - for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; - - memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); - memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); - total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; - - memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); - for (i = 0; i < total_code_sizes_to_pack; i++) - { - mz_uint8 code_size = code_sizes_to_pack[i]; - if (!code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } - } - else - { - TDEFL_RLE_ZERO_CODE_SIZE(); - if (code_size != prev_code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; - } - else if (++rle_repeat_count == 6) - { - TDEFL_RLE_PREV_CODE_SIZE(); - } - } - prev_code_size = code_size; - } - if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } - - tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); - - TDEFL_PUT_BITS(2, 2); - - TDEFL_PUT_BITS(num_lit_codes - 257, 5); - TDEFL_PUT_BITS(num_dist_codes - 1, 5); - - for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; - num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); - for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); - - for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) - { - mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); - TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); - if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); - } -} - -static void tdefl_start_static_block(tdefl_compressor *d) -{ - mz_uint i; - mz_uint8 *p = &d->m_huff_code_sizes[0][0]; - - for (i = 0; i <= 143; ++i) *p++ = 8; - for ( ; i <= 255; ++i) *p++ = 9; - for ( ; i <= 279; ++i) *p++ = 7; - for ( ; i <= 287; ++i) *p++ = 8; - - memset(d->m_huff_code_sizes[1], 5, 32); - - tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); - tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); - - TDEFL_PUT_BITS(1, 2); -} - -static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ - mz_uint flags; - mz_uint8 *pLZ_codes; - mz_uint8 *pOutput_buf = d->m_pOutput_buf; - mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; - mz_uint64 bit_buffer = d->m_bit_buffer; - mz_uint bits_in = d->m_bits_in; - -#define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) - { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - - if (flags & 1) - { - mz_uint s0, s1, n0, n1, sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - // This sequence coaxes MSVC into using cmov's vs. jmp's. - s0 = s_tdefl_small_dist_sym[match_dist & 511]; - n0 = s_tdefl_small_dist_extra[match_dist & 511]; - s1 = s_tdefl_large_dist_sym[match_dist >> 8]; - n1 = s_tdefl_large_dist_extra[match_dist >> 8]; - sym = (match_dist < 512) ? s0 : s1; - num_extra_bits = (match_dist < 512) ? n0 : n1; - - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { - flags >>= 1; - lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - } - - if (pOutput_buf >= d->m_pOutput_buf_end) - return MZ_FALSE; - - *(mz_uint64*)pOutput_buf = bit_buffer; - pOutput_buf += (bits_in >> 3); - bit_buffer >>= (bits_in & ~7); - bits_in &= 7; - } - -#undef TDEFL_PUT_BITS_FAST - - d->m_pOutput_buf = pOutput_buf; - d->m_bits_in = 0; - d->m_bit_buffer = 0; - - while (bits_in) - { - mz_uint32 n = MZ_MIN(bits_in, 16); - TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); - bit_buffer >>= n; - bits_in -= n; - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#else -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ - mz_uint flags; - mz_uint8 *pLZ_codes; - - flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) - { - if (flags == 1) - flags = *pLZ_codes++ | 0x100; - if (flags & 1) - { - mz_uint sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; - - MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); - - if (match_dist < 512) - { - sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; - } - else - { - sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; - } - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { - mz_uint lit = *pLZ_codes++; - MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); - } - } - - TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); - - return (d->m_pOutput_buf < d->m_pOutput_buf_end); -} -#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS - -static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) -{ - if (static_block) - tdefl_start_static_block(d); - else - tdefl_start_dynamic_block(d); - return tdefl_compress_lz_codes(d); -} - -static int tdefl_flush_block(tdefl_compressor *d, int flush) -{ - mz_uint saved_bit_buf, saved_bits_in; - mz_uint8 *pSaved_output_buf; - mz_bool comp_block_succeeded = MZ_FALSE; - int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; - mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; - - d->m_pOutput_buf = pOutput_buf_start; - d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; - - MZ_ASSERT(!d->m_output_flush_remaining); - d->m_output_flush_ofs = 0; - d->m_output_flush_remaining = 0; - - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); - d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); - - if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) - { - TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); - } - - TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); - - pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; - - if (!use_raw_block) - comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); - - // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. - if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && - ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) ) - { - mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - TDEFL_PUT_BITS(0, 2); - if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } - for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) - { - TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); - } - for (i = 0; i < d->m_total_lz_bytes; ++i) - { - TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); - } - } - // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. - else if (!comp_block_succeeded) - { - d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; - tdefl_compress_block(d, MZ_TRUE); - } - - if (flush) - { - if (flush == TDEFL_FINISH) - { - if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } - if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } - } - else - { - mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } - } - } - - MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); - - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; - - if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) - { - if (d->m_pPut_buf_func) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) - return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); - } - else if (pOutput_buf_start == d->m_output_buf) - { - int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); - d->m_out_buf_ofs += bytes_to_copy; - if ((n -= bytes_to_copy) != 0) - { - d->m_output_flush_ofs = bytes_to_copy; - d->m_output_flush_remaining = n; - } - } - else - { - d->m_out_buf_ofs += n; - } - } - - return d->m_output_flush_remaining; -} - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES -#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; - mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; - for ( ; ; ) - { - for ( ; ; ) - { - if (--num_probes_left == 0) return; - #define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; - TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; - } - if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32; - do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && - (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); - if (!probe_len) - { - *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break; - } - else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) - { - *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; - c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); - } - } -} -#else -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; - mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint8 *s = d->m_dict + pos, *p, *q; - mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; - for ( ; ; ) - { - for ( ; ; ) - { - if (--num_probes_left == 0) return; - #define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; - TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; - } - if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; - if (probe_len > match_len) - { - *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; - c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; - } - } -} -#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -static mz_bool tdefl_compress_fast(tdefl_compressor *d) -{ - // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. - mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; - mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; - mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - - while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) - { - const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; - mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); - d->m_src_buf_left -= num_bytes_to_process; - lookahead_size += num_bytes_to_process; - - while (num_bytes_to_process) - { - mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); - memcpy(d->m_dict + dst_pos, d->m_pSrc, n); - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); - d->m_pSrc += n; - dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; - num_bytes_to_process -= n; - } - - dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); - if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; - - while (lookahead_size >= 4) - { - mz_uint cur_match_dist, cur_match_len = 1; - mz_uint8 *pCur_dict = d->m_dict + cur_pos; - mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; - mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; - mz_uint probe_pos = d->m_hash[hash]; - d->m_hash[hash] = (mz_uint16)lookahead_pos; - - if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) - { - const mz_uint16 *p = (const mz_uint16 *)pCur_dict; - const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); - mz_uint32 probe_len = 32; - do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && - (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); - cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); - if (!probe_len) - cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; - - if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U))) - { - cur_match_len = 1; - *pLZ_code_buf++ = (mz_uint8)first_trigram; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - d->m_huff_count[0][(mz_uint8)first_trigram]++; - } - else - { - mz_uint32 s0, s1; - cur_match_len = MZ_MIN(cur_match_len, lookahead_size); - - MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); - - cur_match_dist--; - - pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); - *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; - pLZ_code_buf += 3; - *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); - - s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; - s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; - d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; - - d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; - } - } - else - { - *pLZ_code_buf++ = (mz_uint8)first_trigram; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - d->m_huff_count[0][(mz_uint8)first_trigram]++; - } - - if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } - - total_lz_bytes += cur_match_len; - lookahead_pos += cur_match_len; - dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); - cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; - MZ_ASSERT(lookahead_size >= cur_match_len); - lookahead_size -= cur_match_len; - - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) - { - int n; - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; - } - } - - while (lookahead_size) - { - mz_uint8 lit = d->m_dict[cur_pos]; - - total_lz_bytes++; - *pLZ_code_buf++ = lit; - *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } - - d->m_huff_count[0][lit]++; - - lookahead_pos++; - dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); - cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; - lookahead_size--; - - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) - { - int n; - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; - } - } - } - - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; - return MZ_TRUE; -} -#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - -static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) -{ - d->m_total_lz_bytes++; - *d->m_pLZ_code_buf++ = lit; - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } - d->m_huff_count[0][lit]++; -} - -static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) -{ - mz_uint32 s0, s1; - - MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); - - d->m_total_lz_bytes += match_len; - - d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); - - match_dist -= 1; - d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); - d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; - - *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } - - s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; - d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; - - if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; -} - -static mz_bool tdefl_compress_normal(tdefl_compressor *d) -{ - const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; - tdefl_flush flush = d->m_flush; - - while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) - { - mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; - // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. - if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) - { - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; - mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); - const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; - src_buf_left -= num_bytes_to_process; - d->m_lookahead_size += num_bytes_to_process; - while (pSrc != pSrc_end) - { - mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); - dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; - } - } - else - { - while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - { - mz_uint8 c = *pSrc++; - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - src_buf_left--; - d->m_dict[dst_pos] = c; - if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) - { - mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; - mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); - } - } - } - d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); - if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - break; - - // Simple lazy/greedy parsing state machine. - len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) - { - if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) - { - mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; - cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } - if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; - } - } - else - { - tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); - } - if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) - { - cur_match_dist = cur_match_len = 0; - } - if (d->m_saved_match_len) - { - if (cur_match_len > d->m_saved_match_len) - { - tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); - if (cur_match_len >= 128) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - d->m_saved_match_len = 0; len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; - } - } - else - { - tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); - len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; - } - } - else if (!cur_match_dist) - tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); - else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) - { - tdefl_record_match(d, cur_match_len, cur_match_dist); - len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; - } - // Move the lookahead forward by len_to_move bytes. - d->m_lookahead_pos += len_to_move; - MZ_ASSERT(d->m_lookahead_size >= len_to_move); - d->m_lookahead_size -= len_to_move; - d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); - // Check if it's time to flush the current LZ codes to the internal output buffer. - if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || - ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) ) - { - int n; - d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; - if ((n = tdefl_flush_block(d, 0)) != 0) - return (n < 0) ? MZ_FALSE : MZ_TRUE; - } - } - - d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; - return MZ_TRUE; -} - -static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) -{ - if (d->m_pIn_buf_size) - { - *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; - } - - if (d->m_pOut_buf_size) - { - size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); - d->m_output_flush_ofs += (mz_uint)n; - d->m_output_flush_remaining -= (mz_uint)n; - d->m_out_buf_ofs += n; - - *d->m_pOut_buf_size = d->m_out_buf_ofs; - } - - return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; -} - -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) -{ - if (!d) - { - if (pIn_buf_size) *pIn_buf_size = 0; - if (pOut_buf_size) *pOut_buf_size = 0; - return TDEFL_STATUS_BAD_PARAM; - } - - d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; - d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; - d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; - d->m_out_buf_ofs = 0; - d->m_flush = flush; - - if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || - (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) ) - { - if (pIn_buf_size) *pIn_buf_size = 0; - if (pOut_buf_size) *pOut_buf_size = 0; - return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); - } - d->m_wants_to_finish |= (flush == TDEFL_FINISH); - - if ((d->m_output_flush_remaining) || (d->m_finished)) - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); - -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && - ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && - ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) - { - if (!tdefl_compress_fast(d)) - return d->m_prev_return_status; - } - else -#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - { - if (!tdefl_compress_normal(d)) - return d->m_prev_return_status; - } - - if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) - d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); - - if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) - { - if (tdefl_flush_block(d, flush) < 0) - return d->m_prev_return_status; - d->m_finished = (flush == TDEFL_FINISH); - if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } - } - - return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); -} - -tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) -{ - MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); -} - -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; - d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; - d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); - d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; - d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; - d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; - d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; - d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; - d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; - d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - return TDEFL_STATUS_OKAY; -} - -tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) -{ - return d->m_prev_return_status; -} - -mz_uint32 tdefl_get_adler32(tdefl_compressor *d) -{ - return d->m_adler32; -} - -mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; - pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; - succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); - succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); - MZ_FREE(pComp); return succeeded; -} - -struct tdefl_output_buffer -{ - size_t m_size, m_capacity; - mz_uint8 *m_pBuf; - mz_bool m_expandable; -}; - -static mz_bool tdefl_output_buffer_putter(const void *pBuf, size_t len, void *pUser) -{ - tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; - size_t new_size = p->m_size + len; - if (new_size > p->m_capacity) - { - size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; - do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); - pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; - p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; - } - memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; - return MZ_TRUE; -} - -void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -{ - tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); - if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; - out_buf.m_expandable = MZ_TRUE; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; - *pOut_len = out_buf.m_size; return out_buf.m_pBuf; -} - -size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -{ - tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); - if (!pOut_buf) return 0; - out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; - return out_buf.m_size; -} - -#ifndef MINIZ_NO_ZLIB_APIS -static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; - -// level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) -{ - mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); - if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; - - if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; - else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; - else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; - else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; - else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; - - return comp_flags; -} -#endif //MINIZ_NO_ZLIB_APIS - -#ifdef _MSC_VER -#pragma warning (push) -#pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) -#endif - -// Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at -// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) -{ - tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; - if (!pComp) return NULL; - MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } - // write dummy header - for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); - // compress image data - tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, TDEFL_DEFAULT_MAX_PROBES | TDEFL_WRITE_ZLIB_HEADER); - for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + y * bpl, bpl, TDEFL_NO_FLUSH); } - if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } - // write real header - *pLen_out = out_buf.m_size-41; - { - mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, - 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8, (mz_uint8)"\0\0\04\02\06"[num_chans],0,0,0,0,0,0,0, - (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54}; - c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24); - memcpy(out_buf.m_pBuf, pnghdr, 41); - } - // write footer (IDAT CRC-32, followed by IEND chunk) - if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } - c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24); - // compute final size of file, grab compressed data buffer and return - *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; -} - -#ifdef _MSC_VER -#pragma warning (pop) -#endif - -// ------------------- .ZIP archive reading - -#ifndef MINIZ_NO_ARCHIVE_APIS - -#ifdef MINIZ_NO_STDIO - #define MZ_FILE void * -#else - #include - #include - - #if defined(_MSC_VER) - static FILE *mz_fopen(const char *pFilename, const char *pMode) - { - FILE* pFile = NULL; - fopen_s(&pFile, pFilename, pMode); - return pFile; - } - static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) - { - FILE* pFile = NULL; - if (freopen_s(&pFile, pPath, pMode, pStream)) - return NULL; - return pFile; - } - #else - static FILE *mz_fopen(const char *pFilename, const char *pMode) - { - return fopen(pFilename, pMode); - } - static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) - { - return freopen(pPath, pMode, pStream); - } - #endif // #if defined(_MSC_VER) - - #if defined(_MSC_VER) || defined(__MINGW64__) - #ifndef MINIZ_NO_TIME - #include - #endif - #define MZ_FILE FILE - #define MZ_FOPEN mz_fopen - #define MZ_FCLOSE fclose - #define MZ_FREAD fread - #define MZ_FWRITE fwrite - #define MZ_FTELL64 _ftelli64 - #define MZ_FSEEK64 _fseeki64 - #define MZ_FILE_STAT_STRUCT _stat - #define MZ_FILE_STAT _stat - #define MZ_FFLUSH fflush - #define MZ_FREOPEN mz_freopen - #define MZ_DELETE_FILE remove - #elif defined(__MINGW32__) - #ifndef MINIZ_NO_TIME - #include - #endif - #define MZ_FILE FILE - #define MZ_FOPEN mz_fopen - #define MZ_FCLOSE fclose - #define MZ_FREAD fread - #define MZ_FWRITE fwrite - #define MZ_FTELL64 ftello64 - #define MZ_FSEEK64 fseeko64 - #define MZ_FILE_STAT_STRUCT _stat - #define MZ_FILE_STAT _stat - #define MZ_FFLUSH fflush - #define MZ_FREOPEN mz_freopen - #define MZ_DELETE_FILE remove - #elif defined(__TINYC__) - #ifndef MINIZ_NO_TIME - #include - #endif - #define MZ_FILE FILE - #define MZ_FOPEN mz_fopen - #define MZ_FCLOSE fclose - #define MZ_FREAD fread - #define MZ_FWRITE fwrite - #define MZ_FTELL64 ftell - #define MZ_FSEEK64 fseek - #define MZ_FILE_STAT_STRUCT stat - #define MZ_FILE_STAT stat - #define MZ_FFLUSH fflush - #define MZ_FREOPEN mz_freopen - #define MZ_DELETE_FILE remove - #else - #ifndef MINIZ_NO_TIME - #include - #endif - #define MZ_FILE FILE - #define MZ_FOPEN mz_fopen - #define MZ_FCLOSE fclose - #define MZ_FREAD fread - #define MZ_FWRITE fwrite - #define MZ_FTELL64 ftello - #define MZ_FSEEK64 fseeko - #define MZ_FILE_STAT_STRUCT stat - #define MZ_FILE_STAT stat - #define MZ_FFLUSH fflush - #define MZ_FREOPEN mz_freopen - #define MZ_DELETE_FILE remove - #endif // #ifdef _MSC_VER -#endif // #ifdef MINIZ_NO_STDIO - -#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) - -// Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. -enum -{ - // ZIP archive identifiers and record sizes - MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, - MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, - // Central directory header record offsets - MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, - MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, - MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, - MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, - // Local directory header offsets - MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, - MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, - MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, - // End of central directory offsets - MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, - MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, -}; - -typedef struct -{ - void *m_p; - size_t m_size, m_capacity; - mz_uint m_element_size; -} mz_zip_array; - -struct mz_zip_internal_state_tag -{ - mz_zip_array m_central_dir; - mz_zip_array m_central_dir_offsets; - mz_zip_array m_sorted_central_dir_offsets; - MZ_FILE *m_pFile; - void *m_pMem; - size_t m_mem_size; - size_t m_mem_capacity; -}; - -#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size -#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] - -static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) -{ - pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); - memset(pArray, 0, sizeof(mz_zip_array)); -} - -static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) -{ - void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; - if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } - if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; - pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) -{ - if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) -{ - if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } - pArray->m_size = new_size; - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) -{ - return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); -} - -static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) -{ - size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; - memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); - return MZ_TRUE; -} - -#ifndef MINIZ_NO_TIME -static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) -{ - struct tm tm; - memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; - tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; - tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; - return mktime(&tm); -} - -static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -{ -#ifdef _MSC_VER - struct tm tm_struct; - struct tm *tm = &tm_struct; - errno_t err = localtime_s(tm, &time); - if (err) - { - *pDOS_date = 0; *pDOS_time = 0; - return; - } -#else - struct tm *tm = localtime(&time); -#endif - *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); - *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); -} -#endif - -#ifndef MINIZ_NO_STDIO -static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -{ -#ifdef MINIZ_NO_TIME - (void)pFilename; *pDOS_date = *pDOS_time = 0; -#else - struct MZ_FILE_STAT_STRUCT file_stat; if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; - mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); -#endif // #ifdef MINIZ_NO_TIME - return MZ_TRUE; -} - -static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time) -{ -#ifndef MINIZ_NO_TIME - struct utimbuf t; t.actime = access_time; t.modtime = modified_time; - return !utime(pFilename, &t); -#else - (void)pFilename, (void)access_time, (void)modified_time; - return MZ_TRUE; -#endif // #ifndef MINIZ_NO_TIME -} -#endif - -static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags) -{ - (void)flags; - if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) - return MZ_FALSE; - - if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; - if (!pZip->m_pFree) pZip->m_pFree = def_free_func; - if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; - - pZip->m_zip_mode = MZ_ZIP_MODE_READING; - pZip->m_archive_size = 0; - pZip->m_central_directory_file_ofs = 0; - pZip->m_total_files = 0; - - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) - return MZ_FALSE; - memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - return MZ_TRUE; -} - -static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) -{ - const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; - const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); - mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); - mz_uint8 l = 0, r = 0; - pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - pE = pL + MZ_MIN(l_len, r_len); - while (pL < pE) - { - if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) - break; - pL++; pR++; - } - return (pL == pE) ? (l_len < r_len) : (l < r); -} - -#define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END - -// Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) -static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) -{ - mz_zip_internal_state *pState = pZip->m_pState; - const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; - const mz_zip_array *pCentral_dir = &pState->m_central_dir; - mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - const int size = pZip->m_total_files; - int start = (size - 2) >> 1, end; - while (start >= 0) - { - int child, root = start; - for ( ; ; ) - { - if ((child = (root << 1) + 1) >= size) - break; - child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]))); - if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) - break; - MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; - } - start--; - } - - end = size - 1; - while (end > 0) - { - int child, root = 0; - MZ_SWAP_UINT32(pIndices[end], pIndices[0]); - for ( ; ; ) - { - if ((child = (root << 1) + 1) >= end) - break; - child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])); - if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) - break; - MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; - } - end--; - } -} - -static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags) -{ - mz_uint cdir_size, num_this_disk, cdir_disk_index; - mz_uint64 cdir_ofs; - mz_int64 cur_file_ofs; - const mz_uint8 *p; - mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; - // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. - if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return MZ_FALSE; - // Find the end of central directory record by scanning the file from the end towards the beginning. - cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); - for ( ; ; ) - { - int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) - return MZ_FALSE; - for (i = n - 4; i >= 0; --i) - if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) - break; - if (i >= 0) - { - cur_file_ofs += i; - break; - } - if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) - return MZ_FALSE; - cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); - } - // Read and verify the end of central directory record. - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) - return MZ_FALSE; - if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || - ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) - return MZ_FALSE; - - num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); - cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); - if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) - return MZ_FALSE; - - if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) - return MZ_FALSE; - - cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); - if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) - return MZ_FALSE; - - pZip->m_central_directory_file_ofs = cdir_ofs; - - if (pZip->m_total_files) - { - mz_uint i, n; - // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. - if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || - (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) || - (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) - return MZ_FALSE; - if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) - return MZ_FALSE; - - // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). - p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; - for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) - { - mz_uint total_header_size, comp_size, decomp_size, disk_index; - if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) - return MZ_FALSE; - MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); - MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; - comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) - return MZ_FALSE; - disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); - if ((disk_index != num_this_disk) && (disk_index != 1)) - return MZ_FALSE; - if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) - return MZ_FALSE; - if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) - return MZ_FALSE; - n -= total_header_size; p += total_header_size; - } - } - - if ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) - mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); - - return MZ_TRUE; -} - -mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags) -{ - if ((!pZip) || (!pZip->m_pRead)) - return MZ_FALSE; - if (!mz_zip_reader_init_internal(pZip, flags)) - return MZ_FALSE; - pZip->m_archive_size = size; - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end(pZip); - return MZ_FALSE; - } - return MZ_TRUE; -} - -static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); - memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); - return s; -} - -mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags) -{ - if (!mz_zip_reader_init_internal(pZip, flags)) - return MZ_FALSE; - pZip->m_archive_size = size; - pZip->m_pRead = mz_zip_mem_read_func; - pZip->m_pIO_opaque = pZip; - pZip->m_pState->m_pMem = (void *)pMem; - pZip->m_pState->m_mem_size = size; - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end(pZip); - return MZ_FALSE; - } - return MZ_TRUE; -} - -#ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) - return 0; - return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); -} - -mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) -{ - mz_uint64 file_size; - MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); - if (!pFile) - return MZ_FALSE; - if (MZ_FSEEK64(pFile, 0, SEEK_END)) - return MZ_FALSE; - file_size = MZ_FTELL64(pFile); - if (!mz_zip_reader_init_internal(pZip, flags)) - { - MZ_FCLOSE(pFile); - return MZ_FALSE; - } - pZip->m_pRead = mz_zip_file_read_func; - pZip->m_pIO_opaque = pZip; - pZip->m_pState->m_pFile = pFile; - pZip->m_archive_size = file_size; - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { - mz_zip_reader_end(pZip); - return MZ_FALSE; - } - return MZ_TRUE; -} -#endif // #ifndef MINIZ_NO_STDIO - -mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) -{ - return pZip ? pZip->m_total_files : 0; -} - -static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) -{ - if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return NULL; - return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); -} - -mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) -{ - mz_uint m_bit_flag; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if (!p) - return MZ_FALSE; - m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - return (m_bit_flag & 1); -} - -mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) -{ - mz_uint filename_len, internal_attr, external_attr; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if (!p) - return MZ_FALSE; - - internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); - external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); - if ((!internal_attr) && ((external_attr & 0x10) != 0)) - return MZ_TRUE; - - filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_len) - { - if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') - return MZ_TRUE; - } - - return MZ_FALSE; -} - -mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) -{ - mz_uint n; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if ((!p) || (!pStat)) - return MZ_FALSE; - - // Unpack the central directory record. - pStat->m_file_index = file_index; - pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); - pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); - pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); - pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); - pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); -#ifndef MINIZ_NO_TIME - pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); -#endif - pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); - pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); - pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); - pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); - - // Copy as much of the filename and comment as possible. - n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); - memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; - - n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); - pStat->m_comment_size = n; - memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; - - return MZ_TRUE; -} - -mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) -{ - mz_uint n; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; } - n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_buf_size) - { - n = MZ_MIN(n, filename_buf_size - 1); - memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); - pFilename[n] = '\0'; - } - return n + 1; -} - -static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) -{ - mz_uint i; - if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) - return 0 == memcmp(pA, pB, len); - for (i = 0; i < len; ++i) - if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) - return MZ_FALSE; - return MZ_TRUE; -} - -static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) -{ - const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; - mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); - mz_uint8 l = 0, r = 0; - pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - pE = pL + MZ_MIN(l_len, r_len); - while (pL < pE) - { - if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) - break; - pL++; pR++; - } - return (pL == pE) ? (int)(l_len - r_len) : (l - r); -} - -static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename) -{ - mz_zip_internal_state *pState = pZip->m_pState; - const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; - const mz_zip_array *pCentral_dir = &pState->m_central_dir; - mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - const int size = pZip->m_total_files; - const mz_uint filename_len = (mz_uint)strlen(pFilename); - int l = 0, h = size - 1; - while (l <= h) - { - int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); - if (!comp) - return file_index; - else if (comp < 0) - l = m + 1; - else - h = m - 1; - } - return -1; -} - -int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) -{ - mz_uint file_index; size_t name_len, comment_len; - if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return -1; - if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_p)) - return mz_zip_reader_locate_file_binary_search(pZip, pName); - name_len = strlen(pName); if (name_len > 0xFFFF) return -1; - comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1; - for (file_index = 0; file_index < pZip->m_total_files; file_index++) - { - const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); - mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); - const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; - if (filename_len < name_len) - continue; - if (comment_len) - { - mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); - const char *pFile_comment = pFilename + filename_len + file_extra_len; - if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags))) - continue; - } - if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) - { - int ofs = filename_len - 1; - do - { - if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) - break; - } while (--ofs >= 0); - ofs++; - pFilename += ofs; filename_len -= ofs; - } - if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) - return file_index; - } - return -1; -} - -mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -{ - int status = TINFL_STATUS_DONE; - mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; - mz_zip_archive_file_stat file_stat; - void *pRead_buf; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - tinfl_decompressor inflator; - - if ((buf_size) && (!pBuf)) - return MZ_FALSE; - - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; - - if (!file_stat.m_comp_size) - return MZ_TRUE; - - // Encryption and patch files are not supported. - if (file_stat.m_bit_flag & (1 | 32)) - return MZ_FALSE; - - // This function only supports stored and deflate. - if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) - return MZ_FALSE; - - // Ensure supplied output buffer is large enough. - needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; - if (buf_size < needed_size) - return MZ_FALSE; - - // Read and parse the local directory entry. - cur_file_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return MZ_FALSE; - - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) - return MZ_FALSE; - - if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) - { - // The file is stored or the caller has requested the compressed data. - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) - return MZ_FALSE; - return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); - } - - // Decompress the file either directly from memory or from a file input buffer. - tinfl_init(&inflator); - - if (pZip->m_pState->m_pMem) - { - // Read directly from the archive in memory. - pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; - read_buf_size = read_buf_avail = file_stat.m_comp_size; - comp_remaining = 0; - } - else if (pUser_read_buf) - { - // Use a user provided read buffer. - if (!user_read_buf_size) - return MZ_FALSE; - pRead_buf = (mz_uint8 *)pUser_read_buf; - read_buf_size = user_read_buf_size; - read_buf_avail = 0; - comp_remaining = file_stat.m_uncomp_size; - } - else - { - // Temporarily allocate a read buffer. - read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); -#ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -#else - if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) -#endif - return MZ_FALSE; - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) - return MZ_FALSE; - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } - - do - { - size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); - if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } - cur_file_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - read_buf_ofs = 0; - } - in_buf_size = (size_t)read_buf_avail; - status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); - read_buf_avail -= in_buf_size; - read_buf_ofs += in_buf_size; - out_buf_ofs += out_buf_size; - } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); - - if (status == TINFL_STATUS_DONE) - { - // Make sure the entire file was decompressed, and check its CRC. - if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) - status = TINFL_STATUS_FAILED; - } - - if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - - return status == TINFL_STATUS_DONE; -} - -mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -{ - int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); - if (file_index < 0) - return MZ_FALSE; - return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); -} - -mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) -{ - return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); -} - -mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) -{ - return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); -} - -void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) -{ - mz_uint64 comp_size, uncomp_size, alloc_size; - const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - void *pBuf; - - if (pSize) - *pSize = 0; - if (!p) - return NULL; - - comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - - alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; -#ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -#else - if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) -#endif - return NULL; - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) - return NULL; - - if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return NULL; - } - - if (pSize) *pSize = (size_t)alloc_size; - return pBuf; -} - -void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) -{ - int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); - if (file_index < 0) - { - if (pSize) *pSize = 0; - return MZ_FALSE; - } - return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); -} - -mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -{ - int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT; - mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; - mz_zip_archive_file_stat file_stat; - void *pRead_buf = NULL; void *pWrite_buf = NULL; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; - - if (!file_stat.m_comp_size) - return MZ_TRUE; - - // Encryption and patch files are not supported. - if (file_stat.m_bit_flag & (1 | 32)) - return MZ_FALSE; - - // This function only supports stored and deflate. - if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) - return MZ_FALSE; - - // Read and parse the local directory entry. - cur_file_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return MZ_FALSE; - - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) - return MZ_FALSE; - - // Decompress the file either directly from memory or from a file input buffer. - if (pZip->m_pState->m_pMem) - { - pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; - read_buf_size = read_buf_avail = file_stat.m_comp_size; - comp_remaining = 0; - } - else - { - read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) - return MZ_FALSE; - read_buf_avail = 0; - comp_remaining = file_stat.m_comp_size; - } - - if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) - { - // The file is stored or the caller has requested the compressed data. - if (pZip->m_pState->m_pMem) - { -#ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) -#else - if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) -#endif - return MZ_FALSE; - if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) - status = TINFL_STATUS_FAILED; - else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); - cur_file_ofs += file_stat.m_comp_size; - out_buf_ofs += file_stat.m_comp_size; - comp_remaining = 0; - } - else - { - while (comp_remaining) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } - - if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); - - if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } - cur_file_ofs += read_buf_avail; - out_buf_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - } - } - } - else - { - tinfl_decompressor inflator; - tinfl_init(&inflator); - - if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) - status = TINFL_STATUS_FAILED; - else - { - do - { - mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) - { - read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { - status = TINFL_STATUS_FAILED; - break; - } - cur_file_ofs += read_buf_avail; - comp_remaining -= read_buf_avail; - read_buf_ofs = 0; - } - - in_buf_size = (size_t)read_buf_avail; - status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); - read_buf_avail -= in_buf_size; - read_buf_ofs += in_buf_size; - - if (out_buf_size) - { - if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) - { - status = TINFL_STATUS_FAILED; - break; - } - file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); - if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) - { - status = TINFL_STATUS_FAILED; - break; - } - } - } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); - } - } - - if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) - { - // Make sure the entire file was decompressed, and check its CRC. - if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32)) - status = TINFL_STATUS_FAILED; - } - - if (!pZip->m_pState->m_pMem) - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - if (pWrite_buf) - pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); - - return status == TINFL_STATUS_DONE; -} - -mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -{ - int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); - if (file_index < 0) - return MZ_FALSE; - return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); -} - -#ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) -{ - (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque); -} - -mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) -{ - mz_bool status; - mz_zip_archive_file_stat file_stat; - MZ_FILE *pFile; - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; - pFile = MZ_FOPEN(pDst_filename, "wb"); - if (!pFile) - return MZ_FALSE; - status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); - if (MZ_FCLOSE(pFile) == EOF) - return MZ_FALSE; -#ifndef MINIZ_NO_TIME - if (status) - mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); -#endif - return status; -} -#endif // #ifndef MINIZ_NO_STDIO - -mz_bool mz_zip_reader_end(mz_zip_archive *pZip) -{ - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return MZ_FALSE; - - if (pZip->m_pState) - { - mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; - mz_zip_array_clear(pZip, &pState->m_central_dir); - mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); - mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -#ifndef MINIZ_NO_STDIO - if (pState->m_pFile) - { - MZ_FCLOSE(pState->m_pFile); - pState->m_pFile = NULL; - } -#endif // #ifndef MINIZ_NO_STDIO - - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - } - pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - - return MZ_TRUE; -} - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) -{ - int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); - if (file_index < 0) - return MZ_FALSE; - return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); -} -#endif - -// ------------------- .ZIP archive writing - -#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } -static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } -#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) -#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) - -mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) -{ - if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) - return MZ_FALSE; - - if (pZip->m_file_offset_alignment) - { - // Ensure user specified file offset alignment is a power of 2. - if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) - return MZ_FALSE; - } - - if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; - if (!pZip->m_pFree) pZip->m_pFree = def_free_func; - if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; - - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - pZip->m_archive_size = existing_size; - pZip->m_central_directory_file_ofs = 0; - pZip->m_total_files = 0; - - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) - return MZ_FALSE; - memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); - return MZ_TRUE; -} - -static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_zip_internal_state *pState = pZip->m_pState; - mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); -#ifdef _MSC_VER - if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) -#else - if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) -#endif - return 0; - if (new_size > pState->m_mem_capacity) - { - void *pNew_block; - size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; - if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) - return 0; - pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; - } - memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); - pState->m_mem_size = (size_t)new_size; - return n; -} - -mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) -{ - pZip->m_pWrite = mz_zip_heap_write_func; - pZip->m_pIO_opaque = pZip; - if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) - return MZ_FALSE; - if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) - { - if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) - { - mz_zip_writer_end(pZip); - return MZ_FALSE; - } - pZip->m_pState->m_mem_capacity = initial_allocation_size; - } - return MZ_TRUE; -} - -#ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -{ - mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) - return 0; - return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); -} - -mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) -{ - MZ_FILE *pFile; - pZip->m_pWrite = mz_zip_file_write_func; - pZip->m_pIO_opaque = pZip; - if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) - return MZ_FALSE; - if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) - { - mz_zip_writer_end(pZip); - return MZ_FALSE; - } - pZip->m_pState->m_pFile = pFile; - if (size_to_reserve_at_beginning) - { - mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf); - do - { - size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) - { - mz_zip_writer_end(pZip); - return MZ_FALSE; - } - cur_ofs += n; size_to_reserve_at_beginning -= n; - } while (size_to_reserve_at_beginning); - } - return MZ_TRUE; -} -#endif // #ifndef MINIZ_NO_STDIO - -mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) -{ - mz_zip_internal_state *pState; - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return MZ_FALSE; - // No sense in trying to write to an archive that's already at the support max size - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) - return MZ_FALSE; - - pState = pZip->m_pState; - - if (pState->m_pFile) - { -#ifdef MINIZ_NO_STDIO - pFilename; return MZ_FALSE; -#else - // Archive is being read from stdio - try to reopen as writable. - if (pZip->m_pIO_opaque != pZip) - return MZ_FALSE; - if (!pFilename) - return MZ_FALSE; - pZip->m_pWrite = mz_zip_file_write_func; - if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) - { - // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. - mz_zip_reader_end(pZip); - return MZ_FALSE; - } -#endif // #ifdef MINIZ_NO_STDIO - } - else if (pState->m_pMem) - { - // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. - if (pZip->m_pIO_opaque != pZip) - return MZ_FALSE; - pState->m_mem_capacity = pState->m_mem_size; - pZip->m_pWrite = mz_zip_heap_write_func; - } - // Archive is being read via a user provided read function - make sure the user has specified a write function too. - else if (!pZip->m_pWrite) - return MZ_FALSE; - - // Start writing new files at the archive's current central directory location. - pZip->m_archive_size = pZip->m_central_directory_file_ofs; - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - pZip->m_central_directory_file_ofs = 0; - - return MZ_TRUE; -} - -mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) -{ - return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); -} - -typedef struct -{ - mz_zip_archive *m_pZip; - mz_uint64 m_cur_archive_file_ofs; - mz_uint64 m_comp_size; -} mz_zip_writer_add_state; - -static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser) -{ - mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; - if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) - return MZ_FALSE; - pState->m_cur_archive_file_ofs += len; - pState->m_comp_size += len; - return MZ_TRUE; -} - -static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) -{ - (void)pZip; - memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); - MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); - return MZ_TRUE; -} - -static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) -{ - (void)pZip; - memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); - MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); - MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); - return MZ_TRUE; -} - -static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) -{ - mz_zip_internal_state *pState = pZip->m_pState; - mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; - size_t orig_central_dir_size = pState->m_central_dir.m_size; - mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - - // No zip64 support yet - if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF)) - return MZ_FALSE; - - if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) - return MZ_FALSE; - - if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) - { - // Try to push the central directory array back into its original state. - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return MZ_FALSE; - } - - return MZ_TRUE; -} - -static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) -{ - // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. - if (*pArchive_name == '/') - return MZ_FALSE; - while (*pArchive_name) - { - if ((*pArchive_name == '\\') || (*pArchive_name == ':')) - return MZ_FALSE; - pArchive_name++; - } - return MZ_TRUE; -} - -static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) -{ - mz_uint32 n; - if (!pZip->m_file_offset_alignment) - return 0; - n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); - return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); -} - -static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) -{ - char buf[4096]; - memset(buf, 0, MZ_MIN(sizeof(buf), n)); - while (n) - { - mz_uint32 s = MZ_MIN(sizeof(buf), n); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) - return MZ_FALSE; - cur_file_ofs += s; n -= s; - } - return MZ_TRUE; -} - -mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) -{ - mz_uint16 method = 0, dos_time = 0, dos_date = 0; - mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; - mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; - size_t archive_name_size; - mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - tdefl_compressor *pComp = NULL; - mz_bool store_data_uncompressed; - mz_zip_internal_state *pState; - - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - level = level_and_flags & 0xF; - store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) - return MZ_FALSE; - - pState = pZip->m_pState; - - if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) - return MZ_FALSE; - // No zip64 support yet - if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) - return MZ_FALSE; - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - return MZ_FALSE; - -#ifndef MINIZ_NO_TIME - { - time_t cur_time; time(&cur_time); - mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); - } -#endif // #ifndef MINIZ_NO_TIME - - archive_name_size = strlen(pArchive_name); - if (archive_name_size > 0xFFFF) - return MZ_FALSE; - - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - - // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) - return MZ_FALSE; - - if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) - { - // Set DOS Subdirectory attribute bit. - ext_attributes |= 0x10; - // Subdirectories cannot contain data. - if ((buf_size) || (uncomp_size)) - return MZ_FALSE; - } - - // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) - if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) - return MZ_FALSE; - - if ((!store_data_uncompressed) && (buf_size)) - { - if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) - return MZ_FALSE; - } - - if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } - local_dir_header_ofs += num_alignment_padding_bytes; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); - - MZ_CLEAR_OBJ(local_dir_header); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } - cur_archive_file_ofs += archive_name_size; - - if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - { - uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size); - uncomp_size = buf_size; - if (uncomp_size <= 3) - { - level = 0; - store_data_uncompressed = MZ_TRUE; - } - } - - if (store_data_uncompressed) - { - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } - - cur_archive_file_ofs += buf_size; - comp_size = buf_size; - - if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) - method = MZ_DEFLATED; - } - else if (buf_size) - { - mz_zip_writer_add_state state; - - state.m_pZip = pZip; - state.m_cur_archive_file_ofs = cur_archive_file_ofs; - state.m_comp_size = 0; - - if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || - (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - return MZ_FALSE; - } - - comp_size = state.m_comp_size; - cur_archive_file_ofs = state.m_cur_archive_file_ofs; - - method = MZ_DEFLATED; - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - pComp = NULL; - - // no zip64 support yet - if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) - return MZ_FALSE; - - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) - return MZ_FALSE; - - if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return MZ_FALSE; - - if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) - return MZ_FALSE; - - pZip->m_total_files++; - pZip->m_archive_size = cur_archive_file_ofs; - - return MZ_TRUE; -} - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -{ - mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; - mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; - mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; - size_t archive_name_size; - mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - MZ_FILE *pSrc_file = NULL; - - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - level = level_and_flags & 0xF; - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) - return MZ_FALSE; - if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) - return MZ_FALSE; - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - return MZ_FALSE; - - archive_name_size = strlen(pArchive_name); - if (archive_name_size > 0xFFFF) - return MZ_FALSE; - - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - - // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) - return MZ_FALSE; - - if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) - return MZ_FALSE; - - pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); - if (!pSrc_file) - return MZ_FALSE; - MZ_FSEEK64(pSrc_file, 0, SEEK_END); - uncomp_size = MZ_FTELL64(pSrc_file); - MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - - if (uncomp_size > 0xFFFFFFFF) - { - // No zip64 support yet - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - if (uncomp_size <= 3) - level = 0; - - if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) - return MZ_FALSE; - local_dir_header_ofs += num_alignment_padding_bytes; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); - - MZ_CLEAR_OBJ(local_dir_header); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - cur_archive_file_ofs += archive_name_size; - - if (uncomp_size) - { - mz_uint64 uncomp_remaining = uncomp_size; - void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); - if (!pRead_buf) - { - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - - if (!level) - { - while (uncomp_remaining) - { - mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); - if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); - uncomp_remaining -= n; - cur_archive_file_ofs += n; - } - comp_size = uncomp_size; - } - else - { - mz_bool result = MZ_FALSE; - mz_zip_writer_add_state state; - tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); - if (!pComp) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - - state.m_pZip = pZip; - state.m_cur_archive_file_ofs = cur_archive_file_ofs; - state.m_comp_size = 0; - - if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - - for ( ; ; ) - { - size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); - tdefl_status status; - - if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) - break; - - uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); - uncomp_remaining -= in_buf_size; - - status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); - if (status == TDEFL_STATUS_DONE) - { - result = MZ_TRUE; - break; - } - else if (status != TDEFL_STATUS_OKAY) - break; - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - - if (!result) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - MZ_FCLOSE(pSrc_file); - return MZ_FALSE; - } - - comp_size = state.m_comp_size; - cur_archive_file_ofs = state.m_cur_archive_file_ofs; - - method = MZ_DEFLATED; - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); - } - - MZ_FCLOSE(pSrc_file); pSrc_file = NULL; - - // no zip64 support yet - if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) - return MZ_FALSE; - - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) - return MZ_FALSE; - - if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) - return MZ_FALSE; - - if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) - return MZ_FALSE; - - pZip->m_total_files++; - pZip->m_archive_size = cur_archive_file_ofs; - - return MZ_TRUE; -} -#endif // #ifndef MINIZ_NO_STDIO - -mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index) -{ - mz_uint n, bit_flags, num_alignment_padding_bytes; - mz_uint64 comp_bytes_remaining, local_dir_header_ofs; - mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; - mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; - size_t orig_central_dir_size; - mz_zip_internal_state *pState; - void *pBuf; const mz_uint8 *pSrc_central_header; - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) - return MZ_FALSE; - if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) - return MZ_FALSE; - pState = pZip->m_pState; - - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); - - // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) - return MZ_FALSE; - - cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); - cur_dst_file_ofs = pZip->m_archive_size; - - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) - return MZ_FALSE; - cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - - if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) - return MZ_FALSE; - cur_dst_file_ofs += num_alignment_padding_bytes; - local_dir_header_ofs = cur_dst_file_ofs; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) - return MZ_FALSE; - cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - - n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining))))) - return MZ_FALSE; - - while (comp_bytes_remaining) - { - n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } - cur_src_file_ofs += n; - - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } - cur_dst_file_ofs += n; - - comp_bytes_remaining -= n; - } - - bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); - if (bit_flags & 8) - { - // Copy data descriptor - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } - - n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - return MZ_FALSE; - } - - cur_src_file_ofs += n; - cur_dst_file_ofs += n; - } - pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); - - // no zip64 support yet - if (cur_dst_file_ofs > 0xFFFFFFFF) - return MZ_FALSE; - - orig_central_dir_size = pState->m_central_dir.m_size; - - memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) - return MZ_FALSE; - - n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) - { - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return MZ_FALSE; - } - - if (pState->m_central_dir.m_size > 0xFFFFFFFF) - return MZ_FALSE; - n = (mz_uint32)pState->m_central_dir.m_size; - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) - { - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); - return MZ_FALSE; - } - - pZip->m_total_files++; - pZip->m_archive_size = cur_dst_file_ofs; - - return MZ_TRUE; -} - -mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) -{ - mz_zip_internal_state *pState; - mz_uint64 central_dir_ofs, central_dir_size; - mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) - return MZ_FALSE; - - pState = pZip->m_pState; - - // no zip64 support yet - if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) - return MZ_FALSE; - - central_dir_ofs = 0; - central_dir_size = 0; - if (pZip->m_total_files) - { - // Write central directory - central_dir_ofs = pZip->m_archive_size; - central_dir_size = pState->m_central_dir.m_size; - pZip->m_central_directory_file_ofs = central_dir_ofs; - if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) - return MZ_FALSE; - pZip->m_archive_size += central_dir_size; - } - - // Write end of central directory record - MZ_CLEAR_OBJ(hdr); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); - MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); - - if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr)) - return MZ_FALSE; -#ifndef MINIZ_NO_STDIO - if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) - return MZ_FALSE; -#endif // #ifndef MINIZ_NO_STDIO - - pZip->m_archive_size += sizeof(hdr); - - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; - return MZ_TRUE; -} - -mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize) -{ - if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) - return MZ_FALSE; - if (pZip->m_pWrite != mz_zip_heap_write_func) - return MZ_FALSE; - if (!mz_zip_writer_finalize_archive(pZip)) - return MZ_FALSE; - - *pBuf = pZip->m_pState->m_pMem; - *pSize = pZip->m_pState->m_mem_size; - pZip->m_pState->m_pMem = NULL; - pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; - return MZ_TRUE; -} - -mz_bool mz_zip_writer_end(mz_zip_archive *pZip) -{ - mz_zip_internal_state *pState; - mz_bool status = MZ_TRUE; - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) - return MZ_FALSE; - - pState = pZip->m_pState; - pZip->m_pState = NULL; - mz_zip_array_clear(pZip, &pState->m_central_dir); - mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); - mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); - -#ifndef MINIZ_NO_STDIO - if (pState->m_pFile) - { - MZ_FCLOSE(pState->m_pFile); - pState->m_pFile = NULL; - } -#endif // #ifndef MINIZ_NO_STDIO - - if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) - { - pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); - pState->m_pMem = NULL; - } - - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; - return status; -} - -#ifndef MINIZ_NO_STDIO -mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -{ - mz_bool status, created_new_archive = MZ_FALSE; - mz_zip_archive zip_archive; - struct MZ_FILE_STAT_STRUCT file_stat; - MZ_CLEAR_OBJ(zip_archive); - if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) - return MZ_FALSE; - if (!mz_zip_writer_validate_archive_name(pArchive_name)) - return MZ_FALSE; - if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) - { - // Create a new archive. - if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) - return MZ_FALSE; - created_new_archive = MZ_TRUE; - } - else - { - // Append to an existing archive. - if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) - return MZ_FALSE; - if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) - { - mz_zip_reader_end(&zip_archive); - return MZ_FALSE; - } - } - status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); - // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) - if (!mz_zip_writer_finalize_archive(&zip_archive)) - status = MZ_FALSE; - if (!mz_zip_writer_end(&zip_archive)) - status = MZ_FALSE; - if ((!status) && (created_new_archive)) - { - // It's a new archive and something went wrong, so just delete it. - int ignoredStatus = MZ_DELETE_FILE(pZip_filename); - (void)ignoredStatus; - } - return status; -} - -void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) -{ - int file_index; - mz_zip_archive zip_archive; - void *p = NULL; - - if (pSize) - *pSize = 0; - - if ((!pZip_filename) || (!pArchive_name)) - return NULL; - - MZ_CLEAR_OBJ(zip_archive); - if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) - return NULL; - - if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0) - p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); - - mz_zip_reader_end(&zip_archive); - return p; -} - -#endif // #ifndef MINIZ_NO_STDIO - -#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS - -#endif // #ifndef MINIZ_NO_ARCHIVE_APIS - -#ifdef __cplusplus -} -#endif - -#endif // MINIZ_HEADER_FILE_ONLY - -/* - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - 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 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. - - For more information, please refer to -*/ diff -Nru mapnik-3.0.9+ds/src/miniz_png.cpp mapnik-3.0.13+ds/src/miniz_png.cpp --- mapnik-3.0.9+ds/src/miniz_png.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/miniz_png.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,375 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2015 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 - * - *****************************************************************************/ - -// mapnik -#include -#include -#include -#include - -// miniz -#define MINIZ_NO_ARCHIVE_APIS -#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES - -#pragma GCC diagnostic push -#include -extern "C" { -#include "miniz.c" -} -#pragma GCC diagnostic pop - -// zlib -#include - -// stl -#include -#include -#include - -namespace mapnik { namespace MiniZ { - -PNGWriter::PNGWriter(int level, int strategy) -{ - buffer = nullptr; - compressor = nullptr; - - if (level == -1) - { - level = MZ_DEFAULT_LEVEL; // 6 - } - else if (level < 0 || level > 10) - { - throw std::runtime_error("compression level must be between 0 and 10"); - } - mz_uint flags = s_tdefl_num_probes[level] | TDEFL_WRITE_ZLIB_HEADER; - if (level <= 3) - { - flags |= TDEFL_GREEDY_PARSING_FLAG; - } - if (strategy == Z_FILTERED) flags |= TDEFL_FILTER_MATCHES; - else if (strategy == Z_HUFFMAN_ONLY) flags &= ~TDEFL_MAX_PROBES_MASK; - else if (strategy == Z_RLE) flags |= TDEFL_RLE_MATCHES; - else if (strategy == Z_FIXED) flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; - - buffer = (tdefl_output_buffer *)MZ_MALLOC(sizeof(tdefl_output_buffer)); - if (buffer == nullptr) - { - throw std::bad_alloc(); - } - - buffer->m_pBuf = nullptr; - buffer->m_capacity = 8192; - buffer->m_expandable = MZ_TRUE; - buffer->m_pBuf = (mz_uint8 *)MZ_MALLOC(buffer->m_capacity); - if (buffer->m_pBuf == nullptr) - { - throw std::bad_alloc(); - } - - compressor = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); - if (compressor == nullptr) - { - throw std::bad_alloc(); - } - - // Reset output buffer. - buffer->m_size = 0; - tdefl_status tdstatus = tdefl_init(compressor, tdefl_output_buffer_putter, buffer, flags); - if (tdstatus != TDEFL_STATUS_OKAY) - { - throw std::runtime_error("tdefl_init failed"); - } - - // Write preamble. - mz_bool status = tdefl_output_buffer_putter(preamble, 8, buffer); - if (status != MZ_TRUE) - { - throw std::bad_alloc(); - } -} - -PNGWriter::~PNGWriter() -{ - if (compressor) - { - MZ_FREE(compressor); - } - if (buffer) - { - if (buffer->m_pBuf) - { - MZ_FREE(buffer->m_pBuf); - } - MZ_FREE(buffer); - } -} - -inline void PNGWriter::writeUInt32BE(mz_uint8 *target, mz_uint32 value) -{ - target[0] = (value >> 24) & 0xFF; - target[1] = (value >> 16) & 0xFF; - target[2] = (value >> 8) & 0xFF; - target[3] = value & 0xFF; -} - -size_t PNGWriter::startChunk(const mz_uint8 header[], size_t length) -{ - size_t start = buffer->m_size; - mz_bool status = tdefl_output_buffer_putter(header, length, buffer); - if (status != MZ_TRUE) - { - throw std::bad_alloc(); - } - return start; -} - -void PNGWriter::finishChunk(size_t start) -{ - // Write chunk length at the beginning of the chunk. - size_t payloadLength = buffer->m_size - start - 4 - 4; - writeUInt32BE(buffer->m_pBuf + start, static_cast(payloadLength)); - // Write CRC32 checksum. Don't include the 4-byte length, but /do/ include - // the 4-byte chunk name. - mz_uint32 crc = mz_crc32(MZ_CRC32_INIT, buffer->m_pBuf + start + 4, payloadLength + 4); - mz_uint8 checksum[] = { static_cast(crc >> 24), - static_cast(crc >> 16), - static_cast(crc >> 8), - static_cast(crc) }; - mz_bool status = tdefl_output_buffer_putter(checksum, 4, buffer); - if (status != MZ_TRUE) - { - throw std::bad_alloc(); - } -} - -void PNGWriter::writeIHDR(mz_uint32 width, mz_uint32 height, mz_uint8 pixel_depth) -{ - // Write IHDR chunk. - size_t IHDR = startChunk(IHDR_tpl, 21); - writeUInt32BE(buffer->m_pBuf + IHDR + 8, width); - writeUInt32BE(buffer->m_pBuf + IHDR + 12, height); - - if (pixel_depth == 32) - { - // Alpha full color image. - buffer->m_pBuf[IHDR + 16] = 8; // bit depth - buffer->m_pBuf[IHDR + 17] = 6; // color type (6 == true color with alpha) - } - else if (pixel_depth == 24) - { - // Full color image. - buffer->m_pBuf[IHDR + 16] = 8; // bit depth - buffer->m_pBuf[IHDR + 17] = 2; // color type (2 == true color without alpha) - } - else - { - // Paletted image. - buffer->m_pBuf[IHDR + 16] = pixel_depth; // bit depth - buffer->m_pBuf[IHDR + 17] = 3; // color type (3 == indexed color) - } - - buffer->m_pBuf[IHDR + 18] = 0; // compression method - buffer->m_pBuf[IHDR + 19] = 0; // filter method - buffer->m_pBuf[IHDR + 20] = 0; // interlace method - finishChunk(IHDR); -} - -void PNGWriter::writePLTE(std::vector const& palette) -{ - // Write PLTE chunk. - size_t PLTE = startChunk(PLTE_tpl, 8); - const mz_uint8 *colors = reinterpret_cast(&palette[0]); - mz_bool status = tdefl_output_buffer_putter(colors, palette.size() * 3, buffer); - if (status != MZ_TRUE) - { - throw std::bad_alloc(); - } - finishChunk(PLTE); -} - -void PNGWriter::writetRNS(std::vector const& alpha) -{ - if (alpha.size() == 0) - { - return; - } - - std::vector transparency(alpha.size()); - unsigned char transparencySize = 0; // Stores position of biggest to nonopaque value. - for(unsigned i = 0; i < alpha.size(); i++) - { - transparency[i] = alpha[i]; - if (alpha[i] < 255) - { - transparencySize = i + 1; - } - } - if (transparencySize > 0) - { - // Write tRNS chunk. - size_t tRNS = startChunk(tRNS_tpl, 8); - mz_bool status = tdefl_output_buffer_putter(&transparency[0], transparencySize, buffer); - if (status != MZ_TRUE) - { - throw std::bad_alloc(); - } - finishChunk(tRNS); - } -} - -template -void PNGWriter::writeIDAT(T const& image) -{ - // Write IDAT chunk. - size_t IDAT = startChunk(IDAT_tpl, 8); - mz_uint8 filter_type = 0; - tdefl_status status; - - int bytes_per_pixel = sizeof(typename T::pixel_type); - int stride = image.width() * bytes_per_pixel; - - for (unsigned int y = 0; y < image.height(); y++) - { - // Write filter_type - status = tdefl_compress_buffer(compressor, &filter_type, 1, TDEFL_NO_FLUSH); - if (status != TDEFL_STATUS_OKAY) - { - throw std::runtime_error("failed to compress image"); - } - - // Write scanline - status = tdefl_compress_buffer(compressor, (mz_uint8 *)image.get_row(y), stride, TDEFL_NO_FLUSH); - if (status != TDEFL_STATUS_OKAY) - { - throw std::runtime_error("failed to compress image"); - } - } - - status = tdefl_compress_buffer(compressor, nullptr, 0, TDEFL_FINISH); - if (status != TDEFL_STATUS_DONE) - { - throw std::runtime_error("failed to compress image"); - } - - finishChunk(IDAT); -} - -template -void PNGWriter::writeIDATStripAlpha(T const& image) { - // Write IDAT chunk. - size_t IDAT = startChunk(IDAT_tpl, 8); - mz_uint8 filter_type = 0; - tdefl_status status; - - size_t stride = image.width() * 3; - size_t i, j; - mz_uint8 *scanline = (mz_uint8 *)MZ_MALLOC(stride); - - for (unsigned int y = 0; y < image.height(); y++) { - // Write filter_type - status = tdefl_compress_buffer(compressor, &filter_type, 1, TDEFL_NO_FLUSH); - if (status != TDEFL_STATUS_OKAY) - { - MZ_FREE(scanline); - throw std::runtime_error("failed to compress image"); - } - - // Strip alpha bytes from scanline - mz_uint8 *row = (mz_uint8 *)image.get_row(y); - for (i = 0, j = 0; j < stride; i += 4, j += 3) { - scanline[j] = row[i]; - scanline[j+1] = row[i+1]; - scanline[j+2] = row[i+2]; - } - - // Write scanline - status = tdefl_compress_buffer(compressor, scanline, stride, TDEFL_NO_FLUSH); - if (status != TDEFL_STATUS_OKAY) { - MZ_FREE(scanline); - throw std::runtime_error("failed to compress image"); - } - } - - MZ_FREE(scanline); - - status = tdefl_compress_buffer(compressor, nullptr, 0, TDEFL_FINISH); - if (status != TDEFL_STATUS_DONE) throw std::runtime_error("failed to compress image"); - - finishChunk(IDAT); -} - -void PNGWriter::writeIEND() -{ - // Write IEND chunk. - size_t IEND = startChunk(IEND_tpl, 8); - finishChunk(IEND); -} - -void PNGWriter::toStream(std::ostream& stream) -{ - stream.write((char *)buffer->m_pBuf, buffer->m_size); -} - -const mz_uint8 PNGWriter::preamble[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a -}; - -const mz_uint8 PNGWriter::IHDR_tpl[] = { - 0x00, 0x00, 0x00, 0x0D, // chunk length - 'I', 'H', 'D', 'R', // "IHDR" - 0x00, 0x00, 0x00, 0x00, // image width (4 bytes) - 0x00, 0x00, 0x00, 0x00, // image height (4 bytes) - 0x00, // bit depth (1 byte) - 0x00, // color type (1 byte) - 0x00, // compression method (1 byte), has to be 0 - 0x00, // filter method (1 byte) - 0x00 // interlace method (1 byte) -}; - -const mz_uint8 PNGWriter::PLTE_tpl[] = { - 0x00, 0x00, 0x00, 0x00, // chunk length - 'P', 'L', 'T', 'E' // "IDAT" -}; - -const mz_uint8 PNGWriter::tRNS_tpl[] = { - 0x00, 0x00, 0x00, 0x00, // chunk length - 't', 'R', 'N', 'S' // "IDAT" -}; - -const mz_uint8 PNGWriter::IDAT_tpl[] = { - 0x00, 0x00, 0x00, 0x00, // chunk length - 'I', 'D', 'A', 'T' // "IDAT" -}; - -const mz_uint8 PNGWriter::IEND_tpl[] = { - 0x00, 0x00, 0x00, 0x00, // chunk length - 'I', 'E', 'N', 'D' // "IEND" -}; - -template void PNGWriter::writeIDAT(image_gray8 const& image); -template void PNGWriter::writeIDAT(image_view_gray8 const& image); -template void PNGWriter::writeIDAT(image_rgba8 const& image); -template void PNGWriter::writeIDAT(image_view_rgba8 const& image); -template void PNGWriter::writeIDATStripAlpha(image_rgba8 const& image); -template void PNGWriter::writeIDATStripAlpha(image_view_rgba8 const& image); - -}} diff -Nru mapnik-3.0.9+ds/src/palette.cpp mapnik-3.0.13+ds/src/palette.cpp --- mapnik-3.0.9+ds/src/palette.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/palette.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -37,8 +37,8 @@ // ordering by mean(a,r,g,b), a, r, g, b bool rgba::mean_sort_cmp::operator() (const rgba& x, const rgba& y) const { - int t1 = (int)x.a + x.r + x.g + x.b; - int t2 = (int)y.a + y.r + y.g + y.b; + int t1 = x.a + x.r + x.g + x.b; + int t2 = y.a + y.r + y.g + y.b; if (t1 != t2) return t1 < t2; // https://github.com/mapnik/mapnik/issues/1087 @@ -65,16 +65,6 @@ #endif } -const std::vector& rgba_palette::palette() const -{ - return rgb_pal_; -} - -const std::vector& rgba_palette::alphaTable() const -{ - return alpha_pal_; -} - bool rgba_palette::valid() const { return colors_ > 0; @@ -97,9 +87,9 @@ str << std::hex << std::setfill('0'); for (unsigned i = 0; i < length; i++) { str << " #"; - str << std::setw(2) << (unsigned)rgb_pal_[i].r; - str << std::setw(2) << (unsigned)rgb_pal_[i].g; - str << std::setw(2) << (unsigned)rgb_pal_[i].b; + str << std::setw(2) << static_cast(rgb_pal_[i].r); + str << std::setw(2) << static_cast(rgb_pal_[i].g); + str << std::setw(2) << static_cast(rgb_pal_[i].b); if (i < alphaLength) str << std::setw(2) << alpha_pal_[i]; } str << "]"; diff -Nru mapnik-3.0.9+ds/src/plugin.cpp mapnik-3.0.13+ds/src/plugin.cpp --- mapnik-3.0.9+ds/src/plugin.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/plugin.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -58,16 +58,24 @@ if (module_) module_->dl = LoadLibraryA(filename.c_str()); if (module_ && module_->dl) { - name_func name = reinterpret_cast(dlsym(module_->dl, library_name.c_str())); + callable_returning_string name = reinterpret_cast(dlsym(module_->dl, library_name.c_str())); if (name) name_ = name(); + callable_returning_void init_once = reinterpret_cast(dlsym(module_->dl, "on_plugin_load")); + if (init_once) { + init_once(); + } } #else #ifdef MAPNIK_HAS_DLCFN if (module_) module_->dl = dlopen(filename.c_str(),RTLD_LAZY); if (module_ && module_->dl) { - name_func name = reinterpret_cast(dlsym(module_->dl, library_name.c_str())); + callable_returning_string name = reinterpret_cast(dlsym(module_->dl, library_name.c_str())); if (name) name_ = name(); + callable_returning_void init_once = reinterpret_cast(dlsym(module_->dl, "on_plugin_load")); + if (init_once) { + init_once(); + } } #else throw std::runtime_error("no support for loading dynamic objects (Mapnik not compiled with -DMAPNIK_HAS_DLCFN)"); @@ -93,7 +101,9 @@ */ if (module_->dl && name_ != "gdal" && name_ != "ogr") { +#ifndef MAPNIK_NO_DLCLOSE dlclose(module_->dl),module_->dl=0; +#endif } #endif delete module_; @@ -106,7 +116,7 @@ #ifdef MAPNIK_SUPPORTS_DLOPEN return static_cast(dlsym(module_->dl, sym_name.c_str())); #else - return NULL; + return nullptr; #endif } diff -Nru mapnik-3.0.9+ds/src/png_reader.cpp mapnik-3.0.13+ds/src/png_reader.cpp --- mapnik-3.0.9+ds/src/png_reader.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/png_reader.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,22 +23,17 @@ // mapnik #include #include +#include extern "C" { #include } -#pragma GCC diagnostic push -#include -#include -#include -#include -#pragma GCC diagnostic pop - // stl #include #include +#include namespace mapnik { @@ -47,7 +42,7 @@ class png_reader : public image_reader { using source_type = T; - using input_stream = boost::iostreams::stream; + using input_stream = std::istream; struct png_struct_guard { @@ -73,7 +68,7 @@ int color_type_; bool has_alpha_; public: - explicit png_reader(std::string const& file_name); + explicit png_reader(std::string const& filename); png_reader(char const* data, std::size_t size); ~png_reader(); unsigned width() const final; @@ -90,14 +85,14 @@ namespace { -image_reader* create_png_reader(std::string const& file) +image_reader* create_png_reader(std::string const& filename) { - return new png_reader(file); + return new png_reader(filename); } image_reader* create_png_reader2(char const * data, std::size_t size) { - return new png_reader(data, size); + return new png_reader(data, size); } const bool registered = register_image_reader("png",create_png_reader); @@ -128,31 +123,30 @@ } template -png_reader::png_reader(std::string const& file_name) - : source_(file_name,std::ios_base::in | std::ios_base::binary), - stream_(source_), +png_reader::png_reader(std::string const& filename) + : source_(), + stream_(&source_), width_(0), height_(0), bit_depth_(0), color_type_(0), has_alpha_(false) { - if (!source_.is_open()) throw image_reader_exception("PNG reader: cannot open file '"+ file_name + "'"); - if (!stream_) throw image_reader_exception("PNG reader: cannot open file '"+ file_name + "'"); + source_.open(filename, std::ios_base::in | std::ios_base::binary); + if (!source_.is_open()) throw image_reader_exception("PNG reader: cannot open file '"+ filename + "'"); init(); } template png_reader::png_reader(char const* data, std::size_t size) : source_(data,size), - stream_(source_), + stream_(&source_), width_(0), height_(0), bit_depth_(0), color_type_(0), has_alpha_(false) { - if (!stream_) throw image_reader_exception("PNG reader: cannot open image stream"); init(); } diff -Nru mapnik-3.0.9+ds/src/proj_transform.cpp mapnik-3.0.13+ds/src/proj_transform.cpp --- mapnik-3.0.9+ds/src/proj_transform.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/proj_transform.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef MAPNIK_USE_PROJ4 // proj4 @@ -124,7 +125,7 @@ geometry::point * ptr = ls.data(); double * x = reinterpret_cast(ptr); double * y = x + 1; - double * z = NULL; + double * z = nullptr; if(!forward(x, y, z, size, 2)) { return size; @@ -199,20 +200,21 @@ #ifdef MAPNIK_USE_PROJ4 if (is_dest_longlat_) { - int i; - for(i=0; i * ptr = ls.data(); double * x = reinterpret_cast(ptr); double * y = x + 1; - double * z = NULL; - if(!backward(x, y, z, size, 2)) + double * z = nullptr; + if (!backward(x, y, z, size, 2)) { return size; } @@ -311,31 +313,24 @@ if (is_source_equal_dest_) return true; - double llx = box.minx(); - double ulx = box.minx(); - double lly = box.miny(); - double lry = box.miny(); - double lrx = box.maxx(); - double urx = box.maxx(); - double uly = box.maxy(); - double ury = box.maxy(); - double z = 0.0; - if (!backward(llx,lly,z)) - return false; - if (!backward(lrx,lry,z)) - return false; - if (!backward(ulx,uly,z)) - return false; - if (!backward(urx,ury,z)) + double x[4], y[4]; + x[0] = box.minx(); // llx 0 + y[0] = box.miny(); // lly 1 + x[1] = box.maxx(); // lrx 2 + y[1] = box.miny(); // lry 3 + x[2] = box.minx(); // ulx 4 + y[2] = box.maxy(); // uly 5 + x[3] = box.maxx(); // urx 6 + y[3] = box.maxy(); // ury 7 + + if (!backward(x, y, nullptr, 4, 1)) return false; - double minx = std::min(ulx, llx); - double miny = std::min(lly, lry); - double maxx = std::max(urx, lrx); - double maxy = std::max(ury, uly); - box.init(minx, - miny, - maxx, - maxy); + + double minx = std::min(x[0], x[2]); + double miny = std::min(y[0], y[1]); + double maxx = std::max(x[1], x[3]); + double maxy = std::max(y[2], y[3]); + box.init(minx, miny, maxx, maxy); return true; } @@ -370,21 +365,6 @@ } } -// determine if an ordered sequence of coordinates is in clockwise order -bool is_clockwise(const std::vector< coord > & coords) -{ - int n = coords.size(); - coord c1, c2; - double a = 0.0; - - for (int i=0; i calculate_bbox(std::vector > & points) { std::vector >::iterator it = points.begin(); std::vector >::iterator it_end = points.end(); @@ -425,7 +405,7 @@ } box2d result = calculate_bbox(coords); - if (is_source_longlat_ && !is_clockwise(coords)) + if (is_source_longlat_ && !util::is_clockwise(coords)) { // we've gone to a geographic CS, and our clockwise envelope has // changed into an anticlockwise one. This means we've crossed the antimeridian, and @@ -439,7 +419,6 @@ env.re_center(result.center().x, result.center().y); env.height(result.height()); env.width(result.width()); - return true; } @@ -466,7 +445,7 @@ box2d result = calculate_bbox(coords); - if (is_dest_longlat_ && !is_clockwise(coords)) + if (is_dest_longlat_ && !util::is_clockwise(coords)) { // we've gone to a geographic CS, and our clockwise envelope has // changed into an anticlockwise one. This means we've crossed the antimeridian, and diff -Nru mapnik-3.0.9+ds/src/rapidxml_loader.cpp mapnik-3.0.13+ds/src/rapidxml_loader.cpp --- mapnik-3.0.9+ds/src/rapidxml_loader.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/rapidxml_loader.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,12 +28,16 @@ #include #include #include -#include #include #include #include #include +#pragma GCC diagnostic push +#include +#include +#pragma GCC diagnostic pop + // stl #include #include diff -Nru mapnik-3.0.9+ds/src/raster_colorizer.cpp mapnik-3.0.13+ds/src/raster_colorizer.cpp --- mapnik-3.0.9+ds/src/raster_colorizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/raster_colorizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -149,7 +149,7 @@ inline unsigned interpolate(unsigned start, unsigned end, float fraction) { - return static_cast(fraction * ((float)end - (float)start) + start); + return static_cast(fraction * (static_cast(end) - static_cast(start)) + static_cast(start)); } unsigned raster_colorizer::get_color(float value) const diff -Nru mapnik-3.0.9+ds/src/renderer_common/process_group_symbolizer.cpp mapnik-3.0.13+ds/src/renderer_common/process_group_symbolizer.cpp --- mapnik-3.0.9+ds/src/renderer_common/process_group_symbolizer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/renderer_common/process_group_symbolizer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,233 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2015 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 - * - *****************************************************************************/ - -// mapnik -#include -#include -#include - -namespace mapnik { - -vector_marker_render_thunk::vector_marker_render_thunk(svg_path_ptr const& src, - svg_attribute_type const& attrs, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), attrs_(attrs), tr_(marker_trans), opacity_(opacity), - comp_op_(comp_op), snap_to_pixels_(snap_to_pixels) -{} - -vector_marker_render_thunk::vector_marker_render_thunk(vector_marker_render_thunk && rhs) - : src_(std::move(rhs.src_)), - attrs_(std::move(rhs.attrs_)), - tr_(std::move(rhs.tr_)), - opacity_(std::move(rhs.opacity_)), - comp_op_(std::move(rhs.comp_op_)), - snap_to_pixels_(std::move(rhs.snap_to_pixels_)) {} - - -raster_marker_render_thunk::raster_marker_render_thunk(image_rgba8 const& src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) -{} - -raster_marker_render_thunk::raster_marker_render_thunk(raster_marker_render_thunk && rhs) - : src_(rhs.src_), - tr_(std::move(rhs.tr_)), - opacity_(std::move(rhs.opacity_)), - comp_op_(std::move(rhs.comp_op_)), - snap_to_pixels_(std::move(rhs.snap_to_pixels_)) {} - - -text_render_thunk::text_render_thunk(helper_ptr && helper, - double opacity, composite_mode_e comp_op, - halo_rasterizer_enum halo_rasterizer) - : helper_(std::move(helper)), - placements_(helper_->get()), - opacity_(opacity), - comp_op_(comp_op), - halo_rasterizer_(halo_rasterizer) -{} - -text_render_thunk::text_render_thunk(text_render_thunk && rhs) - : helper_(std::move(rhs.helper_)), - placements_(std::move(rhs.placements_)), - opacity_(std::move(rhs.opacity_)), - comp_op_(std::move(rhs.comp_op_)), - halo_rasterizer_(std::move(rhs.halo_rasterizer_)) {} - -namespace detail { - -template -struct vector_marker_thunk_dispatch : public vector_markers_dispatch -{ - vector_marker_thunk_dispatch(svg_path_ptr const& src, - svg_path_adapter & path, - svg_attribute_type const& attrs, - agg::trans_affine const& marker_trans, - symbolizer_base const& sym, - Detector & detector, - double scale_factor, - feature_impl & feature, - attributes const& vars, - bool snap_to_pixels, - RendererContext const& renderer_context) - : vector_markers_dispatch(src, marker_trans, sym, detector, scale_factor, feature, vars), - attrs_(attrs), comp_op_(get(sym, feature, vars)), - snap_to_pixels_(snap_to_pixels), thunks_(std::get<0>(renderer_context)) - {} - - ~vector_marker_thunk_dispatch() {} - - void render_marker(agg::trans_affine const& marker_tr, double opacity) - { - vector_marker_render_thunk thunk(this->src_, this->attrs_, marker_tr, opacity, comp_op_, snap_to_pixels_); - thunks_.push_back(std::make_unique(std::move(thunk))); - } - -private: - svg_attribute_type const& attrs_; - composite_mode_e comp_op_; - bool snap_to_pixels_; - render_thunk_list & thunks_; -}; - -template -struct raster_marker_thunk_dispatch : public raster_markers_dispatch -{ - raster_marker_thunk_dispatch(image_rgba8 const& src, - agg::trans_affine const& marker_trans, - symbolizer_base const& sym, - Detector & detector, - double scale_factor, - feature_impl & feature, - attributes const& vars, - RendererContext const& renderer_context, - bool snap_to_pixels = false) - : raster_markers_dispatch(src, marker_trans, sym, detector, scale_factor, feature, vars), - comp_op_(get(sym, feature, vars)), - snap_to_pixels_(snap_to_pixels), thunks_(std::get<0>(renderer_context)) - {} - - ~raster_marker_thunk_dispatch() {} - - void render_marker(agg::trans_affine const& marker_tr, double opacity) - { - raster_marker_render_thunk thunk(this->src_, marker_tr, opacity, comp_op_, snap_to_pixels_); - thunks_.push_back(std::make_unique(std::move(thunk))); - } - -private: - composite_mode_e comp_op_; - bool snap_to_pixels_; - render_thunk_list & thunks_; -}; - -} // end detail ns - -render_thunk_extractor::render_thunk_extractor(box2d & box, - render_thunk_list & thunks, - feature_impl & feature, - attributes const& vars, - proj_transform const& prj_trans, - virtual_renderer_common & common, - box2d const& clipping_extent) - : box_(box), thunks_(thunks), feature_(feature), vars_(vars), prj_trans_(prj_trans), - common_(common), clipping_extent_(clipping_extent) -{} - -void render_thunk_extractor::operator()(markers_symbolizer const& sym) const -{ - auto renderer_context = std::tie(thunks_); - using context_type = decltype(renderer_context); - using vector_dispatch_type = detail::vector_marker_thunk_dispatch; - using raster_dispatch_type = detail::raster_marker_thunk_dispatch; - - render_markers_symbolizer( - sym, feature_, prj_trans_, common_, clipping_extent_, renderer_context); - - update_box(); -} - -void render_thunk_extractor::operator()(text_symbolizer const& sym) const -{ - box2d clip_box = clipping_extent_; - helper_ptr helper = std::make_unique( - sym, feature_, vars_, prj_trans_, - common_.width_, common_.height_, - common_.scale_factor_, - common_.t_, common_.font_manager_, *common_.detector_, - clip_box, agg::trans_affine()); - - extract_text_thunk(std::move(helper), sym); -} - -void render_thunk_extractor::operator()(shield_symbolizer const& sym) const -{ - box2d clip_box = clipping_extent_; - helper_ptr helper = std::make_unique( - sym, feature_, vars_, prj_trans_, - common_.width_, common_.height_, - common_.scale_factor_, - common_.t_, common_.font_manager_, *common_.detector_, - clip_box, agg::trans_affine()); - - extract_text_thunk(std::move(helper), sym); -} - -void render_thunk_extractor::extract_text_thunk(helper_ptr && helper, text_symbolizer const& sym) const -{ - double opacity = get(sym, keys::opacity, feature_, common_.vars_, 1.0); - composite_mode_e comp_op = get(sym, keys::comp_op, feature_, common_.vars_, src_over); - halo_rasterizer_enum halo_rasterizer = get(sym, keys::halo_rasterizer, feature_, common_.vars_, HALO_RASTERIZER_FULL); - - text_render_thunk thunk(std::move(helper), opacity, comp_op, halo_rasterizer); - thunks_.push_back(std::make_unique(std::move(thunk))); - - update_box(); -} - -void render_thunk_extractor::update_box() const -{ - label_collision_detector4 & detector = *common_.detector_; - - for (auto const& label : detector) - { - if (box_.width() > 0 && box_.height() > 0) - { - box_.expand_to_include(label.get().box); - } - else - { - box_ = label.get().box; - } - } - - detector.clear(); -} - -} // namespace mapnik diff -Nru mapnik-3.0.9+ds/src/renderer_common/render_group_symbolizer.cpp mapnik-3.0.13+ds/src/renderer_common/render_group_symbolizer.cpp --- mapnik-3.0.9+ds/src/renderer_common/render_group_symbolizer.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/src/renderer_common/render_group_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,196 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +// mapnik +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mapnik { + +void render_group_symbolizer(group_symbolizer const& sym, + feature_impl & feature, + attributes const& vars, + proj_transform const& prj_trans, + box2d const& clipping_extent, + renderer_common & common, + render_thunk_list_dispatch & render_thunks) +{ + // find all column names referenced in the group rules and symbolizers + std::set columns; + group_attribute_collector column_collector(columns, false); + column_collector(sym); + + auto props = get(sym, keys::group_properties); + + // create a new context for the sub features of this group + context_ptr sub_feature_ctx = std::make_shared(); + + // populate new context with column names referenced in the group rules and symbolizers + for (auto const& col_name : columns) + { + sub_feature_ctx->push(col_name); + } + + // keep track of the sub features that we'll want to symbolize + // along with the group rules that they matched + std::vector< std::pair > matches; + + // create a copied 'virtual' common renderer for processing sub feature symbolizers + // create an empty detector for it, so we are sure we won't hit anything + virtual_renderer_common virtual_renderer(common); + + // keep track of which lists of render thunks correspond to + // entries in the group_layout_manager. + std::list layout_thunks; + + // layout manager to store and arrange bboxes of matched features + group_layout_manager layout_manager(props->get_layout()); + layout_manager.set_input_origin(common.width_ * 0.5, common.height_ * 0.5); + + // run feature or sub feature through the group rules & symbolizers + // for each index value in the range + value_integer start = get(sym, keys::start_column); + value_integer end = start + get(sym, keys::num_columns); + for (value_integer col_idx = start; col_idx < end; ++col_idx) + { + // create sub feature with indexed column values + feature_ptr sub_feature = feature_factory::create(sub_feature_ctx, col_idx); + + // copy the necessary columns to sub feature + for(auto const& col_name : columns) + { + if (col_name.find('%') != std::string::npos) + { + if (col_name.size() == 1) + { + // column name is '%' by itself, so give the index as the value + sub_feature->put(col_name, col_idx); + } + else + { + // indexed column + std::string col_idx_str; + if (mapnik::util::to_string(col_idx_str,col_idx)) + { + std::string col_idx_name = col_name; + boost::replace_all(col_idx_name, "%", col_idx_str); + sub_feature->put(col_name, feature.get(col_idx_name)); + } + } + } + else + { + // non-indexed column + sub_feature->put(col_name, feature.get(col_name)); + } + } + + // add a single point geometry at pixel origin + double x = common.width_ / 2.0, y = common.height_ / 2.0, z = 0.0; + common.t_.backward(&x, &y); + prj_trans.forward(x, y, z); + // note that we choose a point in the middle of the screen to + // try to ensure that we don't get edge artefacts due to any + // symbolizers with avoid-edges set: only the avoid-edges of + // the group symbolizer itself should matter. + geometry::point origin_pt(x,y); + sub_feature->set_geometry(origin_pt); + // get the layout for this set of properties + for (auto const& rule : props->get_rules()) + { + if (util::apply_visitor(evaluate(*sub_feature,common.vars_), + *(rule->get_filter())).to_bool()) + { + // add matched rule and feature to the list of things to draw + matches.emplace_back(rule, sub_feature); + + // construct a bounding box around all symbolizers for the matched rule + box2d bounds; + render_thunk_list thunks; + render_thunk_extractor extractor(bounds, thunks, *sub_feature, common.vars_, prj_trans, + virtual_renderer, clipping_extent); + + for (auto const& _sym : *rule) + { + // TODO: construct layout and obtain bounding box + util::apply_visitor(extractor, _sym); + } + + // add the bounding box to the layout manager + layout_manager.add_member_bound_box(bounds); + layout_thunks.emplace_back(std::move(thunks)); + break; + } + } + } + + // create a symbolizer helper + group_symbolizer_helper helper(sym, feature, vars, prj_trans, + common.width_, common.height_, + common.scale_factor_, common.t_, + *common.detector_, clipping_extent); + + for (size_t i = 0; i < matches.size(); ++i) + { + group_rule_ptr match_rule = matches[i].first; + feature_ptr match_feature = matches[i].second; + value_unicode_string rpt_key_value = ""; + + // get repeat key from matched group rule + expression_ptr rpt_key_expr = match_rule->get_repeat_key(); + + // if no repeat key was defined, use default from group symbolizer + if (!rpt_key_expr) + { + rpt_key_expr = get(sym, keys::repeat_key); + } + + // evaluate the repeat key with the matched sub feature if we have one + if (rpt_key_expr) + { + rpt_key_value = util::apply_visitor(evaluate(*match_feature,common.vars_), + *rpt_key_expr).to_unicode(); + } + helper.add_box_element(layout_manager.offset_box_at(i), rpt_key_value); + } + + pixel_position_list const& positions = helper.get(); + for (pixel_position const& pos : positions) + { + size_t layout_i = 0; + for (auto const& thunks : layout_thunks) + { + pixel_position const& offset = layout_manager.offset_at(layout_i); + pixel_position render_offset = pos + offset; + render_thunks.render_list(thunks, render_offset); + ++layout_i; + } + } +} + +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/src/renderer_common/render_markers_symbolizer.cpp mapnik-3.0.13+ds/src/renderer_common/render_markers_symbolizer.cpp --- mapnik-3.0.9+ds/src/renderer_common/render_markers_symbolizer.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/src/renderer_common/render_markers_symbolizer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,265 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 +#include +#include +#include +#include +#include +#include +#include + +namespace mapnik { + +namespace detail { + +template +struct render_marker_symbolizer_visitor +{ + using vector_dispatch_type = vector_markers_dispatch; + using raster_dispatch_type = raster_markers_dispatch; + + render_marker_symbolizer_visitor(std::string const& filename, + markers_symbolizer const& sym, + mapnik::feature_impl & feature, + proj_transform const& prj_trans, + RendererType const& common, + box2d const& clip_box, + ContextType & renderer_context) + : filename_(filename), + sym_(sym), + feature_(feature), + prj_trans_(prj_trans), + common_(common), + clip_box_(clip_box), + renderer_context_(renderer_context) {} + + svg_attribute_type const& get_marker_attributes(svg_path_ptr const& stock_marker, + svg_attribute_type & custom_attr) const + { + auto const& stock_attr = stock_marker->attributes(); + if (push_explicit_style(stock_attr, custom_attr, sym_, feature_, common_.vars_)) + return custom_attr; + else + return stock_attr; + } + + template + void render_marker(Marker const& mark, Dispatch & rasterizer_dispatch) const + { + auto const& vars = common_.vars_; + + agg::trans_affine geom_tr; + if (auto geometry_transform = get_optional(sym_, keys::geometry_transform)) + { + evaluate_transform(geom_tr, feature_, vars, *geometry_transform, common_.scale_factor_); + } + + vertex_converter_type converter(clip_box_, + sym_, + common_.t_, + prj_trans_, + geom_tr, + feature_, + vars, + common_.scale_factor_); + + bool clip = get(sym_, feature_, vars); + double offset = get(sym_, feature_, vars); + double simplify_tolerance = get(sym_, feature_, vars); + double smooth = get(sym_, feature_, vars); + + if (clip) + { + geometry::geometry_types type = geometry::geometry_type(feature_.get_geometry()); + switch (type) + { + case geometry::geometry_types::Polygon: + case geometry::geometry_types::MultiPolygon: + converter.template set(); + break; + case geometry::geometry_types::LineString: + case geometry::geometry_types::MultiLineString: + converter.template set(); + break; + default: + // silence warning: 4 enumeration values not handled in switch + break; + } + } + + converter.template set(); //always transform + if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset + converter.template set(); // optional affine transform + if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter + if (smooth > 0.0) converter.template set(); // optional smooth converter + + apply_markers_multi(feature_, vars, converter, rasterizer_dispatch, sym_); + } + + void operator() (marker_null const&) const {} + + void operator() (marker_svg const& mark) const + { + using namespace mapnik::svg; + + // https://github.com/mapnik/mapnik/issues/1316 + bool snap_to_pixels = !mapnik::marker_cache::instance().is_uri(filename_); + + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + + boost::optional const& stock_vector_marker = mark.get_data(); + svg_path_ptr marker_ptr = *stock_vector_marker; + bool is_ellipse = false; + + svg_attribute_type s_attributes; + auto const& r_attributes = get_marker_attributes(*stock_vector_marker, s_attributes); + + // special case for simple ellipse markers + // to allow for full control over rx/ry dimensions + if (filename_ == "shape://ellipse" + && (has_key(sym_,keys::width) || has_key(sym_,keys::height))) + { + marker_ptr = std::make_shared(); + is_ellipse = true; + } + else + { + box2d const& bbox = mark.bounding_box(); + setup_transform_scaling(image_tr, bbox.width(), bbox.height(), feature_, common_.vars_, sym_); + } + + vertex_stl_adapter stl_storage(marker_ptr->source()); + svg_path_adapter svg_path(stl_storage); + + if (is_ellipse) + { + build_ellipse(sym_, feature_, common_.vars_, *marker_ptr, svg_path); + } + + if (auto image_transform = get_optional(sym_, keys::image_transform)) + { + evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_); + } + + vector_dispatch_type rasterizer_dispatch(marker_ptr, + svg_path, + r_attributes, + image_tr, + sym_, + *common_.detector_, + common_.scale_factor_, + feature_, + common_.vars_, + snap_to_pixels, + renderer_context_); + + render_marker(mark, rasterizer_dispatch); + } + + void operator() (marker_rgba8 const& mark) const + { + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + + setup_transform_scaling(image_tr, mark.width(), mark.height(), feature_, common_.vars_, sym_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_); + box2d const& bbox = mark.bounding_box(); + mapnik::image_rgba8 const& marker = mark.get_data(); + // - clamp sizes to > 4 pixels of interactivity + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * image_tr; + raster_dispatch_type rasterizer_dispatch(marker, + marker_trans, + sym_, + *common_.detector_, + common_.scale_factor_, + feature_, + common_.vars_, + renderer_context_); + + render_marker(mark, rasterizer_dispatch); + } + + private: + std::string const& filename_; + markers_symbolizer const& sym_; + mapnik::feature_impl & feature_; + proj_transform const& prj_trans_; + RendererType const& common_; + box2d const& clip_box_; + ContextType & renderer_context_; +}; + +} // namespace detail + +markers_dispatch_params::markers_dispatch_params(box2d const& size, + agg::trans_affine const& tr, + symbolizer_base const& sym, + feature_impl const& feature, + attributes const& vars, + double scale, + bool snap) + : placement_params{ + size, + tr, + get(sym, feature, vars), + get(sym, feature, vars), + get(sym, feature, vars), + get(sym, feature, vars), + get(sym, feature, vars)} + , placement_method(get(sym, feature, vars)) + , ignore_placement(get(sym, feature, vars)) + , snap_to_pixels(snap) + , scale_factor(scale) + , opacity(get(sym, feature, vars)) +{ + placement_params.spacing *= scale; +} + +void render_markers_symbolizer(markers_symbolizer const& sym, + mapnik::feature_impl & feature, + proj_transform const& prj_trans, + renderer_common const& common, + box2d const& clip_box, + markers_renderer_context & renderer_context) +{ + using Detector = label_collision_detector4; + using RendererType = renderer_common; + using ContextType = markers_renderer_context; + using VisitorType = detail::render_marker_symbolizer_visitor; + + std::string filename = get(sym, keys::file, feature, common.vars_, "shape://ellipse"); + if (!filename.empty()) + { + auto mark = mapnik::marker_cache::instance().find(filename, true); + VisitorType visitor(filename, sym, feature, prj_trans, common, clip_box, + renderer_context); + util::apply_visitor(visitor, *mark); + } +} + +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/src/renderer_common/render_pattern.cpp mapnik-3.0.13+ds/src/renderer_common/render_pattern.cpp --- mapnik-3.0.9+ds/src/renderer_common/render_pattern.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/renderer_common/render_pattern.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,12 +28,15 @@ #include #include +#pragma GCC diagnostic push +#include #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" #include "agg_pixfmt_gray.h" #include "agg_color_rgba.h" #include "agg_color_gray.h" #include "agg_scanline_u.h" +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/renderer_common/render_thunk_extractor.cpp mapnik-3.0.13+ds/src/renderer_common/render_thunk_extractor.cpp --- mapnik-3.0.9+ds/src/renderer_common/render_thunk_extractor.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/src/renderer_common/render_thunk_extractor.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,155 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +// mapnik +#include +#include +#include +#include + +namespace mapnik { + +virtual_renderer_common::virtual_renderer_common(renderer_common const& other) + : renderer_common(other) +{ + // replace collision detector with my own so that I don't pollute the original + detector_ = std::make_shared(other.detector_->extent()); +} + +namespace detail { + +struct thunk_markers_renderer_context : markers_renderer_context +{ + thunk_markers_renderer_context(symbolizer_base const& sym, + feature_impl const& feature, + attributes const& vars, + render_thunk_list & thunks) + : comp_op_(get(sym, feature, vars)) + , thunks_(thunks) + {} + + virtual void render_marker(svg_path_ptr const& src, + svg_path_adapter & path, + svg_attribute_type const& attrs, + markers_dispatch_params const& params, + agg::trans_affine const& marker_tr) + { + vector_marker_render_thunk thunk(src, attrs, marker_tr, params.opacity, + comp_op_, params.snap_to_pixels); + thunks_.emplace_back(std::move(thunk)); + } + + virtual void render_marker(image_rgba8 const& src, + markers_dispatch_params const& params, + agg::trans_affine const& marker_tr) + { + raster_marker_render_thunk thunk(src, marker_tr, params.opacity, + comp_op_, params.snap_to_pixels); + thunks_.emplace_back(std::move(thunk)); + } + +private: + composite_mode_e comp_op_; + render_thunk_list & thunks_; +}; + +} // namespace detail + +render_thunk_extractor::render_thunk_extractor(box2d & box, + render_thunk_list & thunks, + feature_impl & feature, + attributes const& vars, + proj_transform const& prj_trans, + virtual_renderer_common & common, + box2d const& clipping_extent) + : box_(box), thunks_(thunks), feature_(feature), vars_(vars), prj_trans_(prj_trans), + common_(common), clipping_extent_(clipping_extent) +{} + +void render_thunk_extractor::operator()(markers_symbolizer const& sym) const +{ + using context_type = detail::thunk_markers_renderer_context; + context_type renderer_context(sym, feature_, vars_, thunks_); + + render_markers_symbolizer( + sym, feature_, prj_trans_, common_, clipping_extent_, renderer_context); + + update_box(); +} + +void render_thunk_extractor::operator()(text_symbolizer const& sym) const +{ + auto helper = std::make_unique( + sym, feature_, vars_, prj_trans_, + common_.width_, common_.height_, + common_.scale_factor_, + common_.t_, common_.font_manager_, *common_.detector_, + clipping_extent_, agg::trans_affine::identity); + + extract_text_thunk(std::move(helper), sym); +} + +void render_thunk_extractor::operator()(shield_symbolizer const& sym) const +{ + auto helper = std::make_unique( + sym, feature_, vars_, prj_trans_, + common_.width_, common_.height_, + common_.scale_factor_, + common_.t_, common_.font_manager_, *common_.detector_, + clipping_extent_, agg::trans_affine::identity); + + extract_text_thunk(std::move(helper), sym); +} + +void render_thunk_extractor::extract_text_thunk(text_render_thunk::helper_ptr && helper, + text_symbolizer const& sym) const +{ + double opacity = get(sym, keys::opacity, feature_, common_.vars_, 1.0); + composite_mode_e comp_op = get(sym, keys::comp_op, feature_, common_.vars_, src_over); + halo_rasterizer_enum halo_rasterizer = get(sym, keys::halo_rasterizer, feature_, common_.vars_, HALO_RASTERIZER_FULL); + + text_render_thunk thunk(std::move(helper), opacity, comp_op, halo_rasterizer); + thunks_.emplace_back(std::move(thunk)); + + update_box(); +} + +void render_thunk_extractor::update_box() const +{ + label_collision_detector4 & detector = *common_.detector_; + + for (auto const& label : detector) + { + if (box_.width() > 0 && box_.height() > 0) + { + box_.expand_to_include(label.get().box); + } + else + { + box_ = label.get().box; + } + } + + detector.clear(); +} + +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/src/renderer_common.cpp mapnik-3.0.13+ds/src/renderer_common.cpp --- mapnik-3.0.9+ds/src/renderer_common.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/renderer_common.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,10 +29,24 @@ namespace mapnik { +// copy constructor exclusively for virtual_renderer_common +renderer_common::renderer_common(renderer_common const& other) + : width_(other.width_), + height_(other.height_), + scale_factor_(other.scale_factor_), + vars_(other.vars_), + shared_font_library_(other.shared_font_library_), + font_library_(other.font_library_), + font_manager_(other.font_manager_), + query_extent_(other.query_extent_), + t_(other.t_), + detector_(other.detector_) +{} + renderer_common::renderer_common(Map const& map, unsigned width, unsigned height, double scale_factor, attributes const& vars, view_transform && t, - std::shared_ptr detector) + detector_ptr detector) : width_(width), height_(height), scale_factor_(scale_factor), @@ -57,7 +71,7 @@ renderer_common::renderer_common(Map const &m, attributes const& vars, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height, double scale_factor, - std::shared_ptr detector) + detector_ptr detector) : renderer_common(m, width, height, scale_factor, vars, view_transform(m.width(),m.height(),m.get_current_extent(),offset_x,offset_y), @@ -74,4 +88,10 @@ req.width() + req.buffer_size() ,req.height() + req.buffer_size()))) {} +renderer_common::~renderer_common() +{ + // defined in .cpp to make this destructible elsewhere without + // having to #include +} + } diff -Nru mapnik-3.0.9+ds/src/save_map.cpp mapnik-3.0.13+ds/src/save_map.cpp --- mapnik-3.0.9+ds/src/save_map.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/save_map.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -47,7 +47,6 @@ #include #include #include - #pragma GCC diagnostic push #include #include @@ -105,7 +104,7 @@ raster_colorizer dfl; if (colorizer->get_default_mode() != dfl.get_default_mode() || explicit_defaults) { - set_attr(col_node, "default-mode", colorizer->get_default_mode()); + set_attr(col_node, "default-mode", colorizer->get_default_mode().as_string()); } if (colorizer->get_default_color() != dfl.get_default_color() || explicit_defaults) { @@ -404,7 +403,7 @@ filter_mode_e filter_mode = style.get_filter_mode(); if (filter_mode != dfl.get_filter_mode() || explicit_defaults) { - set_attr(style_node, "filter-mode", filter_mode); + set_attr(style_node, "filter-mode", filter_mode.as_string()); } double opacity = style.get_opacity(); diff -Nru mapnik-3.0.9+ds/src/svg/output/svg_renderer.cpp mapnik-3.0.13+ds/src/svg/output/svg_renderer.cpp --- mapnik-3.0.9+ds/src/svg/output/svg_renderer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/svg/output/svg_renderer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff -Nru mapnik-3.0.9+ds/src/svg/svg_parser.cpp mapnik-3.0.13+ds/src/svg/svg_parser.cpp --- mapnik-3.0.9+ds/src/svg/svg_parser.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/svg/svg_parser.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,10 +29,15 @@ #include #include #include +#include + +#pragma GCC diagnostic push +#include #include "agg_ellipse.h" #include "agg_rounded_rect.h" #include "agg_span_gradient.h" #include "agg_color_rgba.h" +#pragma GCC diagnostic pop #pragma GCC diagnostic push #include @@ -106,7 +111,6 @@ } catch (mapnik::config_error const& ex) { - error_messages.emplace_back(ex.what()); } return c; @@ -123,7 +127,7 @@ double parse_double(T & error_messages, const char* str) { using namespace boost::spirit::qi; - qi::double_type double_; + double_type double_; double val = 0.0; if (!parse(str, str + std::strlen(str),double_,val)) { @@ -132,24 +136,40 @@ return val; } - -// parse a double that might end with a % -// if it does then set the ref bool true and divide the result by 100 - -template -double parse_double_optional_percent(T & error_messages, const char* str, bool &percent) +// https://www.w3.org/TR/SVG/coords.html#Units +template +double parse_svg_value(T & error_messages, const char* str, bool & percent) { - using namespace boost::spirit::qi; + using skip_type = boost::spirit::ascii::space_type; using boost::phoenix::ref; - qi::_1_type _1; qi::double_type double_; - qi::char_type char_; - + qi::lit_type lit; + qi::_1_type _1; double val = 0.0; - if (!parse(str, str + std::strlen(str),double_[ref(val)=_1, ref(percent) = false] - >> -char_('%')[ref(val) /= 100.0, ref(percent) = true])) + qi::symbols units; + units.add + ("px", 1.0) + ("pt", DPI/72.0) + ("pc", DPI/6.0) + ("mm", DPI/25.4) + ("cm", DPI/2.54) + ("in", static_cast(DPI)) + ; + const char* cur = str; // phrase_parse modifies the first iterator + const char* end = str + std::strlen(str); + if (!qi::phrase_parse(cur, end, + double_[ref(val) = _1][ref(percent) = false] + > - (units[ ref(val) *= _1] + | + lit('%')[ref(val) *= 0.01][ref(percent) = true]), + skip_type())) + { + error_messages.emplace_back("Failed to parse SVG value: '" + std::string(str) + "'"); + } + else if (cur != end) { - error_messages.emplace_back("Failed to parse double (optional %) from " + std::string(str)); + error_messages.emplace_back("Failed to parse SVG value: '" + std::string(str) + + "', trailing garbage: '" + cur + "'"); } return val; } @@ -159,9 +179,9 @@ { using namespace boost::spirit::qi; using boost::phoenix::ref; - qi::_1_type _1; - qi::double_type double_; - qi::lit_type lit; + _1_type _1; + double_type double_; + lit_type lit; using skip_type = boost::spirit::ascii::space_type; if (!phrase_parse(str, str + std::strlen(str), @@ -411,7 +431,8 @@ } else if (std::strcmp(name, "stroke-width") == 0) { - parser.path_.stroke_width(parse_double(parser.error_messages_, value)); + bool percent; + parser.path_.stroke_width(parse_svg_value(parser.error_messages_, value, percent)); } else if (std::strcmp(name, "stroke-opacity") == 0) { @@ -439,7 +460,19 @@ { parser.path_.miter_limit(parse_double(parser.error_messages_,value)); } - + else if (std::strcmp(name,"stroke-dasharray") == 0) + { + dash_array dash; + if (util::parse_dasharray(value, dash)) + { + parser.path_.dash_array(std::move(dash)); + } + } + else if (std::strcmp(name,"stroke-dashoffset") == 0) + { + double offset = parse_double(parser.error_messages_, value); + parser.path_.dash_offset(offset); + } else if(std::strcmp(name, "opacity") == 0) { double opacity = parse_double(parser.error_messages_, value); @@ -455,7 +488,6 @@ } } - void parse_attr(svg_parser & parser, rapidxml::xml_node const* node) { for (rapidxml::xml_attribute const* attr = node->first_attribute(); @@ -493,12 +525,12 @@ auto const* width_attr = node->first_attribute("width"); if (width_attr) { - width = parse_double_optional_percent(parser.error_messages_, width_attr->value(), has_percent_width); + width = parse_svg_value(parser.error_messages_, width_attr->value(), has_percent_width); } auto const* height_attr = node->first_attribute("height"); if (height_attr) { - height = parse_double_optional_percent(parser.error_messages_, height_attr->value(), has_percent_height); + height = parse_svg_value(parser.error_messages_, height_attr->value(), has_percent_height); } auto const* viewbox_attr = node->first_attribute("viewBox"); if (viewbox_attr) @@ -589,18 +621,18 @@ double y1 = 0.0; double x2 = 0.0; double y2 = 0.0; - + bool percent; auto const* x1_attr = node->first_attribute("x1"); - if (x1_attr) x1 = parse_double(parser.error_messages_, x1_attr->value()); + if (x1_attr) x1 = parse_svg_value(parser.error_messages_, x1_attr->value(), percent); auto const* y1_attr = node->first_attribute("y1"); - if (y1_attr) y1 = parse_double(parser.error_messages_, y1_attr->value()); + if (y1_attr) y1 = parse_svg_value(parser.error_messages_, y1_attr->value(), percent); auto const* x2_attr = node->first_attribute("x2"); - if (x2_attr) x2 = parse_double(parser.error_messages_, x2_attr->value()); + if (x2_attr) x2 = parse_svg_value(parser.error_messages_, x2_attr->value(), percent); auto const* y2_attr = node->first_attribute("y2"); - if (y2_attr) y2 = parse_double(parser.error_messages_, y2_attr->value()); + if (y2_attr) y2 = parse_svg_value(parser.error_messages_, y2_attr->value(), percent); parser.path_.begin_path(); parser.path_.move_to(x1, y1); @@ -613,23 +645,23 @@ double cx = 0.0; double cy = 0.0; double r = 0.0; - + bool percent; auto * attr = node->first_attribute("cx"); if (attr != nullptr) { - cx = parse_double(parser.error_messages_, attr->value()); + cx = parse_svg_value(parser.error_messages_, attr->value(), percent); } attr = node->first_attribute("cy"); if (attr != nullptr) { - cy = parse_double(parser.error_messages_, attr->value()); + cy = parse_svg_value(parser.error_messages_, attr->value(), percent); } attr = node->first_attribute("r"); if (attr != nullptr) { - r = parse_double(parser.error_messages_, attr->value()); + r = parse_svg_value(parser.error_messages_, attr->value(), percent); } parser.path_.begin_path(); @@ -654,29 +686,29 @@ double cy = 0.0; double rx = 0.0; double ry = 0.0; - + bool percent; auto * attr = node->first_attribute("cx"); if (attr != nullptr) { - cx = parse_double(parser.error_messages_, attr->value()); + cx = parse_svg_value(parser.error_messages_, attr->value(), percent); } attr = node->first_attribute("cy"); if (attr) { - cy = parse_double(parser.error_messages_, attr->value()); + cy = parse_svg_value(parser.error_messages_, attr->value(), percent); } attr = node->first_attribute("rx"); if (attr != nullptr) { - rx = parse_double(parser.error_messages_, attr->value()); + rx = parse_svg_value(parser.error_messages_, attr->value(), percent); } attr = node->first_attribute("ry"); if (attr != nullptr) { - ry = parse_double(parser.error_messages_, attr->value()); + ry = parse_svg_value(parser.error_messages_, attr->value(), percent); } if (rx != 0.0 && ry != 0.0) @@ -709,35 +741,35 @@ double h = 0.0; double rx = 0.0; double ry = 0.0; - + bool percent; auto * attr = node->first_attribute("x"); if (attr != nullptr) { - x = parse_double(parser.error_messages_, attr->value()); + x = parse_svg_value(parser.error_messages_, attr->value(), percent); } attr = node->first_attribute("y"); if (attr != nullptr) { - y = parse_double(parser.error_messages_, attr->value()); + y = parse_svg_value(parser.error_messages_, attr->value(), percent); } attr = node->first_attribute("width"); if (attr != nullptr) { - w = parse_double(parser.error_messages_, attr->value()); + w = parse_svg_value(parser.error_messages_, attr->value(), percent); } attr = node->first_attribute("height"); if (attr) { - h = parse_double(parser.error_messages_, attr->value()); + h = parse_svg_value(parser.error_messages_, attr->value(), percent); } bool rounded = true; attr = node->first_attribute("rx"); if (attr != nullptr) { - rx = parse_double(parser.error_messages_, attr->value()); + rx = parse_svg_value(parser.error_messages_, attr->value(), percent); if ( rx > 0.5 * w ) rx = 0.5 * w; } else rounded = false; @@ -745,7 +777,7 @@ attr = node->first_attribute("ry"); if (attr != nullptr) { - ry = parse_double(parser.error_messages_, attr->value()); + ry = parse_svg_value(parser.error_messages_, attr->value(), percent); if ( ry > 0.5 * h ) ry = 0.5 * h; if (!rounded) { @@ -924,19 +956,19 @@ auto * attr = node->first_attribute("cx"); if (attr != nullptr) { - cx = parse_double_optional_percent(parser.error_messages_, attr->value(), has_percent); + cx = parse_svg_value(parser.error_messages_, attr->value(), has_percent); } attr = node->first_attribute("cy"); if (attr != nullptr) { - cy = parse_double_optional_percent(parser.error_messages_, attr->value(), has_percent); + cy = parse_svg_value(parser.error_messages_, attr->value(), has_percent); } attr = node->first_attribute("fx"); if (attr != nullptr) { - fx = parse_double_optional_percent(parser.error_messages_,attr->value(), has_percent); + fx = parse_svg_value(parser.error_messages_,attr->value(), has_percent); } else fx = cx; @@ -944,7 +976,7 @@ attr = node->first_attribute("fy"); if (attr != nullptr) { - fy = parse_double_optional_percent(parser.error_messages_, attr->value(), has_percent); + fy = parse_svg_value(parser.error_messages_, attr->value(), has_percent); } else fy = cy; @@ -952,7 +984,7 @@ attr = node->first_attribute("r"); if (attr != nullptr) { - r = parse_double_optional_percent(parser.error_messages_, attr->value(), has_percent); + r = parse_svg_value(parser.error_messages_, attr->value(), has_percent); } // this logic for detecting %'s will not support mixed coordinates. if (has_percent && parser.temporary_gradient_.second.get_units() == USER_SPACE_ON_USE) @@ -981,25 +1013,25 @@ auto * attr = node->first_attribute("x1"); if (attr != nullptr) { - x1 = parse_double_optional_percent(parser.error_messages_, attr->value(), has_percent); + x1 = parse_svg_value(parser.error_messages_, attr->value(), has_percent); } attr = node->first_attribute("x2"); if (attr != nullptr) { - x2 = parse_double_optional_percent(parser.error_messages_, attr->value(), has_percent); + x2 = parse_svg_value(parser.error_messages_, attr->value(), has_percent); } attr = node->first_attribute("y1"); if (attr != nullptr) { - y1 = parse_double_optional_percent(parser.error_messages_, attr->value(), has_percent); + y1 = parse_svg_value(parser.error_messages_, attr->value(), has_percent); } attr = node->first_attribute("y2"); if (attr != nullptr) { - y2 = parse_double_optional_percent(parser.error_messages_, attr->value(), has_percent); + y2 = parse_svg_value(parser.error_messages_, attr->value(), has_percent); } // this logic for detecting %'s will not support mixed coordinates. if (has_percent && parser.temporary_gradient_.second.get_units() == USER_SPACE_ON_USE) diff -Nru mapnik-3.0.9+ds/src/svg/svg_path_parser.cpp mapnik-3.0.13+ds/src/svg/svg_path_parser.cpp --- mapnik-3.0.9+ds/src/svg/svg_path_parser.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/svg/svg_path_parser.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -21,32 +21,29 @@ *****************************************************************************/ // mapnik -#include -#include -#include -#include - -// agg -#include "agg_path_storage.h" +#include +#include // stl -#include #include +#include -namespace mapnik { namespace svg { - - template - bool parse_path(const char* wkt, PathType & p) - { - using namespace boost::spirit; - using iterator_type = const char*; - using skip_type = ascii::space_type; - svg_path_grammar g(p); - iterator_type first = wkt; - iterator_type last = wkt + std::strlen(wkt); - return qi::phrase_parse(first, last, g, skip_type()); - } +namespace mapnik { +namespace svg { - template bool parse_path(const char*, svg_converter_type&); +template +bool parse_path(const char* wkt, PathType& p) +{ + using namespace boost::spirit; + using iterator_type = const char*; + using skip_type = ascii::space_type; + static const svg_path_grammar g; + iterator_type first = wkt; + iterator_type last = wkt + std::strlen(wkt); + bool status = qi::phrase_parse(first, last, (g)(boost::phoenix::ref(p)), skip_type()); + return (status && (first == last)); +} +template bool MAPNIK_DECL parse_path(const char*, svg_converter_type&); - }} +} // namespace svg +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/src/svg/svg_points_parser.cpp mapnik-3.0.13+ds/src/svg/svg_points_parser.cpp --- mapnik-3.0.9+ds/src/svg/svg_points_parser.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/svg/svg_points_parser.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -22,26 +22,27 @@ // mapnik #include -#include -#include +#include // stl #include #include -namespace mapnik { namespace svg { +namespace mapnik { +namespace svg { - template - bool parse_points(const char* wkt, PathType & p) - { - using namespace boost::spirit; - using iterator_type = const char* ; - using skip_type = ascii::space_type; - svg_points_grammar g(p); - iterator_type first = wkt; - iterator_type last = wkt + std::strlen(wkt); - return qi::phrase_parse(first, last, g, skip_type()); - } +template +bool parse_points(const char* wkt, PathType& p) +{ + using namespace boost::spirit; + using iterator_type = const char*; + using skip_type = ascii::space_type; + static const svg_points_grammar g; + iterator_type first = wkt; + iterator_type last = wkt + std::strlen(wkt); + return qi::phrase_parse(first, last, (g)(boost::phoenix::ref(p)), skip_type()); +} - template bool parse_points(const char*, svg_converter_type&); +template bool parse_points(const char*, svg_converter_type&); - }} +} // namespace svg +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/src/svg/svg_transform_parser.cpp mapnik-3.0.13+ds/src/svg/svg_transform_parser.cpp --- mapnik-3.0.9+ds/src/svg/svg_transform_parser.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/svg/svg_transform_parser.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -21,27 +21,28 @@ *****************************************************************************/ // mapnik -#include -#include +#include +#include // stl #include #include -namespace mapnik { namespace svg { +namespace mapnik { +namespace svg { - template - bool parse_svg_transform(const char * wkt, TransformType & p) - { - using namespace boost::spirit; - using iterator_type = const char *; - using skip_type = ascii::space_type; - // TODO - make it possible for this to be static const - // by avoiding ctor taking arg - https://github.com/mapnik/mapnik/pull/2231 - svg_transform_grammar g(p); - iterator_type first = wkt; - iterator_type last = wkt + std::strlen(wkt); - return qi::phrase_parse(first, last, g, skip_type()); - } +template +bool parse_svg_transform(const char* wkt, TransformType& tr) +{ + using namespace boost::spirit; + using iterator_type = const char*; + using skip_type = ascii::space_type; + static const svg_transform_grammar g; + iterator_type first = wkt; + iterator_type last = wkt + std::strlen(wkt); + return qi::phrase_parse(first, last, (g)(boost::phoenix::ref(tr)), skip_type()); +} - template MAPNIK_DECL bool parse_svg_transform(const char*, agg::trans_affine&); -}} +template bool MAPNIK_DECL parse_svg_transform(const char*, agg::trans_affine&); + +} // namespace svg +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/src/text/face.cpp mapnik-3.0.13+ds/src/text/face.cpp --- mapnik-3.0.9+ds/src/text/face.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/face.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,11 +23,16 @@ #include #include +#pragma GCC diagnostic push +#include + extern "C" { #include FT_GLYPH_H } +#pragma GCC diagnostic pop + namespace mapnik { @@ -36,7 +41,7 @@ bool font_face::set_character_sizes(double size) { - return (FT_Set_Char_Size(face_,0,(FT_F26Dot6)(size * (1<<6)),0,0) == 0); + return (FT_Set_Char_Size(face_,0,static_cast(size * (1<<6)),0,0) == 0); } bool font_face::set_unscaled_character_sizes() @@ -108,7 +113,7 @@ void stroker::init(double radius) { - FT_Stroker_Set(s_, (FT_Fixed) (radius * (1<<6)), + FT_Stroker_Set(s_, static_cast(radius * (1<<6)), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); diff -Nru mapnik-3.0.9+ds/src/text/font_library.cpp mapnik-3.0.13+ds/src/text/font_library.cpp --- mapnik-3.0.9+ds/src/text/font_library.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/font_library.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -28,6 +28,9 @@ #include #include +#pragma GCC diagnostic push +#include + // freetype2 extern "C" { @@ -36,6 +39,8 @@ #include FT_MODULE_H } +#pragma GCC diagnostic pop + namespace { void* _Alloc_Func(FT_Memory, long size) diff -Nru mapnik-3.0.9+ds/src/text/formatting/format.cpp mapnik-3.0.13+ds/src/text/formatting/format.cpp --- mapnik-3.0.9+ds/src/text/formatting/format.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/formatting/format.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,9 +30,11 @@ #include #include -//boost +#pragma GCC diagnostic push +#include #include #include +#pragma GCC diagnostic pop namespace mapnik { namespace formatting { diff -Nru mapnik-3.0.9+ds/src/text/formatting/layout.cpp mapnik-3.0.13+ds/src/text/formatting/layout.cpp --- mapnik-3.0.9+ds/src/text/formatting/layout.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/formatting/layout.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -35,8 +35,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { namespace formatting { @@ -73,9 +75,9 @@ if (xml.has_attribute("text-ratio")) set_property_from_xml(n->text_ratio, "text-ratio", xml); if (xml.has_attribute("wrap-width")) set_property_from_xml(n->wrap_width, "wrap-width", xml); if (xml.has_attribute("wrap-character")) set_property_from_xml(n->wrap_char, "wrap-character", xml); - if (xml.has_attribute("wrap-before")) set_property_from_xml(n->wrap_before, "wrap-before", xml); - if (xml.has_attribute("repeat-wrap-character")) set_property_from_xml(n->repeat_wrap_char, "repeat-wrap-character", xml); - if (xml.has_attribute("rotate-displacement")) set_property_from_xml(n->rotate_displacement, "rotate-displacement", xml); + if (xml.has_attribute("wrap-before")) set_property_from_xml(n->wrap_before, "wrap-before", xml); + if (xml.has_attribute("repeat-wrap-character")) set_property_from_xml(n->repeat_wrap_char, "repeat-wrap-character", xml); + if (xml.has_attribute("rotate-displacement")) set_property_from_xml(n->rotate_displacement, "rotate-displacement", xml); if (xml.has_attribute("orientation")) set_property_from_xml(n->orientation, "orientation", xml); if (xml.has_attribute("horizontal-alignment")) set_property_from_xml(n->halign, "horizontal-alignment", xml); if (xml.has_attribute("vertical-alignment")) set_property_from_xml(n->valign, "vertical-alignment", xml); diff -Nru mapnik-3.0.9+ds/src/text/formatting/list.cpp mapnik-3.0.13+ds/src/text/formatting/list.cpp --- mapnik-3.0.9+ds/src/text/formatting/list.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/formatting/list.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,8 +25,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { using boost::property_tree::ptree; diff -Nru mapnik-3.0.9+ds/src/text/formatting/text.cpp mapnik-3.0.13+ds/src/text/formatting/text.cpp --- mapnik-3.0.9+ds/src/text/formatting/text.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/formatting/text.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,8 +30,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/text/glyph_positions.cpp mapnik-3.0.13+ds/src/text/glyph_positions.cpp --- mapnik-3.0.9+ds/src/text/glyph_positions.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/glyph_positions.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -74,7 +74,7 @@ marker_pos_ = marker_pos; } -marker_info_ptr glyph_positions::get_marker() const +marker_info_ptr const& glyph_positions::get_marker() const { return marker_info_; } diff -Nru mapnik-3.0.9+ds/src/text/placement_finder.cpp mapnik-3.0.13+ds/src/text/placement_finder.cpp --- mapnik-3.0.9+ds/src/text/placement_finder.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/placement_finder.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -39,6 +39,41 @@ namespace mapnik { +namespace { +box2d get_bbox(text_layout const& layout, glyph_info const& glyph, pixel_position const& pos, rotation const& rot) +{ + /* + + (0/ymax) (width/ymax) + *************** + * * + (0/0)* * + * * + *************** + (0/ymin) (width/ymin) + Add glyph offset in y direction, but not in x direction (as we use the full cluster width anyways)! + */ + double width = layout.cluster_width(glyph.char_index); + if (glyph.advance() <= 0) width = -width; + pixel_position tmp, tmp2; + tmp.set(0, glyph.ymax()); + tmp = tmp.rotate(rot); + tmp2.set(width, glyph.ymax()); + tmp2 = tmp2.rotate(rot); + box2d bbox(tmp.x, -tmp.y, + tmp2.x, -tmp2.y); + tmp.set(width, glyph.ymin()); + tmp = tmp.rotate(rot); + bbox.expand_to_include(tmp.x, -tmp.y); + tmp.set(0, glyph.ymin()); + tmp = tmp.rotate(rot); + bbox.expand_to_include(tmp.x, -tmp.y); + pixel_position pos2 = pos + pixel_position(0, glyph.offset.y).rotate(rot); + bbox.move(pos2.x , -pos2.y); + return bbox; +} +} // anonymous namespace + placement_finder::placement_finder(feature_impl const& feature, attributes const& attr, DetectorType &detector, @@ -432,37 +467,4 @@ return true; } -box2d placement_finder::get_bbox(text_layout const& layout, glyph_info const& glyph, pixel_position const& pos, rotation const& rot) -{ - /* - - (0/ymax) (width/ymax) - *************** - * * - (0/0)* * - * * - *************** - (0/ymin) (width/ymin) - Add glyph offset in y direction, but not in x direction (as we use the full cluster width anyways)! - */ - double width = layout.cluster_width(glyph.char_index); - if (glyph.advance() <= 0) width = -width; - pixel_position tmp, tmp2; - tmp.set(0, glyph.ymax()); - tmp = tmp.rotate(rot); - tmp2.set(width, glyph.ymax()); - tmp2 = tmp2.rotate(rot); - box2d bbox(tmp.x, -tmp.y, - tmp2.x, -tmp2.y); - tmp.set(width, glyph.ymin()); - tmp = tmp.rotate(rot); - bbox.expand_to_include(tmp.x, -tmp.y); - tmp.set(0, glyph.ymin()); - tmp = tmp.rotate(rot); - bbox.expand_to_include(tmp.x, -tmp.y); - pixel_position pos2 = pos + pixel_position(0, glyph.offset.y).rotate(rot); - bbox.move(pos2.x , -pos2.y); - return bbox; -} - }// ns mapnik diff -Nru mapnik-3.0.9+ds/src/text/placements/list.cpp mapnik-3.0.13+ds/src/text/placements/list.cpp --- mapnik-3.0.9+ds/src/text/placements/list.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/placements/list.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,8 +24,10 @@ #include #include -//boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/text/renderer.cpp mapnik-3.0.13+ds/src/text/renderer.cpp --- mapnik-3.0.9+ds/src/text/renderer.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/renderer.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -60,7 +60,9 @@ FT_Vector pen; FT_Error error; + glyphs_.clear(); glyphs_.reserve(positions.size()); + for (auto const& glyph_pos : positions) { glyph_info const& glyph = glyph_pos.glyph; @@ -121,7 +123,6 @@ template void agg_text_renderer::render(glyph_positions const& pos) { - glyphs_.clear(); prepare_glyphs(pos); FT_Error error; FT_Vector start; @@ -232,7 +233,6 @@ template void grid_text_renderer::render(glyph_positions const& pos, value_integer feature_id) { - glyphs_.clear(); prepare_glyphs(pos); FT_Error error; FT_Vector start; diff -Nru mapnik-3.0.9+ds/src/text/scrptrun.cpp mapnik-3.0.13+ds/src/text/scrptrun.cpp --- mapnik-3.0.9+ds/src/text/scrptrun.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/scrptrun.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -14,8 +14,11 @@ * http://source.icu-project.org/repos/icu/icu/trunk/license.html */ +#pragma GCC diagnostic push +#include #include #include +#pragma GCC diagnostic pop #include diff -Nru mapnik-3.0.9+ds/src/text/symbolizer_helpers.cpp mapnik-3.0.13+ds/src/text/symbolizer_helpers.cpp --- mapnik-3.0.9+ds/src/text/symbolizer_helpers.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/symbolizer_helpers.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -41,8 +41,39 @@ #include #include +namespace mapnik { +namespace geometry { -namespace mapnik { namespace detail { +struct envelope_impl +{ + template + box2d operator() (T const& ref) const + { + return envelope(ref); + } +}; + +mapnik::box2d envelope(mapnik::base_symbolizer_helper::geometry_cref const& geom) +{ + return mapnik::util::apply_visitor(envelope_impl(), geom); +} + +struct geometry_type_impl +{ + template + auto operator() (T const& ref) const -> decltype(geometry_type(ref)) + { + return geometry_type(ref); + } +}; + +mapnik::geometry::geometry_types geometry_type(mapnik::base_symbolizer_helper::geometry_cref const& geom) +{ + return mapnik::util::apply_visitor(geometry_type_impl(), geom); +} + +} // geometry +namespace detail { template struct apply_vertex_placement @@ -156,23 +187,26 @@ initialize_points(); } -struct largest_bbox_first +template +static It largest_bbox(It begin, It end) { - bool operator() (geometry::geometry const* g0, geometry::geometry const* g1) const + if (begin == end) { - box2d b0 = geometry::envelope(*g0); - box2d b1 = geometry::envelope(*g1); - return b0.width() * b0.height() > b1.width() * b1.height(); + return end; } - bool operator() (base_symbolizer_helper::geometry_cref const& g0, - base_symbolizer_helper::geometry_cref const& g1) const + It largest_geom = begin; + double largest_bbox = geometry::envelope(*largest_geom).area(); + for (++begin; begin != end; ++begin) { - // TODO - this has got to be expensive! Can we cache bbox's if there are repeated calls to same geom? - box2d b0 = geometry::envelope(g0); - box2d b1 = geometry::envelope(g1); - return b0.width() * b0.height() > b1.width() * b1.height(); + double bbox = geometry::envelope(*begin).area(); + if (bbox > largest_bbox) + { + largest_bbox = bbox; + largest_geom = begin; + } } -}; + return largest_geom; +} void base_symbolizer_helper::initialize_geometries() const { @@ -185,10 +219,16 @@ type == geometry::geometry_types::MultiPolygon) { bool largest_box_only = text_props_->largest_bbox_only; - if (largest_box_only) + if (largest_box_only && geometries_to_process_.size() > 1) { - geometries_to_process_.sort(largest_bbox_first()); + auto largest_geom = largest_bbox( + geometries_to_process_.begin(), + geometries_to_process_.end()); geo_itr_ = geometries_to_process_.begin(); + if (geo_itr_ != largest_geom) + { + std::swap(*geo_itr_, *largest_geom); + } geometries_to_process_.erase(++geo_itr_, geometries_to_process_.end()); } } @@ -389,7 +429,7 @@ return true; } //No placement for this point. Keep it in points_ for next try. - point_itr_++; + ++point_itr_; } return false; } @@ -434,7 +474,7 @@ if (marker->is()) return; agg::trans_affine trans; auto image_transform = get_optional(sym_, keys::image_transform); - if (image_transform) evaluate_transform(trans, feature_, vars_, *image_transform); + if (image_transform) evaluate_transform(trans, feature_, vars_, *image_transform, scale_factor_); double width = marker->width(); double height = marker->height(); double px0 = - 0.5 * width; @@ -460,7 +500,6 @@ finder_.set_marker(std::make_shared(marker, trans), bbox, unlock_image, marker_displacement); } - template text_symbolizer_helper::text_symbolizer_helper( text_symbolizer const& sym, feature_impl const& feature, diff -Nru mapnik-3.0.9+ds/src/text/text_layout.cpp mapnik-3.0.13+ds/src/text/text_layout.cpp --- mapnik-3.0.9+ds/src/text/text_layout.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/text_layout.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,8 +29,11 @@ #include #include -// ICU +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop + #include namespace mapnik diff -Nru mapnik-3.0.9+ds/src/text/text_line.cpp mapnik-3.0.13+ds/src/text/text_line.cpp --- mapnik-3.0.9+ds/src/text/text_line.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/text_line.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -51,7 +51,7 @@ void text_line::add_glyph(glyph_info && glyph, double scale_factor_) { - line_height_ = std::max(line_height_, glyph.line_height() + glyph.format->line_spacing); + line_height_ = std::max(line_height_, glyph.line_height() + glyph.format->line_spacing * scale_factor_); double advance = glyph.advance(); if (glyphs_.empty()) { diff -Nru mapnik-3.0.9+ds/src/text/text_properties.cpp mapnik-3.0.13+ds/src/text/text_properties.cpp --- mapnik-3.0.9+ds/src/text/text_properties.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/text/text_properties.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -34,8 +34,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { @@ -101,9 +103,9 @@ set_property_from_xml(expressions.label_position_tolerance, "label-position-tolerance", node); set_property_from_xml(expressions.minimum_padding, "minimum-padding", node); set_property_from_xml(expressions.minimum_path_length, "minimum-path-length", node); - set_property_from_xml(expressions.avoid_edges, "avoid-edges", node); - set_property_from_xml(expressions.allow_overlap, "allow-overlap", node); - set_property_from_xml(expressions.largest_bbox_only, "largest-bbox-only", node); + set_property_from_xml(expressions.avoid_edges, "avoid-edges", node); + set_property_from_xml(expressions.allow_overlap, "allow-overlap", node); + set_property_from_xml(expressions.largest_bbox_only, "largest-bbox-only", node); set_property_from_xml(expressions.max_char_angle_delta, "max-char-angle-delta", node); set_property_from_xml(expressions.upright, "upright", node); } @@ -213,9 +215,9 @@ set_property_from_xml(text_ratio, "text-ratio", node); set_property_from_xml(wrap_width, "wrap-width", node); set_property_from_xml(wrap_char, "wrap-character", node); - set_property_from_xml(wrap_before, "wrap-before", node); - set_property_from_xml(repeat_wrap_char, "repeat-wrap-character", node); - set_property_from_xml(rotate_displacement, "rotate-displacement", node); + set_property_from_xml(wrap_before, "wrap-before", node); + set_property_from_xml(repeat_wrap_char, "repeat-wrap-character", node); + set_property_from_xml(rotate_displacement, "rotate-displacement", node); set_property_from_xml(orientation, "orientation", node); set_property_from_xml(valign, "vertical-alignment", node); set_property_from_xml(halign, "horizontal-alignment", node); diff -Nru mapnik-3.0.9+ds/src/tiff_reader.cpp mapnik-3.0.13+ds/src/tiff_reader.cpp --- mapnik-3.0.9+ds/src/tiff_reader.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/tiff_reader.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -23,21 +23,15 @@ // mapnik #include #include - +#include extern "C" { #include } -#pragma GCC diagnostic push -#include -#include -#include -#include -#pragma GCC diagnostic pop - // stl #include +#include namespace mapnik { namespace impl { @@ -106,7 +100,7 @@ { using tiff_ptr = std::shared_ptr; using source_type = T; - using input_stream = boost::iostreams::stream; + using input_stream = std::istream; struct tiff_closer { @@ -145,7 +139,7 @@ stripped, tiled }; - explicit tiff_reader(std::string const& file_name); + explicit tiff_reader(std::string const& filename); tiff_reader(char const* data, std::size_t size); virtual ~tiff_reader(); unsigned width() const final; @@ -183,14 +177,14 @@ namespace { -image_reader* create_tiff_reader(std::string const& file) +image_reader* create_tiff_reader(std::string const& filename) { - return new tiff_reader(file); + return new tiff_reader(filename); } image_reader* create_tiff_reader2(char const * data, std::size_t size) { - return new tiff_reader(data, size); + return new tiff_reader(data, size); } const bool registered = register_image_reader("tiff",create_tiff_reader); @@ -199,9 +193,9 @@ } template -tiff_reader::tiff_reader(std::string const& file_name) - : source_(file_name, std::ios_base::in | std::ios_base::binary), - stream_(source_), +tiff_reader::tiff_reader(std::string const& filename) + : source_(), + stream_(&source_), tif_(nullptr), read_method_(generic), rows_per_strip_(0), @@ -218,14 +212,15 @@ has_alpha_(false), is_tiled_(false) { - if (!stream_) throw image_reader_exception("TIFF reader: cannot open file "+ file_name); + source_.open(filename, std::ios_base::in | std::ios_base::binary); + if (!stream_) throw image_reader_exception("TIFF reader: cannot open file "+ filename); init(); } template tiff_reader::tiff_reader(char const* data, std::size_t size) : source_(data, size), - stream_(source_), + stream_(&source_), tif_(nullptr), read_method_(generic), rows_per_strip_(0), @@ -243,8 +238,6 @@ is_tiled_(false) { if (!stream_) throw image_reader_exception("TIFF reader: cannot open image stream "); - stream_.rdbuf()->pubsetbuf(0, 0); - stream_.seekg(0, std::ios::beg); init(); } @@ -598,13 +591,9 @@ } template -void tiff_reader::read_generic(std::size_t, std::size_t, image_rgba8& image) +void tiff_reader::read_generic(std::size_t, std::size_t, image_rgba8&) { - TIFF* tif = open(stream_); - if (tif) - { - throw std::runtime_error("tiff_reader: TODO - tiff is not stripped or tiled"); - } + throw std::runtime_error("tiff_reader: TODO - tiff is not stripped or tiled"); } template diff -Nru mapnik-3.0.9+ds/src/twkb.cpp mapnik-3.0.13+ds/src/twkb.cpp --- mapnik-3.0.9+ds/src/twkb.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/src/twkb.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,387 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + + +// mapnik +#include +#include +#include +#include +#include +#include + +namespace mapnik { namespace detail { + +struct twkb_reader : mapnik::util::noncopyable +{ +private: + const char *twkb_; + size_t size_; + unsigned int pos_; + // Metadata on the geometry we are parsing + uint8_t twkb_type_; + uint8_t has_bbox_; + uint8_t has_size_; + uint8_t has_idlist_; + uint8_t has_z_; + uint8_t has_m_; + uint8_t is_empty_; + // Precision factors to convert ints to double + double factor_xy_; + double factor_z_; + double factor_m_; + // An array to keep delta values from 4 dimensions + int64_t coord_x_; + int64_t coord_y_; + int64_t coord_z_; + int64_t coord_m_; + +public: + enum twkbGeometryType : std::uint8_t + { + twkbPoint = 1, + twkbLineString = 2, + twkbPolygon = 3, + twkbMultiPoint = 4, + twkbMultiLineString = 5, + twkbMultiPolygon = 6, + twkbGeometryCollection = 7 + }; + + twkb_reader(char const* twkb, size_t size) + : twkb_(twkb), size_(size), pos_(0), twkb_type_(0), // Geometry type + has_bbox_(0), // Bounding box? + has_size_(0), // Size attribute? + has_idlist_(0), // Presence of X/Y + has_z_(0), // Presence of Z + has_m_(0), // Presence of M + is_empty_(0), // Empty? + factor_xy_(0.0), // Expansion factor for X/Y + factor_z_(0.0), // Expansion factor for Z + factor_m_(0.0) // Expansion factor for M + {} + + mapnik::geometry::geometry read() + { + mapnik::geometry::geometry geom = mapnik::geometry::geometry_empty(); + // Read the metadata bytes, populating all the + // information about optional fields, extended (z/m) dimensions + // expansion factors and so on + read_header(); + + // Each new read call has to reset the coordinate accumulators + coord_x_ = 0; // Accumulation register (x) + coord_y_ = 0; // Accumulation register (y) + coord_z_ = 0; // Accumulation register (z) + coord_m_ = 0; // Accumulation register (m) + + // If the geometry is empty, add nothing to the paths array + if (is_empty_) + return geom; + + // Read the [optional] size information + if (has_size_) + size_ = read_unsigned_integer(); + + // Read the [optional] bounding box information + if (has_bbox_) read_bbox(); + + switch (twkb_type_) + { + case twkbPoint: + geom = read_point(); + break; + case twkbLineString: + geom = read_linestring(); + break; + case twkbPolygon: + geom = read_polygon(); + break; + case twkbMultiPoint: + geom = read_multipoint(); + break; + case twkbMultiLineString: + geom = read_multilinestring(); + break; + case twkbMultiPolygon: + geom = read_multipolygon(); + break; + case twkbGeometryCollection: + geom = read_collection(); + default: + break; + } + return geom; + } + +private: + int64_t unzigzag64(uint64_t val) + { + if (val & 0x01) + return -1 * (int64_t)((val + 1) >> 1); + else + return (int64_t)(val >> 1); + } + + int32_t unzigzag32(uint32_t val) + { + if (val & 0x01) return -1 * (int32_t)((val + 1) >> 1); + else return (int32_t)(val >> 1); + } + + int8_t unzigzag8(uint8_t val) + { + if (val & 0x01) return -1 * (int8_t)((val + 1) >> 1); + else return (int8_t)(val >> 1); + } + + // Read from signed 64bit varint + int64_t read_signed_integer() { return unzigzag64(read_unsigned_integer()); } + + // Read from unsigned 64bit varint + uint64_t read_unsigned_integer() + { + uint64_t nVal = 0; + int nShift = 0; + uint8_t nByte; + + // Check so we don't read beyond the twkb + while (pos_ < size_) + { + nByte = twkb_[pos_]; + // We get here when there is more to read in the input varInt + // Here we take the least significant 7 bits of the read + // byte and put it in the most significant place in the result variable. + nVal |= ((uint64_t)(nByte & 0x7f)) << nShift; + // move the "cursor" of the input buffer step (8 bits) + pos_++; + // move the cursor in the resulting variable (7 bits) + nShift += 7; + // Hibit isn't set, so this is the last byte + if (!(nByte & 0x80)) { + return nVal; + } + } + return 0; + } + + // Every TWKB geometry starts with a metadata header + // + // type_and_dims byte + // metadata_header byte + // [extended_dims] byte + // [size] uvarint + // [bounds] bbox + // + void read_header() + { + uint8_t type_precision = twkb_[pos_++]; + uint8_t metadata = twkb_[pos_++]; + twkb_type_ = type_precision & 0x0F; + int8_t precision = unzigzag8((type_precision & 0xF0) >> 4); + factor_xy_ = std::pow(10, static_cast(precision)); + has_bbox_ = metadata & 0x01; + has_size_ = (metadata & 0x02) >> 1; + has_idlist_ = (metadata & 0x04) >> 2; + uint8_t zm = (metadata & 0x08) >> 3; + is_empty_ = (metadata & 0x10) >> 4; + + // Flag for higher dimensions means read a third byte + // of extended dimension information + if (zm) + { + zm = twkb_[pos_++]; + // Strip Z/M presence and precision from ext byte + has_z_ = (zm & 0x01); + has_m_ = (zm & 0x02) >> 1; + // Convert the precision into factor + int8_t precision_z = (zm & 0x1C) >> 2; + int8_t precision_m = (zm & 0xE0) >> 5; + factor_z_ = pow(10, (double)precision_z); + factor_m_ = pow(10, (double)precision_m); + } + } + + void read_bbox() + { + // we have nowhere to store this box information + // for now, so we'll just move the read head forward + // an appropriate number of times + if (has_bbox_) + { + read_signed_integer(); // uint64_t xmin + read_signed_integer(); // uint64_t xdelta + read_signed_integer(); // uint64_t ymin + read_signed_integer(); // uint64_t ydelta + if (has_z_) + { + read_signed_integer(); // uint64_t zmin + read_signed_integer(); // uint64_t zdelta + } + if (has_m_) + { + read_signed_integer(); // uint64_t mmin + read_signed_integer(); // uint64_t mdelta + } + } + } + + void read_idlist(unsigned int num_ids) + { + // we have nowhere to store this id information + // for now, so we'll just move the read head + // forward an appropriate number of times + if (has_idlist_) + { + for (unsigned int i = 0; i < num_ids; ++i) + { + read_signed_integer(); // uint64_t id + } + } + } + + template + void read_coords(Ring & ring, std::size_t num_points) + { + for (std::size_t i = 0; i < num_points; ++i) + { + coord_x_ += read_signed_integer(); + coord_y_ += read_signed_integer(); + ring.emplace_back( coord_x_ / factor_xy_, coord_y_ / factor_xy_); + // Skip Z and M + if (has_z_) coord_z_ += read_signed_integer(); + if (has_m_) coord_m_ += read_signed_integer(); + } + } + + mapnik::geometry::point read_point() + { + coord_x_ += read_signed_integer(); + coord_y_ += read_signed_integer(); + double x = coord_x_ / factor_xy_; + double y = coord_y_ / factor_xy_; + return mapnik::geometry::point(x, y); + } + + mapnik::geometry::multi_point read_multipoint() + { + mapnik::geometry::multi_point multi_point; + unsigned int num_points = read_unsigned_integer(); + if (has_idlist_) read_idlist(num_points); + + if (num_points > 0) + { + multi_point.reserve(num_points); + for (unsigned int i = 0; i < num_points; ++i) + { + multi_point.emplace_back(read_point()); + } + } + return multi_point; + } + + mapnik::geometry::line_string read_linestring() + { + mapnik::geometry::line_string line; + unsigned int num_points = read_unsigned_integer(); + if (num_points > 0) + { + line.reserve(num_points); + read_coords>(line, num_points); + } + return line; + } + + mapnik::geometry::multi_line_string read_multilinestring() + { + mapnik::geometry::multi_line_string multi_line; + unsigned int num_lines = read_unsigned_integer(); + if (has_idlist_) read_idlist(num_lines); + multi_line.reserve(num_lines); + for (unsigned int i = 0; i < num_lines; ++i) + { + multi_line.push_back(read_linestring()); + } + return multi_line; + } + + mapnik::geometry::polygon read_polygon() + { + unsigned int num_rings = read_unsigned_integer(); + mapnik::geometry::polygon poly; + if (num_rings > 1) + { + poly.interior_rings.reserve(num_rings - 1); + } + + for (unsigned int i = 0; i < num_rings; ++i) + { + mapnik::geometry::linear_ring ring; + unsigned int num_points = read_unsigned_integer(); + if (num_points > 0) + { + ring.reserve(num_points); + read_coords>(ring, num_points); + } + if ( i == 0) poly.set_exterior_ring(std::move(ring)); + else poly.add_hole(std::move(ring)); + } + return poly; + } + + mapnik::geometry::multi_polygon read_multipolygon() + { + mapnik::geometry::multi_polygon multi_poly; + unsigned int num_polys = read_unsigned_integer(); + if (has_idlist_) read_idlist(num_polys); + for (unsigned int i = 0; i < num_polys; ++i) + { + multi_poly.push_back(read_polygon()); + } + return multi_poly; + } + + mapnik::geometry::geometry_collection read_collection() + { + unsigned int num_geometries = read_unsigned_integer(); + mapnik::geometry::geometry_collection collection; + if (has_idlist_) read_idlist(num_geometries); + for (unsigned int i = 0; i < num_geometries; ++i) + { + collection.push_back(read()); + } + return collection; + } +}; + +} // namespace detail + +mapnik::geometry::geometry geometry_utils::from_twkb(const char* wkb, std::size_t size) +{ + detail::twkb_reader reader(wkb, size); + mapnik::geometry::geometry geom(reader.read()); + // note: this will only be applied to polygons + mapnik::geometry::correct(geom); + return geom; +} + +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/src/unicode.cpp mapnik-3.0.13+ds/src/unicode.cpp --- mapnik-3.0.9+ds/src/unicode.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/unicode.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -27,8 +27,10 @@ // std #include -// icu +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { @@ -60,4 +62,12 @@ { if (conv_) ucnv_close(conv_); } + + +void to_utf8(mapnik::value_unicode_string const& input, std::string & target) +{ + target.clear(); // mimic previous target.assign(...) semantics + input.toUTF8String(target); // this appends to target +} + } diff -Nru mapnik-3.0.9+ds/src/value.cpp mapnik-3.0.13+ds/src/value.cpp --- mapnik-3.0.9+ds/src/value.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/src/value.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,928 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +// mapnik +#include +#include +#include + +// stl +#include +#include +#include +// icu +#include +#include + +namespace mapnik { + +namespace detail { + +namespace { +template +struct both_arithmetic : std::integral_constant::value && + std::is_arithmetic::value> {}; + +struct equals +{ + static bool apply(value_null, value_unicode_string const& rhs) + { + return false; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs == rhs) + { + return lhs == rhs; + } +}; + +struct not_equal +{ + // back compatibility shim to equate empty string with null for != test + // https://github.com/mapnik/mapnik/issues/1859 + // TODO - consider removing entire specialization at Mapnik 3.1.x + static bool apply(value_null, value_unicode_string const& rhs) + { + if (rhs.isEmpty()) return false; + return true; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs != rhs) + { + return lhs != rhs; + } +}; + +struct greater_than +{ + static bool apply(value_null, value_unicode_string const& rhs) + { + return false; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs > rhs) + { + return lhs > rhs; + } +}; + +struct greater_or_equal +{ + static bool apply(value_null, value_unicode_string const& rhs) + { + return false; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs >= rhs) + { + return lhs >= rhs; + } +}; + +struct less_than +{ + static bool apply(value_null, value_unicode_string const& rhs) + { + return false; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs < rhs) + { + return lhs < rhs; + } +}; + +struct less_or_equal +{ + static bool apply(value_null, value_unicode_string const& rhs) + { + return false; + } + + template + static auto apply(T const& lhs, T const& rhs) + -> decltype(lhs <= rhs) + { + return lhs <= rhs; + } +}; +} + +template +struct comparison +{ + // special case for unicode_strings (fixes MSVC C4800) + bool operator()(value_unicode_string const& lhs, + value_unicode_string const& rhs) const + { + return Op::apply(lhs, rhs) ? true : false; + } + + ////////////////////////////////////////////////////////////////////////// + // special case for unicode_string and value_null + ////////////////////////////////////////////////////////////////////////// + + bool operator()(value_null const& lhs, value_unicode_string const& rhs) const + { + return Op::apply(lhs, rhs); + } + ////////////////////////////////////////////////////////////////////////// + + // same types + template + bool operator()(T lhs, T rhs) const + { + return Op::apply(lhs, rhs); + } + + // both types are arithmetic - promote to the common type + template ::value, int>::type = 0> + bool operator()(T const& lhs, U const& rhs) const + { + using common_type = typename std::common_type::type; + return Op::apply(static_cast(lhs), static_cast(rhs)); + } + + // + template ::value, int>::type = 0> + bool operator()(T const& lhs, U const& rhs) const + { + return default_result; + } +}; + +template +struct add +{ + using value_type = V; + value_type operator()(value_unicode_string const& lhs, + value_unicode_string const& rhs) const + { + return lhs + rhs; + } + + value_type operator()(value_null const& lhs, + value_null const& rhs) const + { + return lhs; + } + + value_type operator()(value_unicode_string const& lhs, value_null) const + { + return lhs; + } + + value_type operator()(value_null, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(L const& lhs, value_null const&) const + { + return lhs; + } + + template + value_type operator()(value_null const&, R const& rhs) const + { + return rhs; + } + + template + value_type operator()(L const& lhs, value_unicode_string const& rhs) const + { + std::string val; + if (util::to_string(val, lhs)) + return value_unicode_string(val.c_str()) + rhs; + return rhs; + } + + template + value_type operator()(value_unicode_string const& lhs, R const& rhs) const + { + std::string val; + if (util::to_string(val, rhs)) + return lhs + value_unicode_string(val.c_str()); + return lhs; + } + + template + value_type operator()(T1 const& lhs, T2 const& rhs) const + { + return typename std::common_type::type{lhs + rhs}; + } + + value_type operator()(value_bool lhs, value_bool rhs) const + { + return value_integer(lhs + rhs); + } +}; + +template +struct sub +{ + using value_type = V; + + value_type operator()(value_null const& lhs, + value_null const& rhs) const + { + return lhs; + } + + value_type operator()(value_null, value_unicode_string const& rhs) const + { + return rhs; + } + value_type operator()(value_unicode_string const& lhs, value_null) const + { + return lhs; + } + + template + value_type operator()(value_unicode_string const& lhs, R const&) const + { + return lhs; + } + + template + value_type operator()(L const&, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(L const& lhs, value_null const&) const + { + return lhs; + } + + template + value_type operator()(value_null const&, R const& rhs) const + { + return rhs; + } + + template + value_type operator()(T lhs, T rhs) const + { + return lhs - rhs; + } + + value_type operator()(value_unicode_string const&, + value_unicode_string const&) const + { + return value_type(); + } + + template + value_type operator()(T1 const& lhs, T2 const& rhs) const + { + return typename std::common_type::type{lhs - rhs}; + } + + value_type operator()(value_bool lhs, value_bool rhs) const + { + return value_integer(lhs - rhs); + } +}; + +template +struct mult +{ + using value_type = V; + + value_type operator()(value_null const& lhs, + value_null const& rhs) const + { + return lhs; + } + + value_type operator()(value_unicode_string const& lhs, value_null) const + { + return lhs; + } + + value_type operator()(value_null, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(L const& lhs, value_null const&) const + { + return lhs; + } + + template + value_type operator()(value_null const&, R const& rhs) const + { + return rhs; + } + + template + value_type operator()(value_unicode_string const& lhs, R const&) const + { + return lhs; + } + + template + value_type operator()(L const&, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(T lhs, T rhs) const + { + return lhs * rhs; + } + + value_type operator()(value_unicode_string const&, + value_unicode_string const&) const + { + return value_type(); + } + + template + value_type operator()(T1 const& lhs, T2 const& rhs) const + { + return typename std::common_type::type{lhs * rhs}; + } + + value_type operator()(value_bool lhs, value_bool rhs) const + { + return value_integer(lhs * rhs); + } +}; + +template +struct div +{ + using value_type = V; + + value_type operator()(value_null const& lhs, + value_null const& rhs) const + { + return lhs; + } + + value_type operator()(value_unicode_string const& lhs, value_null) const + { + return lhs; + } + + value_type operator()(value_null, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(L const& lhs, value_null const&) const + { + return lhs; + } + + template + value_type operator()(value_null const&, R const& rhs) const + { + return rhs; + } + + template + value_type operator()(T lhs, T rhs) const + { + if (rhs == 0) return value_type(); + return lhs / rhs; + } + + value_type operator()(value_bool lhs, value_bool rhs) const + { + if (rhs == 0) return lhs; + return value_integer(lhs) / value_integer(rhs); + } + + value_type operator()(value_unicode_string const&, + value_unicode_string const&) const + { + return value_type(); + } + + template + value_type operator()(value_unicode_string const& lhs, R const&) const + { + return lhs; + } + + template + value_type operator()(L const&, value_unicode_string const& rhs) const + { + return rhs; + } + + template + value_type operator()(T1 const& lhs, T2 const& rhs) const + { + if (rhs == 0) return value_type(); + using common_type = typename std::common_type::type; + return common_type(lhs) / common_type(rhs); + } +}; + +template +struct mod +{ + using value_type = V; + + template + value_type operator()(T1 const& lhs, T2 const&) const + { + return lhs; + } + + template + value_type operator()(T lhs, T rhs) const + { + return lhs % rhs; + } + + value_type operator()(value_unicode_string const&, + value_unicode_string const&) const + { + return value_type(); + } + + value_type operator()(value_bool, + value_bool) const + { + return false; + } + + value_type operator()(value_double lhs, value_integer rhs) const + { + return std::fmod(lhs, static_cast(rhs)); + } + + value_type operator()(value_integer lhs, value_double rhs) const + { + return std::fmod(static_cast(lhs), rhs); + } + + value_type operator()(value_double lhs, value_double rhs) const + { + return std::fmod(lhs, rhs); + } +}; + +template +struct negate +{ + using value_type = V; + + template + value_type operator()(T val) const + { + return -val; + } + + value_type operator()(value_null val) const + { + return val; + } + + value_type operator()(value_bool val) const + { + return val ? value_integer(-1) : value_integer(0); + } + + value_type operator()(value_unicode_string const&) const + { + return value_type(); + } +}; + +// converters +template +struct convert +{ +}; + +template <> +struct convert +{ + value_bool operator()(value_bool val) const + { + return val; + } + + value_bool operator()(value_unicode_string const& ustr) const + { + return !ustr.isEmpty(); + } + + value_bool operator()(value_null const&) const + { + return false; + } + + template + value_bool operator()(T val) const + { + return val > 0 ? true : false; + } +}; + +template <> +struct convert +{ + value_double operator()(value_double val) const + { + return val; + } + + value_double operator()(value_integer val) const + { + return static_cast(val); + } + + value_double operator()(value_bool val) const + { + return static_cast(val); + } + + value_double operator()(std::string const& val) const + { + value_double result; + if (util::string2double(val, result)) + return result; + return 0; + } + + value_double operator()(value_unicode_string const& val) const + { + std::string utf8; + val.toUTF8String(utf8); + return operator()(utf8); + } + + value_double operator()(value_null const&) const + { + return 0.0; + } +}; + +template <> +struct convert +{ + value_integer operator()(value_integer val) const + { + return val; + } + + value_integer operator()(value_double val) const + { + return static_cast(rint(val)); + } + + value_integer operator()(value_bool val) const + { + return static_cast(val); + } + + value_integer operator()(std::string const& val) const + { + value_integer result; + if (util::string2int(val, result)) + return result; + return value_integer(0); + } + + value_integer operator()(value_unicode_string const& val) const + { + std::string utf8; + val.toUTF8String(utf8); + return operator()(utf8); + } + + value_integer operator()(value_null const&) const + { + return value_integer(0); + } +}; + +template <> +struct convert +{ + template + std::string operator()(T val) const + { + std::string str; + util::to_string(str, val); + return str; + } + + // specializations + std::string operator()(value_unicode_string const& val) const + { + std::string utf8; + val.toUTF8String(utf8); + return utf8; + } + + std::string operator()(value_double val) const + { + std::string str; + util::to_string(str, val); // TODO set precision(16) + return str; + } + + std::string operator()(value_bool val) const + { + return val ? "true" : "false"; + } + + std::string operator()(value_null const&) const + { + return std::string(""); + } +}; + +struct to_unicode_impl +{ + + template + value_unicode_string operator()(T val) const + { + std::string str; + util::to_string(str, val); + return value_unicode_string(str.c_str()); + } + + // specializations + value_unicode_string const& operator()(value_unicode_string const& val) const + { + return val; + } + + value_unicode_string operator()(value_double val) const + { + std::string str; + util::to_string(str, val); + return value_unicode_string(str.c_str()); + } + + value_unicode_string operator()(value_bool val) const + { + return value_unicode_string(val ? "true" : "false"); + } + + value_unicode_string operator()(value_null const&) const + { + return value_unicode_string(""); + } +}; + +struct to_expression_string_impl +{ + struct EscapingByteSink : U_NAMESPACE_QUALIFIER ByteSink + { + std::string dest_; + char quote_; + + explicit EscapingByteSink(char quote) + : quote_(quote) + { + } + + virtual void Append(const char* data, int32_t n) + { + // reserve enough room to hold the appended chunk and quotes; + // if another chunk follows, or any character needs escaping, + // the string will grow naturally + if (dest_.empty()) + { + dest_.reserve(2 + static_cast(n)); + dest_.append(1, quote_); + } + else + { + dest_.reserve(dest_.size() + n + 1); + } + + for (auto end = data + n; data < end; ++data) + { + if (*data == '\\' || *data == quote_) + dest_.append(1, '\\'); + dest_.append(1, *data); + } + } + + virtual void Flush() + { + if (dest_.empty()) + dest_.append(2, quote_); + else + dest_.append(1, quote_); + } + }; + + explicit to_expression_string_impl(char quote = '\'') + : quote_(quote) {} + + std::string operator()(value_unicode_string const& val) const + { + // toUTF8(sink) doesn't Flush() the sink if the source string + // is empty -- we must return a pair of quotes in that case + // https://github.com/mapnik/mapnik/issues/3362 + if (val.isEmpty()) + { + return std::string(2, quote_); + } + EscapingByteSink sink(quote_); + val.toUTF8(sink); + return sink.dest_; + } + + std::string operator()(value_integer val) const + { + std::string output; + util::to_string(output, val); + return output; + } + + std::string operator()(value_double val) const + { + std::string output; + util::to_string(output, val); // TODO precision(16) + return output; + } + + std::string operator()(value_bool val) const + { + return val ? "true" : "false"; + } + + std::string operator()(value_null const&) const + { + return "null"; + } + + const char quote_; +}; + +} // ns detail + +namespace value_adl_barrier { + +bool value::operator==(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +bool value::operator!=(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +bool value::operator>(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +bool value::operator>=(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +bool value::operator<(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +bool value::operator<=(value const& other) const +{ + return util::apply_visitor(detail::comparison(), *this, other); +} + +value value::operator-() const +{ + return util::apply_visitor(detail::negate(), *this); +} + +value_bool value::to_bool() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +std::string value::to_expression_string(char quote) const +{ + return util::apply_visitor(detail::to_expression_string_impl(quote), *this); +} + +std::string value::to_string() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +value_unicode_string value::to_unicode() const +{ + return util::apply_visitor(detail::to_unicode_impl(), *this); +} + +value_double value::to_double() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +value_integer value::to_int() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +bool value::is_null() const +{ + return util::apply_visitor(mapnik::detail::is_null_visitor(), *this); +} + +template <> +value_double value::convert() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +template <> +value_integer value::convert() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +template <> +value_bool value::convert() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +template <> +std::string value::convert() const +{ + return util::apply_visitor(detail::convert(), *this); +} + +// +value operator+(value const& p1, value const& p2) +{ + return value(util::apply_visitor(detail::add(), p1, p2)); +} + +value operator-(value const& p1, value const& p2) +{ + return value(util::apply_visitor(detail::sub(), p1, p2)); +} + +value operator*(value const& p1, value const& p2) +{ + return value(util::apply_visitor(detail::mult(), p1, p2)); +} + +value operator/(value const& p1, value const& p2) +{ + return value(util::apply_visitor(detail::div(), p1, p2)); +} + +value operator%(value const& p1, value const& p2) +{ + return value(util::apply_visitor(detail::mod(), p1, p2)); +} + +} // namespace value_adl_barrier +} // namespace mapnik diff -Nru mapnik-3.0.9+ds/src/vertex_adapters.cpp mapnik-3.0.13+ds/src/vertex_adapters.cpp --- mapnik-3.0.9+ds/src/vertex_adapters.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/src/vertex_adapters.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,213 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 +#include +#include +#include + +namespace mapnik { namespace geometry { + +// point adapter +template +point_vertex_adapter::point_vertex_adapter(point const& pt) + : pt_(pt), + first_(true) {} + +template +unsigned point_vertex_adapter::vertex(coord_type * x, coord_type * y) const +{ + if (first_) + { + *x = pt_.x; + *y = pt_.y; + first_ = false; + return mapnik::SEG_MOVETO; + } + return mapnik::SEG_END; +} + +template +void point_vertex_adapter::rewind(unsigned) const +{ + first_ = true; +} + +template +geometry_types point_vertex_adapter::type () const +{ + return geometry_types::Point; +} + +// line_string adapter +template +line_string_vertex_adapter::line_string_vertex_adapter(line_string const& line) + : line_(line), + current_index_(0), + end_index_(line.size()) +{} + +template +unsigned line_string_vertex_adapter::vertex(coord_type * x, coord_type * y) const +{ + if (current_index_ != end_index_) + { + point const& coord = line_[current_index_++]; + *x = coord.x; + *y = coord.y; + if (current_index_ == 1) + { + return mapnik::SEG_MOVETO; + } + else + { + return mapnik::SEG_LINETO; + } + } + return mapnik::SEG_END; +} + +template +void line_string_vertex_adapter::rewind(unsigned) const +{ + current_index_ = 0; +} + +template +geometry_types line_string_vertex_adapter::type() const +{ + return geometry_types::LineString; +} + +template +polygon_vertex_adapter::polygon_vertex_adapter(polygon const& poly) + : poly_(poly), + rings_itr_(0), + rings_end_(poly_.interior_rings.size() + 1), + current_index_(0), + end_index_((rings_itr_ < rings_end_) ? poly_.exterior_ring.size() : 0), + start_loop_(true) {} + +template +void polygon_vertex_adapter::rewind(unsigned) const +{ + rings_itr_ = 0; + rings_end_ = poly_.interior_rings.size() + 1; + current_index_ = 0; + end_index_ = (rings_itr_ < rings_end_) ? poly_.exterior_ring.size() : 0; + start_loop_ = true; +} +template +unsigned polygon_vertex_adapter::vertex(coord_type * x, coord_type * y) const +{ + if (rings_itr_ == rings_end_) + { + return mapnik::SEG_END; + } + if (current_index_ < end_index_) + { + point const& coord = (rings_itr_ == 0) ? + poly_.exterior_ring[current_index_++] : poly_.interior_rings[rings_itr_- 1][current_index_++]; + *x = coord.x; + *y = coord.y; + if (start_loop_) + { + start_loop_= false; + return mapnik::SEG_MOVETO; + } + if (current_index_ == end_index_) + { + *x = 0; + *y = 0; + return mapnik::SEG_CLOSE; + } + return mapnik::SEG_LINETO; + } + else if (++rings_itr_ != rings_end_) + { + current_index_ = 0; + end_index_ = poly_.interior_rings[rings_itr_ - 1].size(); + point const& coord = poly_.interior_rings[rings_itr_ - 1][current_index_++]; + *x = coord.x; + *y = coord.y; + return mapnik::SEG_MOVETO; + } + return mapnik::SEG_END; +} + +template +geometry_types polygon_vertex_adapter::type () const +{ + return geometry_types::Polygon; +} + +// ring adapter +template +ring_vertex_adapter::ring_vertex_adapter(linear_ring const& ring) + : ring_(ring), + current_index_(0), + end_index_(ring_.size()), + start_loop_(true) {} + +template +void ring_vertex_adapter::rewind(unsigned) const +{ + current_index_ = 0; + end_index_ = ring_.size(); + start_loop_ = true; +} + +template +unsigned ring_vertex_adapter::vertex(coord_type * x, coord_type * y) const +{ + if (current_index_ < end_index_) + { + auto const& coord = ring_[current_index_++]; + *x = coord.x; + *y = coord.y; + if (start_loop_) + { + start_loop_= false; + return mapnik::SEG_MOVETO; + } + if (current_index_ == end_index_) + { + *x = 0; + *y = 0; + return mapnik::SEG_CLOSE; + } + return mapnik::SEG_LINETO; + } + return mapnik::SEG_END; +} +template +geometry_types ring_vertex_adapter::type () const +{ + return geometry_types::Polygon; +} + +template struct point_vertex_adapter; +template struct line_string_vertex_adapter; +template struct polygon_vertex_adapter; +template struct ring_vertex_adapter; + +}} diff -Nru mapnik-3.0.9+ds/src/warp.cpp mapnik-3.0.13+ds/src/warp.cpp --- mapnik-3.0.9+ds/src/warp.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/warp.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -31,7 +31,8 @@ #include #include -// agg +#pragma GCC diagnostic push +#include #include "agg_image_filters.h" #include "agg_trans_bilinear.h" #include "agg_span_interpolator_linear.h" @@ -45,6 +46,7 @@ #include "agg_span_allocator.h" #include "agg_image_accessors.h" #include "agg_renderer_scanline.h" +#pragma GCC diagnostic pop namespace mapnik { @@ -181,10 +183,10 @@ nodata_value_(nodata_value) {} - void operator() (image_null const&) {} + void operator() (image_null const&) const {} template - void operator() (T const& source) + void operator() (T const& source) const { using image_type = T; //source and target image data types must match diff -Nru mapnik-3.0.9+ds/src/webp_reader.cpp mapnik-3.0.13+ds/src/webp_reader.cpp --- mapnik-3.0.9+ds/src/webp_reader.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/webp_reader.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -33,9 +33,6 @@ #include } -#include -#include -#include #pragma GCC diagnostic pop // stl diff -Nru mapnik-3.0.9+ds/src/well_known_srs.cpp mapnik-3.0.13+ds/src/well_known_srs.cpp --- mapnik-3.0.9+ds/src/well_known_srs.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/well_known_srs.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -25,8 +25,10 @@ #include #include -// boost +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop namespace mapnik { diff -Nru mapnik-3.0.9+ds/src/wkb.cpp mapnik-3.0.13+ds/src/wkb.cpp --- mapnik-3.0.9+ds/src/wkb.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/wkb.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -103,13 +103,13 @@ switch (format_) { case wkbSpatiaLite: - byteOrder_ = (wkbByteOrder) wkb_[1]; + byteOrder_ = static_cast(wkb_[1]); pos_ = 39; break; case wkbGeneric: default: - byteOrder_ = (wkbByteOrder) wkb_[0]; + byteOrder_ = static_cast(wkb_[0]); pos_ = 1; break; } @@ -124,8 +124,12 @@ switch (type) { case wkbPoint: - geom = read_point(); + { + auto pt = read_point(); + if (!std::isnan(pt.x) && !std::isnan(pt.y)) + geom = std::move(pt); break; + } case wkbLineString: geom = read_linestring(); break; @@ -146,11 +150,19 @@ break; case wkbPointZ: case wkbPointM: - geom = read_point(); + { + auto pt = read_point(); + if (!std::isnan(pt.x) && !std::isnan(pt.y)) + geom = std::move(pt); break; + } case wkbPointZM: - geom = read_point(); + { + auto pt = read_point(); + if (!std::isnan(pt.x) && !std::isnan(pt.y)) + geom = std::move(pt); break; + } case wkbLineStringZ: case wkbLineStringM: geom = read_linestring(); diff -Nru mapnik-3.0.9+ds/src/xml_tree.cpp mapnik-3.0.13+ds/src/xml_tree.cpp --- mapnik-3.0.9+ds/src/xml_tree.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/src/xml_tree.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -69,11 +69,10 @@ DEFINE_NAME_TRAIT( float, "float") DEFINE_NAME_TRAIT( unsigned, "unsigned") DEFINE_NAME_TRAIT( int, "int") +DEFINE_NAME_TRAIT( bool, "bool") DEFINE_NAME_TRAIT( boolean_type, "boolean_type") #ifdef BIGINT DEFINE_NAME_TRAIT( mapnik::value_integer, "long long" ) -#else -DEFINE_NAME_TRAIT( mapnik::value_integer, "int" ) #endif DEFINE_NAME_TRAIT( std::string, "string" ) DEFINE_NAME_TRAIT( color, "color" ) @@ -413,10 +412,13 @@ #define compile_get_value(T) template T xml_node::get_value() const compile_get_opt_attr(boolean_type); +compile_get_opt_attr(mapnik::value_bool); compile_get_opt_attr(std::string); compile_get_opt_attr(int); compile_get_opt_attr(unsigned); +#ifdef BIGINT compile_get_opt_attr(mapnik::value_integer); +#endif compile_get_opt_attr(float); compile_get_opt_attr(double); compile_get_opt_attr(color); diff -Nru mapnik-3.0.9+ds/test/build.py mapnik-3.0.13+ds/test/build.py --- mapnik-3.0.9+ds/test/build.py 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/build.py 2017-02-08 13:06:42.000000000 +0000 @@ -9,6 +9,8 @@ if not env['CPP_TESTS']: for cpp_test_bin in glob.glob('./*/*-bin'): os.unlink(cpp_test_bin) + if os.path.exists('./unit/run'): os.unlink('./unit/run') + if os.path.exists('./visual/run'): os.unlink('./visual/run') else: test_env['LIBS'] = [env['MAPNIK_NAME']] test_env.AppendUnique(LIBS='mapnik-wkt') diff -Nru mapnik-3.0.9+ds/test/catch_ext.hpp mapnik-3.0.13+ds/test/catch_ext.hpp --- mapnik-3.0.9+ds/test/catch_ext.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/catch_ext.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,22 @@ +#ifndef TEST_CATCH_EXT_HPP +#define TEST_CATCH_EXT_HPP + +#include "catch.hpp" + +#define TRY_CHECK( expr ) \ + try { \ + CHECK( expr ); \ + } \ + catch ( Catch::TestFailureException & ) { \ + /* thrown by CHECK after it catches and reports */ \ + /* an exception from expr => swallow this */ \ + } + +#define TRY_CHECK_FALSE( expr ) \ + try { \ + CHECK_FALSE( expr ); \ + } \ + catch ( Catch::TestFailureException & ) { \ + } + +#endif // TEST_CATCH_EXT_HPP diff -Nru mapnik-3.0.9+ds/test/catch.hpp mapnik-3.0.13+ds/test/catch.hpp --- mapnik-3.0.9+ds/test/catch.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/catch.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,6 +1,6 @@ /* - * CATCH v1.1 build 1 (master branch) - * Generated: 2015-03-27 18:00:16.346230 + * Catch v1.3.2 + * Generated: 2015-12-28 15:07:07.166291 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -13,9 +13,13 @@ #define TWOBLUECUBES_CATCH_HPP_INCLUDED -// #included from: internal/catch_suppress_warnings.h +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif -#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED +// #included from: internal/catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro @@ -30,6 +34,8 @@ # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wvariadic-macros" @@ -37,7 +43,6 @@ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif - #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL #endif @@ -69,16 +74,42 @@ // #included from: catch_compiler_capabilities.h #define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED -// Much of the following code is based on Boost (1.53) +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 #ifdef __clang__ # if __has_feature(cxx_nullptr) -# define CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif # if __has_feature(cxx_noexcept) -# define CATCH_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # endif #endif // __clang__ @@ -87,52 +118,30 @@ // Borland #ifdef __BORLANDC__ -#if (__BORLANDC__ > 0x582 ) -//#define CATCH_CONFIG_SFINAE // Not confirmed -#endif - #endif // __BORLANDC__ //////////////////////////////////////////////////////////////////////////////// // EDG #ifdef __EDG_VERSION__ -#if (__EDG_VERSION__ > 238 ) -//#define CATCH_CONFIG_SFINAE // Not confirmed -#endif - #endif // __EDG_VERSION__ //////////////////////////////////////////////////////////////////////////////// // Digital Mars #ifdef __DMC__ -#if (__DMC__ > 0x840 ) -//#define CATCH_CONFIG_SFINAE // Not confirmed -#endif - #endif // __DMC__ //////////////////////////////////////////////////////////////////////////////// // GCC #ifdef __GNUC__ -#if __GNUC__ < 3 - -#if (__GNUC_MINOR__ >= 96 ) -//#define CATCH_CONFIG_SFINAE +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR #endif -#elif __GNUC__ >= 3 - -// #define CATCH_CONFIG_SFINAE // Taking this out completely for now - -#endif // __GNUC__ < 3 - -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) - -#define CATCH_CONFIG_CPP11_NULLPTR -#endif +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below #endif // __GNUC__ @@ -141,36 +150,101 @@ #ifdef _MSC_VER #if (_MSC_VER >= 1600) -#define CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif -#if (_MSC_VER >= 1310 ) // (VC++ 7.0+) -//#define CATCH_CONFIG_SFINAE // Not confirmed +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #endif #endif // _MSC_VER +//////////////////////////////////////////////////////////////////////////////// + // Use variadic macros if the compiler supports them #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ ( defined __GNUC__ && __GNUC__ >= 3 ) || \ ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) -#ifndef CATCH_CONFIG_NO_VARIADIC_MACROS -#define CATCH_CONFIG_VARIADIC_MACROS -#endif +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS #endif //////////////////////////////////////////////////////////////////////////////// // C++ language feature support -// detect language version: -#if (__cplusplus == 201103L) -# define CATCH_CPP11 -# define CATCH_CPP11_OR_GREATER -#elif (__cplusplus >= 201103L) +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + # define CATCH_CPP11_OR_GREATER + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR #endif // noexcept support: @@ -182,10 +256,38 @@ # define CATCH_NOEXCEPT_IS(x) #endif +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + namespace Catch { + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + class NonCopyable { -#ifdef CATCH_CPP11_OR_GREATER +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; @@ -248,7 +350,7 @@ SourceLineInfo(); SourceLineInfo( char const* _file, std::size_t _line ); SourceLineInfo( SourceLineInfo const& other ); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SourceLineInfo( SourceLineInfo && ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo& operator = ( SourceLineInfo && ) = default; @@ -270,6 +372,9 @@ void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as @@ -355,7 +460,7 @@ template class Ptr { public: - Ptr() : m_p( NULL ){} + Ptr() : m_p( CATCH_NULL ){} Ptr( T* p ) : m_p( p ){ if( m_p ) m_p->addRef(); @@ -371,7 +476,7 @@ void reset() { if( m_p ) m_p->release(); - m_p = NULL; + m_p = CATCH_NULL; } Ptr& operator = ( T* p ){ Ptr temp( p ); @@ -384,12 +489,11 @@ return *this; } void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } - T* get() { return m_p; } - const T* get() const{ return m_p; } + T* get() const{ return m_p; } T& operator*() const { return *m_p; } T* operator->() const { return m_p; } - bool operator !() const { return m_p == NULL; } - operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } private: T* m_p; @@ -486,9 +590,13 @@ struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; - + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + } namespace Catch { @@ -521,28 +629,33 @@ const char* description; }; +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + struct AutoReg { - AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ); + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); template - AutoReg( void (C::*method)(), - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - registerTestCase( new MethodTestCase( method ), - className, - nameAndDesc, - lineInfo ); + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); } - void registerTestCase( ITestCase* testCase, - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ); - ~AutoReg(); private: @@ -550,6 +663,11 @@ void operator= ( AutoReg const& ); }; +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS @@ -573,6 +691,10 @@ } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + #else /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ @@ -594,6 +716,9 @@ } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); #endif // #included from: internal/catch_capture.hpp @@ -637,11 +762,11 @@ // ResultDisposition::Flags enum struct ResultDisposition { enum Flags { - Normal = 0x00, + Normal = 0x01, - ContinueOnFailure = 0x01, // Failures fail test, but execution continues - FalseTest = 0x02, // Prefix expression with ! - SuppressFail = 0x04 // Failures are reported but do not fail the test + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test }; }; inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { @@ -689,7 +814,7 @@ AssertionResult(); AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); ~AssertionResult(); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionResult( AssertionResult const& ) = default; AssertionResult( AssertionResult && ) = default; AssertionResult& operator = ( AssertionResult const& ) = default; @@ -716,122 +841,443 @@ } // end namespace Catch +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + namespace Catch { +namespace Matchers { + namespace Impl { - struct TestFailureException{}; + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } - template class ExpressionLhs; + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; - struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; - struct CopyableStream { - CopyableStream() {} - CopyableStream( CopyableStream const& other ) { - oss << other.oss.str(); - } - CopyableStream& operator=( CopyableStream const& other ) { - oss.str(""); - oss << other.oss.str(); - return *this; - } - std::ostringstream oss; + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; }; - class ResultBuilder { - public: - ResultBuilder( char const* macroName, - SourceLineInfo const& lineInfo, - char const* capturedExpression, - ResultDisposition::Flags resultDisposition ); - - template - ExpressionLhs operator->* ( T const& operand ); - ExpressionLhs operator->* ( bool value ); + template + struct MatcherImpl : Matcher { - template - ResultBuilder& operator << ( T const& value ) { - m_stream.oss << value; - return *this; + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); } + }; - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} - ResultBuilder& setResultType( ResultWas::OfType result ); - ResultBuilder& setResultType( bool result ); - ResultBuilder& setLhs( std::string const& lhs ); - ResultBuilder& setRhs( std::string const& rhs ); - ResultBuilder& setOp( std::string const& op ); + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } - void endExpression(); + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; - std::string reconstructExpression() const; - AssertionResult build() const; + template + class AllOf : public MatcherImpl, ExpressionT> { + public: - void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); - void captureResult( ResultWas::OfType resultType ); - void captureExpression(); - void react(); - bool shouldDebugBreak() const; - bool allowThrows() const; + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} - private: - AssertionInfo m_assertionInfo; - AssertionResultData m_data; - struct ExprComponents { - ExprComponents() : testFalse( false ) {} - bool testFalse; - std::string lhs, rhs, op; - } m_exprComponents; - CopyableStream m_stream; + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } - bool m_shouldDebugBreak; - bool m_shouldThrow; - }; + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } -} // namespace Catch + private: + std::vector > > m_matchers; + }; -// Include after due to circular dependency: -// #included from: catch_expression_lhs.hpp -#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: -// #included from: catch_evaluate.hpp -#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4389) // '==' : signed/unsigned mismatch -#endif + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } -#include + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } -namespace Catch { -namespace Internal { + private: + std::vector > > m_matchers; + }; - enum Operator { - IsEqualTo, - IsNotEqualTo, - IsLessThan, - IsGreaterThan, - IsLessThanOrEqualTo, - IsGreaterThanOrEqualTo - }; + } // namespace Generic - template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; - template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; - template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; - template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; - template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; - template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; - template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } - template - inline T& opCast(T const& t) { return const_cast(t); } + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } -// nullptr_t support based on pull request #154 from Konstantin Baumann -#ifdef CATCH_CONFIG_CPP11_NULLPTR - inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } -#endif // CATCH_CONFIG_CPP11_NULLPTR + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) == 0; + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) == expr.size() - m_data.m_str.size(); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); + + template + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); + + template + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; + + template + inline T& opCast(T const& t) { return const_cast(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR // So the compare overloads can be operator agnostic we convey the operator as a template // enum, which is used to specialise an Evaluator for doing the comparison. @@ -949,13 +1395,51 @@ return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + #ifdef CATCH_CONFIG_CPP11_NULLPTR // pointer to nullptr_t (when comparing against nullptr) template bool compare( std::nullptr_t, T* rhs ) { - return Evaluator::evaluate( NULL, rhs ); + return Evaluator::evaluate( nullptr, rhs ); } template bool compare( T* lhs, std::nullptr_t ) { - return Evaluator::evaluate( lhs, NULL ); + return Evaluator::evaluate( lhs, nullptr ); } #endif // CATCH_CONFIG_CPP11_NULLPTR @@ -969,40 +1453,6 @@ // #included from: catch_tostring.h #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED -// #included from: catch_sfinae.hpp -#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED - -// Try to detect if the current compiler supports SFINAE - -namespace Catch { - - struct TrueType { - static const bool value = true; - typedef void Enable; - char sizer[1]; - }; - struct FalseType { - static const bool value = false; - typedef void Disable; - char sizer[2]; - }; - -#ifdef CATCH_CONFIG_SFINAE - - template struct NotABooleanExpression; - - template struct If : NotABooleanExpression {}; - template<> struct If : TrueType {}; - template<> struct If : FalseType {}; - - template struct SizedIf; - template<> struct SizedIf : TrueType {}; - template<> struct SizedIf : FalseType {}; - -#endif // CATCH_CONFIG_SFINAE - -} // end namespace Catch - #include #include #include @@ -1055,8 +1505,11 @@ #endif -#ifdef CATCH_CPP11_OR_GREATER +#ifdef CATCH_CONFIG_CPP11_TUPLE #include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM #include #endif @@ -1084,6 +1537,11 @@ std::string toString( signed char value ); std::string toString( unsigned char value ); +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ); #endif @@ -1096,34 +1554,15 @@ namespace Detail { - extern std::string unprintableString; - -// SFINAE is currently disabled by default for all compilers. -// If the non SFINAE version of IsStreamInsertable is ambiguous for you -// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE -#ifdef CATCH_CONFIG_SFINAE - - template - class IsStreamInsertableHelper { - template struct TrueIfSizeable : TrueType {}; - - template - static TrueIfSizeable dummy(T2*); - static FalseType dummy(...); - - public: - typedef SizedIf type; - }; - - template - struct IsStreamInsertable : IsStreamInsertableHelper::type {}; - -#else + extern const std::string unprintableString; struct BorgType { template BorgType( T const& ); }; + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + TrueType& testStreamable( std::ostream& ); FalseType testStreamable( FalseType ); @@ -1136,9 +1575,7 @@ enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; }; -#endif - -#if defined(CATCH_CPP11_OR_GREATER) +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) template::value > @@ -1160,7 +1597,7 @@ #endif template struct StringMakerBase { -#if defined(CATCH_CPP11_OR_GREATER) +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) template static std::string convert( T const& v ) { @@ -1200,7 +1637,7 @@ template static std::string convert( U* p ) { if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); + return "NULL"; else return Detail::rawMemoryToString( p ); } @@ -1210,7 +1647,7 @@ struct StringMaker { static std::string convert( R C::* p ) { if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); + return "NULL"; else return Detail::rawMemoryToString( p ); } @@ -1233,7 +1670,7 @@ return Detail::rangeToString( v.begin(), v.end() ); } -#ifdef CATCH_CPP11_OR_GREATER +#ifdef CATCH_CONFIG_CPP11_TUPLE // toString for tuples namespace TupleDetail { @@ -1273,7 +1710,7 @@ return os.str(); } }; -#endif +#endif // CATCH_CONFIG_CPP11_TUPLE namespace Detail { template @@ -1318,13 +1755,13 @@ template class ExpressionLhs { ExpressionLhs& operator = ( ExpressionLhs const& ); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS ExpressionLhs& operator = ( ExpressionLhs && ) = delete; # endif public: ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS ExpressionLhs( ExpressionLhs const& ) = default; ExpressionLhs( ExpressionLhs && ) = default; # endif @@ -1405,11 +1842,11 @@ namespace Catch { template - inline ExpressionLhs ResultBuilder::operator->* ( T const& operand ) { + inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { return ExpressionLhs( *this, operand ); } - inline ExpressionLhs ResultBuilder::operator->* ( bool value ) { + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { return ExpressionLhs( *this, value ); } @@ -1482,6 +1919,7 @@ class AssertionResult; struct AssertionInfo; struct SectionInfo; + struct SectionEndInfo; struct MessageInfo; class ScopedMessageBuilder; struct Counts; @@ -1493,7 +1931,8 @@ virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; - virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; @@ -1581,7 +2020,7 @@ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ - ( __catchResult->*expr ).endExpression(); \ + ( __catchResult <= expr ).endExpression(); \ } \ catch( ... ) { \ __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ @@ -1614,16 +2053,16 @@ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ if( __catchResult.allowThrows() ) \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ + __catchResult.captureExpectedException( matcher ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ @@ -1676,41 +2115,26 @@ /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ try { \ - std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ + std::string matcherAsString = (matcher).toString(); \ __catchResult \ .setLhs( Catch::toString( arg ) ) \ .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ .setOp( "matches" ) \ - .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ + .setResultType( (matcher).match( arg ) ); \ __catchResult.captureExpression(); \ } catch( ... ) { \ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ } \ - INTERNAL_CATCH_REACT( __catchResult ) \ - } while( Catch::alwaysFalse() ) - -// #included from: internal/catch_section.h -#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED - -// #included from: catch_section_info.h -#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED - -namespace Catch { - - struct SectionInfo { - SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description = std::string() ); + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) - std::string name; - std::string description; - SourceLineInfo lineInfo; - }; +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED -} // end namespace Catch +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED // #included from: catch_totals.hpp #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED @@ -1782,6 +2206,31 @@ }; } +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + // #included from: catch_timer.h #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED @@ -2022,6 +2471,8 @@ #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED #include +#include + // #included from: catch_interfaces_registry_hub.h #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED @@ -2046,7 +2497,8 @@ struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; }; @@ -2058,364 +2510,144 @@ } +namespace Catch { -namespace Catch { - - typedef std::string(*exceptionTranslateFunction)(); - - struct IExceptionTranslator { - virtual ~IExceptionTranslator(); - virtual std::string translate() const = 0; - }; - - struct IExceptionTranslatorRegistry { - virtual ~IExceptionTranslatorRegistry(); - - virtual std::string translateActiveException() const = 0; - }; - - class ExceptionTranslatorRegistrar { - template - class ExceptionTranslator : public IExceptionTranslator { - public: - - ExceptionTranslator( std::string(*translateFunction)( T& ) ) - : m_translateFunction( translateFunction ) - {} - - virtual std::string translate() const { - try { - throw; - } - catch( T& ex ) { - return m_translateFunction( ex ); - } - } - - protected: - std::string(*m_translateFunction)( T& ); - }; - - public: - template - ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { - getMutableRegistryHub().registerTranslator - ( new ExceptionTranslator( translateFunction ) ); - } - }; -} - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ - static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ - namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ - static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) - -// #included from: internal/catch_approx.hpp -#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED - -#include -#include - -namespace Catch { -namespace Detail { - - class Approx { - public: - explicit Approx ( double value ) - : m_epsilon( std::numeric_limits::epsilon()*100 ), - m_scale( 1.0 ), - m_value( value ) - {} - - Approx( Approx const& other ) - : m_epsilon( other.m_epsilon ), - m_scale( other.m_scale ), - m_value( other.m_value ) - {} - - static Approx custom() { - return Approx( 0 ); - } - - Approx operator()( double value ) { - Approx approx( value ); - approx.epsilon( m_epsilon ); - approx.scale( m_scale ); - return approx; - } - - friend bool operator == ( double lhs, Approx const& rhs ) { - // Thanks to Richard Harris for his help refining this formula - return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); - } - - friend bool operator == ( Approx const& lhs, double rhs ) { - return operator==( rhs, lhs ); - } - - friend bool operator != ( double lhs, Approx const& rhs ) { - return !operator==( lhs, rhs ); - } - - friend bool operator != ( Approx const& lhs, double rhs ) { - return !operator==( rhs, lhs ); - } - - Approx& epsilon( double newEpsilon ) { - m_epsilon = newEpsilon; - return *this; - } - - Approx& scale( double newScale ) { - m_scale = newScale; - return *this; - } - - std::string toString() const { - std::ostringstream oss; - oss << "Approx( " << Catch::toString( m_value ) << " )"; - return oss.str(); - } - - private: - double m_epsilon; - double m_scale; - double m_value; - }; -} - -template<> -inline std::string toString( Detail::Approx const& value ) { - return value.toString(); -} - -} // end namespace Catch - -// #included from: internal/catch_matchers.hpp -#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED - -namespace Catch { -namespace Matchers { - namespace Impl { - - template - struct Matcher : SharedImpl - { - typedef ExpressionT ExpressionType; - - virtual ~Matcher() {} - virtual Ptr clone() const = 0; - virtual bool match( ExpressionT const& expr ) const = 0; - virtual std::string toString() const = 0; - }; - - template - struct MatcherImpl : Matcher { - - virtual Ptr > clone() const { - return Ptr >( new DerivedT( static_cast( *this ) ) ); - } - }; - - namespace Generic { - - template - class AllOf : public MatcherImpl, ExpressionT> { - public: - - AllOf() {} - AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} - - AllOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( !m_matchers[i]->match( expr ) ) - return false; - return true; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " and "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - template - class AnyOf : public MatcherImpl, ExpressionT> { - public: - - AnyOf() {} - AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} - - AnyOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( m_matchers[i]->match( expr ) ) - return true; - return false; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " or "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - } + typedef std::string(*exceptionTranslateFunction)(); - namespace StdString { + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; - inline std::string makeString( std::string const& str ) { return str; } - inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; - struct Equals : MatcherImpl { - Equals( std::string const& str ) : m_str( str ){} - Equals( Equals const& other ) : m_str( other.m_str ){} + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); - virtual ~Equals(); + virtual std::string translateActiveException() const = 0; + }; - virtual bool match( std::string const& expr ) const { - return m_str == expr; - } - virtual std::string toString() const { - return "equals: \"" + m_str + "\""; + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { + try { + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } } - std::string m_str; + protected: + std::string(*m_translateFunction)( T& ); }; - struct Contains : MatcherImpl { - Contains( std::string const& substr ) : m_substr( substr ){} - Contains( Contains const& other ) : m_substr( other.m_substr ){} + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} - virtual ~Contains(); +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) != std::string::npos; - } - virtual std::string toString() const { - return "contains: \"" + m_substr + "\""; - } +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED - std::string m_substr; - }; +#include +#include - struct StartsWith : MatcherImpl { - StartsWith( std::string const& substr ) : m_substr( substr ){} - StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} +namespace Catch { +namespace Detail { - virtual ~StartsWith(); + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == 0; - } - virtual std::string toString() const { - return "starts with: \"" + m_substr + "\""; - } + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} - std::string m_substr; - }; + static Approx custom() { + return Approx( 0 ); + } - struct EndsWith : MatcherImpl { - EndsWith( std::string const& substr ) : m_substr( substr ){} - EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } - virtual ~EndsWith(); + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == expr.size() - m_substr.size(); - } - virtual std::string toString() const { - return "ends with: \"" + m_substr + "\""; - } + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } - std::string m_substr; - }; - } // namespace StdString - } // namespace Impl + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } - // The following functions create the actual matcher objects. - // This allows the types to be inferred - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); - } + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } - inline Impl::StdString::Equals Equals( std::string const& str ) { - return Impl::StdString::Equals( str ); - } - inline Impl::StdString::Equals Equals( const char* str ) { - return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); - } - inline Impl::StdString::Contains Contains( std::string const& substr ) { - return Impl::StdString::Contains( substr ); - } - inline Impl::StdString::Contains Contains( const char* substr ) { - return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { - return Impl::StdString::StartsWith( substr ); - } - inline Impl::StdString::StartsWith StartsWith( const char* substr ) { - return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { - return Impl::StdString::EndsWith( substr ); - } - inline Impl::StdString::EndsWith EndsWith( const char* substr ) { - return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); - } + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } -} // namespace Matchers + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } -using namespace Matchers; + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } -} // namespace Catch + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch // #included from: internal/catch_interfaces_tag_alias_registry.h #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED @@ -2450,12 +2682,12 @@ template class Option { public: - Option() : nullableValue( NULL ) {} + Option() : nullableValue( CATCH_NULL ) {} Option( T const& _value ) : nullableValue( new( storage ) T( _value ) ) {} Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) {} ~Option() { @@ -2479,7 +2711,7 @@ void reset() { if( nullableValue ) nullableValue->~T(); - nullableValue = NULL; + nullableValue = CATCH_NULL; } T& operator*() { return *nullableValue; } @@ -2491,10 +2723,10 @@ return nullableValue ? *nullableValue : defaultValue; } - bool some() const { return nullableValue != NULL; } - bool none() const { return nullableValue == NULL; } + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } - bool operator !() const { return nullableValue == NULL; } + bool operator !() const { return nullableValue == CATCH_NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( some() ); } @@ -2552,6 +2784,8 @@ TestCaseInfo( TestCaseInfo const& other ); + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + bool isHidden() const; bool throws() const; bool okToFail() const; @@ -2664,7 +2898,7 @@ inline size_t registerTestMethods() { size_t noTestMethods = 0; - int noClasses = objc_getClassList( NULL, 0 ); + int noClasses = objc_getClassList( CATCH_NULL, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); @@ -2806,7 +3040,7 @@ #pragma clang diagnostic ignored "-Wweak-vtables" #endif -// #included from: ../catch_runner.hpp +// #included from: ../catch_session.hpp #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED // #included from: internal/catch_commandline.hpp @@ -2831,6 +3065,67 @@ #pragma clang diagnostic ignored "-Wpadded" #endif +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + #include #include @@ -2842,50 +3137,18 @@ virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; class NamePattern : public Pattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; - public: - NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { - if( startsWith( m_name, "*" ) ) { - m_name = m_name.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_name, "*" ) ) { - m_name = m_name.substr( 0, m_name.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} virtual ~NamePattern(); virtual bool matches( TestCaseInfo const& testCase ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_name == toLower( testCase.name ); - case WildcardAtStart: - return endsWith( toLower( testCase.name ), m_name ); - case WildcardAtEnd: - return startsWith( toLower( testCase.name ), m_name ); - case WildcardAtBothEnds: - return contains( toLower( testCase.name ), m_name ); - } - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunreachable-code" -#endif - throw std::logic_error( "Unknown enum" ); -#ifdef __clang__ -#pragma clang diagnostic pop -#endif + return m_wildcardPattern.matches( toLower( testCase.name ) ); } private: - std::string m_name; - WildcardPosition m_wildcard; + WildcardPattern m_wildcardPattern; }; + class TagPattern : public Pattern { public: TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} @@ -2896,6 +3159,7 @@ private: std::string m_tag; }; + class ExcludedPattern : public Pattern { public: ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} @@ -3093,28 +3357,62 @@ // #included from: catch_stream.h #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + #include -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wpadded" -#endif +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include +#include +#include namespace Catch { - class Stream { + std::ostream& cout(); + std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; public: - Stream(); - Stream( std::streambuf* _streamBuf, bool _isOwned ); - void release(); + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; - std::streambuf* streamBuf; - - private: - bool isOwned; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; }; - - std::ostream& cout(); - std::ostream& cerr(); } #include @@ -3142,6 +3440,7 @@ showHelp( false ), showInvisibles( false ), forceColour( false ), + filenamesAsTags( false ), abortAfter( -1 ), rngSeed( 0 ), verbosity( Verbosity::Normal ), @@ -3161,6 +3460,7 @@ bool showHelp; bool showInvisibles; bool forceColour; + bool filenamesAsTags; int abortAfter; unsigned int rngSeed; @@ -3170,11 +3470,11 @@ ShowDurations::OrNot showDurations; RunTests::InWhatOrder runOrder; - std::string reporterName; std::string outputFilename; std::string name; std::string processName; + std::vector reporterNames; std::vector testsOrTags; }; @@ -3186,12 +3486,11 @@ public: Config() - : m_os( Catch::cout().rdbuf() ) {} Config( ConfigData const& data ) : m_data( data ), - m_os( Catch::cout().rdbuf() ) + m_stream( openStream() ) { if( !data.testsOrTags.empty() ) { TestSpecParser parser( ITagAliasRegistry::get() ); @@ -3202,12 +3501,6 @@ } virtual ~Config() { - m_os.rdbuf( Catch::cout().rdbuf() ); - m_stream.release(); - } - - void setFilename( std::string const& filename ) { - m_data.outputFilename = filename; } std::string const& getFilename() const { @@ -3223,18 +3516,7 @@ bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } - void setStreamBuf( std::streambuf* buf ) { - m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); - } - - void useStream( std::string const& streamName ) { - Stream stream = createStream( streamName ); - setStreamBuf( stream.streamBuf ); - m_stream.release(); - m_stream = stream; - } - - std::string getReporterName() const { return m_data.reporterName; } + std::vector getReporterNames() const { return m_data.reporterNames; } int abortAfter() const { return m_data.abortAfter; } @@ -3245,7 +3527,7 @@ // IConfig interface virtual bool allowThrows() const { return !m_data.noThrow; } - virtual std::ostream& stream() const { return m_os; } + virtual std::ostream& stream() const { return m_stream->stream(); } virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } @@ -3255,10 +3537,22 @@ virtual bool forceColour() const { return m_data.forceColour; } private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } ConfigData m_data; - Stream m_stream; - mutable std::ostream m_os; + std::auto_ptr m_stream; TestSpec m_testSpec; }; @@ -3514,7 +3808,7 @@ template struct IArgFunction { virtual ~IArgFunction() {} -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS IArgFunction() = default; IArgFunction( IArgFunction const& ) = default; # endif @@ -3527,11 +3821,11 @@ template class BoundArgFunction { public: - BoundArgFunction() : functionObj( NULL ) {} + BoundArgFunction() : functionObj( CATCH_NULL ) {} BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} - BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CATCH_NULL ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { - IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL; delete functionObj; functionObj = newFunctionObj; return *this; @@ -3547,7 +3841,7 @@ bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { - return functionObj != NULL; + return functionObj != CATCH_NULL; } private: IArgFunction* functionObj; @@ -3765,12 +4059,7 @@ } }; - // NOTE: std::auto_ptr is deprecated in c++11/c++0x -#if defined(__cplusplus) && __cplusplus > 199711L - typedef std::unique_ptr ArgAutoPtr; -#else - typedef std::auto_ptr ArgAutoPtr; -#endif + typedef CATCH_AUTO_PTR( Arg ) ArgAutoPtr; friend void addOptName( Arg& arg, std::string const& optName ) { @@ -3846,8 +4135,8 @@ m_arg->description = description; return *this; } - ArgBuilder& detail( std::string const& detail ) { - m_arg->detail = detail; + ArgBuilder& detail( std::string const& _detail ) { + m_arg->detail = _detail; return *this; } @@ -3930,14 +4219,14 @@ maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { - Detail::Text usage( it->commands(), Detail::TextAttributes() + Detail::Text usageText( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth - 3 ) ); - for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { - std::string usageCol = i < usage.size() ? usage[i] : ""; + for( std::size_t i = 0; i < (std::max)( usageText.size(), desc.size() ); ++i ) { + std::string usageCol = i < usageText.size() ? usageText[i] : ""; os << usageCol; if( i < desc.size() && !desc[i].empty() ) @@ -4143,6 +4432,7 @@ config.abortAfter = x; } inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } inline void addWarning( ConfigData& config, std::string const& _warning ) { if( _warning == "NoAssertions" ) @@ -4236,7 +4526,7 @@ cli["-r"]["--reporter"] // .placeholder( "name[:filename]" ) .describe( "reporter to use (defaults to console)" ) - .bind( &ConfigData::reporterName, "name" ); + .bind( &addReporterName, "name" ); cli["-n"]["--name"] .describe( "suite name" ) @@ -4273,6 +4563,10 @@ .describe( "load test names to run from a file" ) .bind( &loadTestNamesFromFile, "filename" ); + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + // Less common commands which don't have a short form cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) @@ -4530,18 +4824,18 @@ namespace Catch { struct ReporterConfig { - explicit ReporterConfig( Ptr const& _fullConfig ) + explicit ReporterConfig( Ptr const& _fullConfig ) : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} std::ostream& stream() const { return *m_stream; } - Ptr fullConfig() const { return m_fullConfig; } + Ptr fullConfig() const { return m_fullConfig; } private: std::ostream* m_stream; - Ptr m_fullConfig; + Ptr m_fullConfig; }; struct ReporterPreferences { @@ -4605,7 +4899,7 @@ } virtual ~AssertionStats(); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionStats( AssertionStats const& ) = default; AssertionStats( AssertionStats && ) = default; AssertionStats& operator = ( AssertionStats const& ) = default; @@ -4628,7 +4922,7 @@ missingAssertions( _missingAssertions ) {} virtual ~SectionStats(); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SectionStats( SectionStats const& ) = default; SectionStats( SectionStats && ) = default; SectionStats& operator = ( SectionStats const& ) = default; @@ -4655,7 +4949,7 @@ {} virtual ~TestCaseStats(); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestCaseStats( TestCaseStats const& ) = default; TestCaseStats( TestCaseStats && ) = default; TestCaseStats& operator = ( TestCaseStats const& ) = default; @@ -4683,7 +4977,7 @@ {} virtual ~TestGroupStats(); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestGroupStats( TestGroupStats const& ) = default; TestGroupStats( TestGroupStats && ) = default; TestGroupStats& operator = ( TestGroupStats const& ) = default; @@ -4705,7 +4999,7 @@ {} virtual ~TestRunStats(); -# ifndef CATCH_CPP11_OR_GREATER +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS TestRunStats( TestRunStats const& _other ) : runInfo( _other.runInfo ), totals( _other.totals ), @@ -4743,6 +5037,7 @@ // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; @@ -4751,20 +5046,24 @@ virtual void skipTest( TestCaseInfo const& testInfo ) = 0; }; - struct IReporterFactory { + struct IReporterFactory : IShared { virtual ~IReporterFactory(); virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; virtual std::string getDescription() const = 0; }; struct IReporterRegistry { - typedef std::map FactoryMap; + typedef std::map > FactoryMap; + typedef std::vector > Listeners; virtual ~IReporterRegistry(); - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; }; + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + } #include @@ -4787,8 +5086,7 @@ nameAttr.setInitialIndent( 2 ).setIndent( 4 ); tagsAttr.setIndent( 6 ); - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4816,8 +5114,7 @@ if( !config.testSpec().hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); std::size_t matchedTests = 0; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4857,8 +5154,7 @@ std::map tagCounts; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4929,7 +5225,7 @@ } // end namespace Catch -// #included from: internal/catch_runner_impl.hpp +// #included from: internal/catch_run_context.hpp #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED // #included from: catch_test_case_tracker.hpp @@ -4938,132 +5234,300 @@ #include #include #include +#include namespace Catch { -namespace SectionTracking { +namespace TestCaseTracking { + + struct ITracker : SharedImpl<> { + virtual ~ITracker(); - class TrackedSection { + // static queries + virtual std::string name() const = 0; - typedef std::map TrackedSections; + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { - public: enum RunState { NotStarted, Executing, - ExecutingChildren, - Completed + CompletedCycle }; - TrackedSection( std::string const& name, TrackedSection* parent ) - : m_name( name ), m_runState( NotStarted ), m_parent( parent ) + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) {} - RunState runState() const { return m_runState; } + ITracker& startRun(); - TrackedSection* findChild( std::string const& childName ) { - TrackedSections::iterator it = m_children.find( childName ); - return it != m_children.end() - ? &it->second - : NULL; - } - TrackedSection* acquireChild( std::string const& childName ) { - if( TrackedSection* child = findChild( childName ) ) - return child; - m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); - return findChild( childName ); + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; } - void enter() { - if( m_runState == NotStarted ) - m_runState = Executing; + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; } - void leave() { - for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); - it != itEnd; - ++it ) - if( it->second.runState() != Completed ) { - m_runState = ExecutingChildren; - return; - } - m_runState = Completed; + void completeCycle() { + m_runState = CompletedCycle; } - TrackedSection* getParent() { - return m_parent; + + bool completedCycle() const { + return m_runState == CompletedCycle; } - bool hasChildren() const { - return !m_children.empty(); + ITracker& currentTracker() { + return *m_currentTracker; } + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; - private: + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; std::string m_name; - RunState m_runState; - TrackedSections m_children; - TrackedSection* m_parent; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); - }; + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { + return !m_children.empty(); + } - class TestCaseTracker { - public: - TestCaseTracker( std::string const& testCaseName ) - : m_testCase( testCaseName, NULL ), - m_currentSection( &m_testCase ), - m_completedASectionThisRun( false ) - {} + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } - bool enterSection( std::string const& name ) { - TrackedSection* child = m_currentSection->acquireChild( name ); - if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) - return false; + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } - m_currentSection = child; - m_currentSection->enter(); - return true; + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } } - void leaveSection() { - m_currentSection->leave(); - m_currentSection = m_currentSection->getParent(); - assert( m_currentSection != NULL ); - m_completedASectionThisRun = true; + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); } - bool currentSectionHasChildren() const { - return m_currentSection->hasChildren(); + virtual void close() CATCH_OVERRIDE { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; } - bool isCompleted() const { - return m_testCase.runState() == TrackedSection::Completed; + private: + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); } + }; - class Guard { - public: - Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { - m_tracker.enterTestCase(); + class SectionTracker : public TrackerBase { + public: + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) + {} + virtual ~SectionTracker(); + + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); } - ~Guard() { - m_tracker.leaveTestCase(); + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); } - private: - Guard( Guard const& ); - void operator = ( Guard const& ); - TestCaseTracker& m_tracker; - }; + if( !ctx.completedCycle() && !section->isComplete() ) { - private: - void enterTestCase() { - m_currentSection = &m_testCase; - m_completedASectionThisRun = false; - m_testCase.enter(); + section->open(); + } + return *section; + } + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); + + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; } - void leaveTestCase() { - m_testCase.leave(); + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); } - TrackedSection m_testCase; - TrackedSection* m_currentSection; - bool m_completedASectionThisRun; + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } }; -} // namespace SectionTracking + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } -using SectionTracking::TestCaseTracker; +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; } // namespace Catch @@ -5179,15 +5643,12 @@ public: - explicit RunContext( Ptr const& config, Ptr const& reporter ) - : m_runInfo( config->name() ), + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), m_context( getCurrentMutableContext() ), - m_activeTestCase( NULL ), - m_config( config ), - m_reporter( reporter ), - m_prevRunner( m_context.getRunner() ), - m_prevResultCapture( m_context.getResultCapture() ), - m_prevConfig( m_context.getConfig() ) + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) { m_context.setRunner( this ); m_context.setConfig( m_config ); @@ -5197,10 +5658,6 @@ virtual ~RunContext() { m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); - m_context.setRunner( m_prevRunner ); - m_context.setConfig( NULL ); - m_context.setResultCapture( m_prevResultCapture ); - m_context.setConfig( m_prevConfig ); } void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { @@ -5221,14 +5678,17 @@ m_reporter->testCaseStarting( testInfo ); m_activeTestCase = &testCase; - m_testCaseTracker = TestCaseTracker( testInfo.name ); do { + m_trackerContext.startRun(); do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); runCurrentTest( redirectedCout, redirectedCerr ); } - while( !m_testCaseTracker->isCompleted() && !aborting() ); + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); } + // !TBD: deprecated - this will be replaced by indexed trackers while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); Totals deltaTotals = m_totals.delta( prevTotals ); @@ -5239,8 +5699,8 @@ redirectedCerr, aborting() ) ); - m_activeTestCase = NULL; - m_testCaseTracker.reset(); + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; return deltaTotals; } @@ -5275,8 +5735,10 @@ std::ostringstream oss; oss << sectionInfo.name << "@" << sectionInfo.lineInfo; - if( !m_testCaseTracker->enterSection( oss.str() ) ) + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) return false; + m_activeSections.push_back( §ionTracker ); m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; @@ -5287,30 +5749,40 @@ return true; } bool testForMissingAssertions( Counts& assertions ) { - if( assertions.total() != 0 || - !m_config->warnAboutMissingAssertions() || - m_testCaseTracker->currentSectionHasChildren() ) + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) return false; m_totals.assertions.failed++; assertions.failed++; return true; } - virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { - if( std::uncaught_exception() ) { - m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); - return; - } - - Counts assertions = m_totals.assertions - prevAssertions; + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); - m_testCaseTracker->leaveSection(); + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } - m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); m_messages.clear(); } + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + virtual void pushScopedMessage( MessageInfo const& message ) { m_messages.push_back( message ); } @@ -5376,7 +5848,8 @@ double duration = 0; try { m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); - TestCaseTracker::Guard guard( *m_testCaseTracker ); + + seedRng( *m_config ); Timer timer; timer.start(); @@ -5396,6 +5869,7 @@ catch(...) { makeUnexpectedResultBuilder().useActiveException(); } + m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); @@ -5430,39 +5904,29 @@ void handleUnfinishedSections() { // If sections ended prematurely due to an exception we stored their // infos here so we can tear them down outside the unwind process. - for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), itEnd = m_unfinishedSections.rend(); it != itEnd; ++it ) - sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); + sectionEnded( *it ); m_unfinishedSections.clear(); } - struct UnfinishedSections { - UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) - : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} - - SectionInfo info; - Counts prevAssertions; - double durationInSeconds; - }; - TestRunInfo m_runInfo; IMutableContext& m_context; TestCase const* m_activeTestCase; - Option m_testCaseTracker; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; AssertionResult m_lastResult; Ptr m_config; Totals m_totals; Ptr m_reporter; std::vector m_messages; - IRunner* m_prevRunner; - IResultCapture* m_prevResultCapture; - Ptr m_prevConfig; AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; }; IResultCapture& getResultCapture() { @@ -5483,18 +5947,19 @@ struct Version { Version( unsigned int _majorVersion, unsigned int _minorVersion, - unsigned int _buildNumber, - char const* const _branchName ) - : majorVersion( _majorVersion ), - minorVersion( _minorVersion ), - buildNumber( _buildNumber ), - branchName( _branchName ) - {} + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); unsigned int const majorVersion; unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; unsigned int const buildNumber; - char const* const branchName; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); private: void operator=( Version const& ); @@ -5509,89 +5974,87 @@ namespace Catch { - class Runner { - - public: - Runner( Ptr const& config ) - : m_config( config ) - { - openStream(); - makeReporter(); + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); } + return reporter; + } - Totals runTests() { - - RunContext context( m_config.get(), m_reporter ); + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); - Totals totals; + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } - context.testGroupStarting( "all tests", 1, 1 ); // deprecated? + Totals runTests( Ptr const& config ) { - TestSpec testSpec = m_config->testSpec(); - if( !testSpec.hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + Ptr iconfig = config.get(); - std::vector testCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); - int testsRunForGroup = 0; - for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); - it != itEnd; - ++it ) { - testsRunForGroup++; - if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { + RunContext context( iconfig, reporter ); - if( context.aborting() ) - break; + Totals totals; - totals += context.runTest( *it ); - m_testsAlreadyRun.insert( *it ); - } - } - std::vector skippedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); + context.testGroupStarting( config->name(), 1, 1 ); - for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); - it != itEnd; - ++it ) - m_reporter->skipTest( *it ); + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests - context.testGroupEnded( "all tests", totals, 1, 1 ); - return totals; + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); } - private: - void openStream() { - // Open output file, if specified - if( !m_config->getFilename().empty() ) { - m_ofs.open( m_config->getFilename().c_str() ); - if( m_ofs.fail() ) { - std::ostringstream oss; - oss << "Unable to open file: '" << m_config->getFilename() << "'"; - throw std::domain_error( oss.str() ); - } - m_config->setStreamBuf( m_ofs.rdbuf() ); - } - } - void makeReporter() { - std::string reporterName = m_config->getReporterName().empty() - ? "console" - : m_config->getReporterName(); + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } - m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); - if( !m_reporter ) { - std::ostringstream oss; - oss << "No reporter registered with name: '" << reporterName << "'"; - throw std::domain_error( oss.str() ); - } - } + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; - private: - Ptr m_config; - std::ofstream m_ofs; - Ptr m_reporter; - std::set m_testsAlreadyRun; - }; + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.insert( "#" + filename ); + setTags( test, tags ); + } + } class Session : NonCopyable { static bool alreadyInstantiated; @@ -5614,18 +6077,13 @@ } void showHelp( std::string const& processName ) { - Catch::cout() << "\nCatch v" << libraryVersion.majorVersion << "." - << libraryVersion.minorVersion << " build " - << libraryVersion.buildNumber; - if( libraryVersion.branchName != std::string( "master" ) ) - Catch::cout() << " (" << libraryVersion.branchName << " branch)"; - Catch::cout() << "\n"; + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; m_cli.usage( Catch::cout(), processName ); Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } - int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + int applyCommandLine( int argc, char const* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); @@ -5636,9 +6094,10 @@ catch( std::exception& ex ) { { Colour colourGuard( Colour::Red ); - Catch::cerr() << "\nError(s) in input:\n" - << Text( ex.what(), TextAttributes().setIndent(2) ) - << "\n\n"; + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; } m_cli.usage( Catch::cout(), m_configData.processName ); return (std::numeric_limits::max)(); @@ -5651,7 +6110,7 @@ m_config.reset(); } - int run( int argc, char* const argv[] ) { + int run( int argc, char const* const argv[] ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) @@ -5667,15 +6126,16 @@ { config(); // Force config to be constructed - std::srand( m_configData.rngSeed ); + seedRng( *m_config ); - Runner runner( m_config ); + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); // Handle list request if( Option listed = list( config() ) ) return static_cast( *listed ); - return static_cast( runner.runTests().assertions.failed ); + return static_cast( runTests( m_config ).assertions.failed ); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; @@ -5683,7 +6143,7 @@ } } - Clara::CommandLine const& cli() const { + Clara::CommandLine & cli() { return m_cli; } std::vector const& unusedTokens() const { @@ -5697,7 +6157,6 @@ m_config = new Config( m_configData ); return *m_config; } - private: Clara::CommandLine m_cli; std::vector m_unusedTokens; @@ -5723,16 +6182,76 @@ namespace Catch { - class TestRegistry : public ITestCaseRegistry { - struct LexSort { - bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + class TestRegistry : public ITestCaseRegistry { public: - TestRegistry() : m_unnamedCount( 0 ) {} + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} virtual ~TestRegistry(); virtual void registerTest( TestCase const& testCase ) { @@ -5742,69 +6261,29 @@ oss << "Anonymous test case " << ++m_unnamedCount; return registerTest( testCase.withName( oss.str() ) ); } - - if( m_functions.find( testCase ) == m_functions.end() ) { - m_functions.insert( testCase ); - m_functionsInOrder.push_back( testCase ); - if( !testCase.isHidden() ) - m_nonHiddenFunctions.push_back( testCase ); - } - else { - TestCase const& prev = *m_functions.find( testCase ); - { - Colour colourGuard( Colour::Red ); - Catch::cerr() << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; - } - exit(1); - } + m_functions.push_back( testCase ); } virtual std::vector const& getAllTests() const { - return m_functionsInOrder; - } - - virtual std::vector const& getAllNonHiddenTests() const { - return m_nonHiddenFunctions; + return m_functions; } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { - - for( std::vector::const_iterator it = m_functionsInOrder.begin(), - itEnd = m_functionsInOrder.end(); - it != itEnd; - ++it ) { - bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); - if( includeTest != negated ) - matchingTestCases.push_back( *it ); + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); } - sortTests( config, matchingTestCases ); + return m_sortedFunctions; } private: - - static void sortTests( IConfig const& config, std::vector& matchingTestCases ) { - - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); - break; - case RunTests::InRandomOrder: - { - RandomNumberGenerator rng; - std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); - } - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - } - std::set m_functions; - std::vector m_functionsInOrder; - std::vector m_nonHiddenFunctions; + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised }; /////////////////////////////////////////////////////////////////////////// @@ -5837,29 +6316,38 @@ return className; } - /////////////////////////////////////////////////////////////////////////// + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { - AutoReg::AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ) { + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); } - AutoReg::~AutoReg() {} - - void AutoReg::registerTestCase( ITestCase* testCase, - char const* classOrQualifiedMethodName, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { + /////////////////////////////////////////////////////////////////////////// - getMutableRegistryHub().registerTest - ( makeTestCase( testCase, - extractClassName( classOrQualifiedMethodName ), - nameAndDesc.name, - nameAndDesc.description, - lineInfo ) ); + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); } + AutoReg::~AutoReg() {} + } // end namespace Catch // #included from: catch_reporter_registry.hpp @@ -5873,27 +6361,32 @@ public: - virtual ~ReporterRegistry() { - deleteAllValues( m_factories ); - } + virtual ~ReporterRegistry() CATCH_OVERRIDE {} - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { FactoryMap::const_iterator it = m_factories.find( name ); if( it == m_factories.end() ) - return NULL; + return CATCH_NULL; return it->second->create( ReporterConfig( config ) ); } - void registerReporter( std::string const& name, IReporterFactory* factory ) { + void registerReporter( std::string const& name, Ptr const& factory ) { m_factories.insert( std::make_pair( name, factory ) ); } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } - FactoryMap const& getFactories() const { + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { return m_factories; } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } private: FactoryMap m_factories; + Listeners m_listeners; }; } @@ -5921,13 +6414,13 @@ #ifdef __OBJC__ // In Objective-C try objective-c exceptions first @try { - throw; + return tryTranslators(); } @catch (NSException *exception) { return Catch::toString( [exception description] ); } #else - throw; + return tryTranslators(); #endif } catch( TestFailureException& ) { @@ -5943,20 +6436,15 @@ return msg; } catch(...) { - return tryTranslators( m_translators.begin() ); + return "Unknown exception"; } } - std::string tryTranslators( std::vector::const_iterator it ) const { - if( it == m_translators.end() ) - return "Unknown exception"; - - try { - return (*it)->translate(); - } - catch(...) { - return tryTranslators( it+1 ); - } + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); } private: @@ -5976,24 +6464,27 @@ public: // IRegistryHub RegistryHub() { } - virtual IReporterRegistry const& getReporterRegistry() const { + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { return m_reporterRegistry; } - virtual ITestCaseRegistry const& getTestCaseRegistry() const { + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { return m_testCaseRegistry; } - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { return m_exceptionTranslatorRegistry; } public: // IMutableRegistryHub - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { m_reporterRegistry.registerReporter( name, factory ); } - virtual void registerTest( TestCase const& testInfo ) { + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { m_testCaseRegistry.registerTest( testInfo ); } - virtual void registerTranslator( const IExceptionTranslator* translator ) { + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { m_exceptionTranslatorRegistry.registerTranslator( translator ); } @@ -6005,7 +6496,7 @@ // Single, global, instance inline RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = NULL; + static RegistryHub* theRegistryHub = CATCH_NULL; if( !theRegistryHub ) theRegistryHub = new RegistryHub(); return theRegistryHub; @@ -6020,7 +6511,7 @@ } void cleanUp() { delete getTheRegistryHub(); - getTheRegistryHub() = NULL; + getTheRegistryHub() = CATCH_NULL; cleanUpContext(); } std::string translateActiveException() { @@ -6050,24 +6541,11 @@ } // end namespace Catch -// #included from: catch_context_impl.hpp -#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED - -// #included from: catch_stream.hpp -#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED - -// #included from: catch_streambuf.h -#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED - -#include - -namespace Catch { +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED - class StreamBufBase : public std::streambuf { - public: - virtual ~StreamBufBase() CATCH_NOEXCEPT; - }; -} +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED #include #include @@ -6113,6 +6591,19 @@ /////////////////////////////////////////////////////////////////////////// + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + struct OutputDebugWriter { void operator()( std::string const&str ) { @@ -6120,23 +6611,26 @@ } }; - Stream::Stream() - : streamBuf( NULL ), isOwned( false ) + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) {} - Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) - : streamBuf( _streamBuf ), isOwned( _isOwned ) + std::ostream& DebugOutStream::stream() const { + return m_os; + } + + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) {} - void Stream::release() { - if( isOwned ) { - delete streamBuf; - streamBuf = NULL; - isOwned = false; - } + std::ostream& CoutStream::stream() const { + return m_os; } -#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions std::ostream& cout() { return std::cout; } @@ -6150,7 +6644,7 @@ class Context : public IMutableContext { - Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} Context( Context const& ); void operator=( Context const& ); @@ -6196,7 +6690,7 @@ m_generatorsByTestName.find( testName ); return it != m_generatorsByTestName.end() ? it->second - : NULL; + : CATCH_NULL; } IGeneratorsForTest& getGeneratorsForCurrentTest() { @@ -6217,7 +6711,7 @@ }; namespace { - Context* currentContext = NULL; + Context* currentContext = CATCH_NULL; } IMutableContext& getCurrentMutableContext() { if( !currentContext ) @@ -6228,17 +6722,9 @@ return getCurrentMutableContext(); } - Stream createStream( std::string const& streamName ) { - if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); - if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); - if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); - - throw std::domain_error( "Unknown stream: " + streamName ); - } - void cleanUpContext() { delete currentContext; - currentContext = NULL; + currentContext = CATCH_NULL; } } @@ -6294,12 +6780,13 @@ { CONSOLE_SCREEN_BUFFER_INFO csbiInfo; GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); - originalAttributes = csbiInfo.wAttributes; + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { - case Colour::None: return setTextAttribute( originalAttributes ); + case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Red: return setTextAttribute( FOREGROUND_RED ); case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); @@ -6319,10 +6806,11 @@ private: void setTextAttribute( WORD _textAttribute ) { - SetConsoleTextAttribute( stdoutHandle, _textAttribute ); + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); } HANDLE stdoutHandle; - WORD originalAttributes; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; }; IColourImpl* platformColourInstance() { @@ -6648,6 +7136,21 @@ return TestCase( _testCase, info ); } + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + TestCaseInfo::TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, @@ -6656,18 +7159,10 @@ : name( _name ), className( _className ), description( _description ), - tags( _tags ), lineInfo( _lineInfo ), properties( None ) { - std::ostringstream oss; - for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { - oss << "[" << *it << "]"; - std::string lcaseTag = toLower( *it ); - properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); - lcaseTags.insert( lcaseTag ); - } - tagsAsString = oss.str(); + setTags( *this, _tags ); } TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) @@ -6750,8 +7245,33 @@ namespace Catch { - // These numbers are maintained by a script - Version libraryVersion( 1, 1, 1, "master" ); + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 3, 2, "", 0 ); + } // #included from: catch_message.hpp @@ -6943,7 +7463,7 @@ #else uint64_t getCurrentTicks() { timeval t; - gettimeofday(&t,NULL); + gettimeofday(&t,CATCH_NULL); return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); } #endif @@ -7042,6 +7562,14 @@ return line < other.line || ( line == other.line && file < other.file ); } + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ os << info.file << "(" << info.line << ")"; @@ -7081,8 +7609,13 @@ } Section::~Section() { - if( m_sectionIncluded ) - getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } } // This indicates whether the section should be executed or not @@ -7134,7 +7667,7 @@ // Call sysctl. size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } @@ -7188,9 +7721,11 @@ namespace Detail { - std::string unprintableString = "{?}"; + const std::string unprintableString = "{?}"; namespace { + const int hexThreshold = 255; + struct Endianness { enum Arch { Big, Little }; @@ -7271,19 +7806,17 @@ std::string toString( int value ) { std::ostringstream oss; - if( value > 8192 ) - oss << "0x" << std::hex << value; - else - oss << value; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; return oss.str(); } std::string toString( unsigned long value ) { std::ostringstream oss; - if( value > 8192 ) - oss << "0x" << std::hex << value; - else - oss << value; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; return oss.str(); } @@ -7332,6 +7865,23 @@ return toString( static_cast( value ) ); } +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ) { return "nullptr"; @@ -7361,11 +7911,17 @@ namespace Catch { + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } ResultBuilder::ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), m_shouldDebugBreak( false ), m_shouldThrow( false ) {} @@ -7406,15 +7962,41 @@ setResultType( resultType ); captureExpression(); } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } void ResultBuilder::captureExpression() { AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { getResultCapture().assertionEnded( result ); if( !result.isOk() ) { if( getCurrentContext().getConfig()->shouldDebugBreak() ) m_shouldDebugBreak = true; - if( getCurrentContext().getRunner()->aborting() || m_assertionInfo.resultDisposition == ResultDisposition::Normal ) + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) m_shouldThrow = true; } } @@ -7561,6 +8143,137 @@ } // end namespace Catch +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + // #included from: ../reporters/catch_reporter_xml.hpp #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED @@ -7576,47 +8289,53 @@ StreamingReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = false; + } - virtual ~StreamingReporterBase(); + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual ~StreamingReporterBase() CATCH_OVERRIDE; - virtual void noMatchingTestCases( std::string const& ) {} + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} - virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { currentTestRunInfo = _testRunInfo; } - virtual void testGroupStarting( GroupInfo const& _groupInfo ) { + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { currentGroupInfo = _groupInfo; } - virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { currentTestCaseInfo = _testInfo; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_sectionStack.push_back( _sectionInfo ); } - virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { m_sectionStack.pop_back(); } - virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); } - virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { currentGroupInfo.reset(); } - virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); currentGroupInfo.reset(); currentTestRunInfo.reset(); } - virtual void skipTest( TestCaseInfo const& ) { + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { // Don't do anything with this by default. // It can optionally be overridden in the derived class. } - Ptr m_config; + Ptr m_config; std::ostream& stream; LazyStat currentTestRunInfo; @@ -7624,6 +8343,7 @@ LazyStat currentTestCaseInfo; std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; }; struct CumulativeReporterBase : SharedImpl { @@ -7674,15 +8394,21 @@ CumulativeReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = false; + } ~CumulativeReporterBase(); - virtual void testRunStarting( TestRunInfo const& ) {} - virtual void testGroupStarting( GroupInfo const& ) {} + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } + + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} - virtual void testCaseStarting( TestCaseInfo const& ) {} + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} - virtual void sectionStarting( SectionInfo const& sectionInfo ) { + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); Ptr node; if( m_sectionStack.empty() ) { @@ -7707,7 +8433,7 @@ m_deepestSection = node; } - virtual void assertionStarting( AssertionInfo const& ) {} + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual bool assertionEnded( AssertionStats const& assertionStats ) { assert( !m_sectionStack.empty() ); @@ -7715,13 +8441,13 @@ sectionNode.assertions.push_back( assertionStats ); return true; } - virtual void sectionEnded( SectionStats const& sectionStats ) { + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& node = *m_sectionStack.back(); node.stats = sectionStats; m_sectionStack.pop_back(); } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { Ptr node = new TestCaseNode( testCaseStats ); assert( m_sectionStack.size() == 0 ); node->children.push_back( m_rootSection ); @@ -7732,12 +8458,12 @@ m_deepestSection->stdOut = testCaseStats.stdOut; m_deepestSection->stdErr = testCaseStats.stdErr; } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { Ptr node = new TestGroupNode( testGroupStats ); node->children.swap( m_testCases ); m_testGroups.push_back( node ); } - virtual void testRunEnded( TestRunStats const& testRunStats ) { + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { Ptr node = new TestRunNode( testRunStats ); node->children.swap( m_testGroups ); m_testRuns.push_back( node ); @@ -7745,9 +8471,9 @@ } virtual void testRunEndedCumulative() = 0; - virtual void skipTest( TestCaseInfo const& ) {} + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} - Ptr m_config; + Ptr m_config; std::ostream& stream; std::vector m_assertions; std::vector > > m_sections; @@ -7759,6 +8485,7 @@ Ptr m_rootSection; Ptr m_deepestSection; std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; }; @@ -7772,6 +8499,17 @@ return line; } + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + } // end namespace Catch // #included from: ../internal/catch_reporter_registrars.hpp @@ -7802,7 +8540,7 @@ template class ReporterRegistrar { - class ReporterFactory : public IReporterFactory { + class ReporterFactory : public SharedImpl { // *** Please Note ***: // - If you end up here looking at a compiler error because it's trying to register @@ -7830,22 +8568,102 @@ getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; } #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + // #included from: ../internal/catch_xmlwriter.hpp #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #include #include #include +#include namespace Catch { + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + class XmlWriter { public: @@ -7857,7 +8675,7 @@ ScopedElement( ScopedElement const& other ) : m_writer( other.m_writer ){ - other.m_writer = NULL; + other.m_writer = CATCH_NULL; } ~ScopedElement() { @@ -7897,27 +8715,6 @@ endElement(); } -//# ifndef CATCH_CPP11_OR_GREATER -// XmlWriter& operator = ( XmlWriter const& other ) { -// XmlWriter temp( other ); -// swap( temp ); -// return *this; -// } -//# else -// XmlWriter( XmlWriter const& ) = default; -// XmlWriter( XmlWriter && ) = default; -// XmlWriter& operator = ( XmlWriter const& ) = default; -// XmlWriter& operator = ( XmlWriter && ) = default; -//# endif -// -// void swap( XmlWriter& other ) { -// std::swap( m_tagIsOpen, other.m_tagIsOpen ); -// std::swap( m_needsNewline, other.m_needsNewline ); -// std::swap( m_tags, other.m_tags ); -// std::swap( m_indent, other.m_indent ); -// std::swap( m_os, other.m_os ); -// } - XmlWriter& startElement( std::string const& name ) { ensureTagClosed(); newlineIfNecessary(); @@ -7949,11 +8746,8 @@ } XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) { - stream() << " " << name << "=\""; - writeEncodedText( attribute ); - stream() << "\""; - } + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; return *this; } @@ -7964,9 +8758,9 @@ template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - if( !name.empty() ) - stream() << " " << name << "=\"" << attribute << "\""; - return *this; + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); } XmlWriter& writeText( std::string const& text, bool indent = true ) { @@ -7975,7 +8769,7 @@ ensureTagClosed(); if( tagWasOpen && indent ) stream() << m_indent; - writeEncodedText( text ); + stream() << XmlEncode( text ); m_needsNewline = true; } return *this; @@ -8020,30 +8814,6 @@ } } - void writeEncodedText( std::string const& text ) { - static const char* charsToEncode = "<&\""; - std::string mtext = text; - std::string::size_type pos = mtext.find_first_of( charsToEncode ); - while( pos != std::string::npos ) { - stream() << mtext.substr( 0, pos ); - - switch( mtext[pos] ) { - case '<': - stream() << "<"; - break; - case '&': - stream() << "&"; - break; - case '\"': - stream() << """; - break; - } - mtext = mtext.substr( pos+1 ); - pos = mtext.find_first_of( charsToEncode ); - } - stream() << mtext; - } - bool m_tagIsOpen; bool m_needsNewline; std::vector m_tags; @@ -8052,32 +8822,44 @@ }; } +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + namespace Catch { class XmlReporter : public StreamingReporterBase { public: XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_sectionDepth( 0 ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = true; + } - virtual ~XmlReporter(); + virtual ~XmlReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as an XML document"; } public: // StreamingReporterBase - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - virtual void noMatchingTestCases( std::string const& s ) { + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { StreamingReporterBase::noMatchingTestCases( s ); } - virtual void testRunStarting( TestRunInfo const& testInfo ) { + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testRunStarting( testInfo ); m_xml.setStream( stream ); m_xml.startElement( "Catch" ); @@ -8085,13 +8867,13 @@ m_xml.writeAttribute( "name", m_config->name() ); } - virtual void testGroupStarting( GroupInfo const& groupInfo ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) .writeAttribute( "name", groupInfo.name ); } - virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); @@ -8099,7 +8881,7 @@ m_testCaseTimer.start(); } - virtual void sectionStarting( SectionInfo const& sectionInfo ) { + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) @@ -8108,9 +8890,9 @@ } } - virtual void assertionStarting( AssertionInfo const& ) { } + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { const AssertionResult& assertionResult = assertionStats.assertionResult; // Print any info messages in tags. @@ -8181,7 +8963,7 @@ return true; } - virtual void sectionEnded( SectionStats const& sectionStats ) { + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { StreamingReporterBase::sectionEnded( sectionStats ); if( --m_sectionDepth > 0 ) { XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); @@ -8196,7 +8978,7 @@ } } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); @@ -8207,7 +8989,7 @@ m_xml.endElement(); } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { StreamingReporterBase::testGroupEnded( testGroupStats ); // TODO: Check testGroupStats.aborting and act accordingly. m_xml.scopedElement( "OverallResults" ) @@ -8217,7 +8999,7 @@ m_xml.endElement(); } - virtual void testRunEnded( TestRunStats const& testRunStats ) { + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { StreamingReporterBase::testRunEnded( testRunStats ); m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testRunStats.totals.assertions.passed ) @@ -8248,28 +9030,24 @@ JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = true; + } - ~JunitReporter(); + virtual ~JunitReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results in an XML format that looks like Ant's junitreport target"; } - virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} - - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} - virtual void testRunStarting( TestRunInfo const& runInfo ) { + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { CumulativeReporterBase::testRunStarting( runInfo ); xml.startElement( "testsuites" ); } - virtual void testGroupStarting( GroupInfo const& groupInfo ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { suiteTimer.start(); stdOutForSuite.str(""); stdErrForSuite.str(""); @@ -8277,25 +9055,25 @@ CumulativeReporterBase::testGroupStarting( groupInfo ); } - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) unexpectedExceptions++; return CumulativeReporterBase::assertionEnded( assertionStats ); } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { stdOutForSuite << testCaseStats.stdOut; stdErrForSuite << testCaseStats.stdErr; CumulativeReporterBase::testCaseEnded( testCaseStats ); } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { double suiteTime = suiteTimer.getElapsedSeconds(); CumulativeReporterBase::testGroupEnded( testGroupStats ); writeGroup( *m_testGroups.back(), suiteTime ); } - virtual void testRunEndedCumulative() { + virtual void testRunEndedCumulative() CATCH_OVERRIDE { xml.endElement(); } @@ -8460,24 +9238,19 @@ m_headerPrinted( false ) {} - virtual ~ConsoleReporter(); + virtual ~ConsoleReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as plain lines of text"; } - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } - virtual void noMatchingTestCases( std::string const& spec ) { + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { stream << "No test cases matched '" << spec << "'" << std::endl; } - virtual void assertionStarting( AssertionInfo const& ) { + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; @@ -8497,11 +9270,11 @@ return true; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_headerPrinted = false; StreamingReporterBase::sectionStarting( _sectionInfo ); } - virtual void sectionEnded( SectionStats const& _sectionStats ) { + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { if( _sectionStats.missingAssertions ) { lazyPrint(); Colour colour( Colour::ResultError ); @@ -8523,11 +9296,11 @@ StreamingReporterBase::sectionEnded( _sectionStats ); } - virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( _testCaseStats ); m_headerPrinted = false; } - virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { if( currentGroupInfo.used ) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; @@ -8536,7 +9309,7 @@ } StreamingReporterBase::testGroupEnded( _testGroupStats ); } - virtual void testRunEnded( TestRunStats const& _testRunStats ) { + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { printTotalsDivider( _testRunStats.totals ); printTotals( _testRunStats.totals ); stream << std::endl; @@ -8700,12 +9473,7 @@ stream << "\n" << getLineOfChars<'~'>() << "\n"; Colour colour( Colour::SecondaryText ); stream << currentTestRunInfo->name - << " is a Catch v" << libraryVersion.majorVersion << "." - << libraryVersion.minorVersion << " b" - << libraryVersion.buildNumber; - if( libraryVersion.branchName != std::string( "master" ) ) - stream << " (" << libraryVersion.branchName << ")"; - stream << " host application.\n" + << " is a Catch v" << libraryVersion << " host application.\n" << "Run with -? for options\n\n"; if( m_config->rngSeed() != 0 ) @@ -9180,8 +9948,14 @@ } // end namespace Catch namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods NonCopyable::~NonCopyable() {} IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} IContext::~IContext() {} IResultCapture::~IResultCapture() {} @@ -9215,6 +9989,7 @@ FreeFunctionTestCase::~FreeFunctionTestCase() {} IGeneratorInfo::~IGeneratorInfo() {} IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} TestSpec::Pattern::~Pattern() {} TestSpec::NamePattern::~NamePattern() {} TestSpec::TagPattern::~TagPattern() {} @@ -9226,6 +10001,13 @@ Matchers::Impl::StdString::EndsWith::~EndsWith() {} void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } } #ifdef __clang__ @@ -9241,7 +10023,7 @@ #ifndef __OBJC__ // Standard C/C++ main entry point -int main (int argc, char * const argv[]) { +int main (int argc, char * argv[]) { return Catch::Session().run( argc, argv ); } @@ -9279,8 +10061,9 @@ #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) -#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) @@ -9291,6 +10074,7 @@ #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) @@ -9306,6 +10090,7 @@ #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) @@ -9313,6 +10098,7 @@ #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) @@ -9332,11 +10118,11 @@ #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif -#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) -#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) -#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -9344,8 +10130,9 @@ #define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) -#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) @@ -9354,8 +10141,9 @@ #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) -#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) @@ -9371,6 +10159,7 @@ #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) @@ -9378,6 +10167,7 @@ #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) @@ -9401,27 +10191,13 @@ #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif -#define GIVEN( desc ) SECTION( " Given: " desc, "" ) -#define WHEN( desc ) SECTION( " When: " desc, "" ) -#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) -#define THEN( desc ) SECTION( " Then: " desc, "" ) -#define AND_THEN( desc ) SECTION( " And: " desc, "" ) +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) using Catch::Detail::Approx; -// #included from: internal/catch_reenable_warnings.h - -#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(pop) -# else -# pragma clang diagnostic pop -# endif -#elif defined __GNUC__ -# pragma GCC diagnostic pop -#endif - #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED diff -Nru mapnik-3.0.9+ds/test/cleanup.hpp mapnik-3.0.13+ds/test/cleanup.hpp --- mapnik-3.0.9+ds/test/cleanup.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/cleanup.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,6 +1,9 @@ #ifndef TEST_MEMORY_CLEANUP #define TEST_MEMORY_CLEANUP +#pragma GCC diagnostic push +#include + #if defined(HAVE_LIBXML2) #include #include @@ -16,6 +19,8 @@ #include #endif +#pragma GCC diagnostic pop + namespace testing { inline void run_cleanup() diff -Nru mapnik-3.0.9+ds/test/run mapnik-3.0.13+ds/test/run --- mapnik-3.0.9+ds/test/run 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/run 2017-02-08 13:06:42.000000000 +0000 @@ -1,5 +1,8 @@ #!/usr/bin/env bash +set -o pipefail +set -eu + failures=0 cd "$( dirname "${BASH_SOURCE[0]}" )" @@ -9,30 +12,45 @@ function run_step { >&2 echo -e "\033[1m\033[34m* $1\033[0m"; } function run_substep { >&2 echo -e "\033[1m\033[36m* $1\033[0m"; } function run_success { >&2 echo -e "\033[1m\033[32m* $1\033[0m"; } +function run_warn { >&2 echo -e "\033[1m\033[31m* $1\033[0m"; } run_step "Starting Mapnik tests" +ran_a_test=false if [ -d "test/data" ]; then run_substep "Running C++ Unit tests..." - ./test/unit/run - failures=$((failures+$?)) + if [[ -f ./test/unit/run ]]; then + ran_a_test=true + ./test/unit/run || failures=$((failures+$?)) + else + run_warn "Skipping unit tests since they were not built" + fi run_substep "Running standalone C++ tests..." + found_test=false if [ -n "$(find test/standalone/ -maxdepth 1 -name '*-bin' -print -quit)" ]; then for FILE in test/standalone/*-bin; do - ${FILE}; - failures=$((failures+$?)) + found_test=true + ran_a_test=true + ${FILE} || failures=$((failures+$?)) done fi + if [[ $found_test == false ]]; then + run_warn "Skipping standalone tests since they were not built" + fi if [ -d "test/data-visual/styles" ]; then run_substep "Running visual tests..." - if [ -z "$JOBS" ]; then + if [ -z "${JOBS:-}" ]; then JOBS=1 fi - ./test/visual/run -j $JOBS - failures=$((failures+$?)) + if [[ -f ./test/visual/run ]]; then + ran_a_test=true + ./test/visual/run -j $JOBS || failures=$((failures+$?)) + else + run_warn "Skipping visual tests since they were not built" + fi else echo "Notice: Skipping visual tests, the visual tests data are not present under the standard directory \"test/data-visual\"." fi @@ -41,4 +59,8 @@ echo "Notice: Skipping all tests, the test data are not present under the standard directory \"test/data\"." fi +if [[ $ran_a_test == false ]]; then + run_warn "**** WARNING: no tests were run ****" +fi + exit $failures diff -Nru mapnik-3.0.9+ds/test/standalone/font_registration_test.cpp mapnik-3.0.13+ds/test/standalone/font_registration_test.cpp --- mapnik-3.0.9+ds/test/standalone/font_registration_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/standalone/font_registration_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -40,11 +40,6 @@ REQUIRE( mapnik::util::is_directory( fontdir ) ); // test map cached fonts - REQUIRE( m.register_fonts(fontdir , false ) ); - REQUIRE( m.get_font_memory_cache().size() == 0 ); - REQUIRE( m.get_font_file_mapping().size() == 1 ); - REQUIRE( m.load_fonts() ); - REQUIRE( m.get_font_memory_cache().size() == 1 ); REQUIRE( m.register_fonts(fontdir , true ) ); REQUIRE( m.get_font_file_mapping().size() == 22 ); REQUIRE( m.load_fonts() ); @@ -59,7 +54,7 @@ // test font-directory from XML mapnik::Map m3(1,1); - mapnik::load_map_string(m3,""); + mapnik::load_map_string(m3,""); REQUIRE( m3.get_font_memory_cache().size() == 0 ); REQUIRE( m3.load_fonts() ); REQUIRE( m3.get_font_memory_cache().size() == 1 ); @@ -97,22 +92,11 @@ // now restore the original severity logger.set_severity(original_severity); - // register unifont, since we know it sits in the root fonts/ dir - REQUIRE( mapnik::freetype_engine::register_fonts(fontdir) ); - face_names = mapnik::freetype_engine::face_names(); - REQUIRE( face_names.size() > 0 ); - REQUIRE( face_names.size() == 1 ); - - // re-register unifont, should not have any affect - REQUIRE( mapnik::freetype_engine::register_fonts(fontdir, false) ); - face_names = mapnik::freetype_engine::face_names(); - REQUIRE( face_names.size() == 1 ); - // single dejavu font in separate location std::string dejavu_bold_oblique("test/data/fonts/DejaVuSansMono-BoldOblique.ttf"); REQUIRE( mapnik::freetype_engine::register_font(dejavu_bold_oblique) ); face_names = mapnik::freetype_engine::face_names(); - REQUIRE( face_names.size() == 2 ); + REQUIRE( face_names.size() == 1 ); // now, inspect font mapping and confirm the correct 'DejaVu Sans Mono Bold Oblique' is registered using font_file_mapping = std::map >; @@ -188,4 +172,4 @@ } } -} \ No newline at end of file +} diff -Nru mapnik-3.0.9+ds/test/unit/color/css_color.cpp mapnik-3.0.13+ds/test/unit/color/css_color.cpp --- mapnik-3.0.9+ds/test/unit/color/css_color.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/color/css_color.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,7 +1,9 @@ + #include "catch.hpp" #include #include #include +#include TEST_CASE("css color") { @@ -164,4 +166,27 @@ CHECK( !boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space) ); } } + SECTION("operator<< / to_string()") + { + mapnik::color c("salmon"); + std::ostringstream ss; + ss << c ; + CHECK(ss.str() == "rgb(250,128,114)"); + c.set_alpha(127); + ss.seekp(0); + ss << c ; + CHECK(ss.str() == "rgba(250,128,114,0.498)"); + } + SECTION("premultiply/demultiply") + { + mapnik::color c("cornflowerblue"); + c.set_alpha(127); + c.premultiply(); + CHECK(int(c.red()) == 50); + CHECK(int(c.green()) == 74); + CHECK(int(c.blue()) == 118); + CHECK(int(c.alpha()) == 127); + c.demultiply(); + CHECK(c == mapnik::color(100, 148, 236, 127)); + } } diff -Nru mapnik-3.0.9+ds/test/unit/core/box2d_test.cpp mapnik-3.0.13+ds/test/unit/core/box2d_test.cpp --- mapnik-3.0.9+ds/test/unit/core/box2d_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/core/box2d_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,7 +1,9 @@ + #include "catch.hpp" #include #include +#include "agg_trans_affine.h" TEST_CASE("box2d") { SECTION("coord init") { @@ -159,4 +161,62 @@ REQUIRE(e1 == e2); } +SECTION("mapnik::box2d intersects") +{ + mapnik::box2d b0(0,0,100,100); + // another box2d + mapnik::box2d b1(100,100,200,200); + CHECK(b0.intersects(b1)); + CHECK(b1.intersects(b0)); + mapnik::box2d b2(100.001,100,200,200); + CHECK(!b0.intersects(b2)); + CHECK(!b2.intersects(b0)); + // coord + CHECK(b0.intersects(mapnik::coord(100,100))); + CHECK(!b0.intersects(mapnik::coord(100.001,100))); +} + +SECTION("mapnik::box2d intersect") +{ + mapnik::box2d b0(0,0,100,100); + mapnik::box2d b1(100,100,200,200); + CHECK(b0.intersect(b1) == mapnik::box2d(100,100,100,100)); + CHECK(b1.intersect(b0) == mapnik::box2d(100,100,100,100)); + mapnik::box2d b2(100.001,100,200,200); + CHECK(b0.intersect(b2) == mapnik::box2d()); + CHECK(b2.intersect(b0) == mapnik::box2d()); +} + +SECTION("mapnik::box2d re_center") +{ + mapnik::box2d b(0, 0, 100, 100); + b.re_center(0, 0); + CHECK(b == mapnik::box2d(-50, -50, 50, 50)); + b.re_center(mapnik::coord2d(50,50)); + CHECK(b == mapnik::box2d(0, 0, 100, 100)); +} + +SECTION("mapnik::box2d operator+=") +{ + mapnik::box2d b(0, 0, 50, 50); + b += mapnik::box2d(100, 100, 200, 200); + CHECK(b == mapnik::box2d(0, 0, 200, 200)); + b += 100; + CHECK(b == mapnik::box2d(-100, -100, 300, 300)); +} + +SECTION("mapnik::box2d operator*= operator=/ ") +{ + mapnik::box2d b(0, 0, 100, 100); + b *= 2.0; + CHECK(b == mapnik::box2d(-50, -50, 150, 150)); + b /= 2.0; + CHECK(b == mapnik::box2d(0, 0, 100, 100)); + + agg::trans_affine tr; + tr.translate(-50,-50); + tr.scale(2.0); + b *= tr; + CHECK(b == mapnik::box2d(-100, -100, 100, 100)); +} } // TEST_CASE diff -Nru mapnik-3.0.9+ds/test/unit/core/comparison_test.cpp mapnik-3.0.13+ds/test/unit/core/comparison_test.cpp --- mapnik-3.0.9+ds/test/unit/core/comparison_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/core/comparison_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/core/conversions_test.cpp mapnik-3.0.13+ds/test/unit/core/conversions_test.cpp --- mapnik-3.0.9+ds/test/unit/core/conversions_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/core/conversions_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include @@ -283,16 +284,19 @@ REQUIRE( string2bool("true",val) ); REQUIRE( val == true ); - // mapnik::value hashability - using values_container = std::unordered_map; + // mapnik::value hash() and operator== works for all T in value + mapnik::transcoder tr("utf8"); + using values_container = std::unordered_map; values_container vc; - mapnik::value val2(1); - vc[val2] = 1; - REQUIRE( vc[1] == static_cast(1) ); + mapnik::value keys[5] = {true, 123456789, 3.14159f, tr.transcode("Мапник"), mapnik::value_null()} ; + for (auto const& k : keys) + { + vc.insert({k, k}); + REQUIRE( vc[k] == k ); + } // mapnik::value << to ostream std::stringstream s; - mapnik::transcoder tr("utf-8"); mapnik::value_unicode_string ustr = tr.transcode("hello world!"); mapnik::value streamable(ustr); s << streamable; diff -Nru mapnik-3.0.9+ds/test/unit/core/exceptions_test.cpp mapnik-3.0.13+ds/test/unit/core/exceptions_test.cpp --- mapnik-3.0.9+ds/test/unit/core/exceptions_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/core/exceptions_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/core/expressions_test.cpp mapnik-3.0.13+ds/test/unit/core/expressions_test.cpp --- mapnik-3.0.9+ds/test/unit/core/expressions_test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/core/expressions_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,206 @@ +#include "catch_ext.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace { + +template +mapnik::feature_ptr make_test_feature(mapnik::value_integer id, std::string const& wkt, Properties const& prop) +{ + auto ctx = std::make_shared(); + mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx, id)); + mapnik::geometry::geometry geom; + if (mapnik::from_wkt(wkt, geom)) + { + feature->set_geometry(std::move(geom)); + } + + for (auto const& kv : prop) + { + feature->put_new(kv.first, kv.second); + } + return feature; +} + +template +mapnik::value_type evaluate(Feature const& feature, Expression const& expr) +{ + auto value = mapnik::util::apply_visitor( + mapnik::evaluate( + feature, mapnik::attributes()), expr); + return value; +} + +mapnik::value evaluate_string(mapnik::feature_ptr const& feature, std::string const& str) +{ + auto expr = mapnik::parse_expression(str); + return evaluate(*feature, *expr); +} + +std::string parse_and_dump(std::string const& str) +{ + auto expr = mapnik::parse_expression(str); + return mapnik::to_expression_string(*expr); +} + +} // namespace + +TEST_CASE("expressions") +{ + using namespace std::placeholders; + using properties_type = std::vector > ; + mapnik::transcoder tr("utf8"); + + properties_type prop = {{ "foo" , tr.transcode("bar") }, + { "name" , tr.transcode("Québec")}, + { "grass" , tr.transcode("grow")}, + { "wind" , tr.transcode("blow")}, + { "sky" , tr.transcode("is blue")}, + { "double", mapnik::value_double(1.23456)}, + { "int" , mapnik::value_integer(123)}, + { "bool" , mapnik::value_bool(true)}, + { "null" , mapnik::value_null()}}; + + auto feature = make_test_feature(1, "POINT(100 200)", prop); + auto eval = std::bind(evaluate_string, feature, _1); + auto approx = Approx::custom().epsilon(1e-6); + + TRY_CHECK(eval(" [foo]='bar' ") == true); + + // primary expressions + // null + TRY_CHECK(parse_and_dump("null") == "null"); + // boolean + TRY_CHECK(parse_and_dump("true") == "true"); + TRY_CHECK(parse_and_dump("false") == "false"); + // floating point + TRY_CHECK(parse_and_dump("3.14159") == "3.14159"); + // integer + TRY_CHECK(parse_and_dump("123") == "123"); + // unicode + TRY_CHECK(parse_and_dump("''") == "''"); + TRY_CHECK(parse_and_dump("'single-quoted string'") == "'single-quoted string'"); + TRY_CHECK(parse_and_dump("\"double-quoted string\"") == "'double-quoted string'"); + TRY_CHECK(parse_and_dump("'escaped \\' apostrophe'") == "'escaped \\' apostrophe'"); + TRY_CHECK(parse_and_dump("'escaped \\\\ backslash'") == "'escaped \\\\ backslash'"); + + // floating point constants + TRY_CHECK(parse_and_dump("pi") == "3.14159"); + TRY_CHECK(parse_and_dump("deg_to_rad") == "0.0174533"); + TRY_CHECK(parse_and_dump("rad_to_deg") == "57.2958"); + + // unary functions + // sin / cos + TRY_CHECK(eval(" sin(0.25 * pi) / cos(0.25 * pi) ").to_double() == approx(1.0)); + // tan + TRY_CHECK(eval(" tan(0.25 * pi) ").to_double() == approx(1.0)); + // atan + TRY_CHECK(eval(" rad_to_deg * atan(1.0) ").to_double() == approx(45.0)); + // exp + TRY_CHECK(eval(" exp(0.0) ") == 1.0); + // log + TRY_CHECK(eval(" log(1.0) ") == 0.0); + TRY_CHECK(eval(" log(exp(1.0)) ") == 1.0); + // abs + TRY_CHECK(eval(" abs(cos(-pi)) ") == 1.0); + // length (string) + TRY_CHECK(eval(" length('1234567890') ").to_int() == 10); + + // binary functions + // min + TRY_CHECK(eval(" min(-0.01, 0.001) ") == -0.01); + // max + TRY_CHECK(eval(" max(0.01, -0.1) ") == 0.01); + // pow + TRY_CHECK(eval(" pow(2, 32) ") == 4294967296.0); + + // geometry types + TRY_CHECK(eval(" [mapnik::geometry_type] = point ") == true); + TRY_CHECK(eval(" [mapnik::geometry_type] <> linestring ") == true); + TRY_CHECK(eval(" [mapnik::geometry_type] != polygon ") == true); + TRY_CHECK(eval(" [mapnik::geometry_type] neq collection ") == true); + TRY_CHECK(eval(" [mapnik::geometry_type] eq collection ") == false); + + //unary expression + TRY_CHECK(eval(" -123.456 ") == -123.456); + TRY_CHECK(eval(" +123.456 ") == 123.456); + + // multiplicative/additive + auto expr = mapnik::parse_expression("(2.0 * 2.0 + 3.0 * 3.0)/(2.0 * 2.0 - 3.0 * 3.0)"); + TRY_CHECK(evaluate(*feature, *expr) == -2.6); + auto expr2 = mapnik::parse_expression("(2.0 * 2.0 + 3.0 * 3.0)/((2.0 - 3.0) * (2.0 + 3.0))"); + TRY_CHECK(evaluate(*feature, *expr) == evaluate(*feature, *expr2)); + + // logical + TRY_CHECK(eval(" [int] = 123 and [double] = 1.23456 && [bool] = true and [null] = null && [foo] = 'bar' ") == true); + TRY_CHECK(eval(" [int] = 456 or [foo].match('foo') || length([foo]) = 3 ") == true); + TRY_CHECK(eval(" not true and not true ") == eval(" (not true ) and (not true ) ")); + TRY_CHECK(eval(" not true or not true ") == eval(" (not true ) or (not true ) ")); + TRY_CHECK(eval(" not false and not false ") == eval(" (not false) and (not false) ")); + TRY_CHECK(eval(" not false or not false ") == eval(" (not false) or (not false) ")); + + // test not/and/or precedence using combinations of "not EQ1 OP1 not EQ2 OP2 not EQ3" + TRY_CHECK(eval(" not [grass] = 'grow' and not [wind] = 'blow' and not [sky] = 'is blue' ") == false); + TRY_CHECK(eval(" not [grass] = 'grow' and not [wind] = 'blow' or not [sky] = 'is blue' ") == false); + TRY_CHECK(eval(" not [grass] = 'grow' or not [wind] = 'blow' and not [sky] = 'is blue' ") == false); + TRY_CHECK(eval(" not [grass] = 'grow' or not [wind] = 'blow' or not [sky] = 'is blue' ") == false); + TRY_CHECK(eval(" not [grass] = 'grew' and not [wind] = 'blew' and not [sky] = 'was blue' ") == true); + TRY_CHECK(eval(" not [grass] = 'grew' and not [wind] = 'blew' or not [sky] = 'was blue' ") == true); + TRY_CHECK(eval(" not [grass] = 'grew' or not [wind] = 'blew' and not [sky] = 'was blue' ") == true); + TRY_CHECK(eval(" not [grass] = 'grew' or not [wind] = 'blew' or not [sky] = 'was blue' ") == true); + + // relational + TRY_CHECK(eval(" [int] > 100 and [int] gt 100.0 and [double] < 2 and [double] lt 2.0 ") == true); + TRY_CHECK(eval(" [int] >= 123 and [int] ge 123.0 and [double] <= 1.23456 and [double] le 1.23456 ") == true); + + // empty string/null equality + TRY_CHECK(eval("[null] = null") == true); + TRY_CHECK(eval("[null] != null") == false); + TRY_CHECK(eval("[null] = ''") == false); + ///////////////////// ref: https://github.com/mapnik/mapnik/issues/1859 + TRY_CHECK(eval("[null] != ''") == false); // back compatible - will be changed in 3.1.x + ////////////////////// + TRY_CHECK(eval("'' = [null]") == false); + TRY_CHECK(eval("'' != [null]") == true); + + // regex + // replace + TRY_CHECK(eval(" [foo].replace('(\\B)|( )','$1 ') ") == tr.transcode("b a r")); + + // https://en.wikipedia.org/wiki/Chess_symbols_in_Unicode + //'\u265C\u265E\u265D\u265B\u265A\u265D\u265E\u265C' - black chess figures + // replace black knights with white knights + auto val0 = eval(u8"'\u265C\u265E\u265D\u265B\u265A\u265D\u265E\u265C'.replace('\u265E','\u2658')"); + auto val1 = eval("'♜♞♝♛♚♝♞♜'.replace('♞','♘')"); // ==> expected ♜♘♝♛♚♝♘♜ + TRY_CHECK(val0 == val1); + TRY_CHECK(val0.to_string() == val1.to_string()); // UTF-8 + TRY_CHECK(val0.to_unicode() == val1.to_unicode()); // Unicode (UTF-16) + + // following test will fail if boost_regex is built without ICU support (unpaired surrogates in output) + TRY_CHECK(eval("[name].replace('(\\B)|( )',' ') ") == tr.transcode("Q u é b e c")); + TRY_CHECK(eval("'Москва'.replace('(? diff -Nru mapnik-3.0.9+ds/test/unit/core/value_test.cpp mapnik-3.0.13+ds/test/unit/core/value_test.cpp --- mapnik-3.0.9+ds/test/unit/core/value_test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/core/value_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,110 @@ + +#include "catch.hpp" + +#include +#include + +TEST_CASE("mapnik::value") +{ + SECTION("add/sub/mult/div") + { + mapnik::value v0 = 1; // mapnik::value_integer + mapnik::value v1 = 1.001; // mapnik::value_double + mapnik::value v2 = true; // mapnik::value_boolean + + CHECK(v0.is()); + CHECK(v1.is()); + CHECK(v2.is()); + + // add + auto add0 = v0 + v1; // result value_double + auto add1 = v1 + v0; + auto add2 = v1 + v2; // result value_double + auto add3 = v2 + v1; + auto add4 = v0 + v2; // result value_integer + auto add5 = v2 + v0; + auto add6 = v2 + v2; // result_integer + // check type promotion + CHECK(add0.is()); + CHECK(add1.is()); + CHECK(add2.is()); + CHECK(add3.is()); + CHECK(add4.is()); + CHECK(add5.is()); + CHECK(add6.is()); + // + CHECK(add6 == v0 + v0); + // check commutative rules + CHECK(add0 == add1); + CHECK(add2 == add3); + CHECK(add4 == add5); + + // sub + auto sub0 = v0 - v1; // result value_double + auto sub1 = v1 - v0; + auto sub2 = v1 - v2; // result value_double + auto sub3 = v2 - v1; + auto sub4 = v0 - v2; // result value_integer + auto sub5 = v2 - v0; + auto sub6 = v2 - v2; // result value_integer + + CHECK(sub0.is()); + CHECK(sub1.is()); + CHECK(sub2.is()); + CHECK(sub3.is()); + CHECK(sub4.is()); + CHECK(sub5.is()); + CHECK(sub6.is()); + + // check commutative rules + CHECK(sub0 == -sub1); + CHECK(sub2 == -sub3); + CHECK(sub4 == -sub5); + CHECK(sub6 == v0 - v0); + + // multl + auto mult0 = v0 * v1; // result value_double + auto mult1 = v1 * v0; + auto mult2 = v1 * v2; // result value_double + auto mult3 = v2 * v1; + auto mult4 = v0 * v2; // result value_integer + auto mult5 = v2 * v0; + auto mult6 = v2 * v2; // result value_integer + + CHECK(mult0.is()); + CHECK(mult1.is()); + CHECK(mult2.is()); + CHECK(mult3.is()); + CHECK(mult4.is()); + CHECK(mult5.is()); + CHECK(mult6.is()); + // check commutative rules + CHECK(mult0 == mult1); + CHECK(mult2 == mult3); + CHECK(mult4 == mult5); + // + CHECK(mult6 == v0 * v0); + + // div + auto div0 = v0 / v1; // result value_double + auto div1 = v1 / v0; + auto div2 = v1 / v2; // result value_double + auto div3 = v2 / v1; + auto div4 = v0 / v2; // result value_integer + auto div5 = v2 / v0; + auto div6 = v2 / v2; // result value_interger + + CHECK(div0.is()); + CHECK(div1.is()); + CHECK(div2.is()); + CHECK(div3.is()); + CHECK(div4.is()); + CHECK(div5.is()); + CHECK(div6.is()); + + CHECK(div0 == 1.0/div1); + CHECK(div2 == 1.0/div3); + CHECK(div4 == 1.0/div5); + CHECK(div6 == v0/v0); + } +} diff -Nru mapnik-3.0.9+ds/test/unit/data/well-known-geometries.test mapnik-3.0.13+ds/test/unit/data/well-known-geometries.test --- mapnik-3.0.9+ds/test/unit/data/well-known-geometries.test 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/data/well-known-geometries.test 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,13 @@ +POINT (30 10);\x01010000000000000000003e400000000000002440;\x01003c14 +LINESTRING (30 10, 10 30, 40 40);\x0102000000030000000000000000003e40000000000000244000000000000024400000000000003e4000000000000044400000000000004440;\x0200033c1427283c14 +POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10));\x010300000001000000050000000000000000003e4000000000000024400000000000004440000000000000444000000000000034400000000000004440000000000000244000000000000034400000000000003e400000000000002440;\x030001053c14143c270013272813 +POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10),(20 30, 35 35, 30 20, 20 30));\x0103000000020000000500000000000000008041400000000000002440000000000080464000000000008046400000000000002e40000000000000444000000000000024400000000000003440000000000080414000000000000024400400000000000000000034400000000000003e40000000000080414000000000008041400000000000003e40000000000000344000000000000034400000000000003e40;\x03000205461414463b0909273213041d281e0a091d1314 +MULTIPOINT ((10 40), (40 30), (20 20), (30 10));\x010400000004000000010100000000000000000024400000000000004440010100000000000000000044400000000000003e4001010000000000000000003440000000000000344001010000000000000000003e400000000000002440;\x04000414503c1327131413 +MULTIPOINT (10 40, 40 30, 20 20, 30 10);\x010400000004000000010100000000000000000024400000000000004440010100000000000000000044400000000000003e4001010000000000000000003440000000000000344001010000000000000000003e400000000000002440;\x04000414503c1327131413 +MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10));\x010500000002000000010200000003000000000000000000244000000000000024400000000000003440000000000000344000000000000024400000000000004440010200000004000000000000000000444000000000000044400000000000003e400000000000003e40000000000000444000000000000034400000000000003e400000000000002440;\x05000203141414141328043c00131314131313 +MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)));\x010600000002000000010300000001000000040000000000000000003e40000000000000344000000000008046400000000000004440000000000000244000000000000044400000000000003e400000000000003440010300000001000000050000000000000000002e4000000000000014400000000000004440000000000000244000000000000024400000000000003440000000000000144000000000000024400000000000002e400000000000001440;\x06000201043c281e284500282701051d1d320a3b1409131409 +MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((20 35, 10 30, 10 10, 30 5, 45 20, 20 35),(30 20, 20 15, 20 25, 30 20)));\x01060000000200000001030000000100000004000000000000000000444000000000000044400000000000003440000000000080464000000000008046400000000000003e4000000000000044400000000000004440010300000002000000060000000000000000003440000000000080414000000000000024400000000000003e40000000000000244000000000000024400000000000003e4000000000000014400000000000804640000000000000344000000000000034400000000000804140040000000000000000003e40000000000000344000000000000034400000000000002e40000000000000344000000000000039400000000000003e400000000000003440;\x06000201045050270a321d0914020627091309002728091e1e311e04141d130900141409 +GEOMETRYCOLLECTION(POINT(4 6),LINESTRING(4 6,7 10));\x010700000002000000010100000000000000000010400000000000001840010200000002000000000000000000104000000000000018400000000000001c400000000000002440;\x0700020100080c020002080c0608 +POINT EMPTY;\x0101000000000000000000f87f000000000000f87f;\x0110 +LINESTRING EMPTY;\x010200000000000000;\x0210 +POLYGON EMPTY;\x010300000000000000;\x0310 diff -Nru mapnik-3.0.9+ds/test/unit/datasource/csv.cpp mapnik-3.0.13+ds/test/unit/datasource/csv.cpp --- mapnik-3.0.9+ds/test/unit/datasource/csv.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/datasource/csv.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,6 +24,7 @@ #include "ds_test_util.hpp" #include +#include #include #include #include @@ -68,6 +69,10 @@ mapnik::parameters params; params["type"] = std::string("csv"); params["file"] = file_name; + if (!base.empty()) + { + params["base"] = base; + } params["strict"] = mapnik::value_bool(strict); auto ds = mapnik::datasource_cache::instance().create(params); // require a non-null pointer returned @@ -75,31 +80,11 @@ return ds; } -int create_disk_index(std::string const& filename, bool silent = true) -{ - std::string cmd; - if (std::getenv("DYLD_LIBRARY_PATH") != nullptr) - { - cmd += std::string("export DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && "; - } - cmd += "mapnik-index " + filename; - if (silent) - { -#ifndef _WINDOWS - cmd += " 2>/dev/null"; -#else - cmd += " 2> nul"; -#endif - } - return std::system(cmd.c_str()); -} - } // anonymous namespace -static const std::string csv_plugin("./plugins/input/csv.input"); - TEST_CASE("csv") { + std::string csv_plugin("./plugins/input/csv.input"); if (mapnik::util::exists(csv_plugin)) { // make the tests silent since we intentionally test error conditions that are noisy @@ -157,7 +142,7 @@ int ret_posix = (ret >> 8) & 0x000000ff; INFO(ret); INFO(ret_posix); - require_fail = (path == "test/data/csv/warns/feature_id_counting.csv") ? false : true; + require_fail = (boost::iends_with(path,"feature_id_counting.csv")) ? false : true; if (!require_fail) { REQUIRE(mapnik::util::exists(path + ".index")); @@ -204,7 +189,7 @@ int ret_posix = (ret >> 8) & 0x000000ff; INFO(ret); INFO(ret_posix); - if (path != "test/data/csv/more_headers_than_column_values.csv") // mapnik-index won't create *.index for 0 features + if (!boost::iends_with(path,"more_headers_than_column_values.csv")) // mapnik-index won't create *.index for 0 features { CHECK(mapnik::util::exists(path + ".index")); } @@ -288,7 +273,7 @@ INFO(ret_posix); CHECK(mapnik::util::exists(filepath + ".index")); } - auto ds = get_csv_ds(filepath,true,base); + auto ds = get_csv_ds(filename,true,base); CHECK(ds->type() == mapnik::datasource::datasource_t::Vector); auto fields = ds->get_descriptor().get_descriptors(); require_field_names(fields, {"Precinct", "Phone", "Address", "City", "geo_longitude", "geo_latitude", "geo_accuracy"}); @@ -892,7 +877,15 @@ auto feature = all_features(ds)->next(); REQUIRE(bool(feature)); REQUIRE(feature->has_key("Name")); - CHECK(feature->get("Name") == ustring(name.c_str())); + std::string utf8; + mapnik::transcoder tr("utf-8"); + ustring expected_string = tr.transcode(name.c_str()); + mapnik::value val(expected_string); + mapnik::to_utf8(expected_string,utf8); + INFO(feature->get("Name")); + INFO(utf8); + INFO(val); + CHECK(feature->get("Name") == val); } } // END SECTION @@ -983,7 +976,7 @@ using ustring = mapnik::value_unicode_string; using row = std::pair; - for (auto const &r : { + for (auto const& r : { row{"test/data/csv/fails/needs_headers_two_lines.csv", 2}, row{"test/data/csv/fails/needs_headers_one_line.csv", 1}, row{"test/data/csv/fails/needs_headers_one_line_no_newline.csv", 1}}) diff -Nru mapnik-3.0.9+ds/test/unit/datasource/ds_test_util.hpp mapnik-3.0.13+ds/test/unit/datasource/ds_test_util.hpp --- mapnik-3.0.9+ds/test/unit/datasource/ds_test_util.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/datasource/ds_test_util.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -20,6 +20,10 @@ * *****************************************************************************/ + +#ifndef MAPNIK_UNIT_DATSOURCE_UTIL +#define MAPNIK_UNIT_DATSOURCE_UTIL + #include "catch.hpp" #include @@ -36,7 +40,7 @@ std::stringstream s; for (auto const& item : vec) { - s << item << "\n"; + s << " " << item << "\n"; } return s.str(); } @@ -47,34 +51,41 @@ std::stringstream s; for (auto const& item : vec) { - s << item.get_name() << "\n"; + s << " " << item.get_name() << "\n"; } return s.str(); } +#define REQUIRE_FIELD_NAMES(fields, names) \ + INFO("fields:\n" + vector_to_string(fields) + "names:\n" + vector_to_string(names)); \ + REQUIRE(fields.size() == names.size()); \ + auto itr_a = fields.begin(); \ + auto const end_a = fields.end(); \ + auto itr_b = names.begin(); \ + for (; itr_a != end_a; ++itr_a, ++itr_b) \ + { \ + CHECK(itr_a->get_name() == *itr_b); \ + } \ + inline void require_field_names(std::vector const &fields, std::initializer_list const &names) { - INFO("fields: " + vector_to_string(fields) + " names: " + vector_to_string(names)); - REQUIRE(fields.size() == names.size()); - auto itr_a = fields.begin(); - auto const end_a = fields.end(); - auto itr_b = names.begin(); - for (; itr_a != end_a; ++itr_a, ++itr_b) - { - CHECK(itr_a->get_name() == *itr_b); - } + REQUIRE_FIELD_NAMES(fields,names); } +#define REQUIRE_FIELD_TYPES(fields, types) \ + REQUIRE(fields.size() == types.size()); \ + auto itr_a = fields.begin(); \ + auto const end_a = fields.end(); \ + auto itr_b = types.begin(); \ + for (; itr_a != end_a; ++itr_a, ++itr_b) { \ + CHECK(itr_a->get_type() == *itr_b); \ + } \ + inline void require_field_types(std::vector const &fields, - std::initializer_list const &types) { - REQUIRE(fields.size() == types.size()); - auto itr_a = fields.begin(); - auto const end_a = fields.end(); - auto itr_b = types.begin(); - for (; itr_a != end_a; ++itr_a, ++itr_b) { - CHECK(itr_a->get_type() == *itr_b); - } + std::initializer_list const &types) +{ + REQUIRE_FIELD_TYPES(fields, types); } inline mapnik::featureset_ptr all_features(mapnik::datasource_ptr ds) { @@ -95,13 +106,18 @@ } using attr = std::tuple; + +#define REQUIRE_ATTRIBUTES(feature, attrs) \ + REQUIRE(bool(feature)); \ + for (auto const &kv : attrs) { \ + REQUIRE(feature->has_key(std::get<0>(kv))); \ + CHECK(feature->get(std::get<0>(kv)) == std::get<1>(kv)); \ + } \ + + inline void require_attributes(mapnik::feature_ptr feature, std::initializer_list const &attrs) { - REQUIRE(bool(feature)); - for (auto const &kv : attrs) { - REQUIRE(feature->has_key(std::get<0>(kv))); - CHECK(feature->get(std::get<0>(kv)) == std::get<1>(kv)); - } + REQUIRE_ATTRIBUTES(feature, attrs); } namespace detail { @@ -169,4 +185,25 @@ CHECK(feature_count(feature->get_geometry()) == num_parts); } +inline int create_disk_index(std::string const& filename, bool silent = true) +{ + std::string cmd; + if (std::getenv("DYLD_LIBRARY_PATH") != nullptr) + { + cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " "; + } + cmd += "mapnik-index " + filename; + if (silent) + { +#ifndef _WINDOWS + cmd += " 2>/dev/null"; +#else + cmd += " 2> nul"; +#endif + } + return std::system(cmd.c_str()); +} + } + +#endif // MAPNIK_UNIT_DATSOURCE_UTIL diff -Nru mapnik-3.0.9+ds/test/unit/datasource/geojson.cpp mapnik-3.0.13+ds/test/unit/datasource/geojson.cpp --- mapnik-3.0.9+ds/test/unit/datasource/geojson.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/datasource/geojson.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -21,7 +21,9 @@ *****************************************************************************/ #include "catch.hpp" +#include "ds_test_util.hpp" +#include #include #include #include @@ -61,25 +63,6 @@ return std::make_pair(ds,feature); } -int create_disk_index(std::string const& filename, bool silent = true) -{ - std::string cmd; - if (std::getenv("DYLD_LIBRARY_PATH") != nullptr) - { - cmd += std::string("export DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && "; - } - cmd += "mapnik-index " + filename; - if (silent) - { -#ifndef _WINDOWS - cmd += " 2>/dev/null"; -#else - cmd += " 2> nul"; -#endif - } - return std::system(cmd.c_str()); -} - } TEST_CASE("geojson") { @@ -113,6 +96,97 @@ } } + SECTION("GeoJSON an empty FeatureCollection") + { + for (auto cache_features : {true, false}) + { + mapnik::parameters params; + params["type"] = "geojson"; + params["file"] = "./test/data/json/empty_featurecollection.json"; + params["cache_features"] = cache_features; + auto ds = mapnik::datasource_cache::instance().create(params); + CHECK(ds != nullptr); + auto fs = all_features(ds); + REQUIRE(!mapnik::is_valid(fs)); + while (auto f = fs->next()) + { + CHECK(false); // shouldn't get here + } + } + } + + SECTION("GeoJSON num_features_to_query") + { + std::string filename = "./test/data/json/featurecollection-multipleprops.geojson"; + for (mapnik::value_integer num_features_to_query : { mapnik::value_integer(-1), + mapnik::value_integer(0), + mapnik::value_integer(1), + mapnik::value_integer(2), + mapnik::value_integer(3), + std::numeric_limits::max()}) + { + for (auto create_index : { true, false }) + { + if (create_index) + { + int ret = create_disk_index(filename); + int ret_posix = (ret >> 8) & 0x000000ff; + INFO(ret); + INFO(ret_posix); + CHECK(mapnik::util::exists(filename + ".index")); + } + + for (auto cache_features : {true, false}) + { + mapnik::parameters params; + params["type"] = "geojson"; + params["file"] = filename; + params["cache_features"] = cache_features; + params["num_features_to_query"] = num_features_to_query; + auto ds = mapnik::datasource_cache::instance().create(params); + CHECK(ds != nullptr); + auto fields = ds->get_descriptor().get_descriptors(); + if (!create_index && cache_features) + { + // when there's no index and caching is enabled descriptor is always fully initialised + REQUIRE(fields.size() == 2); + } + else + { + // at least 1 feature should be queried + REQUIRE(fields.size() == std::min(std::max(mapnik::value_integer(1), num_features_to_query), + mapnik::value_integer(2))); + } + } + // cleanup + if (create_index && mapnik::util::exists(filename + ".index")) + { + mapnik::util::remove(filename + ".index"); + } + } + } + } + + SECTION("GeoJSON attribute descriptors are alphabetically ordered") + { + for (auto cache_features : {true, false}) + { + mapnik::parameters params; + params["type"] = "geojson"; + params["file"] = "./test/data/json/properties.json"; + params["cache_features"] = cache_features; + auto ds = mapnik::datasource_cache::instance().create(params); + CHECK(ds != nullptr); + std::vector expected_names = {"a", "b", "c", "d", "e"}; + auto fields = ds->get_descriptor().get_descriptors(); + std::size_t index = 0; + for (auto const& field : fields) + { + REQUIRE(field.get_name() == expected_names[index++]); + } + } + } + SECTION("GeoJSON invalid Point") { for (auto cache_features : {true, false}) @@ -302,8 +376,6 @@ } auto features = ds->features(query); auto features2 = ds->features_at_point(ds->envelope().center(),0); - REQUIRE(features != nullptr); - REQUIRE(features2 != nullptr); auto feature = features->next(); auto feature2 = features2->next(); REQUIRE(feature != nullptr); @@ -421,7 +493,6 @@ query.add_property_name(field.get_name()); } auto features = ds->features(query); - REQUIRE(features != nullptr); auto feature = features->next(); REQUIRE(feature != nullptr); REQUIRE(feature->envelope() == mapnik::box2d(123,456,123,456)); @@ -443,7 +514,8 @@ for (auto const& c_str : {"./test/data/json/feature-malformed-1.geojson", "./test/data/json/feature-malformed-2.geojson", - "./test/data/json/feature-malformed-3.geojson"}) + "./test/data/json/feature-malformed-3.geojson", + "./test/data/json/feature-malformed-4.geojson"}) { std::string filename(c_str); params["file"] = filename; @@ -483,43 +555,46 @@ SECTION("GeoJSON ensure mapnik::featureset::next() throws on malformed input") { - std::string filename{"./test/data/json/featurecollection-malformed.json"}; mapnik::parameters params; params["type"] = "geojson"; - params["file"] = filename; - - // cleanup in the case of a failed previous run - if (mapnik::util::exists(filename + ".index")) + for (auto const& c_str : {"./test/data/json/featurecollection-malformed.json", + "./test/data/json/featurecollection-malformed-2.json"}) { - mapnik::util::remove(filename + ".index"); - } + std::string filename(c_str); + params["file"] = filename; + // cleanup in the case of a failed previous run + if (mapnik::util::exists(filename + ".index")) + { + mapnik::util::remove(filename + ".index"); + } - CHECK(!mapnik::util::exists(filename + ".index")); - int ret = create_disk_index(filename); - int ret_posix = (ret >> 8) & 0x000000ff; - INFO(ret); - INFO(ret_posix); - CHECK(mapnik::util::exists(filename + ".index")); + CHECK(!mapnik::util::exists(filename + ".index")); + int ret = create_disk_index(filename); + int ret_posix = (ret >> 8) & 0x000000ff; + INFO(ret); + INFO(ret_posix); + CHECK(mapnik::util::exists(filename + ".index")); - for (auto cache_features : {true,false}) - { - params["cache_features"] = cache_features; - auto ds = mapnik::datasource_cache::instance().create(params); - auto fields = ds->get_descriptor().get_descriptors(); - mapnik::query query(ds->envelope()); - auto features = ds->features(query); - REQUIRE_THROWS( - auto feature = features->next(); - while (feature != nullptr) - { - feature = features->next(); - }); - } + for (auto cache_features : {true,false}) + { + params["cache_features"] = cache_features; + auto ds = mapnik::datasource_cache::instance().create(params); + auto fields = ds->get_descriptor().get_descriptors(); + mapnik::query query(ds->envelope()); + auto features = ds->features(query); + REQUIRE_THROWS( + auto feature = features->next(); + while (feature != nullptr) + { + feature = features->next(); + }); + } - // cleanup - if (mapnik::util::exists(filename + ".index")) - { - mapnik::util::remove(filename + ".index"); + // cleanup + if (mapnik::util::exists(filename + ".index")) + { + mapnik::util::remove(filename + ".index"); + } } } @@ -624,6 +699,115 @@ } // cleanup if (create_index && mapnik::util::exists(filename + ".index")) + { + mapnik::util::remove(filename + ".index"); + } + } + } + + SECTION("GeoJSON descriptor returns all field names") + { + mapnik::parameters params; + params["type"] = "geojson"; + + std::string filename("./test/data/json/featurecollection-multipleprops.geojson"); + params["file"] = filename; + + // cleanup in the case of a failed previous run + if (mapnik::util::exists(filename + ".index")) + { + mapnik::util::remove(filename + ".index"); + } + + for (auto create_index : { true, false }) + { + if (create_index) + { + CHECK(!mapnik::util::exists(filename + ".index")); + int ret = create_disk_index(filename); + int ret_posix = (ret >> 8) & 0x000000ff; + INFO(ret); + INFO(ret_posix); + CHECK(mapnik::util::exists(filename + ".index")); + } + + for (auto cache_features : {true, false}) + { + params["cache_features"] = cache_features; + auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(bool(ds)); + auto fields = ds->get_descriptor().get_descriptors(); + std::initializer_list names = {"one", "two"}; + REQUIRE_FIELD_NAMES(fields, names); + } + // cleanup + if (create_index && mapnik::util::exists(filename + ".index")) + { + mapnik::util::remove(filename + ".index"); + } + } + } + + SECTION("GeoJSON properties are properly expressed") + { + mapnik::transcoder tr("utf8"); + mapnik::parameters params; + params["type"] = "geojson"; + + std::string filename("./test/data/json/escaped.geojson"); + params["file"] = filename; + + // cleanup in the case of a failed previous run + if (mapnik::util::exists(filename + ".index")) + { + mapnik::util::remove(filename + ".index"); + } + + for (auto create_index : { true, false }) + { + if (create_index) + { + CHECK(!mapnik::util::exists(filename + ".index")); + int ret = create_disk_index(filename); + int ret_posix = (ret >> 8) & 0x000000ff; + INFO(ret); + INFO(ret_posix); + CHECK(mapnik::util::exists(filename + ".index")); + } + + for (auto cache_features : {true, false}) + { + params["cache_features"] = cache_features; + auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(bool(ds)); + auto fields = ds->get_descriptor().get_descriptors(); + std::initializer_list names = {"NOM_FR","array","boolean","description","double","empty_array", "empty_object","int","name","object","spaces"}; + REQUIRE_FIELD_NAMES(fields, names); + + auto fs = all_features(ds); + std::initializer_list attrs = { + attr{"name", tr.transcode("Test")}, + attr{"NOM_FR", tr.transcode("Québec")}, + attr{"boolean", mapnik::value_bool("true")}, + attr{"description", tr.transcode("Test: \u005C")}, + attr{"double", mapnik::value_double(1.1)}, + attr{"int", mapnik::value_integer(1)}, + attr{"object", tr.transcode("{\"name\":\"waka\",\"spaces\":\"value with spaces\",\"int\":1,\"double\":1.1,\"boolean\":false" + ",\"NOM_FR\":\"Québec\",\"array\":[\"string\",\"value with spaces\",3,1.1,null,true" + ",\"Québec\"],\"another_object\":{\"name\":\"nested object\"}}")}, + attr{"spaces", tr.transcode("this has spaces")}, + attr{"array", tr.transcode("[\"string\",\"value with spaces\",3,1.1,null,true," + "\"Québec\",{\"name\":\"object within an array\"}," + "[\"array\",\"within\",\"an\",\"array\"]]")}, + attr{"empty_array", tr.transcode("[]")}, + attr{"empty_object", tr.transcode("{}")}, + }; + auto feature = fs->next(); + REQUIRE(bool(feature)); + REQUIRE_ATTRIBUTES(feature, attrs); + } + // cleanup + if (create_index && mapnik::util::exists(filename + ".index")) { mapnik::util::remove(filename + ".index"); } diff -Nru mapnik-3.0.9+ds/test/unit/datasource/memory.cpp mapnik-3.0.13+ds/test/unit/datasource/memory.cpp --- mapnik-3.0.9+ds/test/unit/datasource/memory.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/datasource/memory.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,46 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 "catch.hpp" +#include "ds_test_util.hpp" + +#include +#include +#include +#include + + +TEST_CASE("memory datasource") { + + SECTION("empty featureset") + { + mapnik::parameters params; + mapnik::datasource_ptr ds = std::make_shared(params); + CHECK(ds != nullptr); + auto fs = all_features(ds); + REQUIRE(!mapnik::is_valid(fs)); + while (auto f = fs->next()) + { + CHECK(false); // shouldn't get here + } + } +} diff -Nru mapnik-3.0.9+ds/test/unit/datasource/ogr.cpp mapnik-3.0.13+ds/test/unit/datasource/ogr.cpp --- mapnik-3.0.9+ds/test/unit/datasource/ogr.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/datasource/ogr.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -21,7 +21,7 @@ *****************************************************************************/ #include "catch.hpp" - +#include #include #include #include @@ -45,8 +45,10 @@ mapnik::image_rgba8 im(256,256); mapnik::agg_renderer ren(m, im); ren.apply(); - //mapnik::save_to_file(im, "./test/data/images/point_json.png"); std::string filename("./test/data/images/point_json.png"); + if (std::getenv("UPDATE") != nullptr) { + mapnik::save_to_file(im, filename); + } std::unique_ptr reader(mapnik::get_image_reader(filename,"png")); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); mapnik::image_rgba8 expected = mapnik::util::get(data); diff -Nru mapnik-3.0.9+ds/test/unit/datasource/postgis.cpp mapnik-3.0.13+ds/test/unit/datasource/postgis.cpp --- mapnik-3.0.9+ds/test/unit/datasource/postgis.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/datasource/postgis.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,24 +29,24 @@ #include /* - -Compile and run just this test: - -clang++ -o test-postgis -g -I./test/ test/unit/run.cpp test/unit/datasource/postgis.cpp `mapnik-config --all-flags` && ./test-postgis -d yes - + Compile and run just this test: + clang++ -o test-postgis -g -I./test/ test/unit/run.cpp test/unit/datasource/postgis.cpp `mapnik-config --all-flags` && ./test-postgis -d yes */ +#include + namespace { -int run(std::string const& command, bool silent = false) +bool run(std::string const& command, bool okay_to_fail = false) { std::string cmd; if (std::getenv("DYLD_LIBRARY_PATH") != nullptr) { - cmd += std::string("export DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && "; + cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && "; } cmd += command; - if (silent) + // silence output unless MAPNIK_TEST_DEBUG is defined + if (std::getenv("MAPNIK_TEST_DEBUG") == nullptr) { #ifndef _WINDOWS cmd += " 2>/dev/null"; @@ -54,41 +54,287 @@ cmd += " 2> nul"; #endif } + else + { + std::clog << "Running " << cmd << "\n"; + } bool worked = (std::system(cmd.c_str()) == 0); - if (silent == true) return true; + if (okay_to_fail == true) return true; return worked; } +std::string const dbname("mapnik-tmp-postgis-test-db"); +bool status = false; + +bool ping_postmaster() +{ + return (run("psql --version") + && run("dropdb --if-exists " + dbname) + && run("createdb -T template_postgis " + dbname)); +} + +} + TEST_CASE("postgis") { - SECTION("Postgis data initialization") + SECTION("Ping Postmaster (check if server is runnging and accessible") { - REQUIRE(run("dropdb mapnik-tmp-postgis-test-db",true)); - REQUIRE(run("createdb -T template_postgis mapnik-tmp-postgis-test-db")); - std::stringstream cmd; - cmd << "psql -q mapnik-tmp-postgis-test-db -f ./test/data/sql/table1.sql"; - REQUIRE(run(cmd.str())); + if (!ping_postmaster()) + { + WARN("Can't run postgis.input tests - check postmaster is running and accessible"); + return; + } + else + { + status = true; + } } - - std::string datasource_plugin("./plugins/input/postgis.input"); - if (mapnik::util::exists(datasource_plugin)) + if (status) { - SECTION("Postgis plugin initialization") + SECTION("Postgis data initialization") + { + //don't add 'true' here, to get error message, when drop fails. If it works nothing is output + REQUIRE(run("dropdb --if-exists " + dbname)); + REQUIRE(run("createdb -T template_postgis " + dbname)); + //REQUIRE(run("createdb " + dbname)); + // Breaks when raster support is missing (unfortunately this is common) + //REQUIRE(run("psql -c 'CREATE EXTENSION postgis;' " + dbname, true)); + REQUIRE(run("psql -q -f ./test/data/sql/postgis-create-db-and-tables.sql " + dbname)); + } + + mapnik::parameters base_params; + base_params["type"] = "postgis"; + base_params["dbname"] = dbname; + + SECTION("Postgis should throw without 'table' parameter") + { + mapnik::parameters params(base_params); + CHECK_THROWS(mapnik::datasource_cache::instance().create(params)); + } + + SECTION("Postgis should throw with 'max_async_connection' greater than 'max_size'") { - mapnik::parameters params; - params["type"] = "postgis"; - params["dbname"] = "mapnik-tmp-postgis-test-db"; + mapnik::parameters params(base_params); params["table"] = "test"; + params["max_async_connection"] = "2"; + params["max_size"] = "1"; + CHECK_THROWS(mapnik::datasource_cache::instance().create(params)); + } + + SECTION("Postgis should throw with invalid metadata query") + { + mapnik::parameters params(base_params); + params["table"] = "does_not_exist"; + CHECK_THROWS(mapnik::datasource_cache::instance().create(params)); + } + + SECTION("Postgis should throw with invalid key field") + { + mapnik::parameters params(base_params); + params["table"] = "test_invalid_id"; + params["key_field"] = "id"; + CHECK_THROWS(mapnik::datasource_cache::instance().create(params)); + } + + SECTION("Postgis should throw with multicolumn primary key") + { + mapnik::parameters params(base_params); + params["table"] = "test_invalid_multi_col_pk"; + params["autodetect_key_field"] = "true"; + CHECK_THROWS(mapnik::datasource_cache::instance().create(params)); + } + + SECTION("Postgis should throw without geom column") + { + mapnik::parameters params(base_params); + params["table"] = "test_no_geom_col"; auto ds = mapnik::datasource_cache::instance().create(params); REQUIRE(ds != nullptr); - CHECK(ds->type() == mapnik::datasource::datasource_t::Vector); + CHECK_THROWS(all_features(ds)); + } + + SECTION("Postgis should throw with invalid credentials") + { + mapnik::parameters params(base_params); + params["table"] = "test"; + params["user"] = "not_a_valid_user"; + params["password"] = "not_a_valid_pwd"; + CHECK_THROWS(mapnik::datasource_cache::instance().create(params)); + } + + SECTION("Postgis initialize dataset with persist_connection, schema, extent, geometry field, autodectect key field, simplify_geometries, row_limit") + { + mapnik::parameters params(base_params); + params["persist_connection"] = "false"; + params["table"] = "public.test"; + params["geometry_field"] = "geom"; + params["autodetect_key_field"] = "true"; + params["extent"] = "-1 -1, -1 2, 4 3, 3 -1, -1 -1"; + params["simplify_geometries"] = "true"; + params["row_limit"] = "1"; + auto ds = mapnik::datasource_cache::instance().create(params); + } + + SECTION("Postgis dataset geometry type") + { + mapnik::parameters params(base_params); + params["table"] = "(SELECT * FROM test WHERE gid=1) as data"; + auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(ds != nullptr); + CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Point); + } + + SECTION("Postgis query field names") + { + mapnik::parameters params(base_params); + params["table"] = "test"; + auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(ds != nullptr); + REQUIRE(ds->type() == mapnik::datasource::datasource_t::Vector); auto fields = ds->get_descriptor().get_descriptors(); - require_field_names(fields, {"gid"}); - require_field_types(fields, {mapnik::Integer}); + require_field_names(fields, { "gid", "colbigint", "col_text", "col-char", "col+bool", "colnumeric", "colsmallint", "colfloat4", "colfloat8", "colcharacter" }); + require_field_types(fields, { mapnik::Integer, mapnik::Integer, mapnik::String, mapnik::String, mapnik::Boolean, mapnik::Double, mapnik::Integer, mapnik::Double, mapnik::Double, mapnik::String }); } - } -} + SECTION("Postgis iterate features") + { + mapnik::parameters params(base_params); + params["table"] = "test"; + params["key_field"] = "gid"; + params["max_async_connection"] = "2"; + //params["cursor_size"] = "2"; + auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(ds != nullptr); -} \ No newline at end of file + auto featureset = ds->features_at_point(mapnik::coord2d(1, 1)); + mapnik::feature_ptr feature; + while ((bool(feature = featureset->next()))) { + REQUIRE(feature->get(2).to_string() == feature->get("col_text").to_string()); + REQUIRE(feature->get(4).to_bool() == feature->get("col+bool").to_bool()); + REQUIRE(feature->get(5).to_double() == feature->get("colnumeric").to_double()); + REQUIRE(feature->get(5).to_string() == feature->get("colnumeric").to_string()); + } + + featureset = all_features(ds); + feature = featureset->next(); + //deactivate char tests for now: not yet implemented. + //add at postgis_datasource.cpp:423 + //case 18: // char + //REQUIRE("A" == feature->get("col-char").to_string()); + feature = featureset->next(); + //REQUIRE("B" == feature->get("col-char").to_string()); + feature = featureset->next(); + REQUIRE(false == feature->get("col+bool").to_bool()); + } + + SECTION("Postgis cursorresultest") + { + mapnik::parameters params(base_params); + params["table"] = "(SELECT * FROM test) as data"; + params["cursor_size"] = "2"; + auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(ds != nullptr); + auto featureset = all_features(ds); + CHECK(count_features(featureset) == 8); + + featureset = all_features(ds); + mapnik::feature_ptr feature; + while (bool(feature = featureset->next())) { + CHECK(feature->size() == 10); + } + + featureset = all_features(ds); + require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::Point); + require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::Point); + require_geometry(featureset->next(), 2, mapnik::geometry::geometry_types::MultiPoint); + require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::LineString); + require_geometry(featureset->next(), 2, mapnik::geometry::geometry_types::MultiLineString); + require_geometry(featureset->next(), 1, mapnik::geometry::geometry_types::Polygon); + require_geometry(featureset->next(), 2, mapnik::geometry::geometry_types::MultiPolygon); + require_geometry(featureset->next(), 3, mapnik::geometry::geometry_types::GeometryCollection); + } + + SECTION("Postgis bbox query") + { + mapnik::parameters params(base_params); + params["table"] = "(SELECT * FROM public.test) as data WHERE geom && !bbox!"; + auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(ds != nullptr); + mapnik::box2d ext = ds->envelope(); + CAPTURE(ext); + INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy()); + REQUIRE(ext.minx() == -2); + REQUIRE(ext.miny() == -2); + REQUIRE(ext.maxx() == 5); + REQUIRE(ext.maxy() == 4); + } + + SECTION("Postgis query extent: full dataset") + { + //include schema to increase coverage + mapnik::parameters params(base_params); + params["table"] = "(SELECT * FROM public.test) as data"; + auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(ds != nullptr); + mapnik::box2d ext = ds->envelope(); + CAPTURE(ext); + INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy()); + REQUIRE(ext.minx() == -2); + REQUIRE(ext.miny() == -2); + REQUIRE(ext.maxx() == 5); + REQUIRE(ext.maxy() == 4); + } +/* deactivated for merging: still investigating a proper fix + SECTION("Postgis query extent from subquery") + { + mapnik::parameters params(base_params); + params["table"] = "(SELECT * FROM test where gid=4) as data"; + auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(ds != nullptr); + mapnik::box2d ext = ds->envelope(); + CAPTURE(ext); + INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy()); + REQUIRE(ext.minx() == 0); + REQUIRE(ext.miny() == 0); + REQUIRE(ext.maxx() == 1); + REQUIRE(ext.maxy() == 2); + } +*/ + SECTION("Postgis query extent: from subquery with 'extent_from_subquery=true'") + { + mapnik::parameters params(base_params); + params["table"] = "(SELECT * FROM test where gid=4) as data"; + params["extent_from_subquery"] = "true"; + auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(ds != nullptr); + mapnik::box2d ext = ds->envelope(); + CAPTURE(ext); + INFO(std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy()); + REQUIRE(ext.minx() == 0); + REQUIRE(ext.miny() == 0); + REQUIRE(ext.maxx() == 1); + REQUIRE(ext.maxy() == 2); + } +/* deactivated for merging: still investigating a proper fix + SECTION("Postgis query extent: subset with 'extent_from_subquery=true' and 'scale_denominator'") + { + mapnik::parameters params(base_params); + // !!!! postgis-vt-util::z() returns 'null' when 'scale_denominator > 600000000' + // https://github.com/mapbox/postgis-vt-util/blob/559f073877696a6bfea41baf3e1065f9cf4d18d1/postgis-vt-util.sql#L615-L617 + params["table"] = "(SELECT * FROM test where gid=4 AND z(!scale_denominator!) BETWEEN 0 AND 22) as data"; + params["extent_from_subquery"] = "true"; + auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(ds != nullptr); + mapnik::box2d ext = ds->envelope(); + CAPTURE(ext); + INFO("" << std::setprecision(6) << std::fixed << ext.minx() << "/" << ext.miny() << " " << ext.maxx() << "/" << ext.maxy()); + REQUIRE(ext.minx() == 0); + REQUIRE(ext.miny() == 0); + REQUIRE(ext.maxx() == 1); + REQUIRE(ext.maxy() == 2); + } +*/ + + } +} diff -Nru mapnik-3.0.9+ds/test/unit/datasource/shapeindex.cpp mapnik-3.0.13+ds/test/unit/datasource/shapeindex.cpp --- mapnik-3.0.9+ds/test/unit/datasource/shapeindex.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/datasource/shapeindex.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,8 +24,10 @@ #include #include +#include #include #include +#include #pragma GCC diagnostic push #include #include @@ -35,10 +37,14 @@ std::size_t count_shapefile_features(std::string const& filename) { +#if defined(MAPNIK_MEMORY_MAPPED_FILE) + mapnik::mapped_memory_cache::instance().clear(); +#endif mapnik::parameters params; params["type"] = "shape"; params["file"] = filename; auto ds = mapnik::datasource_cache::instance().create(params); + REQUIRE(ds != nullptr); CHECK(ds->type() == mapnik::datasource::datasource_t::Vector); auto fields = ds->get_descriptor().get_descriptors(); mapnik::query query(ds->envelope()); @@ -47,6 +53,7 @@ query.add_property_name(field.get_name()); } auto features = ds->features(query); + REQUIRE(features != nullptr); std::size_t feature_count = 0; auto feature = features->next(); @@ -55,17 +62,21 @@ ++feature_count; feature = features->next(); } + return feature_count; } -int create_shapefile_index(std::string const& filename, bool silent = true) +int create_shapefile_index(std::string const& filename, bool index_parts, bool silent = true) { std::string cmd; if (std::getenv("DYLD_LIBRARY_PATH") != nullptr) { - cmd += std::string("export DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && "; + cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " "; } - cmd += "shapeindex " + filename; + + cmd += "shapeindex "; + if (index_parts) cmd+= "--index-parts "; + cmd += filename; if (silent) { #ifndef _WINDOWS @@ -79,39 +90,92 @@ } +TEST_CASE("invalid shapeindex") +{ + std::string shape_plugin("./plugins/input/shape.input"); + if (mapnik::util::exists(shape_plugin)) + { + SECTION("Invalid index") + { + for (auto val : {std::make_tuple(true, std::string("mapnik-invalid-index.................")), // invalid header + std::make_tuple(false, std::string("mapnik-index................."))}) // valid header + invalid index + { + std::string path = "test/data/shp/boundaries.shp"; + std::string index_path = path.substr(0, path.rfind(".")) + ".index"; + // remove *.index if present + if (mapnik::util::exists(index_path)) + { + mapnik::util::remove(index_path); + } + // count features + + std::size_t feature_count = count_shapefile_features(path); + + // create index + std::ofstream index(index_path.c_str(), std::ios::binary); + index.write(std::get<1>(val).c_str(), std::get<1>(val).size()); + index.close(); + + // count features + std::size_t feature_count_indexed = count_shapefile_features(path); + if (std::get<0>(val)) // fallback to un-indexed access + { + // ensure number of features are the same + CHECK(feature_count == feature_count_indexed); + } + else // the header is valid but index file itself is not - expect datasource to fail and return 0 features. + { + CHECK(feature_count_indexed == 0); + } + // remove *.index if present + if (mapnik::util::exists(index_path)) + { + mapnik::util::remove(index_path); + } + } + } + } +} + TEST_CASE("shapeindex") { std::string shape_plugin("./plugins/input/shape.input"); if (mapnik::util::exists(shape_plugin)) { - SECTION("Shapefile index") + SECTION("Index") { for (auto const& path : mapnik::util::list_directory("test/data/shp/")) { if (boost::iends_with(path,".shp")) { - std::string index_path = path.substr(0, path.rfind(".")) + ".index"; - // remove *.index if present - if (mapnik::util::exists(index_path)) - { - mapnik::util::remove(index_path); - } - // count features - std::size_t feature_count = count_shapefile_features(path); - // create *.index - create_shapefile_index(path); - if (feature_count == 0) + for (bool index_parts : {false, true} ) { - REQUIRE(!mapnik::util::exists(index_path)); // index won't be created if there's no features - } - // count features - std::size_t feature_count_indexed = count_shapefile_features(path); - // ensure number of features are the same - REQUIRE(feature_count == feature_count_indexed); - // remove *.index if present - if (mapnik::util::exists(index_path)) - { - mapnik::util::remove(index_path); + CAPTURE(path); + CAPTURE(index_parts); + + std::string index_path = path.substr(0, path.rfind(".")) + ".index"; + // remove *.index if present + if (mapnik::util::exists(index_path)) + { + mapnik::util::remove(index_path); + } + // count features + std::size_t feature_count = count_shapefile_features(path); + // create *.index + REQUIRE(create_shapefile_index(path, index_parts) == 0); + if (feature_count == 0) + { + REQUIRE(!mapnik::util::exists(index_path)); // index won't be created if there's no features + } + // count features + std::size_t feature_count_indexed = count_shapefile_features(path); + // ensure number of features are the same + REQUIRE(feature_count == feature_count_indexed); + // remove *.index if present + if (mapnik::util::exists(index_path)) + { + mapnik::util::remove(index_path); + } } } } diff -Nru mapnik-3.0.9+ds/test/unit/datasource/topojson.cpp mapnik-3.0.13+ds/test/unit/datasource/topojson.cpp --- mapnik-3.0.9+ds/test/unit/datasource/topojson.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/datasource/topojson.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,113 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 "catch.hpp" +#include "ds_test_util.hpp" + +#include +#include +#include +#include +#include + +namespace { + +using iterator_type = char const*; +const mapnik::topojson::topojson_grammar grammar; + +bool parse_topology(std::string const& filename, mapnik::topojson::topology & topo) +{ + mapnik::util::file file(filename); + std::string buffer; + buffer.resize(file.size()); + std::fread(&buffer[0], buffer.size(), 1, file.get()); + if (!file) return false; + boost::spirit::standard::space_type space; + iterator_type itr = buffer.c_str(); + iterator_type end = itr + buffer.length(); + bool result = boost::spirit::qi::phrase_parse(itr, end, grammar, space, topo); + return (result && (itr == end)); +} + +} + +TEST_CASE("topojson") +{ + SECTION("geometry parsing") + { + mapnik::value_integer feature_id = 0; + mapnik::context_ptr ctx = std::make_shared(); + mapnik::transcoder tr("utf8"); + for (auto const& path : mapnik::util::list_directory("test/data/topojson/")) + { + mapnik::topojson::topology topo; + REQUIRE(parse_topology(path, topo)); + for (auto const& geom : topo.geometries) + { + mapnik::box2d bbox = mapnik::util::apply_visitor(mapnik::topojson::bounding_box_visitor(topo), geom); + CHECK(bbox.valid()); + mapnik::topojson::feature_generator visitor(ctx, tr, topo, feature_id++); + mapnik::feature_ptr feature = mapnik::util::apply_visitor(visitor, geom); + CHECK(feature); + CHECK(feature->envelope() == bbox); + } + } + } + + SECTION("TopoJSON properties are properly expressed") + { + std::string filename("./test/data/topojson/escaped.topojson"); + mapnik::context_ptr ctx = std::make_shared(); + mapnik::transcoder tr("utf8"); + mapnik::topojson::topology topo; + REQUIRE(parse_topology(filename, topo)); + mapnik::value_integer feature_id = 0; + for (auto const& geom : topo.geometries) + { + mapnik::box2d bbox = mapnik::util::apply_visitor(mapnik::topojson::bounding_box_visitor(topo), geom); + CHECK(bbox.valid()); + mapnik::topojson::feature_generator visitor(ctx, tr, topo, feature_id); + mapnik::feature_ptr feature = mapnik::util::apply_visitor(visitor, geom); + CHECK(feature); + CHECK(feature->envelope() == bbox); + std::initializer_list attrs = { + attr{"name", tr.transcode("Test")}, + attr{"NOM_FR", tr.transcode("Québec")}, + attr{"boolean", mapnik::value_bool("true")}, + attr{"description", tr.transcode("Test: \u005C")}, + attr{"double", mapnik::value_double(1.1)}, + attr{"int", mapnik::value_integer(1)}, + attr{"object", tr.transcode("{\"name\":\"waka\",\"spaces\":\"value with spaces\",\"int\":1,\"double\":1.1,\"boolean\":false" + ",\"NOM_FR\":\"Québec\",\"array\":[\"string\",\"value with spaces\",3,1.1,null,true" + ",\"Québec\"],\"another_object\":{\"name\":\"nested object\"}}")}, + attr{"spaces", tr.transcode("this has spaces")}, + attr{"array", tr.transcode("[\"string\",\"value with spaces\",3,1.1,null,true," + "\"Québec\",{\"name\":\"object within an array\"}," + "[\"array\",\"within\",\"an\",\"array\"]]")}, + attr{"empty_array", tr.transcode("[]")}, + attr{"empty_object", tr.transcode("{}")}, + }; + REQUIRE_ATTRIBUTES(feature, attrs); + } + } + +} diff -Nru mapnik-3.0.9+ds/test/unit/font/fontset_runtime_test.cpp mapnik-3.0.13+ds/test/unit/font/fontset_runtime_test.cpp --- mapnik-3.0.9+ds/test/unit/font/fontset_runtime_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/font/fontset_runtime_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/geometry/centroid.cpp mapnik-3.0.13+ds/test/unit/geometry/centroid.cpp --- mapnik-3.0.9+ds/test/unit/geometry/centroid.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/centroid.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/geometry/geometry.cpp mapnik-3.0.13+ds/test/unit/geometry/geometry.cpp --- mapnik-3.0.9+ds/test/unit/geometry/geometry.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/geometry.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -9,7 +9,7 @@ SECTION("json point") { mapnik::util::file input("./test/data/json/point1.json"); - REQUIRE( input.open() ); + REQUIRE( input ); mapnik::geometry::geometry geom; REQUIRE( input.data() ); std::string json_string(input.data().get(), input.size()); @@ -24,7 +24,20 @@ SECTION("json point reversed") { mapnik::util::file input("./test/data/json/point2.json"); - REQUIRE( input.open() ); + REQUIRE( input ); + mapnik::geometry::geometry geom; + REQUIRE( input.data() ); + std::string json_string(input.data().get(), input.size()); + REQUIRE( mapnik::json::from_geojson(json_string,geom) ); + REQUIRE( geom.is >() ); + auto const& point = mapnik::util::get >(geom); + REQUIRE( point.x == 30 ); + REQUIRE( point.y == 10 ); +} + +SECTION("json point reversed + extra attributes") { + mapnik::util::file input("./test/data/json/point3.json"); + REQUIRE( input ); mapnik::geometry::geometry geom; REQUIRE( input.data() ); std::string json_string(input.data().get(), input.size()); diff -Nru mapnik-3.0.9+ds/test/unit/geometry/geometry_envelope_test.cpp mapnik-3.0.13+ds/test/unit/geometry/geometry_envelope_test.cpp --- mapnik-3.0.9+ds/test/unit/geometry/geometry_envelope_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/geometry_envelope_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -2,15 +2,18 @@ #include #include -#include -TEST_CASE("geometry ops - envelope") { +namespace { -SECTION("envelope_test - double") { +template +void envelope_test() +{ using namespace mapnik::geometry; + using coord_type = T; + { - geometry geom(point(1,2)); - mapnik::box2d bbox = mapnik::geometry::envelope(geom); + geometry geom(point(1,2)); + mapnik::box2d bbox = mapnik::geometry::envelope(geom); REQUIRE( bbox.minx() == 1 ); REQUIRE( bbox.miny() == 2 ); REQUIRE( bbox.maxx() == 1 ); @@ -18,80 +21,67 @@ } { // Test empty geom - geometry geom = mapnik::geometry::geometry_empty(); - mapnik::box2d bbox = mapnik::geometry::envelope(geom); + geometry geom = mapnik::geometry::geometry_empty(); + mapnik::box2d bbox = mapnik::geometry::envelope(geom); REQUIRE_FALSE( bbox.valid() ); } { - line_string line; + line_string line; line.add_coord(0,0); line.add_coord(1,1); line.add_coord(2,2); - geometry geom(line); - mapnik::box2d bbox = mapnik::geometry::envelope(geom); + geometry geom(line); + mapnik::box2d bbox = mapnik::geometry::envelope(geom); REQUIRE( bbox.minx() == 0 ); REQUIRE( bbox.miny() == 0 ); REQUIRE( bbox.maxx() == 2 ); REQUIRE( bbox.maxy() == 2 ); } { - line_string line; + line_string line; line.add_coord(0,0); line.add_coord(1,1); line.add_coord(2,2); - line_string line2; + line_string line2; line2.add_coord(0,0); line2.add_coord(-1,-1); line2.add_coord(-2,-2); - multi_line_string multi_line; + multi_line_string multi_line; multi_line.emplace_back(std::move(line)); multi_line.emplace_back(std::move(line2)); - geometry geom(multi_line); - mapnik::box2d bbox = mapnik::geometry::envelope(geom); + geometry geom(multi_line); + mapnik::box2d bbox = mapnik::geometry::envelope(geom); REQUIRE( bbox.minx() == -2 ); REQUIRE( bbox.miny() == -2 ); REQUIRE( bbox.maxx() == 2 ); REQUIRE( bbox.maxy() == 2 ); } { - polygon poly; - linear_ring ring; + polygon poly; + linear_ring ring; ring.add_coord(0,0); ring.add_coord(-10,0); ring.add_coord(-10,10); ring.add_coord(0,10); ring.add_coord(0,0); poly.set_exterior_ring(std::move(ring)); - geometry geom(poly); - mapnik::box2d bbox = mapnik::geometry::envelope(geom); + geometry geom(poly); + mapnik::box2d bbox = mapnik::geometry::envelope(geom); REQUIRE( bbox.minx() == -10 ); REQUIRE( bbox.miny() == 0 ); REQUIRE( bbox.maxx() == 0 ); REQUIRE( bbox.maxy() == 10 ); - multi_polygon mp; + multi_polygon mp; mp.push_back(poly); - geometry geom_mp(mp); - bbox = mapnik::geometry::envelope(geom_mp); - REQUIRE( bbox.minx() == -10 ); - REQUIRE( bbox.miny() == 0 ); - REQUIRE( bbox.maxx() == 0 ); - REQUIRE( bbox.maxy() == 10 ); - - correct(geom); - bbox = mapnik::geometry::envelope(geom); - REQUIRE( bbox.minx() == -10 ); - REQUIRE( bbox.miny() == 0 ); - REQUIRE( bbox.maxx() == 0 ); - REQUIRE( bbox.maxy() == 10 ); - correct(geom_mp); + geometry geom_mp(mp); bbox = mapnik::geometry::envelope(geom_mp); REQUIRE( bbox.minx() == -10 ); REQUIRE( bbox.miny() == 0 ); REQUIRE( bbox.maxx() == 0 ); REQUIRE( bbox.maxy() == 10 ); - geometry_collection gc; + geometry_collection gc; bbox = mapnik::geometry::envelope(gc); REQUIRE_FALSE( bbox.valid() ); gc.push_back(geom_mp); @@ -100,7 +90,7 @@ REQUIRE( bbox.miny() == 0 ); REQUIRE( bbox.maxx() == 0 ); REQUIRE( bbox.maxy() == 10 ); - gc.emplace_back(point(-50,-50)); + gc.emplace_back(point(-50,-50)); bbox = mapnik::geometry::envelope(gc); REQUIRE( bbox.minx() == -50 ); REQUIRE( bbox.miny() == -50 ); @@ -110,30 +100,30 @@ { // polygon with hole - polygon poly; - linear_ring ring; + polygon poly; + linear_ring ring; ring.add_coord(0,0); ring.add_coord(-10,0); ring.add_coord(-10,10); ring.add_coord(0,10); ring.add_coord(0,0); poly.set_exterior_ring(std::move(ring)); - linear_ring hole; + linear_ring hole; hole.add_coord(-7,7); hole.add_coord(-7,3); hole.add_coord(-3,3); hole.add_coord(-3,7); hole.add_coord(-7,7); poly.add_hole(std::move(hole)); - geometry geom(poly); - mapnik::box2d bbox = mapnik::geometry::envelope(poly); + geometry geom(poly); + mapnik::box2d bbox = mapnik::geometry::envelope(poly); REQUIRE( bbox.minx() == -10 ); REQUIRE( bbox.miny() == 0 ); REQUIRE( bbox.maxx() == 0 ); REQUIRE( bbox.maxy() == 10 ); // add another hole inside the first hole // which should be considered a hit - linear_ring fill; + linear_ring fill; fill.add_coord(-6,4); fill.add_coord(-6,6); fill.add_coord(-4,6); @@ -149,3 +139,14 @@ } } + +TEST_CASE("geometry ops - envelope") { + +SECTION("envelope_test") +{ + envelope_test(); + envelope_test(); + envelope_test(); +} + +} diff -Nru mapnik-3.0.9+ds/test/unit/geometry/geometry_equal.hpp mapnik-3.0.13+ds/test/unit/geometry/geometry_equal.hpp --- mapnik-3.0.9+ds/test/unit/geometry/geometry_equal.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/geometry_equal.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,6 @@ +#ifndef MAPNIK_UNIT_GEOMETRY_EQUAL +#define MAPNIK_UNIT_GEOMETRY_EQUAL + #include "catch.hpp" // boost @@ -81,7 +84,15 @@ #include #include -using namespace mapnik::geometry; +using mapnik::geometry::geometry; +using mapnik::geometry::geometry_empty; +using mapnik::geometry::point; +using mapnik::geometry::line_string; +using mapnik::geometry::polygon; +using mapnik::geometry::multi_point; +using mapnik::geometry::multi_line_string; +using mapnik::geometry::multi_polygon; +using mapnik::geometry::geometry_collection; template void assert_g_equal(geometry const& g1, geometry const& g2); @@ -89,26 +100,26 @@ struct geometry_equal_visitor { template - void operator() (T1 const&, T2 const&) + void operator() (T1 const&, T2 const&) const { // comparing two different types! REQUIRE(false); } - void operator() (geometry_empty const&, geometry_empty const&) + void operator() (geometry_empty const&, geometry_empty const&) const { REQUIRE(true); } template - void operator() (point const& p1, point const& p2) + void operator() (point const& p1, point const& p2) const { REQUIRE(p1.x == Approx(p2.x)); REQUIRE(p1.y == Approx(p2.y)); } template - void operator() (line_string const& ls1, line_string const& ls2) + void operator() (line_string const& ls1, line_string const& ls2) const { if (ls1.size() != ls2.size()) { @@ -123,7 +134,7 @@ } template - void operator() (polygon const& p1, polygon const& p2) + void operator() (polygon const& p1, polygon const& p2) const { (*this)(static_cast const&>(p1.exterior_ring), static_cast const&>(p2.exterior_ring)); @@ -139,13 +150,13 @@ } template - void operator() (multi_point const& mp1, multi_point const& mp2) + void operator() (multi_point const& mp1, multi_point const& mp2) const { (*this)(static_cast const&>(mp1), static_cast const&>(mp2)); } template - void operator() (multi_line_string const& mls1, multi_line_string const& mls2) + void operator() (multi_line_string const& mls1, multi_line_string const& mls2) const { if (mls1.size() != mls2.size()) { @@ -159,7 +170,7 @@ } template - void operator() (multi_polygon const& mpoly1, multi_polygon const& mpoly2) + void operator() (multi_polygon const& mpoly1, multi_polygon const& mpoly2) const { if (mpoly1.size() != mpoly2.size()) { @@ -173,7 +184,7 @@ } template - void operator() (mapnik::util::recursive_wrapper > const& c1_, mapnik::util::recursive_wrapper > const& c2_) + void operator() (mapnik::util::recursive_wrapper > const& c1_, mapnik::util::recursive_wrapper > const& c2_) const { geometry_collection const& c1 = static_cast const&>(c1_); geometry_collection const& c2 = static_cast const&>(c2_); @@ -189,7 +200,7 @@ } template - void operator() (geometry_collection const& c1, geometry_collection const& c2) + void operator() (geometry_collection const& c1, geometry_collection const& c2) const { if (c1.size() != c2.size()) { @@ -214,3 +225,5 @@ { return geometry_equal_visitor()(g1,g2); } + +#endif // MAPNIK_UNIT_GEOMETRY_EQUAL diff -Nru mapnik-3.0.9+ds/test/unit/geometry/geometry_hit_test.cpp mapnik-3.0.13+ds/test/unit/geometry/geometry_hit_test.cpp --- mapnik-3.0.9+ds/test/unit/geometry/geometry_hit_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/geometry_hit_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/geometry/geometry_is_simple.cpp mapnik-3.0.13+ds/test/unit/geometry/geometry_is_simple.cpp --- mapnik-3.0.9+ds/test/unit/geometry/geometry_is_simple.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/geometry_is_simple.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include @@ -163,6 +164,36 @@ CHECK( !mapnik::geometry::is_simple(poly) ); } +#if BOOST_VERSION >= 106000 + +SECTION("polygon that is empty") { + mapnik::geometry::polygon poly; + CHECK( !mapnik::geometry::is_simple(poly) ); +} + +SECTION("polygon that has empty exterior ring") { + mapnik::geometry::polygon poly; + mapnik::geometry::linear_ring ring; + poly.set_exterior_ring(std::move(ring)); + CHECK( !mapnik::geometry::is_simple(poly) ); +} + +SECTION("polygon that has empty interior ring") { + mapnik::geometry::polygon poly; + mapnik::geometry::linear_ring ring; + ring.add_coord(0,0); + ring.add_coord(1,0); + ring.add_coord(1,1); + ring.add_coord(0,1); + ring.add_coord(0,0); + poly.set_exterior_ring(std::move(ring)); + mapnik::geometry::linear_ring ring2; + poly.add_hole(std::move(ring2)); + CHECK( !mapnik::geometry::is_simple(poly) ); +} + +#else // BOOST_VERSION >= 1.60 + SECTION("polygon that is empty") { mapnik::geometry::polygon poly; CHECK( mapnik::geometry::is_simple(poly) ); @@ -189,6 +220,8 @@ CHECK( mapnik::geometry::is_simple(poly) ); } +#endif // BOOST_VERSION >= 1.60 + // A polygon with a spike can still be simple SECTION("polygon with spike") { mapnik::geometry::polygon poly; diff -Nru mapnik-3.0.9+ds/test/unit/geometry/geometry_is_valid.cpp mapnik-3.0.13+ds/test/unit/geometry/geometry_is_valid.cpp --- mapnik-3.0.9+ds/test/unit/geometry/geometry_is_valid.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/geometry_is_valid.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include @@ -43,6 +44,8 @@ CHECK( failure == boost::geometry::no_failure ); } +#if BOOST_VERSION < 106000 + SECTION("point unitialized") { mapnik::geometry::point pt2; CHECK( mapnik::geometry::is_valid(pt2) ); @@ -53,6 +56,37 @@ CHECK( mapnik::geometry::is_valid(pt2, failure2) ); CHECK( failure2 == boost::geometry::no_failure ); } +#endif + +#if BOOST_VERSION >= 106000 + +SECTION("point NaN") { + mapnik::geometry::point pt(std::numeric_limits::quiet_NaN(),std::numeric_limits::quiet_NaN()); + CHECK( std::isnan(pt.x) ); + CHECK( std::isnan(pt.y) ); + CHECK( !mapnik::geometry::is_valid(pt) ); + std::string message; + CHECK( !mapnik::geometry::is_valid(pt, message) ); + CHECK( message == "Geometry has point(s) with invalid coordinate(s)"); + boost::geometry::validity_failure_type failure; + CHECK( !mapnik::geometry::is_valid(pt, failure) ); + CHECK( failure == boost::geometry::failure_invalid_coordinate ); +} + +SECTION("point Infinity") { + mapnik::geometry::point pt(std::numeric_limits::infinity(),std::numeric_limits::infinity()); + CHECK( std::isinf(pt.x) ); + CHECK( std::isinf(pt.y) ); + CHECK( !mapnik::geometry::is_valid(pt) ); + std::string message; + CHECK( !mapnik::geometry::is_valid(pt, message) ); + CHECK( message == "Geometry has point(s) with invalid coordinate(s)"); + boost::geometry::validity_failure_type failure; + CHECK( !mapnik::geometry::is_valid(pt, failure) ); + CHECK( failure == boost::geometry::failure_invalid_coordinate ); +} + +#else // BOOST_VERSION >= 1.60 // This is funky that boost geometry is_valid does not check for NAN when dealing with a point // this test is here in case the logic ever changes @@ -86,9 +120,11 @@ CHECK( failure == boost::geometry::no_failure ); } +#endif // BOOST_VERSION >= 1.60 + SECTION("multi point") { mapnik::geometry::multi_point mpt; - mpt.add_coord(0,0); + mpt.add_coord(0,0); mpt.add_coord(1,1); CHECK( mapnik::geometry::is_valid(mpt) ); std::string message; @@ -113,7 +149,7 @@ SECTION("line_string") { mapnik::geometry::line_string line; - line.add_coord(0,0); + line.add_coord(0,0); line.add_coord(1,1); CHECK( mapnik::geometry::is_valid(line) ); std::string message; @@ -127,7 +163,7 @@ // This shouldn't fail -- test added in case logic ever changes SECTION("line_string repeated points") { mapnik::geometry::line_string line; - line.add_coord(0,0); + line.add_coord(0,0); line.add_coord(1,1); line.add_coord(1,1); line.add_coord(2,2); @@ -153,10 +189,10 @@ SECTION("multi_line_string") { mapnik::geometry::line_string line1; - line1.add_coord(0,0); + line1.add_coord(0,0); line1.add_coord(1,1); mapnik::geometry::line_string line2; - line2.add_coord(0,1); + line2.add_coord(0,1); line2.add_coord(1,2); mapnik::geometry::multi_line_string lines; lines.emplace_back(line1); @@ -184,7 +220,7 @@ SECTION("polygon") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(1,0); ring.add_coord(1,1); ring.add_coord(0,1); @@ -202,7 +238,7 @@ SECTION("polygon invalid winding order") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(0,1); ring.add_coord(1,1); ring.add_coord(1,0); @@ -221,7 +257,7 @@ SECTION("polygon 2 repeated points") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(1,0); ring.add_coord(1,1); ring.add_coord(1,1); @@ -240,7 +276,7 @@ SECTION("polygon 3 repeated points") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(1,0); ring.add_coord(1,1); ring.add_coord(1,1); @@ -271,7 +307,7 @@ SECTION("polygon with spike") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(1,0); ring.add_coord(1,1); ring.add_coord(2,2); @@ -291,14 +327,14 @@ SECTION("polygon with hole") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(3,0); ring.add_coord(3,3); ring.add_coord(0,3); ring.add_coord(0,0); poly.set_exterior_ring(std::move(ring)); mapnik::geometry::linear_ring hole; - hole.add_coord(1,1); + hole.add_coord(1,1); hole.add_coord(1,2); hole.add_coord(2,2); hole.add_coord(2,1); @@ -316,7 +352,7 @@ SECTION("polygon with empty hole") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(3,0); ring.add_coord(3,3); ring.add_coord(0,3); @@ -337,14 +373,14 @@ SECTION("polygon with hole with invalid winding order") { mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(3,0); ring.add_coord(3,3); ring.add_coord(0,3); ring.add_coord(0,0); poly.set_exterior_ring(std::move(ring)); mapnik::geometry::linear_ring hole; - hole.add_coord(1,1); + hole.add_coord(1,1); hole.add_coord(2,1); hole.add_coord(2,2); hole.add_coord(1,2); @@ -363,7 +399,7 @@ mapnik::geometry::multi_polygon mp; mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(1,0); ring.add_coord(1,1); ring.add_coord(0,1); @@ -371,7 +407,7 @@ poly.set_exterior_ring(std::move(ring)); mapnik::geometry::polygon poly2; mapnik::geometry::linear_ring ring2; - ring2.add_coord(0,0); + ring2.add_coord(0,0); ring2.add_coord(-1,0); ring2.add_coord(-1,-1); ring2.add_coord(0,-1); @@ -392,14 +428,14 @@ mapnik::geometry::multi_polygon mp; mapnik::geometry::polygon poly; mapnik::geometry::linear_ring ring; - ring.add_coord(0,0); + ring.add_coord(0,0); ring.add_coord(3,0); ring.add_coord(3,3); ring.add_coord(0,3); ring.add_coord(0,0); poly.set_exterior_ring(std::move(ring)); mapnik::geometry::linear_ring hole; - hole.add_coord(1,1); + hole.add_coord(1,1); hole.add_coord(1,2); hole.add_coord(2,2); hole.add_coord(2,1); @@ -407,14 +443,14 @@ poly.add_hole(std::move(hole)); mapnik::geometry::polygon poly2; mapnik::geometry::linear_ring ring2; - ring2.add_coord(0,0); + ring2.add_coord(0,0); ring2.add_coord(-3,0); ring2.add_coord(-3,-3); ring2.add_coord(0,-3); ring2.add_coord(0,0); poly2.set_exterior_ring(std::move(ring2)); mapnik::geometry::linear_ring hole2; - hole2.add_coord(-1,-1); + hole2.add_coord(-1,-1); hole2.add_coord(-1,-2); hole2.add_coord(-2,-2); hole2.add_coord(-2,-1); diff -Nru mapnik-3.0.9+ds/test/unit/geometry/geometry_reprojection.cpp mapnik-3.0.13+ds/test/unit/geometry/geometry_reprojection.cpp --- mapnik-3.0.9+ds/test/unit/geometry/geometry_reprojection.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/geometry_reprojection.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include "geometry_equal.hpp" diff -Nru mapnik-3.0.9+ds/test/unit/geometry/geometry_strategy_test.cpp mapnik-3.0.13+ds/test/unit/geometry/geometry_strategy_test.cpp --- mapnik-3.0.9+ds/test/unit/geometry/geometry_strategy_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/geometry_strategy_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include "geometry_equal.hpp" diff -Nru mapnik-3.0.9+ds/test/unit/geometry/geometry_test_helper.cpp mapnik-3.0.13+ds/test/unit/geometry/geometry_test_helper.cpp --- mapnik-3.0.9+ds/test/unit/geometry/geometry_test_helper.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/geometry_test_helper.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,15 @@ +#include +#include +#include + + +namespace mapnik { namespace geometry { +// instantiate types required by geometry_envelope_test +template mapnik::box2d envelope(geometry const& geom); +template mapnik::box2d envelope(geometry const& geom); +template mapnik::box2d envelope(polygon const& geom); +template mapnik::box2d envelope(polygon const& geom); +template mapnik::box2d envelope(geometry_collection const& geom); +template mapnik::box2d envelope(geometry_collection const& geom); + +}} diff -Nru mapnik-3.0.9+ds/test/unit/geometry/has_empty.cpp mapnik-3.0.13+ds/test/unit/geometry/has_empty.cpp --- mapnik-3.0.9+ds/test/unit/geometry/has_empty.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/has_empty.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/geometry/is_clockwise.cpp mapnik-3.0.13+ds/test/unit/geometry/is_clockwise.cpp --- mapnik-3.0.9+ds/test/unit/geometry/is_clockwise.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/is_clockwise.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,27 @@ +#include "catch.hpp" + +#include +#include + +TEST_CASE("Ring is_clockwise") { + + // Input is rather thin triangle to test precision issues aren't getting in the way. + SECTION("Clockwise") + { + mapnik::geometry::linear_ring ring; + ring.emplace_back(-13499697.0366658326, 4698431.85179749783); + ring.emplace_back(-13499697.1113113686, 4698431.85179749783); + ring.emplace_back(-13499697.0366658326, 4698431.92644303292); + ring.emplace_back(-13499697.0366658326, 4698431.85179749783); + REQUIRE(mapnik::util::is_clockwise(ring) == true); + } + SECTION("Anti-Clockwise") + { + mapnik::geometry::linear_ring ring; + ring.emplace_back(-13499697.0366658326, 4698431.85179749783); + ring.emplace_back(-13499697.0366658326, 4698431.92644303292); + ring.emplace_back(-13499697.1113113686, 4698431.85179749783); + ring.emplace_back(-13499697.0366658326, 4698431.85179749783); + REQUIRE(mapnik::util::is_clockwise(ring) == false); + } +} diff -Nru mapnik-3.0.9+ds/test/unit/geometry/is_empty.cpp mapnik-3.0.13+ds/test/unit/geometry/is_empty.cpp --- mapnik-3.0.9+ds/test/unit/geometry/is_empty.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/is_empty.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/geometry/remove_empty.cpp mapnik-3.0.13+ds/test/unit/geometry/remove_empty.cpp --- mapnik-3.0.9+ds/test/unit/geometry/remove_empty.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/geometry/remove_empty.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/imaging/image_apply_opacity.cpp mapnik-3.0.13+ds/test/unit/imaging/image_apply_opacity.cpp --- mapnik-3.0.9+ds/test/unit/imaging/image_apply_opacity.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/imaging/image_apply_opacity.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" // mapnik diff -Nru mapnik-3.0.9+ds/test/unit/imaging/image.cpp mapnik-3.0.13+ds/test/unit/imaging/image.cpp --- mapnik-3.0.9+ds/test/unit/imaging/image.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/imaging/image.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" // mapnik @@ -362,4 +363,30 @@ } } +SECTION("image::swap") +{ + auto blue = mapnik::color(50, 50, 250).rgba(); + auto orange = mapnik::color(250, 150, 0).rgba(); + + mapnik::image_rgba8 im; + mapnik::image_rgba8 im2(16, 16); + mapnik::image_rgba8 im3(16, 16); + + im2.set(blue); + im3.set(orange); + + // swap two non-empty images + CHECK_NOTHROW(im2.swap(im3)); + CHECK(im2(0, 0) == orange); + CHECK(im3(0, 0) == blue); + + // swap empty <-> non-empty + CHECK_NOTHROW(im.swap(im3)); + CHECK(im3.data() == nullptr); + CHECKED_IF(im.data() != nullptr) + { + CHECK(im(0, 0) == blue); + } +} + } // END TEST CASE diff -Nru mapnik-3.0.9+ds/test/unit/imaging/image_filter.cpp mapnik-3.0.13+ds/test/unit/imaging/image_filter.cpp --- mapnik-3.0.9+ds/test/unit/imaging/image_filter.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/imaging/image_filter.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" // mapnik @@ -6,29 +7,30 @@ #include #include #include -#include -#include -#include +#include +// stl +#include +#include TEST_CASE("image filter") { SECTION("test bad filter input") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("red")); - + REQUIRE_THROWS( mapnik::filter::filter_image(im, "foo,asdfasdf()"); ); REQUIRE_THROWS( mapnik::filter::filter_image(im, "colorize-alpha("); ); REQUIRE_THROWS( mapnik::filter::filter_image(im, "color-to-alpha(blue"); ); REQUIRE_THROWS( mapnik::filter::filter_image(im, "color-to-alpha(,blue)"); ); REQUIRE_THROWS( mapnik::filter::filter_image(im, "colorize-alpha()"); ); - REQUIRE_THROWS( + REQUIRE_THROWS( mapnik::image_rgba8 const& im2 = im; mapnik::image_rgba8 new_im = mapnik::filter::filter_image(im2, "foo"); ); - + CHECK(im(0,0) == 0xffff0000); CHECK(im(0,1) == 0xffff0000); CHECK(im(0,2) == 0xffff0000); @@ -38,11 +40,11 @@ CHECK(im(2,0) == 0xffff0000); CHECK(im(2,1) == 0xffff0000); CHECK(im(2,2) == 0xffff0000); - + } // END SECTION SECTION("test blur") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("red")); @@ -58,11 +60,11 @@ CHECK(im(2,0) == 0xffc60038); CHECK(im(2,1) == 0xffe2001c); CHECK(im(2,2) == 0xffc60038); - + } // END SECTION SECTION("test blur constant") { - + mapnik::image_rgba8 im_orig(3,3); mapnik::fill(im_orig,mapnik::color("blue")); mapnik::set_pixel(im_orig, 1, 1, mapnik::color("red")); @@ -79,11 +81,11 @@ CHECK(im(2,0) == 0xffc60038); CHECK(im(2,1) == 0xffe2001c); CHECK(im(2,2) == 0xffc60038); - + } // END SECTION SECTION("test gray") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("red")); @@ -99,11 +101,11 @@ CHECK(im(2,0) == 0xff1c1c1c); CHECK(im(2,1) == 0xff1c1c1c); CHECK(im(2,2) == 0xff1c1c1c); - + } // END SECTION SECTION("test agg stack blur") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("red")); @@ -123,7 +125,7 @@ } // END SECTION SECTION("test scale-hsla 1") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("red")); @@ -139,7 +141,7 @@ CHECK(im(2,0) == 0x80004000); CHECK(im(2,1) == 0x80004000); CHECK(im(2,2) == 0x80004000); - + } // END SECTION SECTION("test scale-hsla 2") { @@ -172,7 +174,7 @@ } // END SECTION SECTION("test emboss") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("white")); mapnik::set_pixel(im, 1, 1, mapnik::color("orange")); @@ -188,11 +190,11 @@ CHECK(im(2,0) == 0xffffffff); CHECK(im(2,1) == 0xffffffff); CHECK(im(2,2) == 0xffffffff); - + } // END SECTION SECTION("test sharpen") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("gray")); @@ -208,11 +210,11 @@ CHECK(im(2,0) == 0xffff0000); CHECK(im(2,1) == 0xffff0000); CHECK(im(2,2) == 0xffff0000); - + } // END SECTION SECTION("test edge detect") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("gray")); @@ -228,11 +230,11 @@ CHECK(im(2,0) == 0xff000000); CHECK(im(2,1) == 0xff008080); CHECK(im(2,2) == 0xff000000); - + } // END SECTION SECTION("test sobel") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("gray")); @@ -248,11 +250,11 @@ CHECK(im(2,0) == 0xfffeffff); CHECK(im(2,1) == 0xfffeffff); CHECK(im(2,2) == 0xfffeffff); - + } // END SECTION SECTION("test x-gradient") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("gray")); @@ -268,11 +270,11 @@ CHECK(im(2,0) == 0xff808080); CHECK(im(2,1) == 0xff41c0c0); CHECK(im(2,2) == 0xff808080); - + } // END SECTION SECTION("test y-gradient") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("gray")); @@ -288,11 +290,11 @@ CHECK(im(2,0) == 0xff808080); CHECK(im(2,1) == 0xff808080); CHECK(im(2,2) == 0xff808080); - + } // END SECTION SECTION("test invert") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("gray")); @@ -308,11 +310,11 @@ CHECK(im(2,0) == 0xff00ffff); CHECK(im(2,1) == 0xff00ffff); CHECK(im(2,2) == 0xff00ffff); - + } // END SECTION SECTION("test colorize-alpha - one color") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("gray")); @@ -328,11 +330,11 @@ CHECK(im(2,0) == 0xffff0000); CHECK(im(2,1) == 0xffff0000); CHECK(im(2,2) == 0xffff0000); - + } // END SECTION SECTION("test colorize-alpha - two color") { - + mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("gray")); @@ -348,7 +350,7 @@ CHECK(im(2,0) == 0xfffd0000); CHECK(im(2,1) == 0xfffd0000); CHECK(im(2,2) == 0xfffd0000); - + } // END SECTION SECTION("test colorize-alpha - one color with transparency") { @@ -391,15 +393,53 @@ } // END SECTION +SECTION("test parsing image-filters") { + + std::string str = ""; // empty string + std::vector filters; + CHECK(parse_image_filters(str, filters)); + CHECK(filters.size() == 0); + + std::array expected = {{ "emboss", + "emboss", + "blur", + "gray", + "edge-detect", + "sobel", + "sharpen", + "x-gradient", + "y-gradient", + "invert", + "color-blind-protanope", + "color-blind-deuteranope", + "color-blind-tritanope", + "agg-stack-blur(1,1)", + "agg-stack-blur(1,1)", + "agg-stack-blur(2,2)", + "agg-stack-blur(2,3)"}}; + + str += "emboss emboss() blur,gray ,edge-detect, sobel , , sharpen,,,x-gradient y-gradientinvert"; + str += "color-blind-protanope color-blind-deuteranope color-blind-tritanope agg-stack-blur,agg-stack-blur(),agg-stack-blur(2),agg-stack-blur(2,3)" ; + CHECK(parse_image_filters(str, filters)); + CHECK(filters.size() == expected.size()); + std::size_t count = 0; + for (auto const& filter : filters) + { + std::stringstream ss; + ss << filter; + CHECK (expected[count++] == ss.str()); + } +} + SECTION("test colorize-alpha - parsing correct input") { - mapnik::image_filter_grammar> filter_grammar; - boost::spirit::qi::ascii::space_type space; - std::vector f; std::string s("colorize-alpha(#0000ff 0%, #00ff00 100%)"); - CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), filter_grammar, space, f) ); + std::vector f; + REQUIRE(parse_image_filters(s, f)); mapnik::filter::colorize_alpha const & ca = mapnik::util::get(f.front()); + CHECK(ca.size() == 2); + CHECKED_IF(ca.size() > 0) { mapnik::filter::color_stop const & s2 = ca[0]; CHECK( s2.color.alpha() == 0xff ); @@ -409,6 +449,7 @@ CHECK( s2.offset == 0.0 ); } + CHECKED_IF(ca.size() > 1) { mapnik::filter::color_stop const & s2 = ca[1]; CHECK( s2.color.alpha() == 0xff ); @@ -422,20 +463,15 @@ SECTION("test colorize-alpha - parsing incorrect input") { - mapnik::image_filter_grammar> filter_grammar; - boost::spirit::qi::ascii::space_type space; std::string s("colorize-alpha(#0000ff 0%, #00ff00 00 100%)"); - std::string::const_iterator itr = s.cbegin(); - std::string::const_iterator end = s.cend(); std::vector f; - CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), filter_grammar, space, f) ); + CHECK(!parse_image_filters(s, f)); CHECK( f.empty() ); - CHECK( itr != end ); } // END SECTION SECTION("test color-blind-protanope") { - + mapnik::image_rgba8 im(2,2); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 0, 1, mapnik::color("green")); @@ -448,11 +484,11 @@ CHECK(im(0,1) == 0xff006e7c); CHECK(im(1,0) == 0xffd9f6ff); CHECK(im(1,1) == 0xff1d7e8e); - + } // END SECTION SECTION("test color-blind-deuteranope") { - + mapnik::image_rgba8 im(2,2); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 0, 1, mapnik::color("green")); @@ -465,11 +501,11 @@ CHECK(im(0,1) == 0xff1c688b); CHECK(im(1,0) == 0xffe9f5ff); CHECK(im(1,1) == 0xff0077a0); - + } // END SECTION SECTION("test color-blind-tritanope") { - + mapnik::image_rgba8 im(2,2); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 0, 1, mapnik::color("green")); @@ -482,8 +518,7 @@ CHECK(im(0,1) == 0xff80763a); CHECK(im(1,0) == 0xfff8f3ff); CHECK(im(1,1) == 0xff0017fd); - + } // END SECTION } // END TEST CASE - diff -Nru mapnik-3.0.9+ds/test/unit/imaging/image_io_test.cpp mapnik-3.0.13+ds/test/unit/imaging/image_io_test.cpp --- mapnik-3.0.9+ds/test/unit/imaging/image_io_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/imaging/image_io_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,6 +1,7 @@ #include "catch.hpp" -#include +#include +#include #include #include #include @@ -11,6 +12,41 @@ #include #endif +#pragma GCC diagnostic push +#include +#include +#include +#pragma GCC diagnostic pop + +inline void make_directory(std::string const& dir) { + boost::filesystem::create_directories(dir); +} + +namespace { +template +void check_tiny_png_image_quantising(T const& im) +{ + std::ostringstream ss(std::ios::binary); + mapnik::save_to_stream(im, ss, "png8"); + ss.flush(); + std::string str = ss.str(); + std::unique_ptr reader(mapnik::get_image_reader(str.data(), str.size())); + auto w = reader->width(); + auto h = reader->height(); + CHECK(w > 0); + CHECK(h > 0); + auto im2 = mapnik::util::get(reader->read(0, 0, w, h)); + for (std::size_t i = 0; i < w; ++i) + { + for (std::size_t j = 0; j < h; ++j) + { + REQUIRE(im2(i,j) == im(i,j)); + } + } +} + +} + TEST_CASE("image io") { SECTION("readers") { @@ -110,7 +146,91 @@ int q1 = mapnik::detail::parse_jpeg_quality("jpeg:quality=50"); REQUIRE(q0 == q1); #endif +} // END SECTION + +SECTION("image_util : save_to_file/save_to_stream/save_to_string") +{ + mapnik::image_rgba8 im(256,256); + std::string named_color = "lightblue"; + mapnik::fill(im, mapnik::color(named_color).rgba()); + //////////////////////////////////////////////////// + std::vector > supported_types; +#if defined(HAVE_PNG) + supported_types.push_back(std::make_tuple("png","png")); + supported_types.push_back(std::make_tuple("png","png24")); + supported_types.push_back(std::make_tuple("png","png32")); + supported_types.push_back(std::make_tuple("png","png8")); + supported_types.push_back(std::make_tuple("png","png256")); +#endif +#if defined(HAVE_JPEG) + supported_types.push_back(std::make_tuple("jpeg","jpeg")); + supported_types.push_back(std::make_tuple("jpeg","jpeg80")); + supported_types.push_back(std::make_tuple("jpeg","jpeg90")); +#endif +#if defined(HAVE_TIFF) + supported_types.push_back(std::make_tuple("tiff","tiff")); +#endif +#if defined(HAVE_WEBP) + supported_types.push_back(std::make_tuple("webp","webp")); +#endif + + std::string directory_name("/tmp/mapnik-tests/"); + make_directory(directory_name); + REQUIRE(mapnik::util::exists(directory_name)); + + for (auto const& info : supported_types) + { + std::string extension; + std::string format; + std::tie(extension, format) = info; + std::string filename = (boost::format(directory_name + "mapnik-%1%.%2%") % named_color % extension).str(); + mapnik::save_to_file(im, filename); + std::string str = mapnik::save_to_string(im, format); + std::ostringstream ss; + mapnik::save_to_stream(im, ss, format); + CHECK(str.length() == ss.str().length()); + // wrap reader in scope to ensure the file handle is + // released before we try to remove the file + { + std::unique_ptr reader(mapnik::get_image_reader(filename, extension)); + unsigned w = reader->width(); + unsigned h = reader->height(); + auto im2 = reader->read(0, 0, w, h); + CHECK(im2.size() == im.size()); + if (extension == "png" || extension == "tiff") + { + CHECK(0 == std::memcmp(im2.bytes(), im.bytes(), im.width() * im.height())); + } + } + if (mapnik::util::exists(filename)) + { + mapnik::util::remove(filename); + } + } +} + +SECTION("Quantising small (less than 3 pixel images preserve original colours") +{ +#if defined(HAVE_PNG) + { // 1x1 + mapnik::image_rgba8 im(1,1); // 1 pixel + im(0,0) = mapnik::color("green").rgba(); + check_tiny_png_image_quantising(im); + } + { // 1x2 + mapnik::image_rgba8 im(1,2); // 2 pixels + mapnik::fill(im, mapnik::color("red").rgba()); + im(0,0) = mapnik::color("green").rgba(); + check_tiny_png_image_quantising(im); + } + { // 2x1 + mapnik::image_rgba8 im(2,1); // 2 pixels + mapnik::fill(im, mapnik::color("red").rgba()); + im(0,0) = mapnik::color("green").rgba(); + check_tiny_png_image_quantising(im); + } +#endif } // END SECTION } // END TEST_CASE diff -Nru mapnik-3.0.9+ds/test/unit/imaging/image_is_solid.cpp mapnik-3.0.13+ds/test/unit/imaging/image_is_solid.cpp --- mapnik-3.0.9+ds/test/unit/imaging/image_is_solid.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/imaging/image_is_solid.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" // mapnik diff -Nru mapnik-3.0.9+ds/test/unit/imaging/image_painted_test.cpp mapnik-3.0.13+ds/test/unit/imaging/image_painted_test.cpp --- mapnik-3.0.9+ds/test/unit/imaging/image_painted_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/imaging/image_painted_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/imaging/image_premultiply.cpp mapnik-3.0.13+ds/test/unit/imaging/image_premultiply.cpp --- mapnik-3.0.9+ds/test/unit/imaging/image_premultiply.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/imaging/image_premultiply.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" // mapnik diff -Nru mapnik-3.0.9+ds/test/unit/imaging/image_set_pixel.cpp mapnik-3.0.13+ds/test/unit/imaging/image_set_pixel.cpp --- mapnik-3.0.9+ds/test/unit/imaging/image_set_pixel.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/imaging/image_set_pixel.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" // mapnik diff -Nru mapnik-3.0.9+ds/test/unit/imaging/image_view.cpp mapnik-3.0.13+ds/test/unit/imaging/image_view.cpp --- mapnik-3.0.9+ds/test/unit/imaging/image_view.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/imaging/image_view.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" // mapnik diff -Nru mapnik-3.0.9+ds/test/unit/imaging/tiff_io.cpp mapnik-3.0.13+ds/test/unit/imaging/tiff_io.cpp --- mapnik-3.0.9+ds/test/unit/imaging/tiff_io.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/imaging/tiff_io.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,4 +1,3 @@ - // disabled on windows due to https://github.com/mapnik/mapnik/issues/2838 // TODO - get to the bottom of why including `tiff_reader.cpp` breaks windows // or re-write image_readers to allow `#include tiff_reader.hpp` @@ -12,7 +11,7 @@ #include "../../../src/tiff_reader.cpp" #define TIFF_ASSERT(filename) \ - mapnik::tiff_reader tiff_reader(filename); \ + mapnik::tiff_reader tiff_reader(filename); \ REQUIRE( tiff_reader.width() == 256 ); \ REQUIRE( tiff_reader.height() == 256 ); \ REQUIRE( tiff_reader.planar_config() == PLANARCONFIG_CONTIG ); \ @@ -20,7 +19,7 @@ REQUIRE( reader->width() == 256 ); \ REQUIRE( reader->height() == 256 ); \ mapnik::util::file file(filename); \ - mapnik::tiff_reader tiff_reader2(file.data().get(),file.size()); \ + mapnik::tiff_reader tiff_reader2(file.data().get(),file.size()); \ REQUIRE( tiff_reader2.width() == 256 ); \ REQUIRE( tiff_reader2.height() == 256 ); \ std::unique_ptr reader2(mapnik::get_image_reader(file.data().get(),file.size())); \ @@ -57,11 +56,13 @@ REQUIRE( subimage.width() == 1 ); \ REQUIRE( subimage.height() == 1 ); \ -TEST_CASE("tiff io") { +TEST_CASE("tiff io") +{ -SECTION("scan rgb8 striped") { +SECTION("scan rgb8 striped") +{ std::string filename("./test/data/tiff/scan_512x512_rgb8_striped.tif"); - mapnik::tiff_reader tiff_reader(filename); + mapnik::tiff_reader tiff_reader(filename); REQUIRE( tiff_reader.width() == 512 ); REQUIRE( tiff_reader.height() == 512 ); REQUIRE( tiff_reader.planar_config() == PLANARCONFIG_CONTIG ); @@ -76,7 +77,7 @@ REQUIRE( reader->width() == 512 ); REQUIRE( reader->height() == 512 ); mapnik::util::file file(filename); - mapnik::tiff_reader tiff_reader2(file.data().get(),file.size()); + mapnik::tiff_reader tiff_reader2(file.data().get(),file.size()); REQUIRE( tiff_reader2.width() == 512 ); REQUIRE( tiff_reader2.height() == 512 ); std::unique_ptr reader2(mapnik::get_image_reader(file.data().get(),file.size())); @@ -91,7 +92,7 @@ SECTION("scan rgb8 tiled") { std::string filename("./test/data/tiff/scan_512x512_rgb8_tiled.tif"); - mapnik::tiff_reader tiff_reader(filename); + mapnik::tiff_reader tiff_reader(filename); REQUIRE( tiff_reader.width() == 512 ); REQUIRE( tiff_reader.height() == 512 ); REQUIRE( tiff_reader.planar_config() == PLANARCONFIG_CONTIG ); @@ -106,7 +107,7 @@ REQUIRE( reader->width() == 512 ); REQUIRE( reader->height() == 512 ); mapnik::util::file file(filename); - mapnik::tiff_reader tiff_reader2(file.data().get(),file.size()); + mapnik::tiff_reader tiff_reader2(file.data().get(),file.size()); REQUIRE( tiff_reader2.width() == 512 ); REQUIRE( tiff_reader2.height() == 512 ); std::unique_ptr reader2(mapnik::get_image_reader(file.data().get(),file.size())); diff -Nru mapnik-3.0.9+ds/test/unit/numerics/enumeration.cpp mapnik-3.0.13+ds/test/unit/numerics/enumeration.cpp --- mapnik-3.0.9+ds/test/unit/numerics/enumeration.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/numerics/enumeration.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,17 @@ + +#include "catch.hpp" +#include +#include +#include + +TEST_CASE("enumeration") { + + mapnik::line_cap_e e(mapnik::ROUND_CAP); + CHECK( e.as_string() == "round" ); + // note: test the << operator, which calls `as_string` internally + // is not used in mapnik, but kept for back compat + std::stringstream s; + s << e; + CHECK( s.str() == "round" ); + +} \ No newline at end of file diff -Nru mapnik-3.0.9+ds/test/unit/numerics/safe_cast.cpp mapnik-3.0.13+ds/test/unit/numerics/safe_cast.cpp --- mapnik-3.0.9+ds/test/unit/numerics/safe_cast.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/numerics/safe_cast.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/pixel/agg_blend_src_over_test.cpp mapnik-3.0.13+ds/test/unit/pixel/agg_blend_src_over_test.cpp --- mapnik-3.0.9+ds/test/unit/pixel/agg_blend_src_over_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/pixel/agg_blend_src_over_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/pixel/palette.cpp mapnik-3.0.13+ds/test/unit/pixel/palette.cpp --- mapnik-3.0.9+ds/test/unit/pixel/palette.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/pixel/palette.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/projection/proj_transform.cpp mapnik-3.0.13+ds/test/unit/projection/proj_transform.cpp --- mapnik-3.0.9+ds/test/unit/projection/proj_transform.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/projection/proj_transform.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/run.cpp mapnik-3.0.13+ds/test/unit/run.cpp --- mapnik-3.0.9+ds/test/unit/run.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/run.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,17 +1,73 @@ #define CATCH_CONFIG_RUNNER #include "catch.hpp" +#include +#include #include +#include #include "cleanup.hpp" // run_cleanup() +std::string plugin_path; + +inline void set_plugin_path(Catch::ConfigData&, std::string const& _plugin_path ) { + plugin_path = _plugin_path; +} + +std::string working_dir; + +inline void set_working_dir(Catch::ConfigData&, std::string const& _working_dir ) { + working_dir = _working_dir; +} + + int main (int argc, char* const argv[]) { - mapnik::datasource_cache::instance().register_datasources("plugins/input/"); + Catch::Session session; - int result = Catch::Session().run( argc, argv ); + auto & cli = session.cli(); + + cli["-p"]["--plugins"] + .describe("path to mapnik plugins") + .bind(&set_plugin_path, "plugins"); + + cli["-C"]["--working-directory"] + .describe("change working directory") + .bind(&set_working_dir, "working directory"); + + int result = session.applyCommandLine(argc, argv); + + if (!plugin_path.empty()) + { + if (!mapnik::util::exists(plugin_path)) + { + std::clog << "Could not find " << plugin_path << "\n"; + return -1; + } + mapnik::datasource_cache::instance().register_datasources(plugin_path); + } + else + { + mapnik::datasource_cache::instance().register_datasources("plugins/input/"); + } + + if (!working_dir.empty()) + { + if (!mapnik::util::exists(working_dir)) + { + std::clog << "Could not find " << working_dir << "\n"; + return -1; + } + boost::filesystem::current_path(working_dir); + } + + if (result == 0) + { + result = session.run(); + } testing::run_cleanup(); return result; + } diff -Nru mapnik-3.0.9+ds/test/unit/serialization/parse_hex.hpp mapnik-3.0.13+ds/test/unit/serialization/parse_hex.hpp --- mapnik-3.0.9+ds/test/unit/serialization/parse_hex.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/serialization/parse_hex.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,44 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2016 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_PARSE_HEX_HPP +#define MAPNIK_PARSE_HEX_HPP + +#include +#include + +namespace mapnik { namespace util { + +template +bool parse_hex(std::string const& input, Out & output) +{ + boost::spirit::qi::lit_type lit; + auto itr = input.begin(); + auto end = input.end(); + using hex2 = boost::spirit::qi::uint_parser< unsigned, 16, 2, 2 >; + return boost::spirit::qi::parse(itr, end, -(lit("\\x") | lit("0x")) > *hex2(), output); +} + +}} + + +#endif // MAPNIK_PARSE_HEX_HPP diff -Nru mapnik-3.0.9+ds/test/unit/serialization/wkb_formats_test.cpp mapnik-3.0.13+ds/test/unit/serialization/wkb_formats_test.cpp --- mapnik-3.0.9+ds/test/unit/serialization/wkb_formats_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/serialization/wkb_formats_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -2,11 +2,9 @@ #include #include -#include #include #include #include -#include #include TEST_CASE("geometry formats") { @@ -55,9 +53,6 @@ unsigned char sq_invalid_blob[] = { 0x23, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x23 }; - mapnik::context_ptr ctx(new mapnik::context_type); - mapnik::feature_ptr feature = mapnik::feature_factory::create(ctx, 1); - // test of parsing wkb geometries try { diff -Nru mapnik-3.0.9+ds/test/unit/serialization/wkb_test.cpp mapnik-3.0.13+ds/test/unit/serialization/wkb_test.cpp --- mapnik-3.0.9+ds/test/unit/serialization/wkb_test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/serialization/wkb_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,117 @@ +#include "catch.hpp" +// mapnik +#include +#include +#include +#include +#include +// bool +#include +#include +#include +// stl +#include "parse_hex.hpp" +#include +#include +#include +#include + +#if BOOST_VERSION >= 105800 +namespace { + +struct spatially_equal_visitor +{ + using result_type = bool; + + result_type operator() (mapnik::geometry::geometry_empty, mapnik::geometry::geometry_empty) const + { + return true; + } + + result_type operator() (mapnik::geometry::geometry_collection const& lhs, mapnik::geometry::geometry_collection const& rhs) const + { + std::size_t size0 = lhs.size(); + std::size_t size1 = rhs.size(); + if (size0 != size1) return false; + for (std::size_t index = 0; index < size0 ; ++index) + { + if (!mapnik::util::apply_visitor(*this, lhs[index], rhs[index])) + return false; + } + return true; + } + + result_type operator() (mapnik::geometry::multi_point const& lhs, mapnik::geometry::multi_point const& rhs) const + { + std::size_t size0 = lhs.size(); + std::size_t size1 = rhs.size(); + if (size0 != size1) return false; + auto tmp0 = lhs; + auto tmp1 = rhs; + std::sort(tmp0.begin(), tmp0.end(), boost::geometry::less>()); + std::sort(tmp1.begin(), tmp1.end(), boost::geometry::less>()); + for (std::size_t index = 0; index < size0 ; ++index) + { + if (!boost::geometry::equals(tmp0[index], tmp1[index])) return false; + } + return true; + } + + template + result_type operator() (T const& lhs, T const& rhs) const + { + if (mapnik::geometry::is_empty(lhs) && mapnik::geometry::is_empty(rhs)) + return true; //Empty geometries of the same type are considered to be spatially equal + return boost::geometry::equals(lhs, rhs); + } + + template + result_type operator() (T0 const& lhs, T1 const& rhs) const + { + return false; + } + +}; + +template +bool spatially_equal(mapnik::geometry::geometry const& g0, mapnik::geometry::geometry const& g1) +{ + return mapnik::util::apply_visitor(spatially_equal_visitor(), g0, g1); +} + +} +#endif + +TEST_CASE("Well-known-geometries") +{ + SECTION("wkb") + { + std::string filename("test/unit/data/well-known-geometries.test"); + std::ifstream is(filename.c_str(),std::ios_base::in | std::ios_base::binary); + if (!is) throw std::runtime_error("could not open: '" + filename + "'"); + + for (std::string line; std::getline(is, line,'\n');) + { + std::vector columns; + boost::split(columns, line, boost::is_any_of(";")); + REQUIRE(columns.size() == 3); + std::vector wkb, twkb; + REQUIRE(mapnik::util::parse_hex(columns[1], wkb)); + REQUIRE(mapnik::util::parse_hex(columns[2], twkb)); + mapnik::geometry::geometry geom_0 = mapnik::geometry_utils::from_wkb(wkb.data(), wkb.size(), mapnik::wkbAuto); + mapnik::geometry::geometry geom_1 = mapnik::geometry_utils::from_twkb(twkb.data(), twkb.size()); + // compare WKTs + std::string wkt0, wkt1; + REQUIRE(mapnik::util::to_wkt(wkt0, geom_0)); + REQUIRE(mapnik::util::to_wkt(wkt1, geom_1)); + if (!mapnik::geometry::is_empty(geom_0) && !mapnik::geometry::is_empty(geom_1)) + { + REQUIRE(wkt0 == wkt1); + // compare spatially (NOTE: GeometryCollection comparison also enforces strict order) +#if BOOST_VERSION >= 105800 + REQUIRE(spatially_equal(geom_0, geom_1)); +#endif + } + } + } +} diff -Nru mapnik-3.0.9+ds/test/unit/serialization/xml_parser_trim.cpp mapnik-3.0.13+ds/test/unit/serialization/xml_parser_trim.cpp --- mapnik-3.0.9+ds/test/unit/serialization/xml_parser_trim.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/serialization/xml_parser_trim.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/svg/svg_parser_test.cpp mapnik-3.0.13+ds/test/unit/svg/svg_parser_test.cpp --- mapnik-3.0.9+ds/test/unit/svg/svg_parser_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/svg/svg_parser_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -30,25 +30,44 @@ #include #include #include - -#include +#include "util.hpp" #include #include -namespace detail { - -template -struct vertex_equal +namespace // internal { - template - bool operator() (T const& lhs, T const& rhs) const + struct test_parser { - static const double eps = 1.0 / std::pow(10,N); - return (std::fabs(std::get<0>(lhs) - std::get<0>(rhs)) < eps) - && (std::fabs(std::get<1>(lhs) - std::get<1>(rhs)) < eps) - && std::get<2>(lhs) == std::get<2>(rhs); + mapnik::svg_storage_type path; + mapnik::svg::vertex_stl_adapter stl_storage; + mapnik::svg::svg_path_adapter svg_path; + mapnik::svg::svg_converter_type svg; + mapnik::svg::svg_parser p; + + test_parser() + : stl_storage(path.source()) + , svg_path(stl_storage) + , svg(svg_path, path.attributes()) + , p(svg) + {} + + mapnik::svg::svg_parser* operator->() + { + return &p; + } + }; + + template + std::string join(C const& container) + { + std::string result; + for (auto const& str : container) + { + if (!result.empty()) result += "\n "; + result += str; + } + return result; } -}; } TEST_CASE("SVG parser") { @@ -66,142 +85,112 @@ SECTION("SVG::parse i/o") { std::string svg_name("FAIL"); + char const* expected_errors[] = + { + "Unable to open 'FAIL'" + }; - using namespace mapnik::svg; - mapnik::svg_storage_type path; - vertex_stl_adapter stl_storage(path.source()); - svg_path_adapter svg_path(stl_storage); - svg_converter_type svg(svg_path, path.attributes()); - svg_parser p(svg); - - if (!p.parse(svg_name)) - { - auto const& errors = p.error_messages(); - REQUIRE(errors.size() == 1); - REQUIRE(errors[0] == "Unable to open 'FAIL'"); - } + test_parser p; + REQUIRE(!p->parse(svg_name)); + REQUIRE(join(p->error_messages()) == join(expected_errors)); } SECTION("SVG::parse_from_string syntax error") { std::string svg_name("./test/data/svg/invalid.svg"); + char const* expected_errors[] = + { + "Unable to parse '\n\n'" + }; + std::ifstream in(svg_name.c_str()); std::string svg_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - using namespace mapnik::svg; - mapnik::svg_storage_type path; - vertex_stl_adapter stl_storage(path.source()); - svg_path_adapter svg_path(stl_storage); - svg_converter_type svg(svg_path, path.attributes()); - svg_parser p(svg); - - if (!p.parse_from_string(svg_str)) - { - auto const& errors = p.error_messages(); - REQUIRE(errors.size() == 1); - REQUIRE(errors[0] == "Unable to parse '\n\n'"); - } + test_parser p; + REQUIRE(!p->parse_from_string(svg_str)); + REQUIRE(join(p->error_messages()) == join(expected_errors)); } SECTION("SVG::parse_from_string syntax error") { std::string svg_name("./test/data/svg/invalid.svg"); + char const* expected_errors[] = + { + "svg_parser::parse - Unable to parse './test/data/svg/invalid.svg'" + }; - using namespace mapnik::svg; - mapnik::svg_storage_type path; - vertex_stl_adapter stl_storage(path.source()); - svg_path_adapter svg_path(stl_storage); - svg_converter_type svg(svg_path, path.attributes()); - svg_parser p(svg); - - if (!p.parse(svg_name)) - { - auto const& errors = p.error_messages(); - REQUIRE(errors.size() == 1); - REQUIRE(errors[0] == "svg_parser::parse - Unable to parse './test/data/svg/invalid.svg'"); - } + test_parser p; + REQUIRE(!p->parse(svg_name)); + REQUIRE(join(p->error_messages()) == join(expected_errors)); } SECTION("SVG parser color ") { std::string svg_name("./test/data/svg/color_fail.svg"); + char const* expected_errors[] = + { + "Failed to parse color: \"fail\"", + "Failed to parse SVG value: 'fail'", + "Failed to parse color: \"fail\"", + }; + std::ifstream in(svg_name.c_str()); std::string svg_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - using namespace mapnik::svg; - mapnik::svg_storage_type path; - vertex_stl_adapter stl_storage(path.source()); - svg_path_adapter svg_path(stl_storage); - svg_converter_type svg(svg_path, path.attributes()); - svg_parser p(svg); - - if (!p.parse_from_string(svg_str)) - { - auto const& errors = p.error_messages(); - REQUIRE(errors.size() == 3); - REQUIRE(errors[0] == "Failed to parse color: \"fail\""); - REQUIRE(errors[1] == "Failed to parse double: \"fail\""); - REQUIRE(errors[2] == "Failed to parse color: \"fail\""); - } + test_parser p; + REQUIRE(!p->parse_from_string(svg_str)); + REQUIRE(join(p->error_messages()) == join(expected_errors)); } SECTION("SVG - cope with erroneous geometries") { std::string svg_name("./test/data/svg/errors.svg"); + char const* expected_errors[] = + { + "parse_rect: Invalid width", + "Failed to parse SVG value: 'FAIL'", + "parse_rect: Invalid height", + "parse_rect: Invalid rx", + "parse_rect: Invalid ry", + "Failed to parse SVG value: '100invalidunit', trailing garbage: 'validunit'", + "unable to parse invalid svg ", + "unable to parse invalid svg with id 'fail-path'", + "unable to parse invalid svg with id 'fail-path'", + "parse_circle: Invalid radius", + "Failed to parse 'points'", + "Failed to parse 'points'", + "parse_ellipse: Invalid rx", + "parse_ellipse: Invalid ry", + }; + std::ifstream in(svg_name.c_str()); std::string svg_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - using namespace mapnik::svg; - mapnik::svg_storage_type path; - vertex_stl_adapter stl_storage(path.source()); - svg_path_adapter svg_path(stl_storage); - svg_converter_type svg(svg_path, path.attributes()); - svg_parser p(svg); - if (!p.parse_from_string(svg_str)) - { - auto const& errors = p.error_messages(); - REQUIRE(errors.size() == 13); - REQUIRE(errors[0] == "parse_rect: Invalid width"); - REQUIRE(errors[1] == "Failed to parse double: \"FAIL\""); - REQUIRE(errors[2] == "parse_rect: Invalid height"); - REQUIRE(errors[3] == "parse_rect: Invalid rx"); - REQUIRE(errors[4] == "parse_rect: Invalid ry"); - REQUIRE(errors[5] == "unable to parse invalid svg "); - REQUIRE(errors[6] == "unable to parse invalid svg with id 'fail-path'"); - REQUIRE(errors[7] == "unable to parse invalid svg with id 'fail-path'"); - REQUIRE(errors[8] == "parse_circle: Invalid radius"); - REQUIRE(errors[9] == "Failed to parse 'points'"); - REQUIRE(errors[10] == "Failed to parse 'points'"); - REQUIRE(errors[11] == "parse_ellipse: Invalid rx"); - REQUIRE(errors[12] == "parse_ellipse: Invalid ry"); - } + test_parser p; + REQUIRE(!p->parse_from_string(svg_str)); + REQUIRE(join(p->error_messages()) == join(expected_errors)); } SECTION("SVG parser double % ") { std::string svg_name("./test/data/svg/gradient-radial-error.svg"); + char const* expected_errors[] = + { + "Failed to parse SVG value: 'FAIL'" + }; + std::ifstream in(svg_name.c_str()); std::string svg_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - using namespace mapnik::svg; - mapnik::svg_storage_type path; - vertex_stl_adapter stl_storage(path.source()); - svg_path_adapter svg_path(stl_storage); - svg_converter_type svg(svg_path, path.attributes()); - svg_parser p(svg); - - if (!p.parse_from_string(svg_str)) - { - auto const& errors = p.error_messages(); - REQUIRE(errors.size() == 1); - REQUIRE(errors[0] == "Failed to parse double (optional %) from FAIL"); - } + test_parser p; + REQUIRE(!p->parse_from_string(svg_str)); + REQUIRE(join(p->error_messages()) == join(expected_errors)); } SECTION("SVG parser display=none") @@ -328,7 +317,7 @@ std::make_tuple(0, 10,2), std::make_tuple(0, 10,95)}; - REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(),detail::vertex_equal<3>())); + REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(),vertex_equal<3>())); } SECTION("SVG viewbox fallback") @@ -337,16 +326,10 @@ std::ifstream in(svg_name.c_str()); std::string svg_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - - using namespace mapnik::svg; - mapnik::svg_storage_type path; - vertex_stl_adapter stl_storage(path.source()); - svg_path_adapter svg_path(stl_storage); - svg_converter_type svg(svg_path, path.attributes()); - svg_parser p(svg); - p.parse_from_string(svg_str); - auto width = svg.width(); - auto height = svg.height(); + test_parser p; + REQUIRE(p->parse_from_string(svg_str)); + auto width = p.svg.width(); + auto height = p.svg.height(); REQUIRE(width == 100); REQUIRE(height == 100); } @@ -394,7 +377,7 @@ std::make_tuple(0, 10,2), std::make_tuple(0, 10,95)}; - REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(),detail::vertex_equal<3>())); + REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(),vertex_equal<3>())); } SECTION("SVG beveled ") @@ -621,41 +604,33 @@ SECTION("SVG missing def") { std::string svg_name("./test/data/svg/gradient-nodef.svg"); - using namespace mapnik::svg; - mapnik::svg_storage_type path; - vertex_stl_adapter stl_storage(path.source()); - svg_path_adapter svg_path(stl_storage); - svg_converter_type svg(svg_path, path.attributes()); - svg_parser p(svg); - REQUIRE(!p.parse(svg_name)); - auto const& errors = p.error_messages(); - REQUIRE(errors.size() == 2); - REQUIRE(errors[0] == "Failed to find gradient fill: MyGradient"); - REQUIRE(errors[1] == "Failed to find gradient stroke: MyGradient"); + char const* expected_errors[] = + { + "Failed to find gradient fill: MyGradient", + "Failed to find gradient stroke: MyGradient", + }; + + test_parser p; + REQUIRE(!p->parse(svg_name)); + REQUIRE(join(p->error_messages()) == join(expected_errors)); } SECTION("SVG missing id") { - std::string svg_name("./test/data/svg/gradient-no-id.svg"); + char const* expected_errors[] = + { + "Failed to find gradient fill: MyGradient", + "Failed to find gradient stroke: MyGradient", + }; + std::ifstream in(svg_name.c_str()); std::string svg_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - using namespace mapnik::svg; - mapnik::svg_storage_type path; - vertex_stl_adapter stl_storage(path.source()); - svg_path_adapter svg_path(stl_storage); - svg_converter_type svg(svg_path, path.attributes()); - svg_parser p(svg); - - if (!p.parse_from_string(svg_str)) - { - auto const& errors = p.error_messages(); - REQUIRE(errors.size() == 2); - REQUIRE(errors[0] == "Failed to find gradient fill: MyGradient"); - REQUIRE(errors[1] == "Failed to find gradient stroke: MyGradient"); - } + test_parser p; + REQUIRE(!p->parse_from_string(svg_str)); + REQUIRE(join(p->error_messages()) == join(expected_errors)); } SECTION("SVG missing inheritance") diff -Nru mapnik-3.0.9+ds/test/unit/svg/svg_path_parser_test.cpp mapnik-3.0.13+ds/test/unit/svg/svg_path_parser_test.cpp --- mapnik-3.0.9+ds/test/unit/svg/svg_path_parser_test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/svg/svg_path_parser_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,164 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 "catch.hpp" + +#include +#include +#include +#include +#include +#include "util.hpp" + +namespace { + +template +void test_path_parser(std::string const& str, Expected const& expected) +{ + using namespace mapnik::svg; + mapnik::svg_path_ptr marker_path(std::make_shared()); + vertex_stl_adapter stl_storage(marker_path->source()); + svg_path_adapter svg_path(stl_storage); + svg_converter_type svg(svg_path, marker_path->attributes()); + + CHECK(mapnik::svg::parse_path(str.c_str(), svg)); + double x,y; + unsigned cmd; + auto & p = svg.storage(); + std::vector> vec; + while ((cmd = p.vertex(&x,&y)) != mapnik::SEG_END) + { + vec.emplace_back(x, y, cmd); + //std::cerr << "std::make_tuple(" << x << ", " << y << ", " << cmd << ")," << std::endl; + } + REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(), vertex_equal<3>())); +} +} // anonymous ns + +TEST_CASE("SVG path parser") { + + SECTION("MoveTo/LineTo") + { + std::string str = "M 100 100 L 300 100 L 200 300 z"; + std::string str2 = "M100,100L300,100L200,300z"; + std::string str3 = "M100,100l200 0L200,300z"; + std::vector> expected = { + std::make_tuple(100, 100, 1), + std::make_tuple(300, 100, 2), + std::make_tuple(200, 300, 2), + std::make_tuple(100, 100, 79) }; + test_path_parser(str, expected); + test_path_parser(str2, expected); + test_path_parser(str3, expected); + } + + SECTION("MoveTo/HLine/VLine") + { + std::string str = "M100 100H300V200z"; + std::string str2 = "M100,100h200v100z"; + std::vector> expected = { + std::make_tuple(100, 100, 1), + std::make_tuple(300, 100, 2), + std::make_tuple(300, 200, 2), + std::make_tuple(100, 100, 79) + }; + test_path_parser(str, expected); + test_path_parser(str2, expected); + } + + SECTION("Arcs") + { + std::string str = "M300,200 h-150 a150,150 0 1,0 150,-150 z"; + + std::vector> expected = { + std::make_tuple(300, 200, 1), + std::make_tuple(150, 200, 2), + std::make_tuple(150, 282.843, 4), + std::make_tuple(217.157, 350, 4), + std::make_tuple(300, 350, 4), + std::make_tuple(382.843, 350, 4), + std::make_tuple(450, 282.843, 4), + std::make_tuple(450, 200, 4), + std::make_tuple(450, 117.157, 4), + std::make_tuple(382.843, 50, 4), + std::make_tuple(300, 50, 4), + std::make_tuple(300, 200, 79)}; + test_path_parser(str, expected); + } + + + SECTION("Arcs 2") + { + std::string str = "M275,175 v-150 a150,150 0 0,0 -150,150 z"; + + std::vector> expected = { + std::make_tuple(275, 175, 1), + std::make_tuple(275, 25, 2), + std::make_tuple(192.157, 25, 4), + std::make_tuple(125, 92.1573, 4), + std::make_tuple(125, 175, 4), + std::make_tuple(275, 175, 79)}; + test_path_parser(str, expected); + } + + SECTION("Arcs 3") + { + std::string str = "M600,350 l 50,-25" + "a25,25 -30 0,1 50,-25 l 50,-25" + "a25,50 -30 0,1 50,-25 l 50,-25" + "a25,75 -30 0,1 50,-25 l 50,-25" + "a25,100 -30 0,1 50,-25 l 50,-25"; + + std::vector> expected = { + std::make_tuple(600, 350, 1), + std::make_tuple(650, 325, 2), + std::make_tuple(643.096, 311.193, 4), + std::make_tuple(648.693, 294.404, 4), + std::make_tuple(662.5, 287.5, 4), + std::make_tuple(676.307, 280.596, 4), + std::make_tuple(693.096, 286.193, 4), + std::make_tuple(700, 300, 4), + std::make_tuple(750, 275, 2), + std::make_tuple(734.991, 248.079, 4), + std::make_tuple(734.017, 220.66, 4), + std::make_tuple(747.825, 213.756, 4), + std::make_tuple(761.632, 206.852, 4), + std::make_tuple(784.991, 223.079, 4), + std::make_tuple(800, 250, 4), + std::make_tuple(850, 225, 2), + std::make_tuple(827.153, 184.812, 4), + std::make_tuple(819.825, 146.636, 4), + std::make_tuple(833.632, 139.733, 4), + std::make_tuple(847.44, 132.829, 4), + std::make_tuple(877.153, 159.812, 4), + std::make_tuple(900, 200, 4), + std::make_tuple(950, 175, 2), + std::make_tuple(919.382, 121.506, 4), + std::make_tuple(905.754, 72.5436, 4), + std::make_tuple(919.561, 65.64, 4), + std::make_tuple(933.368, 58.7365, 4), + std::make_tuple(969.382, 96.5057, 4), + std::make_tuple(1000, 150, 4), + std::make_tuple(1050, 125, 2)}; + test_path_parser(str, expected); + } +} diff -Nru mapnik-3.0.9+ds/test/unit/svg/util.hpp mapnik-3.0.13+ds/test/unit/svg/util.hpp --- mapnik-3.0.9+ds/test/unit/svg/util.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/svg/util.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -0,0 +1,44 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2015 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 + * + *****************************************************************************/ + +#ifndef TEST_UNIT_SVG_UTIL_HPP +#define TEST_UNIT_SVG_UTIL_HPP + +#include + +namespace { + +template +struct vertex_equal +{ + template + bool operator() (T const& lhs, T const& rhs) const + { + static const double eps = 1.0 / std::pow(10,N); + return (std::fabs(std::get<0>(lhs) - std::get<0>(rhs)) < eps) + && (std::fabs(std::get<1>(lhs) - std::get<1>(rhs)) < eps) + && std::get<2>(lhs) == std::get<2>(rhs); + } +}; +} + +#endif // TEST_UNIT_SVG_UTIL_HPP diff -Nru mapnik-3.0.9+ds/test/unit/symbolizer/symbolizer_test.cpp mapnik-3.0.13+ds/test/unit/symbolizer/symbolizer_test.cpp --- mapnik-3.0.9+ds/test/unit/symbolizer/symbolizer_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/symbolizer/symbolizer_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/unit/text/shaping.cpp mapnik-3.0.13+ds/test/unit/text/shaping.cpp --- mapnik-3.0.9+ds/test/unit/text/shaping.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/text/shaping.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include #include diff -Nru mapnik-3.0.9+ds/test/unit/vertex_adapter/clipping_test.cpp mapnik-3.0.13+ds/test/unit/vertex_adapter/clipping_test.cpp --- mapnik-3.0.9+ds/test/unit/vertex_adapter/clipping_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/vertex_adapter/clipping_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" // mapnik diff -Nru mapnik-3.0.9+ds/test/unit/vertex_adapter/line_offset_test.cpp mapnik-3.0.13+ds/test/unit/vertex_adapter/line_offset_test.cpp --- mapnik-3.0.9+ds/test/unit/vertex_adapter/line_offset_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/vertex_adapter/line_offset_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" // mapnik diff -Nru mapnik-3.0.9+ds/test/unit/vertex_adapter/offset_converter.cpp mapnik-3.0.13+ds/test/unit/vertex_adapter/offset_converter.cpp --- mapnik-3.0.9+ds/test/unit/vertex_adapter/offset_converter.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/vertex_adapter/offset_converter.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" // mapnik diff -Nru mapnik-3.0.9+ds/test/unit/vertex_adapter/simplify_converters_test.cpp mapnik-3.0.13+ds/test/unit/vertex_adapter/simplify_converters_test.cpp --- mapnik-3.0.9+ds/test/unit/vertex_adapter/simplify_converters_test.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/vertex_adapter/simplify_converters_test.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" //#include diff -Nru mapnik-3.0.9+ds/test/unit/vertex_adapter/vertex_adapter.cpp mapnik-3.0.13+ds/test/unit/vertex_adapter/vertex_adapter.cpp --- mapnik-3.0.9+ds/test/unit/vertex_adapter/vertex_adapter.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/unit/vertex_adapter/vertex_adapter.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -1,3 +1,4 @@ + #include "catch.hpp" #include diff -Nru mapnik-3.0.9+ds/test/visual/renderer.hpp mapnik-3.0.13+ds/test/visual/renderer.hpp --- mapnik-3.0.9+ds/test/visual/renderer.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/visual/renderer.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -38,10 +38,21 @@ #if defined(GRID_RENDERER) #include #endif + #if defined(HAVE_CAIRO) #include #include +#ifdef CAIRO_HAS_SVG_SURFACE +#include +#endif +#ifdef CAIRO_HAS_PS_SURFACE +#include +#endif +#ifdef CAIRO_HAS_PDF_SURFACE +#include #endif +#endif + #if defined(SVG_RENDERER) #include #endif @@ -53,7 +64,7 @@ { template -struct renderer_base +struct raster_renderer_base { using image_type = ImageType; @@ -80,7 +91,35 @@ } }; -struct agg_renderer : renderer_base +struct vector_renderer_base +{ + using image_type = std::string; + + static constexpr const bool support_tiles = false; + + unsigned compare(image_type const & actual, boost::filesystem::path const& reference) const + { + std::ifstream stream(reference.string().c_str(), std::ios_base::in | std::ios_base::binary); + if (!stream) + { + throw std::runtime_error("Could not open: " + reference.string()); + } + std::string expected(std::istreambuf_iterator(stream.rdbuf()), std::istreambuf_iterator()); + return std::max(actual.size(), expected.size()) - std::min(actual.size(), expected.size()); + } + + void save(image_type const & image, boost::filesystem::path const& path) const + { + std::ofstream file(path.string().c_str(), std::ios::out | std::ios::trunc | std::ios::binary); + if (!file) + { + throw std::runtime_error("Cannot open file for writing: " + path.string()); + } + file << image; + } +}; + +struct agg_renderer : raster_renderer_base { static constexpr const char * name = "agg"; @@ -94,7 +133,7 @@ }; #if defined(HAVE_CAIRO) -struct cairo_renderer : renderer_base +struct cairo_renderer : raster_renderer_base { static constexpr const char * name = "cairo"; @@ -111,14 +150,65 @@ return image; } }; + +using surface_create_type = cairo_surface_t *(&)(cairo_write_func_t, void *, double, double); + +template +struct cairo_vector_renderer : vector_renderer_base +{ + static cairo_status_t write(void *closure, + const unsigned char *data, + unsigned int length) + { + std::ostringstream & ss = *reinterpret_cast(closure); + ss.write(reinterpret_cast(data), length); + return ss ? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_WRITE_ERROR; + } + + image_type render(mapnik::Map const & map, double scale_factor) const + { + std::ostringstream ss(std::stringstream::binary); + mapnik::cairo_surface_ptr image_surface( + SurfaceCreateFunction(write, &ss, map.width(), map.height()), + mapnik::cairo_surface_closer()); + mapnik::cairo_ptr image_context(mapnik::create_context(image_surface)); + mapnik::cairo_renderer ren(map, image_context, scale_factor); + ren.apply(); + cairo_surface_finish(&*image_surface); + return ss.str(); + } +}; + +#ifdef CAIRO_HAS_SVG_SURFACE +struct cairo_svg_renderer : cairo_vector_renderer +{ + static constexpr const char * name = "cairo-svg"; + static constexpr const char * ext = ".svg"; +}; +#endif + +#ifdef CAIRO_HAS_PS_SURFACE +struct cairo_ps_renderer : cairo_vector_renderer +{ + static constexpr const char * name = "cairo-ps"; + static constexpr const char * ext = ".ps"; +}; +#endif + +#ifdef CAIRO_HAS_PDF_SURFACE +struct cairo_pdf_renderer : cairo_vector_renderer +{ + static constexpr const char * name = "cairo-pdf"; + static constexpr const char * ext = ".pdf"; +}; +#endif #endif #if defined(SVG_RENDERER) -struct svg_renderer : renderer_base +struct svg_renderer : vector_renderer_base { static constexpr const char * name = "svg"; static constexpr const char * ext = ".svg"; - static constexpr const bool support_tiles = false; image_type render(mapnik::Map const & map, double scale_factor) const { @@ -128,35 +218,11 @@ ren.apply(); return ss.str(); } - - unsigned compare(image_type const & actual, boost::filesystem::path const& reference) const - { - std::ifstream stream(reference.string().c_str(),std::ios_base::in|std::ios_base::binary); - if (!stream.is_open()) - { - throw std::runtime_error("could not open: '" + reference.string() + "'"); - } - std::string expected(std::istreambuf_iterator(stream.rdbuf()),(std::istreambuf_iterator())); - stream.close(); - return std::max(actual.size(), expected.size()) - std::min(actual.size(), expected.size()); - } - - void save(image_type const & image, boost::filesystem::path const& path) const - { - std::ofstream file(path.string().c_str(), std::ios::out | std::ios::trunc | std::ios::binary); - if (!file) { - throw std::runtime_error((std::string("cannot open file for writing file ") + path.string()).c_str()); - } else { - file << image; - file.close(); - } - } - }; #endif #if defined(GRID_RENDERER) -struct grid_renderer : renderer_base +struct grid_renderer : raster_renderer_base { static constexpr const char * name = "grid"; @@ -335,6 +401,15 @@ using renderer_type = mapnik::util::variant #if defined(HAVE_CAIRO) ,renderer +#ifdef CAIRO_HAS_SVG_SURFACE + ,renderer +#endif +#ifdef CAIRO_HAS_PS_SURFACE + ,renderer +#endif +#ifdef CAIRO_HAS_PDF_SURFACE + ,renderer +#endif #endif #if defined(SVG_RENDERER) ,renderer diff -Nru mapnik-3.0.9+ds/test/visual/run.cpp mapnik-3.0.13+ds/test/visual/run.cpp --- mapnik-3.0.9+ds/test/visual/run.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/visual/run.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -48,30 +48,48 @@ runner::renderer_container create_renderers(po::variables_map const & args, boost::filesystem::path const & output_dir, - bool append_all = false) + bool force_append = false) { boost::filesystem::path reference_dir(args["images-dir"].as()); bool overwrite = args.count("overwrite"); runner::renderer_container renderers; - if (append_all || args.count(agg_renderer::name)) + if (force_append || args.count(agg_renderer::name)) { renderers.emplace_back(renderer(output_dir, reference_dir, overwrite)); } #if defined(HAVE_CAIRO) - if (append_all || args.count(cairo_renderer::name)) + if (force_append || args.count(cairo_renderer::name)) { renderers.emplace_back(renderer(output_dir, reference_dir, overwrite)); } +#ifdef CAIRO_HAS_SVG_SURFACE + if (args.count(cairo_svg_renderer::name)) + { + renderers.emplace_back(renderer(output_dir, reference_dir, overwrite)); + } +#endif +#ifdef CAIRO_HAS_PS_SURFACE + if (args.count(cairo_ps_renderer::name)) + { + renderers.emplace_back(renderer(output_dir, reference_dir, overwrite)); + } +#endif +#ifdef CAIRO_HAS_PDF_SURFACE + if (args.count(cairo_pdf_renderer::name)) + { + renderers.emplace_back(renderer(output_dir, reference_dir, overwrite)); + } +#endif #endif #if defined(SVG_RENDERER) - if (append_all || args.count(svg_renderer::name)) + if (force_append || args.count(svg_renderer::name)) { renderers.emplace_back(renderer(output_dir, reference_dir, overwrite)); } #endif #if defined(GRID_RENDERER) - if (append_all || args.count(grid_renderer::name)) + if (force_append || args.count(grid_renderer::name)) { renderers.emplace_back(renderer(output_dir, reference_dir, overwrite)); } @@ -112,6 +130,15 @@ (agg_renderer::name, "render with AGG renderer") #if defined(HAVE_CAIRO) (cairo_renderer::name, "render with Cairo renderer") +#ifdef CAIRO_HAS_SVG_SURFACE + (cairo_svg_renderer::name, "render with Cairo SVG renderer") +#endif +#ifdef CAIRO_HAS_PS_SURFACE + (cairo_ps_renderer::name, "render with Cairo PS renderer") +#endif +#ifdef CAIRO_HAS_PDF_SURFACE + (cairo_pdf_renderer::name, "render with Cairo PDF renderer") +#endif #endif #if defined(SVG_RENDERER) (svg_renderer::name, "render with SVG renderer") @@ -183,7 +210,7 @@ } catch (std::exception & e) { - std::cerr << "Error runnig tests: " << e.what() << std::endl; + std::cerr << "Error running tests: " << e.what() << std::endl; return 1; } diff -Nru mapnik-3.0.9+ds/test/visual/runner.cpp mapnik-3.0.13+ds/test/visual/runner.cpp --- mapnik-3.0.9+ds/test/visual/runner.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/test/visual/runner.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -57,13 +57,13 @@ } template ::type* = nullptr> - void operator()(T const & renderer) + void operator()(T const& renderer) const { test(renderer); } template ::type* = nullptr> - void operator()(T const & renderer) + void operator()(T const & renderer) const { if (tiles_.width == 1 && tiles_.height == 1) { @@ -73,7 +73,7 @@ private: template - void test(T const & renderer) + void test(T const & renderer) const { map_size size { map_.width(), map_.height() }; std::chrono::high_resolution_clock::time_point start(std::chrono::high_resolution_clock::now()); @@ -96,7 +96,7 @@ } template ::type* = nullptr> - typename T::image_type render(T const & renderer) + typename T::image_type render(T const& renderer) const { if (tiles_.width == 1 && tiles_.height == 1) { @@ -109,7 +109,7 @@ } template ::type* = nullptr> - typename T::image_type render(T const & renderer) + typename T::image_type render(T const & renderer) const { return renderer.render(map_, scale_factor_); } @@ -150,7 +150,8 @@ result_list runner::test(std::vector const & style_names, report_type & report) const { - std::vector files(style_names.size()); + std::vector files; + files.reserve(style_names.size()); std::transform(style_names.begin(), style_names.end(), std::back_inserter(files), [&](runner::path_type const & name) { @@ -363,4 +364,3 @@ } } - diff -Nru mapnik-3.0.9+ds/.travis.yml mapnik-3.0.13+ds/.travis.yml --- mapnik-3.0.9+ds/.travis.yml 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/.travis.yml 2017-02-08 13:06:42.000000000 +0000 @@ -1,23 +1,20 @@ -language: cpp - -sudo: false +language: generic git: depth: 10 - submodules: true + submodules: false env: global: - - secure: "N3a5nzzsgpuu45k8qWdYsHNxrSnqeAGLTOYpfYoAH7B94vuf7pa7XV1tQjXbxrnx2D6ryTdtUtyRKwy7zXbwXxGt4DpczWEo8f6DUd6+obAp3kdnXABg2Sj4oA7KMs0F0CmoADy0jdUZD5YyOJHu64LCIIgzEQ9q49PFMNbU3IE=" - - secure: "iQYPNpMtejcgYeUkWZGIWz1msIco5qydJrhZTSCQOYahAQerdT7q5WZEpEo3G6IWOGgO1eo7GFuY8DvqQjw1+jC9b9mhkRNdo3LhGTKS9Gsbl5Q27k0rjlaFZmmQHrfPlQJwhfAIp+KLugHtQw5bCoLh+95E3j0F0DayF1tuJ3s=" + - CCACHE_TEMPDIR=/tmp/.ccache-temp + - CCACHE_COMPRESS=1 + - HEAVY_JOBS="2" + - PREFIX=/tmp/mapnik + - secure: "D5CLP5lbyFru788iZO8RqDenY/YsHPREvr34zCEi93xMqOTxPmME/zyuEZSyjP5ZLyf8g/fxOuPYSDbOQ1QLwNDBWxB0JomWOahyimHKrMCrMcGHCjl//2W2mE+p9VwF5VLGgfy7CskGkS49Mye37FDK0ejwuq6MDI45DsH4Fkk=" + - secure: "ZPHyAVL3ID5g3KEmwcnzG9z2tAQwSx526Qd3Y6tsZ3Yj+aSagVBiZQjZGKWgNX74lymtmYKnb2Md46apWLeImt6tjB3MWTu7WwWoZRnqUligz/8Nmg4Lgo7EOCkQcjN/gpA1i+cM5b+ZKDTZYOaHO6/+DAaunQzA7/p99hw/XYg=" + - secure: "F6ivqDNMBQQnrDGA9+7IX+GDswuIqQQd7YPJdQqa2Ked9jddAQDeJClb05ig3JlwfOlYLGZOd43ZX0pKuMtI2Gbkwz211agGP9S3YunwlRg8iWtJlO5kYFUdKCmJNhjg4icfkGELCgwXn+zuEWFSLpkPcjqAFKFlQrIJeAJJgKM=" addons: postgresql: "9.4" - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.5 - packages: - - clang-3.5 cache: directories: @@ -26,66 +23,102 @@ matrix: include: - os: linux - compiler: clang - env: JOBS=8 MASON_PUBLISH=true + sudo: false + compiler: ": clang" + env: JOBS=4 CXX="ccache g++-6" CC="gcc-6" + addons: + apt: + sources: [ 'ubuntu-toolchain-r-test'] + packages: [ 'libstdc++-6-dev', 'g++-6', 'xutils-dev'] - os: linux - compiler: gcc - env: JOBS=6 - - os: osx - compiler: clang - env: JOBS=8 MASON_PUBLISH=true + sudo: false + compiler: ": clang" + env: JOBS=8 MASON_PUBLISH=true CXX="ccache clang++-3.9 -Qunused-arguments" CC="clang-3.9" TRIGGER=true + addons: + apt: + sources: [ 'ubuntu-toolchain-r-test'] + packages: [ 'libstdc++-4.9-dev', 'xutils-dev'] + - os: linux + sudo: false + compiler: ": clang-coverage" + env: JOBS=8 COVERAGE=true CXX="ccache clang++-3.9 -Qunused-arguments" CC="clang-3.9" + addons: + apt: + sources: [ 'ubuntu-toolchain-r-test'] + packages: ['libstdc++-4.9-dev', 'xutils-dev' ] - os: osx - compiler: clang - env: JOBS=8 COVERAGE=true + compiler: ": clang-osx" + # https://docs.travis-ci.com/user/languages/objective-c/#Supported-OS-X-iOS-SDK-versions + osx_image: xcode7.3 # upgrades clang from 6 -> 7 + env: JOBS=4 MASON_PUBLISH=true CXX="ccache clang++ -Qunused-arguments" before_install: + # workaround travis rvm bug + # http://superuser.com/questions/1044130/why-am-i-having-how-can-i-fix-this-error-shell-session-update-command-not-f + - | + if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + rvm get head || true + fi + - source scripts/travis-common.sh + - export PYTHONUSERBASE=$(pwd)/mason_packages/.link + - export PATH=${PREFIX}/bin:$(pwd)/mason_packages/.link/bin:${PYTHONUSERBASE}/bin:${PATH} - export COVERAGE=${COVERAGE:-false} - export MASON_PUBLISH=${MASON_PUBLISH:-false} + - export BENCH=${BENCH:-false} - if [[ ${TRAVIS_BRANCH} != 'master' ]]; then export MASON_PUBLISH=false; fi - if [[ ${TRAVIS_PULL_REQUEST} != 'false' ]]; then export MASON_PUBLISH=false; fi + - git_submodule_update --init --depth=10 install: - - if [[ $(uname -s) == 'Linux' ]]; then - export CXX="ccache clang++-3.5 -Qunused-arguments"; - export CC="ccache clang-3.5 -Qunused-arguments"; - export PYTHONPATH=$(pwd)/mason_packages/.link/lib/python2.7/site-packages; - else - brew rm postgis --force; - brew install postgis --force; - pg_ctl -w start -l postgres.log --pgdata /usr/local/var/postgres; - createuser -s postgres; - export PYTHONPATH=$(pwd)/mason_packages/.link/lib/python/site-packages; - fi - - psql -c 'create database template_postgis;' -U postgres; - - psql -c 'create extension postgis;' -d template_postgis -U postgres; - - if [[ ${COVERAGE} == true ]]; then - PYTHONUSERBASE=$(pwd)/mason_packages/.link pip install --user cpp-coveralls; - fi + - on 'linux' export PYTHONPATH=${PYTHONUSERBASE}/lib/python2.7/site-packages + - on 'osx' export PYTHONPATH=${PYTHONUSERBASE}/lib/python/site-packages + - on 'osx' export DATA_PATH=$(brew --prefix)/var/postgres + - on 'osx' rm -rf ${DATA_PATH} + - on 'osx' initdb ${DATA_PATH} -E utf8 + - on 'osx' pg_ctl -w start -l postgres.log --pgdata ${DATA_PATH}; + - on 'osx' cat postgres.log; + - on 'osx' createuser -s postgres + - psql -c 'create database template_postgis;' -U postgres + - psql -c 'create extension postgis;' -d template_postgis -U postgres + - enabled ${COVERAGE} pip install --user cpp-coveralls -script: +before_script: - source bootstrap.sh - - if [[ ${COVERAGE} == true ]]; then - ./configure CUSTOM_LDFLAGS='--coverage' CUSTOM_CXXFLAGS='--coverage' CUSTOM_CFLAGS='--coverage' DEBUG=True; - elif [[ ${MASON_PUBLISH} == true ]]; then - export MASON_NAME=mapnik; - export MASON_VERSION=latest; - export MASON_LIB_FILE=lib/libmapnik-wkt.a; - source ./.mason/mason.sh; - ./configure PREFIX=${MASON_PREFIX} PATH_REPLACE='' MAPNIK_BUNDLED_SHARE_DIRECTORY=True RUNTIME_LINK='static'; - else - ./configure; - fi - - make - - make test || TEST_RESULT=$? - - if [[ ${COVERAGE} == true ]]; then - ./mason_packages/.link/bin/cpp-coveralls --build-root . --gcov-options '\-lp' --exclude mason_packages --exclude .sconf_temp --exclude benchmark --exclude deps --exclude scons --exclude test --exclude demo --exclude docs --exclude fonts --exclude utils > /dev/null; - fi - - if [[ ${COVERAGE} != true ]]; then - make bench; - fi - - if [[ ${TEST_RESULT} != 0 ]]; then exit $TEST_RESULT ; fi; - - if [[ ${MASON_PUBLISH} == true ]]; then - ./mason_latest.sh build; - ./mason_latest.sh link; + - | + if [[ $(uname -s) == 'Linux' ]]; then + mason install clang++ 3.9.1 + export PATH=$(mason prefix clang++ 3.9.1)/bin:${PATH} + mason install llvm-cov 3.9.1 + export PATH=$(mason prefix llvm-cov 3.9.1)/bin:${PATH} + which llvm-cov + export LLVM_COV="$(mason prefix llvm-cov 3.9.1)/bin/llvm-cov" + fi + - ccache --version + - ccache -p || true + - ccache --show-stats || true + - commit_message_parse + +script: + - export SCONSFLAGS='--debug=time' + - configure BENCHMARK=${BENCH} + - cat config.log + # we limit the `make` to 40 min + # to ensure that slow builds still upload their + # ccache results and therefore should be faster + # (and might work) for the next build + - DURATION=2400 + - scripts/travis-command-wrapper.py -s "date" -i 120 --deadline=$(( $(date +%s) + ${DURATION} )) make + - RESULT=0 + - make test || RESULT=$? + # we allow visual failures with g++ for now: https://github.com/mapnik/mapnik/issues/3567 + - if [[ ${RESULT} != 0 ]] && [[ ${CXX} =~ 'clang++' ]]; then false; fi; + - enabled ${COVERAGE} coverage + - enabled ${BENCH} make bench + +after_success: + - enabled ${TRIGGER} trigger_downstream + - if enabled ${MASON_PUBLISH}; then + source ./.mason/mason.sh && + ./mason_latest.sh build && ./mason_latest.sh publish; fi diff -Nru mapnik-3.0.9+ds/utils/mapnik-config/build.py mapnik-3.0.13+ds/utils/mapnik-config/build.py --- mapnik-3.0.9+ds/utils/mapnik-config/build.py 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/mapnik-config/build.py 2017-02-08 13:06:42.000000000 +0000 @@ -63,7 +63,7 @@ CONFIG_MAPNIK_LIBPATH="%(mapnik_libpath)s" CONFIG_DEP_LIBS='%(dep_libs)s' CONFIG_MAPNIK_LDFLAGS="%(ldflags)s" -CONFIG_MAPNIK_INCLUDE="${CONFIG_PREFIX}/include -I${CONFIG_PREFIX}/include/mapnik/agg" +CONFIG_MAPNIK_INCLUDE="${CONFIG_PREFIX}/include -I${CONFIG_PREFIX}/include/mapnik/agg -I${CONFIG_PREFIX}/include/mapnik" CONFIG_DEP_INCLUDES="%(dep_includes)s" CONFIG_CXXFLAGS="%(cxxflags)s" CONFIG_CXX='%(cxx)s' @@ -80,7 +80,15 @@ os.chmod(config_file,0755) except: pass -cxxflags = ' '.join(config_env['LIBMAPNIK_CXXFLAGS']) + +cxxflags_raw = config_env['LIBMAPNIK_CXXFLAGS']; +# strip clang specific flags to avoid breaking gcc +# while it is not recommended to mix compilers, this nevertheless +# makes it easier to compile apps with gcc and mapnik-config against mapnik built with clang +to_remove = ['-Wno-unsequenced','-Wno-unknown-warning-option','-Wtautological-compare','-Wheader-hygiene'] +cxxflags_cleaned = [item for item in config_env['LIBMAPNIK_CXXFLAGS'] if item not in to_remove]; + +cxxflags = ' '.join(cxxflags_cleaned) defines = ' '.join(config_env['LIBMAPNIK_DEFINES']) @@ -131,11 +139,6 @@ mapnik_bundled_proj_data = '' mapnik_bundled_icu_data = '' -if config_env.get('MAPNIK_BUNDLED_SHARE_DIRECTORY'): - mapnik_bundled_gdal_data = 'lib/mapnik/share/gdal' - mapnik_bundled_proj_data = 'lib/mapnik/share/proj' - mapnik_bundled_icu_data = 'lib/mapnik/share/icu' - configuration = { "git_revision": git_revision, "git_describe": git_describe, @@ -156,7 +159,7 @@ "mapnik_bundled_icu_data":mapnik_bundled_icu_data, } -## if we are statically linking depedencies +## if we are statically linking dependencies ## then they do not need to be reported in ldflags #if env['RUNTIME_LINK'] == 'static': # configuration['ldflags'] = '' diff -Nru mapnik-3.0.9+ds/utils/mapnik-index/build.py mapnik-3.0.13+ds/utils/mapnik-index/build.py --- mapnik-3.0.9+ds/utils/mapnik-index/build.py 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/mapnik-index/build.py 2017-02-08 13:06:42.000000000 +0000 @@ -24,18 +24,19 @@ from copy import copy Import ('env') +Import ('plugin_base') -program_env = env.Clone() +program_env = plugin_base.Clone() source = Split( """ mapnik-index.cpp process_csv_file.cpp process_geojson_file.cpp + ../../plugins/input/csv/csv_utils.cpp """ ) -#headers = ['#plugins/input/shape'] + env['CPPPATH'] headers = env['CPPPATH'] boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND'] diff -Nru mapnik-3.0.9+ds/utils/mapnik-index/mapnik-index.cpp mapnik-3.0.13+ds/utils/mapnik-index/mapnik-index.cpp --- mapnik-3.0.9+ds/utils/mapnik-index/mapnik-index.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/mapnik-index/mapnik-index.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -163,7 +163,7 @@ std::clog << "max tree depth:" << depth << std::endl; std::clog << "split ratio:" << ratio << std::endl; - using box_type = mapnik::box2d; + using box_type = mapnik::box2d; using item_type = std::pair>; for (auto const& filename : files_to_process) @@ -175,22 +175,26 @@ } std::vector boxes; - mapnik::box2d extent; + box_type extent; if (mapnik::detail::is_csv(filename)) { std::clog << "processing '" << filename << "' as CSV\n"; auto result = mapnik::detail::process_csv_file(boxes, filename, manual_headers, separator, quote); - if (!result.first) continue; + if (!result.first) + { + std::clog << "Error: failed to process " << filename << std::endl; + return EXIT_FAILURE; + } extent = result.second; } else if (mapnik::detail::is_geojson(filename)) { std::clog << "processing '" << filename << "' as GeoJSON\n"; - auto result = mapnik::detail::process_geojson_file(boxes, filename, validate_features); + auto result = mapnik::detail::process_geojson_file(boxes, filename, validate_features, verbose); if (!result.first) { std::clog << "Error: failed to process " << filename << std::endl; - continue; + return EXIT_FAILURE; } extent = result.second; } @@ -198,10 +202,12 @@ if (extent.valid()) { std::clog << extent << std::endl; - mapnik::quad_tree> tree(extent, depth, ratio); + mapnik::box2d extent_d(extent.minx(), extent.miny(), extent.maxx(), extent.maxy()); + mapnik::quad_tree> tree(extent_d, depth, ratio); for (auto const& item : boxes) { - tree.insert(std::get<1>(item), std::get<0>(item)); + auto ext_f = std::get<0>(item); + tree.insert(std::get<1>(item), mapnik::box2d(ext_f.minx(), ext_f.miny(), ext_f.maxx(), ext_f.maxy())); } std::fstream file((filename + ".index").c_str(), @@ -222,6 +228,11 @@ file.close(); } } + else + { + std::clog << "Invalid extent " << extent << std::endl; + return EXIT_FAILURE; + } } std::clog << "done!" << std::endl; return EXIT_SUCCESS; diff -Nru mapnik-3.0.9+ds/utils/mapnik-index/process_csv_file.cpp mapnik-3.0.13+ds/utils/mapnik-index/process_csv_file.cpp --- mapnik-3.0.9+ds/utils/mapnik-index/process_csv_file.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/mapnik-index/process_csv_file.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -21,13 +21,16 @@ *****************************************************************************/ #include "process_csv_file.hpp" +#include "../../plugins/input/csv/csv_getline.hpp" #include "../../plugins/input/csv/csv_utils.hpp" +#include #include #include #if defined(MAPNIK_MEMORY_MAPPED_FILE) #pragma GCC diagnostic push #include +#include #include #include #pragma GCC diagnostic pop @@ -35,13 +38,20 @@ #endif #include +#include +#include namespace mapnik { namespace detail { template -std::pair> process_csv_file(T & boxes, std::string const& filename, std::string const& manual_headers, char separator, char quote) +std::pair process_csv_file(T & boxes, std::string const& filename, std::string const& manual_headers, char separator, char quote) { - mapnik::box2d extent; + using box_type = typename T::value_type::first_type; + csv_utils::csv_file_parser p; + p.manual_headers_ = manual_headers; + p.separator_ = separator; + p.quote_ = quote; + #if defined(MAPNIK_MEMORY_MAPPED_FILE) using file_source_type = boost::interprocess::ibufferstream; file_source_type csv_file; @@ -56,7 +66,7 @@ else { std::clog << "Error : cannot mmap " << filename << std::endl; - return std::make_pair(false, extent); + return std::make_pair(false, box_type(p.extent_)); } #else #if defined(_WINDOWS) @@ -67,173 +77,24 @@ if (!csv_file.is_open()) { std::clog << "Error : cannot open " << filename << std::endl; - return std::make_pair(false, extent); + return std::make_pair(false, box_type(p.extent_)); } #endif - auto file_length = ::detail::file_length(csv_file); - // set back to start - csv_file.seekg(0, std::ios::beg); - char newline; - bool has_newline; - char detected_quote; - std::tie(newline, has_newline, detected_quote) = ::detail::autodect_newline_and_quote(csv_file, file_length); - if (quote == 0) quote = detected_quote; - // set back to start - csv_file.seekg(0, std::ios::beg); - // get first line - std::string csv_line; - csv_utils::getline_csv(csv_file, csv_line, newline, quote); - if (separator == 0) separator = ::detail::detect_separator(csv_line); - csv_file.seekg(0, std::ios::beg); - int line_number = 0; - ::detail::geometry_column_locator locator; - std::vector headers; - std::clog << "Parsing CSV using SEPARATOR=" << separator << " QUOTE=" << quote << std::endl; - if (!manual_headers.empty()) - { - std::size_t index = 0; - headers = csv_utils::parse_line(manual_headers, separator, quote); - for (auto const& header : headers) - { - ::detail::locate_geometry_column(header, index++, locator); - headers.push_back(header); - } - } - else // parse first line as headers - { - while (csv_utils::getline_csv(csv_file,csv_line,newline, quote)) - { - try - { - headers = csv_utils::parse_line(csv_line, separator, quote); - // skip blank lines - if (headers.size() > 0 && headers[0].empty()) ++line_number; - else - { - std::size_t index = 0; - for (auto & header : headers) - { - mapnik::util::trim(header); - if (header.empty()) - { - // create a placeholder for the empty header - std::ostringstream s; - s << "_" << index; - header = s.str(); - } - else - { - ::detail::locate_geometry_column(header, index, locator); - } - ++index; - } - ++line_number; - break; - } - } - catch (std::exception const& ex) - { - std::string s("CSV index: error parsing headers: "); - s += ex.what(); - std::clog << s << std::endl; - return std::make_pair(false, extent); - } - } - } - - std::size_t num_headers = headers.size(); - if (!::detail::valid(locator, num_headers)) - { - std::clog << "CSV index: could not detect column(s) with the name(s) of wkt, geojson, x/y, or " - << "latitude/longitude in:\n" - << csv_line - << "\n - this is required for reading geometry data" - << std::endl; - return std::make_pair(false, extent); - } - - auto pos = csv_file.tellg(); - - // handle rare case of a single line of data and user-provided headers - // where a lack of a newline will mean that csv_utils::getline_csv returns false - bool is_first_row = false; - if (!has_newline) + try { - csv_file.setstate(std::ios::failbit); - pos = 0; - if (!csv_line.empty()) - { - is_first_row = true; - } + p.parse_csv_and_boxes(csv_file, boxes); + return std::make_pair(true, box_type(p.extent_)); } - while (is_first_row || csv_utils::getline_csv(csv_file, csv_line, newline, quote)) + catch (std::exception const& ex) { - ++line_number; - auto record_offset = pos; - auto record_size = csv_line.length(); - pos = csv_file.tellg(); - is_first_row = false; - // skip blank lines - if (record_size <= 10) - { - std::string trimmed = csv_line; - boost::trim_if(trimmed, boost::algorithm::is_any_of("\",'\r\n ")); - if (trimmed.empty()) - { - std::clog << "CSV index: empty row encountered at line: " << line_number << std::endl; - continue; - } - } - try - { - auto values = csv_utils::parse_line(csv_line, separator, quote); - unsigned num_fields = values.size(); - if (num_fields > num_headers || num_fields < num_headers) - { - // skip this row - std::ostringstream s; - s << "CSV Index: # of columns(" - << num_fields << ") > # of headers(" - << num_headers << ") parsed for row " << line_number; - throw mapnik::datasource_exception(s.str()); - } - - auto geom = ::detail::extract_geometry(values, locator); - if (!geom.is()) - { - auto box = mapnik::geometry::envelope(geom); - if (!extent.valid()) extent = box; - else extent.expand_to_include(box); - boxes.emplace_back(std::move(box), make_pair(record_offset, record_size)); - } - else - { - std::ostringstream s; - s << "CSV Index: expected geometry column: could not parse row " - << line_number << " " - << values[locator.index] << "'"; - throw mapnik::datasource_exception(s.str()); - } - } - catch (mapnik::datasource_exception const& ex ) - { - std::clog << ex.what() << " at line: " << line_number << std::endl; - } - catch (std::exception const& ex) - { - std::ostringstream s; - s << "CSV Index: unexpected error parsing line: " << line_number - << " - found " << headers.size() << " with values like: " << csv_line << "\n" - << " and got error like: " << ex.what(); - std::clog << s.str() << std::endl; - } + std::clog << ex.what() << std::endl; + return std::make_pair(false, box_type(p.extent_)); } - return std::make_pair(true, extent);; } -using box_type = mapnik::box2d; +using box_type = mapnik::box2d; using item_type = std::pair>; using boxes_type = std::vector; -template std::pair> process_csv_file(boxes_type&, std::string const&, std::string const&, char, char); +template std::pair process_csv_file(boxes_type&, std::string const&, std::string const&, char, char); }} diff -Nru mapnik-3.0.9+ds/utils/mapnik-index/process_csv_file.hpp mapnik-3.0.13+ds/utils/mapnik-index/process_csv_file.hpp --- mapnik-3.0.9+ds/utils/mapnik-index/process_csv_file.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/mapnik-index/process_csv_file.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,7 +29,7 @@ namespace mapnik { namespace detail { template -std::pair> process_csv_file(T & boxes, std::string const& filename, std::string const& manual_headers, char separator, char quote); +std::pair process_csv_file(T & boxes, std::string const& filename, std::string const& manual_headers, char separator, char quote); }} diff -Nru mapnik-3.0.9+ds/utils/mapnik-index/process_geojson_file.cpp mapnik-3.0.13+ds/utils/mapnik-index/process_geojson_file.cpp --- mapnik-3.0.9+ds/utils/mapnik-index/process_geojson_file.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/mapnik-index/process_geojson_file.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -21,11 +21,6 @@ *****************************************************************************/ #include "process_geojson_file.hpp" -#include -#include -#include -#include -#include #if defined(MAPNIK_MEMORY_MAPPED_FILE) #pragma GCC diagnostic push @@ -35,40 +30,46 @@ #include #pragma GCC diagnostic pop #include +#else +#include #endif -#include #include #include namespace { + +template struct feature_validate_callback { - feature_validate_callback(mapnik::box2d const& box) + feature_validate_callback(mapnik::box2d const& box) : box_(box) {} void operator() (mapnik::feature_ptr const& f) const { - if (box_ != f->envelope()) + if (box_ != box_) { throw std::runtime_error("Bounding boxes mismatch validation feature"); } } - mapnik::box2d const& box_; + mapnik::box2d const& box_; }; +using box_type = mapnik::box2d; +using boxes_type = std::vector>>; using base_iterator_type = char const*; -const mapnik::json::extract_bounding_box_grammar geojson_datasource_static_bbox_grammar; +const mapnik::json::extract_bounding_box_grammar geojson_datasource_static_bbox_grammar; const mapnik::transcoder tr("utf8"); -const mapnik::json::feature_grammar_callback fc_grammar(tr); +const mapnik::json::feature_grammar_callback> fc_grammar(tr); } namespace mapnik { namespace detail { template -std::pair> process_geojson_file(T & boxes, std::string const& filename, bool validate_features) +std::pair process_geojson_file(T & boxes, std::string const& filename, bool validate_features, bool verbose) { - mapnik::box2d extent; + using box_type = typename T::value_type::first_type; + box_type extent; #if defined(MAPNIK_MEMORY_MAPPED_FILE) mapnik::mapped_region_ptr mapped_region; boost::optional memory = @@ -86,7 +87,7 @@ char const* end = start + mapped_region->get_size(); #else mapnik::util::file file(filename); - if (!file.open()) + if (!file) { std::clog << "Error : cannot open " << filename << std::endl; return std::make_pair(false, extent); @@ -125,23 +126,26 @@ { base_iterator_type feat_itr = start + item.second.first; base_iterator_type feat_end = feat_itr + item.second.second; - feature_validate_callback callback(item.first); + feature_validate_callback callback(item.first); bool result = boost::spirit::qi::phrase_parse(feat_itr, feat_end, (fc_grammar) (boost::phoenix::ref(ctx), boost::phoenix::ref(start_id), boost::phoenix::ref(callback)), space); if (!result || feat_itr != feat_end) { + if (verbose) std::clog << std::string(start + item.second.first, feat_end ) << std::endl; return std::make_pair(false, extent); } } } + else if (validate_features) + { + if (verbose) std::clog << "Invalid bbox encountered " << item.first << std::endl; + return std::make_pair(false, extent); + } } return std::make_pair(true, extent); } -using box_type = mapnik::box2d; -using item_type = std::pair>; -using boxes_type = std::vector; -template std::pair> process_geojson_file(boxes_type&, std::string const&, bool); +template std::pair process_geojson_file(boxes_type&, std::string const&, bool, bool); }} diff -Nru mapnik-3.0.9+ds/utils/mapnik-index/process_geojson_file.hpp mapnik-3.0.13+ds/utils/mapnik-index/process_geojson_file.hpp --- mapnik-3.0.9+ds/utils/mapnik-index/process_geojson_file.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/mapnik-index/process_geojson_file.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -29,7 +29,7 @@ namespace mapnik { namespace detail { template -std::pair> process_geojson_file(T & boxes, std::string const& filename, bool validate_features); +std::pair process_geojson_file(T & boxes, std::string const& filename, bool validate_features, bool verbose); }} diff -Nru mapnik-3.0.9+ds/utils/mapnik-render/mapnik-render.cpp mapnik-3.0.13+ds/utils/mapnik-render/mapnik-render.cpp --- mapnik-3.0.9+ds/utils/mapnik-render/mapnik-render.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/mapnik-render/mapnik-render.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -21,7 +21,7 @@ namespace po = boost::program_options; bool verbose = false; - bool auto_open = true; + bool auto_open = false; int return_value = 0; std::string xml_file; std::string img_file; @@ -32,12 +32,12 @@ try { - po::options_description desc("nik2img utility"); + po::options_description desc("mapnik-render utility"); desc.add_options() ("help,h", "produce usage message") ("version,V","print version string") ("verbose,v","verbose output") - ("open","automatically open the file after rendering (os x only)") + ("open","automatically open the file after rendering") ("xml",po::value(),"xml map to read") ("img",po::value(),"image to render") ("scale-factor",po::value(),"scale factor for rendering") diff -Nru mapnik-3.0.9+ds/utils/pgsql2sqlite/main.cpp mapnik-3.0.13+ds/utils/pgsql2sqlite/main.cpp --- mapnik-3.0.9+ds/utils/pgsql2sqlite/main.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/pgsql2sqlite/main.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,10 +26,13 @@ #include #include "connection_manager.hpp" -// boost +#pragma GCC diagnostic push +#include #include -#include #include +#pragma GCC diagnostic pop + +#include //stl #include diff -Nru mapnik-3.0.9+ds/utils/pgsql2sqlite/pgsql2sqlite.hpp mapnik-3.0.13+ds/utils/pgsql2sqlite/pgsql2sqlite.hpp --- mapnik-3.0.9+ds/utils/pgsql2sqlite/pgsql2sqlite.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/pgsql2sqlite/pgsql2sqlite.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -352,23 +352,23 @@ break; } case 23: - output_rec.push_back(sqlite::value_type(int4net(buf))); + output_rec.emplace_back(int4net(buf)); break; case 21: - output_rec.push_back(sqlite::value_type(int2net(buf))); + output_rec.emplace_back(int(int2net(buf))); break; case 700: { float val; float4net(val,buf); - output_rec.push_back(sqlite::value_type(val)); + output_rec.emplace_back(double(val)); break; } case 701: { double val; float8net(val,buf); - output_rec.push_back(sqlite::value_type(val)); + output_rec.emplace_back(val); break; } case 1700: @@ -377,7 +377,7 @@ double val; if (mapnik::util::string2double(str,val)) { - output_rec.push_back(sqlite::value_type(val)); + output_rec.emplace_back(val); } break; } diff -Nru mapnik-3.0.9+ds/utils/pgsql2sqlite/sqlite.hpp mapnik-3.0.13+ds/utils/pgsql2sqlite/sqlite.hpp --- mapnik-3.0.9+ds/utils/pgsql2sqlite/sqlite.hpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/pgsql2sqlite/sqlite.hpp 2017-02-08 13:06:42.000000000 +0000 @@ -24,8 +24,11 @@ #include // boost #include -//sqlite3 + +#pragma GCC diagnostic push +#include #include +#pragma GCC diagnostic pop //stl #ifdef MAPNIK_DEBUG diff -Nru mapnik-3.0.9+ds/utils/shapeindex/build.py mapnik-3.0.13+ds/utils/shapeindex/build.py --- mapnik-3.0.9+ds/utils/shapeindex/build.py 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/shapeindex/build.py 2017-02-08 13:06:42.000000000 +0000 @@ -25,7 +25,9 @@ Import ('env') -program_env = env.Clone() +Import ('plugin_base') + +program_env = plugin_base.Clone() source = Split( """ diff -Nru mapnik-3.0.9+ds/utils/shapeindex/shapeindex.cpp mapnik-3.0.13+ds/utils/shapeindex/shapeindex.cpp --- mapnik-3.0.9+ds/utils/shapeindex/shapeindex.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/shapeindex/shapeindex.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -26,9 +26,10 @@ #include #include #include +#include #include "shapefile.hpp" #include "shape_io.hpp" - +#include "shape_index_featureset.hpp" #pragma GCC diagnostic push #include #include @@ -44,8 +45,9 @@ namespace po = boost::program_options; bool verbose=false; - unsigned int depth=DEFAULT_DEPTH; - double ratio=DEFAULT_RATIO; + bool index_parts = false; + unsigned int depth = DEFAULT_DEPTH; + double ratio = DEFAULT_RATIO; std::vector shape_files; try @@ -54,6 +56,7 @@ desc.add_options() ("help,h", "produce usage message") ("version,V","print version string") + ("index-parts","index individual shape parts (default: no)") ("verbose,v","verbose output") ("depth,d", po::value(), "max tree depth\n(default 8)") ("ratio,r",po::value(),"split ratio (default 0.55)") @@ -69,18 +72,22 @@ if (vm.count("version")) { std::clog << "version 0.3.0" <(); @@ -98,7 +105,7 @@ catch (std::exception const& ex) { std::clog << "Error: " << ex.what() << std::endl; - return -1; + return EXIT_FAILURE; } std::clog << "max tree depth:" << depth << std::endl; @@ -107,7 +114,7 @@ if (shape_files.size() == 0) { std::clog << "no shape files to index" << std::endl; - return 0; + return EXIT_FAILURE; } for (auto const& filename : shape_files) { @@ -157,54 +164,103 @@ std::clog << "type=" << shape_type << std::endl; std::clog << "extent:" << extent << std::endl; + if (!extent.valid() || std::isnan(extent.width()) || std::isnan(extent.height())) + { + std::clog << "Invalid extent aborting..." << std::endl; + return EXIT_FAILURE; + } int pos = 50; shx.seek(pos * 2); - mapnik::quad_tree tree(extent, depth, ratio); + mapnik::quad_tree tree(extent, depth, ratio); int count = 0; - while (shx.is_good() && pos <= file_length - 4) + if (shape_type != shape_io::shape_null) { - int offset = shx.read_xdr_integer(); - int content_length = shx.read_xdr_integer(); - pos += 4; - box2d item_ext; - shp.seek(offset * 2); - int record_number = shp.read_xdr_integer(); - if (content_length != shp.read_xdr_integer()) - { - std::clog << "Content length mismatch for record number " << record_number << std::endl; - continue; - } - shape_type = shp.read_ndr_integer(); - - if (shape_type==shape_io::shape_point - || shape_type==shape_io::shape_pointm - || shape_type == shape_io::shape_pointz) - { - double x=shp.read_double(); - double y=shp.read_double(); - item_ext=box2d(x,y,x,y); - } - else - { - shp.read_envelope(item_ext); - } - if (verbose) - { - std::clog << "record number " << record_number << " box=" << item_ext << std::endl; - } - if (item_ext.valid()) + while (shx.is_good() && pos <= file_length - 4) { - tree.insert(offset * 2,item_ext); - ++count; + int offset = shx.read_xdr_integer(); + int shx_content_length = shx.read_xdr_integer(); + pos += 4; + box2d item_ext; + shp.seek(offset * 2); + int record_number = shp.read_xdr_integer(); + int shp_content_length = shp.read_xdr_integer(); + if (shx_content_length != shp_content_length) + { + std::clog << "Content length mismatch for record number " << record_number << std::endl; + continue; + } + shape_type = shp.read_ndr_integer(); + + if (shape_type == shape_io::shape_null) continue; + + if (shape_type==shape_io::shape_point + || shape_type==shape_io::shape_pointm + || shape_type == shape_io::shape_pointz) + { + double x=shp.read_double(); + double y=shp.read_double(); + item_ext=box2d(x,y,x,y); + } + else if (index_parts && + (shape_type == shape_io::shape_polygon || shape_type == shape_io::shape_polygonm || shape_type == shape_io::shape_polygonz + || shape_type == shape_io::shape_polyline || shape_type == shape_io::shape_polylinem || shape_type == shape_io::shape_polylinez)) + { + shp.read_envelope(item_ext); + int num_parts = shp.read_ndr_integer(); + int num_points = shp.read_ndr_integer(); + std::vector parts; + parts.resize(num_parts); + std::for_each(parts.begin(), parts.end(), [&](int & part) { part = shp.read_ndr_integer();}); + for (int k = 0; k < num_parts; ++k) + { + int start = parts[k]; + int end; + if (k == num_parts - 1) end = num_points; + else end = parts[k + 1]; + + mapnik::geometry::linear_ring ring; + ring.reserve(end - start); + for (int j = start; j < end; ++j) + { + double x = shp.read_double(); + double y = shp.read_double(); + ring.emplace_back(x, y); + } + item_ext = mapnik::geometry::envelope(ring); + if (item_ext.valid()) + { + if (verbose) + { + std::clog << "record number " << record_number << " box=" << item_ext << std::endl; + } + tree.insert(mapnik::detail::node(offset * 2, start, end),item_ext); + ++count; + } + } + item_ext = mapnik::box2d(); //invalid + } + else + { + shp.read_envelope(item_ext); + } + + if (item_ext.valid()) + { + if (verbose) + { + std::clog << "record number " << record_number << " box=" << item_ext << std::endl; + } + tree.insert(mapnik::detail::node(offset * 2,-1,0),item_ext); + ++count; + } } } if (count > 0) { std::clog << " number shapes=" << count << std::endl; - std::fstream file((shapename+".index").c_str(), - std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary); + std::ofstream file((shapename+".index").c_str(), std::ios::trunc | std::ios::binary); if (!file) { std::clog << "cannot open index file for writing file \"" @@ -227,5 +283,5 @@ } std::clog << "done!" << std::endl; - return 0; + return EXIT_SUCCESS; } diff -Nru mapnik-3.0.9+ds/utils/svg2png/svg2png.cpp mapnik-3.0.13+ds/utils/svg2png/svg2png.cpp --- mapnik-3.0.9+ds/utils/svg2png/svg2png.cpp 2015-11-26 10:13:12.000000000 +0000 +++ mapnik-3.0.13+ds/utils/svg2png/svg2png.cpp 2017-02-08 13:06:42.000000000 +0000 @@ -40,12 +40,16 @@ #include #pragma GCC diagnostic pop +#pragma GCC diagnostic push +#include #include "agg_rasterizer_scanline_aa.h" #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_renderer_base.h" #include "agg_pixfmt_rgba.h" #include "agg_scanline_u.h" +#pragma GCC diagnostic pop + struct main_marker_visitor { @@ -56,7 +60,7 @@ verbose_(verbose), auto_open_(auto_open) {} - int operator() (mapnik::marker_svg const& marker) + int operator() (mapnik::marker_svg const& marker) const { using pixfmt = agg::pixfmt_rgba32_pre; using renderer_base = agg::renderer_base; @@ -67,6 +71,11 @@ double opacity = 1; int w = marker.width(); int h = marker.height(); + if (w == 0 || h == 0) + { + // fallback to svg width/height or viewBox + std::tie(w, h) = marker.dimensions(); + } if (verbose_) { std::clog << "found width of '" << w << "' and height of '" << h << "'\n"; @@ -117,14 +126,14 @@ // default template - int operator() (T const&) + int operator() (T const&) const { std::clog << "svg2png error: '" << svg_name_ << "' is not a valid vector!\n"; return -1; } private: - std::string const& svg_name_; + std::string svg_name_; bool verbose_; bool auto_open_; };