- added some comments to clear that using rowid as default key_field for sqlite is *EXTREMELY* dangerous (aka no primary key, unexpected results may appear)

- more cosmetics in sqlite plugin
- refactor unquote function to be lighter and simpler
This commit is contained in:
kunitoki 2011-10-18 23:32:25 +02:00
parent 8b9d05db0a
commit 5d72d50f74
4 changed files with 216 additions and 232 deletions

View file

@ -67,9 +67,7 @@ sqlite_datasource::sqlite_datasource(parameters const& params, bool bind)
metadata_(*params_.get<std::string>("metadata","")),
geometry_table_(*params_.get<std::string>("geometry_table","")),
geometry_field_(*params_.get<std::string>("geometry_field","")),
// index_table_ defaults to "idx_{geometry_table_}_{geometry_field_}"
index_table_(*params_.get<std::string>("index_table","")),
// http://www.sqlite.org/lang_createtable.html#rowid
key_field_(*params_.get<std::string>("key_field","")),
row_offset_(*params_.get<int>("row_offset",0)),
row_limit_(*params_.get<int>("row_limit",0)),
@ -94,65 +92,6 @@ sqlite_datasource::sqlite_datasource(parameters const& params, bool bind)
}
}
void sqlite_datasource::parse_attachdb(std::string const& attachdb) const
{
boost::char_separator<char> sep(",");
boost::tokenizer<boost::char_separator<char> > tok(attachdb, sep);
// The attachdb line is a comma sparated list of [dbname@]filename
for (boost::tokenizer<boost::char_separator<char> >::iterator beg = tok.begin();
beg != tok.end(); ++beg)
{
std::string const& spec(*beg);
size_t atpos = spec.find('@');
// See if it contains an @ sign
if (atpos == spec.npos)
{
throw datasource_exception("attachdb parameter has syntax dbname@filename[,...]");
}
// Break out the dbname and the filename
std::string dbname = boost::trim_copy(spec.substr(0, atpos));
std::string filename = boost::trim_copy(spec.substr(atpos+1));
// Normalize the filename and make it relative to dataset_name_
if (filename.compare(":memory:") != 0)
{
boost::filesystem::path child_path(filename);
// It is a relative path. Fix it.
if (! child_path.has_root_directory() && ! child_path.has_root_name())
{
boost::filesystem::path absolute_path(dataset_name_);
// support symlinks
#if (BOOST_FILESYSTEM_VERSION == 3)
if (boost::filesystem::is_symlink(absolute_path))
{
absolute_path = boost::filesystem::read_symlink(absolute_path);
}
filename = boost::filesystem::absolute(absolute_path.parent_path() / filename).string();
#else
if (boost::filesystem::is_symlink(absolute_path))
{
//cannot figure out how to resolve on in v2 so just print a warning
std::clog << "###Warning: '" << absolute_path.string() << "' is a symlink which is not supported in attachdb\n";
}
filename = boost::filesystem::complete(absolute_path.branch_path() / filename).normalize().string();
#endif
}
}
// And add an init_statement_
init_statements_.push_back("attach database '" + filename + "' as " + dbname);
}
}
void sqlite_datasource::bind() const
{
if (is_bound_) return;
@ -160,6 +99,10 @@ void sqlite_datasource::bind() const
boost::optional<std::string> file = params_.get<std::string>("file");
if (! file) throw datasource_exception("Sqlite Plugin: missing <file> parameter");
// Be careful, automatically using rowid as key field of the table can lead
// to misleading results http://www.gaia-gis.it/spatialite-2.4.0-5/SpatialIndex-Update.pdf
// TODO - We should try to avoid this and eventually force to specify a valid table primary key
boost::optional<std::string> key_field_name = params_.get<std::string>("key_field");
if (key_field_name)
{
@ -231,9 +174,9 @@ void sqlite_datasource::bind() const
for (std::vector<std::string>::const_iterator iter = init_statements_.begin();
iter!=init_statements_.end(); ++iter)
{
#ifdef MAPNIK_DEBUG
#ifdef MAPNIK_DEBUG
std::clog << "Sqlite Plugin: Execute init sql: " << *iter << std::endl;
#endif
#endif
dataset_->execute(*iter);
}
@ -297,9 +240,9 @@ void sqlite_datasource::bind() const
break;
default:
#ifdef MAPNIK_DEBUG
#ifdef MAPNIK_DEBUG
std::clog << "Sqlite Plugin: unknown type_oid=" << type_oid << std::endl;
#endif
#endif
break;
}
}
@ -365,7 +308,7 @@ void sqlite_datasource::bind() const
desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::String));
}
}
#ifdef MAPNIK_DEBUG
#ifdef MAPNIK_DEBUG
else
{
// "Column Affinity" says default to "Numeric" but for now we pass..
@ -378,7 +321,7 @@ void sqlite_datasource::bind() const
<< "' unhandled due to unknown type: "
<< fld_type << std::endl;
}
#endif
#endif
}
if (! found_table)
@ -414,23 +357,25 @@ void sqlite_datasource::bind() const
std::ostringstream s;
s << "SELECT pkid,xmin,xmax,ymin,ymax FROM " << index_table_;
s << " LIMIT 0";
if (dataset_->execute_with_code(s.str()) == SQLITE_OK)
{
has_spatial_index_ = true;
}
#ifdef MAPNIK_DEBUG
#ifdef MAPNIK_DEBUG
else
{
std::clog << "SQLite Plugin: rtree index lookup did not succeed: '" << sqlite3_errmsg(*(*dataset_)) << "'\n";
}
#endif
#endif
}
if (metadata_ != "" && ! extent_initialized_)
if (! metadata_.empty() && ! extent_initialized_)
{
std::ostringstream s;
s << "SELECT xmin, ymin, xmax, ymax FROM " << metadata_;
s << " WHERE LOWER(f_table_name) = LOWER('" << geometry_table_ << "')";
boost::scoped_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str()));
if (rs->is_valid() && rs->step_next())
{
@ -449,10 +394,11 @@ void sqlite_datasource::bind() const
std::ostringstream s;
s << "SELECT MIN(xmin), MIN(ymin), MAX(xmax), MAX(ymax) FROM "
<< index_table_;
boost::scoped_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str()));
if (rs->is_valid() && rs->step_next())
{
if (!rs->column_isnull(0))
if (! rs->column_isnull(0))
{
try
{
@ -473,11 +419,8 @@ void sqlite_datasource::bind() const
}
#ifdef MAPNIK_DEBUG
if (! has_spatial_index_
&& use_spatial_index_
&& using_subquery_
&& key_field_ == "rowid"
&& ! boost::algorithm::icontains(table_,"rowid"))
if (! has_spatial_index_ && use_spatial_index_ && using_subquery_
&& key_field_ == "rowid" && ! boost::algorithm::icontains(table_, "rowid"))
{
// this is an impossible situation because rowid will be null via a subquery
std::clog << "Sqlite Plugin: WARNING: spatial index usage will fail because rowid "
@ -493,7 +436,6 @@ void sqlite_datasource::bind() const
if (! extent_initialized_ || ! has_spatial_index_)
{
std::ostringstream s;
s << "SELECT " << geometry_field_ << "," << key_field_
<< " FROM " << geometry_table_;
@ -514,22 +456,31 @@ void sqlite_datasource::bind() const
boost::shared_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str()));
// spatial index sql
std::string spatial_index_sql = "create virtual table " + index_table_
+ " using rtree(pkid, xmin, xmax, ymin, ymax)";
std::string spatial_index_insert_sql = "insert into " + index_table_
+ " values (?,?,?,?,?)" ;
sqlite3_stmt* stmt = 0;
std::ostringstream spatial_index_sql;
spatial_index_sql << "create virtual table " << index_table_
<< " using rtree(pkid, xmin, xmax, ymin, ymax)";
std::ostringstream spatial_index_insert_sql;
spatial_index_insert_sql << "insert into " << index_table_
<< " values (?,?,?,?,?)";
sqlite3_stmt* stmt = 0;
if (use_spatial_index_)
{
dataset_->execute(spatial_index_sql);
int rc = sqlite3_prepare_v2 (*(*dataset_), spatial_index_insert_sql.c_str(), -1, &stmt, 0);
dataset_->execute(spatial_index_sql.str());
const int rc = sqlite3_prepare_v2 (*(*dataset_),
spatial_index_insert_sql.str().c_str(),
-1,
&stmt,
0);
if (rc != SQLITE_OK)
{
std::ostringstream index_error;
index_error << "Sqlite Plugin: auto-index table creation failed: '"
<< sqlite3_errmsg(*(*dataset_)) << "' query was: "
<< spatial_index_insert_sql;
throw datasource_exception(index_error.str());
}
}
@ -547,6 +498,7 @@ void sqlite_datasource::bind() const
mapnik::feature_ptr feature(mapnik::feature_factory::create(0));
mapnik::geometry_utils::from_wkb(feature->paths(), data, size, multiple_geometries_, format_);
mapnik::box2d<double> const& bbox = feature->envelope();
if (bbox.valid())
{
extent_initialized_ = true;
@ -570,19 +522,20 @@ void sqlite_datasource::bind() const
type_error << "Sqlite Plugin: invalid type for key field '"
<< key_field_ << "' when creating index '" << index_table_
<< "' type was: " << type_oid << "";
throw datasource_exception(type_error.str());
}
sqlite_int64 pkid = rs->column_integer64(1);
if (sqlite3_bind_int64(stmt, 1 , pkid ) != SQLITE_OK)
const sqlite_int64 pkid = rs->column_integer64(1);
if (sqlite3_bind_int64(stmt, 1, pkid) != SQLITE_OK)
{
throw datasource_exception("invalid value for for key field while generating index");
}
if ((sqlite3_bind_double(stmt, 2 , bbox.minx() ) != SQLITE_OK) ||
(sqlite3_bind_double(stmt, 3 , bbox.maxx() ) != SQLITE_OK) ||
(sqlite3_bind_double(stmt, 4 , bbox.miny() ) != SQLITE_OK) ||
(sqlite3_bind_double(stmt, 5 , bbox.maxy() ) != SQLITE_OK))
if ((sqlite3_bind_double(stmt, 2, bbox.minx()) != SQLITE_OK) ||
(sqlite3_bind_double(stmt, 3, bbox.maxx()) != SQLITE_OK) ||
(sqlite3_bind_double(stmt, 4, bbox.miny()) != SQLITE_OK) ||
(sqlite3_bind_double(stmt, 5, bbox.maxy()) != SQLITE_OK))
{
throw datasource_exception("invalid value for for extent while generating index");
}
@ -613,20 +566,21 @@ void sqlite_datasource::bind() const
}
}
int res = sqlite3_finalize(stmt);
const int res = sqlite3_finalize(stmt);
if (res != SQLITE_OK)
{
throw datasource_exception("auto-indexing failed: set use_spatial_index=false to disable auto-indexing and avoid this error");
}
}
if (!extent_initialized_)
if (! extent_initialized_)
{
std::ostringstream s;
s << "Sqlite Plugin: extent could not be determined for table '"
<< geometry_table_ << "' and geometry field '" << geometry_field_ << "'"
<< " because an rtree spatial index is missing or empty."
<< " - either set the table 'extent' or create an rtree spatial index";
throw datasource_exception(s.str());
}
@ -641,6 +595,65 @@ sqlite_datasource::~sqlite_datasource()
}
}
void sqlite_datasource::parse_attachdb(std::string const& attachdb) const
{
boost::char_separator<char> sep(",");
boost::tokenizer<boost::char_separator<char> > tok(attachdb, sep);
// The attachdb line is a comma sparated list of [dbname@]filename
for (boost::tokenizer<boost::char_separator<char> >::iterator beg = tok.begin();
beg != tok.end(); ++beg)
{
std::string const& spec(*beg);
size_t atpos = spec.find('@');
// See if it contains an @ sign
if (atpos == spec.npos)
{
throw datasource_exception("attachdb parameter has syntax dbname@filename[,...]");
}
// Break out the dbname and the filename
std::string dbname = boost::trim_copy(spec.substr(0, atpos));
std::string filename = boost::trim_copy(spec.substr(atpos + 1));
// Normalize the filename and make it relative to dataset_name_
if (filename.compare(":memory:") != 0)
{
boost::filesystem::path child_path(filename);
// It is a relative path. Fix it.
if (! child_path.has_root_directory() && ! child_path.has_root_name())
{
boost::filesystem::path absolute_path(dataset_name_);
// support symlinks
#if (BOOST_FILESYSTEM_VERSION == 3)
if (boost::filesystem::is_symlink(absolute_path))
{
absolute_path = boost::filesystem::read_symlink(absolute_path);
}
filename = boost::filesystem::absolute(absolute_path.parent_path() / filename).string();
#else
if (boost::filesystem::is_symlink(absolute_path))
{
//cannot figure out how to resolve on in v2 so just print a warning
std::clog << "###Warning: '" << absolute_path.string() << "' is a symlink which is not supported in attachdb\n";
}
filename = boost::filesystem::complete(absolute_path.branch_path() / filename).normalize().string();
#endif
}
}
// And add an init_statement_
init_statements_.push_back("attach database '" + filename + "' as " + dbname);
}
}
std::string sqlite_datasource::name()
{
return "sqlite";
@ -725,10 +738,10 @@ featureset_ptr sqlite_datasource::features(query const& q) const
s << " OFFSET " << row_offset_;
}
#ifdef MAPNIK_DEBUG
std::clog << "Sqlite Plugin: table_: " << table_ << "\n\n";
#ifdef MAPNIK_DEBUG
std::clog << "Sqlite Plugin: table: " << table_ << "\n\n";
std::clog << "Sqlite Plugin: query:" << s.str() << "\n\n";
#endif
#endif
boost::shared_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str()));
@ -799,9 +812,9 @@ featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const
s << " OFFSET " << row_offset_;
}
#ifdef MAPNIK_DEBUG
#ifdef MAPNIK_DEBUG
std::clog << "Sqlite Plugin: " << s.str() << std::endl;
#endif
#endif
boost::shared_ptr<sqlite_resultset> rs(dataset_->execute_query(s.str()));

View file

@ -31,7 +31,6 @@
#include <mapnik/wkb.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/feature_factory.hpp>
#include <string.h>
// ogr
#include "sqlite_featureset.hpp"
@ -60,41 +59,6 @@ sqlite_featureset::sqlite_featureset(boost::shared_ptr<sqlite_resultset> rs,
sqlite_featureset::~sqlite_featureset() {}
// TODO - refactor, make a static member using std::string or better UnicodeString
void sqlite_dequote(char *z)
{
char quote = z[0];
if (quote=='[' || quote=='\'' || quote=='"' || quote=='`')
{
int iIn = 1; // Index of next byte to read from input
int iOut = 0; // Index of next byte to write to output
// If the first byte was a '[', then the close-quote character is a ']'
if (quote == '[')
{
quote = ']';
}
while (z[iIn])
{
if (z[iIn] == quote)
{
if (z[iIn+1] != quote) break;
z[iOut++] = quote;
iIn += 2;
}
else
{
z[iOut++] = z[iIn++];
}
}
z[iOut] = '\0';
}
}
feature_ptr sqlite_featureset::next()
{
if (rs_->is_valid () && rs_->step_next ())
@ -119,94 +83,52 @@ feature_ptr sqlite_featureset::next()
if (! fld_name)
continue;
if (! using_subquery_)
std::string fld_name_str(fld_name);
// subqueries in sqlite lead to field double quoting which we need to strip
if (using_subquery_)
{
switch (type_oid)
{
case SQLITE_INTEGER:
{
boost::put(*feature, fld_name, rs_->column_integer (i));
break;
}
case SQLITE_FLOAT:
{
boost::put(*feature, fld_name, rs_->column_double (i));
break;
}
case SQLITE_TEXT:
{
int text_size;
const char * data = rs_->column_text(i, text_size);
UnicodeString ustr = tr_->transcode(data, text_size);
boost::put(*feature, fld_name, ustr);
break;
}
case SQLITE_NULL:
{
boost::put(*feature,fld_name,mapnik::value_null());
break;
}
case SQLITE_BLOB:
break;
default:
#ifdef MAPNIK_DEBUG
std::clog << "Sqlite Plugin: unhandled type_oid=" << type_oid << std::endl;
#endif
break;
}
sqlite_utils::dequote(fld_name_str);
}
else
switch (type_oid)
{
// TODO - refactor this code, it is C99 but not valid in C++ (even if GCC allows this)
// subqueries in sqlite lead to field double quoting which we need to strip
char fld_name2[strlen(fld_name)];
strcpy(fld_name2,fld_name);
sqlite_dequote(fld_name2);
switch (type_oid)
case SQLITE_INTEGER:
{
case SQLITE_INTEGER:
{
boost::put(*feature,fld_name2,rs_->column_integer (i));
break;
}
case SQLITE_FLOAT:
{
boost::put(*feature,fld_name2,rs_->column_double (i));
break;
}
case SQLITE_TEXT:
{
int text_size;
const char * data = rs_->column_text(i,text_size);
UnicodeString ustr = tr_->transcode(data,text_size);
boost::put(*feature,fld_name2,ustr);
break;
}
case SQLITE_NULL:
{
boost::put(*feature,fld_name2,mapnik::value_null());
break;
}
case SQLITE_BLOB:
break;
default:
#ifdef MAPNIK_DEBUG
std::clog << "Sqlite Plugin: unhandled type_oid=" << type_oid << std::endl;
#endif
boost::put(*feature, fld_name_str, rs_->column_integer (i));
break;
}
case SQLITE_FLOAT:
{
boost::put(*feature, fld_name_str, rs_->column_double (i));
break;
}
case SQLITE_TEXT:
{
int text_size;
const char * data = rs_->column_text(i, text_size);
UnicodeString ustr = tr_->transcode(data, text_size);
boost::put(*feature, fld_name_str, ustr);
break;
}
case SQLITE_NULL:
{
boost::put(*feature, fld_name_str, mapnik::value_null());
break;
}
case SQLITE_BLOB:
break;
default:
#ifdef MAPNIK_DEBUG
std::clog << "Sqlite Plugin: field " << fld_name_str
<< " unhandled type_oid=" << type_oid << std::endl;
#endif
break;
}
}

View file

@ -24,6 +24,9 @@
#ifndef SQLITE_TYPES_HPP
#define SQLITE_TYPES_HPP
// stdc++
#include <string.h>
// mapnik
#include <mapnik/datasource.hpp>
@ -36,6 +39,22 @@ extern "C" {
}
//==============================================================================
class sqlite_utils
{
public:
static void dequote(std::string& s)
{
if (s[0] == '[' || s[0] == '\'' || s[0] == '"' || s[0] == '`')
{
s = s.substr(1, s.length() - 1);
}
}
};
//==============================================================================
class sqlite_resultset

View file

@ -19,25 +19,26 @@ HEADERS += \
../include/mapnik/svg/svg_renderer.hpp \
../include/mapnik/svg/svg_storage.hpp \
../include/mapnik/svg/svg_transform_grammar.hpp \
../include/mapnik/agg_renderer.hpp \
../include/mapnik/agg_pattern_source.hpp \
../include/mapnik/agg_rasterizer.hpp \
../include/mapnik/agg_renderer.hpp \
../include/mapnik/arrow.hpp \
../include/mapnik/attribute.hpp \
../include/mapnik/attribute_collector.hpp \
../include/mapnik/attribute_descriptor.hpp \
../include/mapnik/attribute.hpp \
../include/mapnik/box2d.hpp \
../include/mapnik/cairo_renderer.hpp \
../include/mapnik/color.hpp \
../include/mapnik/color_factory.hpp \
../include/mapnik/config.hpp \
../include/mapnik/color.hpp \
../include/mapnik/config_error.hpp \
../include/mapnik/coord.hpp \
../include/mapnik/config.hpp \
../include/mapnik/coord_array.hpp \
../include/mapnik/coord.hpp \
../include/mapnik/css_color_grammar_deprecated.hpp \
../include/mapnik/css_color_grammar.hpp \
../include/mapnik/ctrans.hpp \
../include/mapnik/datasource.hpp \
../include/mapnik/datasource_cache.hpp \
../include/mapnik/datasource.hpp \
../include/mapnik/distance.hpp \
../include/mapnik/ellipsoid.hpp \
../include/mapnik/enumeration.hpp \
@ -46,8 +47,9 @@ HEADERS += \
../include/mapnik/expression_node.hpp \
../include/mapnik/expression_string.hpp \
../include/mapnik/factory.hpp \
../include/mapnik/feature.hpp \
../include/mapnik/fastmath.hpp \
../include/mapnik/feature_factory.hpp \
../include/mapnik/feature.hpp \
../include/mapnik/feature_layer_desc.hpp \
../include/mapnik/feature_style_processor.hpp \
../include/mapnik/feature_type_style.hpp \
@ -61,10 +63,11 @@ HEADERS += \
../include/mapnik/geom_util.hpp \
../include/mapnik/global.hpp \
../include/mapnik/glyph_symbolizer.hpp \
../include/mapnik/gradient.hpp \
../include/mapnik/graphics.hpp \
../include/mapnik/hextree.hpp \
../include/mapnik/hit_test_filter.hpp \
../include/mapnik/image_cache.hpp \
../include/mapnik/image_compositing.hpp \
../include/mapnik/image_data.hpp \
../include/mapnik/image_reader.hpp \
../include/mapnik/image_util.hpp \
@ -78,13 +81,22 @@ HEADERS += \
../include/mapnik/line_symbolizer.hpp \
../include/mapnik/load_map.hpp \
../include/mapnik/map.hpp \
../include/mapnik/mapped_memory_cache.hpp \
../include/mapnik/marker_cache.hpp \
../include/mapnik/marker.hpp \
../include/mapnik/markers_placement.hpp \
../include/mapnik/markers_symbolizer.hpp \
../include/mapnik/memory.hpp \
../include/mapnik/memory_datasource.hpp \
../include/mapnik/memory_featureset.hpp \
../include/mapnik/memory.hpp \
../include/mapnik/metawriter_factory.hpp \
../include/mapnik/metawriter.hpp \
../include/mapnik/metawriter_inmem.hpp \
../include/mapnik/metawriter_json.hpp \
../include/mapnik/octree.hpp \
../include/mapnik/palette.hpp \
../include/mapnik/params.hpp \
../include/mapnik/parse_path.hpp \
../include/mapnik/path_expression_grammar.hpp \
../include/mapnik/placement_finder.hpp \
../include/mapnik/plugin.hpp \
@ -98,34 +110,40 @@ HEADERS += \
../include/mapnik/ptree_helpers.hpp \
../include/mapnik/quad_tree.hpp \
../include/mapnik/query.hpp \
../include/mapnik/raster.hpp \
../include/mapnik/raster_colorizer.hpp \
../include/mapnik/raster.hpp \
../include/mapnik/raster_symbolizer.hpp \
../include/mapnik/rule.hpp \
../include/mapnik/save_map.hpp \
../include/mapnik/scale_denominator.hpp \
../include/mapnik/segment.hpp \
../include/mapnik/shield_symbolizer.hpp \
../include/mapnik/sql_utils.hpp \
../include/mapnik/stroke.hpp \
../include/mapnik/style.hpp \
../include/mapnik/style_factory.hpp \
../include/mapnik/svg_renderer.hpp \
../include/mapnik/symbolizer.hpp \
../include/mapnik/text_path.hpp \
../include/mapnik/text_placements.hpp \
../include/mapnik/text_placements_simple.hpp \
../include/mapnik/text_symbolizer.hpp \
../include/mapnik/timer.hpp \
../include/mapnik/unicode.hpp \
../include/mapnik/utils.hpp \
../include/mapnik/value_error.hpp \
../include/mapnik/value.hpp \
../include/mapnik/version.hpp \
../include/mapnik/vertex.hpp \
../include/mapnik/vertex_transform.hpp \
../include/mapnik/vertex_vector.hpp \
../include/mapnik/wall_clock_timer.hpp \
../include/mapnik/warp.hpp \
../include/mapnik/wkb.hpp
SOURCES += \
../src/agg/process_markers_symbolizer.cpp \
../src/agg/process_point_symbolizer.cpp \
../src/agg/process_shield_symbolizer.cpp \
../src/agg_renderer.cpp \
../src/arrow.cpp \
../src/box2d.cpp \
../src/cairo_renderer.cpp \
@ -133,25 +151,33 @@ SOURCES += \
../src/datasource_cache.cpp \
../src/distance.cpp \
../src/expression_string.cpp \
../src/feature_style_processor.cpp \
../src/feature_type_style.cpp \
../src/filter_factory.cpp \
../src/font_engine_freetype.cpp \
../src/font_set.cpp \
../src/glyph_symbolizer.cpp \
../src/gradient.cpp \
../src/graphics.cpp \
../src/image_cache.cpp \
../src/image_reader.cpp \
../src/image_util.cpp \
../src/jpeg_reader.cpp \
../src/layer.cpp \
../src/libxml2_loader.cpp \
../src/line_pattern_symbolizer.cpp \
../src/line_symbolizer.cpp \
../src/load_map.cpp \
../src/map.cpp \
../src/markers_cache.cpp \
../src/mapped_memory_cache.cpp \
../src/marker_cache.cpp \
../src/markers_symbolizer.cpp \
../src/memory.cpp \
../src/memory_datasource.cpp \
../src/params.cpp \
../src/metawriter.cpp \
../src/metawriter_factory.cpp \
../src/metawriter_inmem.cpp \
../src/palette.cpp \
../src/parse_path.cpp \
../src/placement_finder.cpp \
../src/plugin.cpp \
../src/png_reader.cpp \
@ -159,23 +185,27 @@ SOURCES += \
../src/polygon_pattern_symbolizer.cpp \
../src/projection.cpp \
../src/proj_transform.cpp \
../src/raster_colorizer.cpp \
../src/save_map.cpp \
../src/scale_denominator.cpp \
../src/shield_symbolizer.cpp \
../src/stroke.cpp \
../src/svg_parser.cpp \
../src/svg_path_parser.cpp \
../src/svg_point_parser.cpp \
../src/svg_points_parser.cpp \
../src/svg_transform_parser.cpp \
../src/symbolizer.cpp \
../src/text_placements.cpp \
../src/text_symbolizer.cpp \
../src/tiff_reader.cpp \
../src/unicode.cpp \
../src/warp.cpp \
../src/wkb.cpp
include(plugins.pri)
unix {
DEFINES += LINUX=1
INCLUDEPATH += /usr/include/freetype
}