1#include "Utilities/Parsing.h"
3#include "JsonSerialization.h"
4#include "BaseRasterSource.h"
5#include "FloatRasterSource.h"
6#include "ColorRasterSource.h"
7#include "NullRasterSource.h"
8#include "WCSRasterSource.h"
9#include "WMSRasterSource.h"
11#include "MemoryCache.h"
13#include "Foundation/Logging/Logger.h"
14#include "Foundation/Platform/IO.h"
16#include "../Libraries/tiny-AES-c/aes.hpp"
18#include "rapidjson/document.h"
19#include "rapidjson/prettywriter.h"
25namespace rj = rapidjson;
31 using namespace Cogs::Core::TerrainProvider;
34 bool getDouble(
double& rv,
const rj::Value& parent,
const char* name)
36 auto it = parent.FindMember(name);
37 if (it == parent.MemberEnd()) {
38 LOG_ERROR(logger,
"Missing required member %s", name);
41 else if (!it->value.IsNumber()) {
42 LOG_ERROR(logger,
"Member %s is not a number", name);
45 rv = it->value.GetDouble();
49 bool getBool(
bool& rv,
const rj::Value& parent,
const char* name,
bool required)
51 auto it = parent.FindMember(name);
52 if (it == parent.MemberEnd()) {
53 if(required) LOG_ERROR(logger,
"Missing required member %s", name);
56 else if(!it->value.IsBool()) {
57 LOG_ERROR(logger,
"Member %s is not a boolean value", name);
60 rv = it->value.GetBool();
64 bool getUnsigned(
unsigned& rv,
const rj::Value& parent,
const char* name,
bool required =
true)
66 auto it = parent.FindMember(name);
67 if (it == parent.MemberEnd()) {
68 if (required) LOG_ERROR(logger,
"Missing required member %s", name);
71 if (!it->value.IsUint()) {
72 if (required) LOG_ERROR(logger,
"Member %s is not an unsigned number", name);
75 rv = it->value.GetUint();
79 Cogs::Core::StringRef findStringMember(
const rj::Value& parent,
const char* name,
bool required =
true)
81 auto it = parent.FindMember(name);
82 if (it == parent.MemberEnd()) {
83 if (required) LOG_ERROR(logger,
"Missing required %s member", name);
84 return Cogs::Core::NoString;
86 if (!it->value.IsString()) {
87 LOG_ERROR(logger,
"Member %s is not a string", name);
88 return Cogs::Core::NoString;
90 return Cogs::Core::Strings::add(it->value.GetString());
97 if (tmp.find(
"EPSG:") == 0) {
98 cs.kind = CoordSys::Kind::EPSG;
100 cs.id = std::strtol(text.
data() + 5, &ptr, 10);
101 if (ptr ==
nullptr || *ptr !=
'\0') {
102 LOG_ERROR(logger,
"Error parsing coordinate system '%s'", tmp.c_str());
107 LOG_ERROR(logger,
"Error parsing coordinate system '%s'", tmp.c_str());
114 switch (coordSys.kind) {
115 case CoordSys::Kind::EPSG:
117 tmp.append(std::to_string(coordSys.id));
118 return Cogs::Core::Strings::add(tmp);
120 assert(
false &&
"Illegal coordysys kind");
121 return Cogs::Core::NoString;
125 bool deserializeTiling(
Tiling& tiling,
const rj::Document& doc)
127 auto it = doc.FindMember(
"Tiling");
128 if (it == doc.MemberEnd()) {
129 LOG_ERROR(logger,
"Missing required member Tiling");
132 if (!it->value.IsObject()) {
133 LOG_ERROR(logger,
"Member Tiling is not an object");
136 if (!getUnsigned(tiling.levels, it->value,
"Levels",
false)) tiling.levels = 1u;
137 if (!getUnsigned(tiling.overlapStart, it->value,
"OverlapStart",
false)) tiling.overlapStart = 0u;
138 if (!getUnsigned(tiling.overlapEnd, it->value,
"OverlapEnd",
false)) tiling.overlapEnd = 0u;
140 getDouble(tiling.size.x, it->value,
"LevelZeroDeltaX") &&
141 getDouble(tiling.size.y, it->value,
"LevelZeroDeltaY") &&
142 getUnsigned(tiling.width, it->value,
"TileWidth") &&
143 getUnsigned(tiling.height, it->value,
"TileHeight");
146 bool serializeTiling(rj::Document& doc,
const Tiling& tiling)
148 auto& allocator = doc.GetAllocator();
149 rapidjson::Value tilingValue;
150 tilingValue.SetObject();
151 tilingValue.AddMember(
"LevelZeroDeltaX", tiling.size.x, allocator);
152 tilingValue.AddMember(
"LevelZeroDeltaY", tiling.size.y, allocator);
153 tilingValue.AddMember(
"TileWidth", tiling.width, allocator);
154 tilingValue.AddMember(
"TileHeight", tiling.height, allocator);
155 if (1 < tiling.levels) tilingValue.AddMember(
"Levels", tiling.levels, allocator);
156 if (tiling.overlapStart != 0) tilingValue.AddMember(
"OverlapStart", tiling.overlapStart, allocator);
157 if (tiling.overlapEnd != 0) tilingValue.AddMember(
"OverlapEnd", tiling.overlapEnd, allocator);
158 doc.AddMember(
"Tiling", tilingValue, allocator);
162 bool deserializeExtent(
Extent& extent,
const rj::Document& doc)
164 auto it = doc.FindMember(
"Extents");
165 if (it == doc.MemberEnd()) {
166 LOG_ERROR(logger,
"Missing required member Extetns");
169 if (!it->value.IsObject()) {
170 LOG_ERROR(logger,
"Member Extents is not an object.");
174 getDouble(extent.min.x, it->value,
"MinX") &&
175 getDouble(extent.min.y, it->value,
"MinY") &&
176 getDouble(extent.max.x, it->value,
"MaxX") &&
177 getDouble(extent.max.y, it->value,
"MaxY");
180 bool serializeExtent(rj::Document& doc,
const Extent& extent)
182 auto& allocator = doc.GetAllocator();
185 extents.AddMember(
"MinX", extent.min.x, allocator);
186 extents.AddMember(
"MaxX", extent.max.x, allocator);
187 extents.AddMember(
"MinY", extent.min.y, allocator);
188 extents.AddMember(
"MaxY", extent.max.y, allocator);
189 doc.AddMember(
"Extents", extents, allocator);
193 bool deserializeBaseConf(
BaseConfig& conf,
const rj::Document& doc)
195 auto common_it = doc.FindMember(
"Common");
196 if (common_it == doc.MemberEnd()) {
197 LOG_ERROR(logger,
"Missing required Common member");
200 if (!common_it->value.IsObject()) {
201 LOG_ERROR(logger,
"Common member is not an object");
204 auto cs_it = common_it->value.FindMember(
"SRS");
205 if (cs_it == common_it->value.MemberEnd()) {
206 LOG_ERROR(logger,
"Missing required SRS member");
209 if (!cs_it->value.IsString()) {
210 LOG_ERROR(logger,
"SRS member is not a string");
213 if(!deserializeCoordSys(conf.coordsys,
Cogs::StringView(cs_it->value.GetString())))
return false;
215 if (
auto name = findStringMember(doc,
"Name"); name != Cogs::Core::NoString) {
220 conf.cacheKey = findStringMember(doc,
"CacheKey",
false);
222 auto common = doc.FindMember(
"Common");
223 if (common != doc.MemberEnd() && common->value.IsObject()) {
224 getBool(conf.offline, common->value,
"Offline",
false);
227 auto tf_it = common_it->value.FindMember(
"TextureFormat");
228 if (tf_it != common_it->value.MemberEnd()) {
229 if (!tf_it->value.IsString()) {
230 LOG_ERROR(logger,
"Member TextureFormat is not a string");
233 LOG_DEBUG(logger,
"MOO: %s", tf_it->value.GetString());
234 conf.textureFormat = Cogs::Core::parseTextureFormat(
Cogs::StringView(tf_it->value.GetString()), Cogs::TextureFormat::Unknown);
237 if (
auto mimeType = findStringMember(common_it->value,
"MimeType",
false); mimeType != NoString) {
238 conf.mimeType = parseMimeType(Strings::get(mimeType));
241 auto nd_it = common_it->value.FindMember(
"NoData");
242 if (nd_it != common_it->value.MemberEnd()) {
243 if (nd_it->value.IsString()) {
245 conf.noData = std::strtof(nd_it->value.GetString(), &e);
246 if (e ==
nullptr || *e !=
'\0') {
247 LOG_ERROR(logger,
"Failed to parse Common.NoData value '%s' as a double.", nd_it->value.GetString());
251 else if (nd_it->value.IsNumber()) {
252 conf.noData = nd_it->value.GetFloat();
255 LOG_ERROR(logger,
"Common.NoData is neither string nor float.");
260 deserializeExtent(conf.extent, doc) &&
261 deserializeTiling(conf.tiling, doc);
264 bool serializeBaseConf(rj::Document& doc,
const BaseConfig& conf)
266 auto& allocator = doc.GetAllocator();
269 common.AddMember(
"SRS", rj::StringRef(Cogs::Core::Strings::getC(serializeCoordSys(conf.coordsys))), allocator);
270 if (conf.textureFormat != Cogs::TextureFormat::Unknown) {
271 auto* formatInfo = Cogs::getFormatInfo(conf.textureFormat);
272 if (formatInfo) common.AddMember(
"TextureFormat", rapidjson::StringRef(formatInfo->name), allocator);
274 if (conf.offline) common.AddMember(
"Offline", conf.offline, allocator);
276 if (conf.cacheKey != Cogs::Core::NoString) doc.AddMember(
"CacheKey", rj::StringRef(Cogs::Core::Strings::getC(conf.cacheKey)), allocator);
277 if (conf.name != Cogs::Core::NoString) doc.AddMember(
"Name", rj::StringRef(Cogs::Core::Strings::getC(conf.name)), allocator);
278 if (conf.mimeType != MimeType::None) common.AddMember(
"MimeType", rj::StringRef(Cogs::Core::Strings::getC(mimeTypeString(conf.mimeType))), allocator);
280 doc.AddMember(
"Common", common, allocator);
282 serializeExtent(doc, conf.extent) &&
283 serializeTiling(doc, conf.tiling);
287 bool deserializeFloatConf(
FloatConfig& conf, rj::Document& doc)
289 if (!deserializeBaseConf(conf, doc))
return false;
291 if (
auto it = doc.FindMember(
"FloatValue"); it != doc.MemberEnd()) {
292 if (!it->value.IsNumber()) {
293 LOG_ERROR(logger,
"Member FloatValue is not a number.");
296 conf.value = it->value.GetFloat();
301 bool serializeFloatRasterSource(rj::Document& doc,
const FloatConfig& conf)
303 auto& allocator = doc.GetAllocator();
304 if (conf.value != 0.f) {
305 doc.AddMember(
"FloatValue", conf.value, allocator);
307 return serializeBaseConf(doc, conf);
310 bool deserializeColorConf(
ColorConfig& conf,
const rj::Document& doc)
312 if (!deserializeBaseConf(conf, doc))
return false;
314 auto col_it = doc.FindMember(
"Colors");
315 if (col_it == doc.MemberEnd()) {
316 LOG_ERROR(logger,
"Required member Colors missing");
319 if (!col_it->value.IsArray()) {
320 LOG_ERROR(logger,
"Member Colors is not an array");
323 for (
auto& col : col_it->value.GetArray()) {
324 if (!col.IsArray()) {
325 LOG_ERROR(logger,
"Item of Color array is not an array");
328 auto colarr = col.GetArray();
329 if (colarr.Size() != 4) {
330 LOG_ERROR(logger,
"Item of color array is not of length 4");
334 for (rj::SizeType i = 0; i < 4; i++) {
335 if (!colarr[i].IsNumber()) {
336 LOG_ERROR(logger,
"Item of array in color array is not a number");
339 color[i] = colarr[i].GetFloat();
341 conf.colors.push_back(color);
346 bool serializeColorRasterSource(rj::Document& doc,
const ColorConfig& conf)
348 auto& allocator = doc.GetAllocator();
352 for (
auto& color : conf.colors) {
355 c.PushBack(color.r, allocator);
356 c.PushBack(color.g, allocator);
357 c.PushBack(color.b, allocator);
358 c.PushBack(color.a, allocator);
359 colors.PushBack(c, allocator);
361 doc.AddMember(
"Colors", colors, allocator);
362 return serializeBaseConf(doc, conf);
365 bool deserializeHTTPConf(
HTTPConfig& conf,
const rj::Document& doc)
367 if (!deserializeBaseConf(conf, doc))
return false;
369 conf.baseUrl = findStringMember(doc,
"Url",
true);
370 if (conf.baseUrl == NoString)
return false;
371 conf.username = findStringMember(doc,
"Username",
false);
372 if (
auto pw_it = doc.FindMember(
"Password"); pw_it != doc.MemberEnd()) {
373 if (!pw_it->value.IsString()) { LOG_ERROR(logger,
"Member 'Password' is not a string");
return false; }
374 auto buffer = base64_decode(pw_it->value.GetString());
375 if ((buffer.size() % AES_BLOCKLEN) != 0) { LOG_ERROR(logger,
"Key is not a multiple of %u", AES_BLOCKLEN);
return false; }
376 if ((buffer.size() < 2 * AES_BLOCKLEN)) { LOG_ERROR(logger,
"Encrypted key must be at least %u bytes", 2 * AES_BLOCKLEN);
return false; }
379 uint8_t key[AES_KEYLEN] = {
380 0xdf, 0x8c, 0x7c, 0x5d, 0x27, 0x21, 0xec, 0x1a,
381 0xd1, 0x1f, 0xfb, 0x76, 0x76, 0x37, 0x4e, 0x48,
382 0x18, 0x61, 0x10, 0x89, 0xe0, 0xec, 0x16, 0x0d,
383 0x41, 0xb9, 0x28, 0x7a, 0x77, 0xe2, 0xd1, 0x80
387 AES_init_ctx(&ctx, key);
388 AES_CBC_decrypt_buffer(&ctx, (uint8_t*)buffer.data(),
static_cast<uint32_t
>(buffer.size()));
391 auto* start = buffer.c_str() + AES_BLOCKLEN;
395 auto* end = buffer.c_str() + buffer.size();
397 if (end < start) { LOG_ERROR(logger,
"Key has invalid padding");
return false; }
404 bool serializeHTTPConf(rj::Document& doc,
const HTTPConfig& conf,
bool include_credentials)
406 auto& allocator = doc.GetAllocator();
407 if (conf.baseUrl != NoString) doc.AddMember(
"Url", rj::StringRef(Strings::getC(conf.baseUrl)), allocator);
408 if (include_credentials) {
409 if (conf.username != NoString) doc.AddMember(
"Username", rj::StringRef(Strings::getC(conf.username)), allocator);
410 if (conf.password != NoString) doc.AddMember(
"Password", rj::StringRef(Strings::getC(conf.password)), allocator);
412 return serializeBaseConf(doc, conf);
415 bool deserializeWCSConf(
WCSConfig& conf,
const rj::Document& doc)
417 if (!deserializeHTTPConf(conf, doc))
return false;
419 conf.layer = findStringMember(doc,
"Layer",
true);
420 if (conf.layer == NoString)
423 conf.format = findStringMember(doc,
"Format",
true);
424 if (conf.format == NoString)
427 conf.interpolation = findStringMember(doc,
"Interpolation",
false);
428 conf.interpolationFieldName = findStringMember(doc,
"InterpolationFieldName",
false);
429 getBool(conf.invertZ, doc,
"InvertZ",
false);
430 getBool(conf.allowNoData, doc,
"AllowNoData",
false);
434 bool serializeWCSRasterSource(rj::Document& doc,
const WCSConfig& conf,
bool include_credentials)
438 auto& allocator = doc.GetAllocator();
439 if (conf.layer != NoString) doc.AddMember(
"Layer", rj::StringRef(Strings::getC(conf.layer)), allocator);
440 if (conf.format != NoString) doc.AddMember(
"Format", rj::StringRef(Strings::getC(conf.format)), allocator);
441 if (conf.interpolation != NoString &&
442 conf.interpolation != def.interpolation) {
443 doc.AddMember(
"Interpolation", rj::StringRef(Strings::getC(conf.interpolation)), allocator);
445 if (conf.interpolationFieldName != NoString &&
446 conf.interpolationFieldName != def.interpolationFieldName) {
447 doc.AddMember(
"InterpolationFieldName", rj::StringRef(Strings::getC(conf.interpolationFieldName)), allocator);
449 if (conf.invertZ) doc.AddMember(
"InvertZ", conf.invertZ, allocator);
450 if (conf.allowNoData) doc.AddMember(
"AllowNoData", conf.allowNoData, allocator);
451 return serializeHTTPConf(doc, conf, include_credentials);
454 bool deserializeWMSOtherArguments(std::vector<std::pair<StringRef, StringRef>>& otherArguments, rj::Value& parent)
456 auto common_it = parent.FindMember(
"OtherArguments");
457 if (common_it == parent.MemberEnd())
return true;
458 if (!common_it->value.IsArray()) { LOG_ERROR(logger,
"OtherArguments is not an Array");
return false; }
459 for (
auto& item : common_it->value.GetArray()) {
460 if (!item.IsObject()) { LOG_ERROR(logger,
"OtherArguments item is not an Object");
return false; }
461 if (item.MemberCount() != 2) { LOG_ERROR(logger,
"OtherArguments item should have exactly two members.");
return false; }
462 auto key = item.FindMember(
"Key");
463 if (key == item.MemberEnd()) { LOG_ERROR(logger,
"OtherArguments item is missing 'Key' item");
return false; }
464 if (!key->value.IsString()) { LOG_ERROR(logger,
"OtherArguments item has 'Key' item that has non-string value");
return false; }
465 auto value = item.FindMember(
"Value");
466 if (value == item.MemberEnd()) { LOG_ERROR(logger,
"OtherArguments item is missing 'Value' item");
return false; }
467 if (!value->value.IsString()) { LOG_ERROR(logger,
"OtherArguments item has 'Value' item that has non-string value");
return false; }
468 otherArguments.emplace_back(std::make_pair(Strings::add(key->value.GetString()),
469 Strings::add(value->value.GetString())));
474 bool serializeWMSOtherArguments(rj::Document& doc, rj::Value& parent,
const std::vector<std::pair<StringRef, StringRef>>& otherArguments)
476 if (otherArguments.empty())
return true;
477 auto& allocator = doc.GetAllocator();
479 container.SetArray();
480 for (
auto& arg : otherArguments) {
481 if (arg.first == NoString || arg.second == NoString) { LOG_ERROR(logger,
"Malformed WMS OtherArgument");
return false; }
484 item.AddMember(
"Key", rj::StringRef(Strings::getC(arg.first)), allocator);
485 item.AddMember(
"Value", rj::StringRef(Strings::getC(arg.second)), allocator);
486 container.PushBack(item, allocator);
488 parent.AddMember(
"OtherArguments", container, allocator);
492 bool deserializeWMSLayerDescriptions(std::vector<WMSLayerDescription>& layerDescriptions, rj::Value& parent)
494 auto desc_it = parent.FindMember(
"Layers");
495 if (desc_it == parent.MemberEnd()) { LOG_ERROR(logger,
"Missing required item 'Layers'");
return false; }
496 if (!desc_it->value.IsArray()) { LOG_ERROR(logger,
"Value of item 'Layers' is not an array.");
return false; }
497 if (desc_it->value.GetArray().Empty()) { LOG_ERROR(logger,
"Item 'Layers' needs at least on item");
return false; }
498 for (
auto& item : desc_it->value.GetArray()) {
500 layer.name = NoString;
501 if (
auto it = item.FindMember(
"Name"); it != item.MemberEnd()) {
502 if (!it->value.IsString()) { LOG_ERROR(logger,
"Layer Name is not a string");
return false; }
503 layer.name = Strings::add(it->value.GetString());
504 }
else { LOG_ERROR(logger,
"Layer missing compulsory member 'Name'");
return false; }
505 if (
auto it = item.FindMember(
"Style"); it != item.MemberEnd()) {
506 if (!it->value.IsString()) { LOG_ERROR(logger,
"Layer Style is not a string");
return false; }
507 layer.style = Strings::add(it->value.GetString());
509 if (
auto it = item.FindMember(
"MinLevel"); it != item.MemberEnd()) {
510 if (!it->value.IsUint()) { LOG_ERROR(logger,
"Layer MinLevel is not an unsigned integer.");
return false; }
511 layer.minLevel = it->value.GetUint();
513 if (
auto it = item.FindMember(
"MaxLevel"); it != item.MemberEnd()) {
514 if (!it->value.IsUint()) { LOG_ERROR(logger,
"Layer MaxLevel is not an unsigned integer.");
return false; }
515 layer.maxLevel = it->value.GetUint();
517 if (!deserializeWMSOtherArguments(layer.otherArguments, item))
return false;
518 layerDescriptions.emplace_back(std::move(layer));
523 bool serializeWMSLayerDescriptions(rj::Document& doc, rj::Value& parent,
const std::vector<WMSLayerDescription>& layerDescriptions)
525 if (layerDescriptions.empty()) { LOG_ERROR(logger,
"No layers defined");
return false; }
526 auto& allocator = doc.GetAllocator();
528 container.SetArray();
530 for (
auto& layer : layerDescriptions) {
531 if (layer.name == NoString) { LOG_ERROR(logger,
"Layer without name");
return false; }
534 item.AddMember(
"Name", rj::StringRef(Strings::getC(layer.name)), allocator);
535 if (layer.style != layerDefaults.style) {
536 if (layer.style == NoString) { LOG_ERROR(logger,
"Layer Style is an empty string");
return false; }
537 item.AddMember(
"Style", rj::StringRef(Strings::getC(layer.style)), allocator);
539 if (layer.minLevel != layerDefaults.minLevel) {
540 item.AddMember(
"MinLevel", layer.minLevel, allocator);
542 if (layer.maxLevel != layerDefaults.maxLevel) {
543 item.AddMember(
"MaxLevel", layer.maxLevel, allocator);
545 if (!serializeWMSOtherArguments(doc, item, layer.otherArguments))
return false;
546 container.PushBack(item, allocator);
548 parent.AddMember(
"Layers", container, allocator);
552 bool deserializeWMSConf(
WMSConfig& conf, rj::Document& doc)
554 if (!deserializeHTTPConf(conf, doc))
return false;
556 if (
auto version = findStringMember(doc,
"Version",
false); version != NoString) {
557 switch (Strings::get(version).hash()) {
558 case Cogs::hash(
"1.0.0"): conf.version = WMSVersion::v1_0_0;
break;
559 case Cogs::hash(
"1.1.0"): conf.version = WMSVersion::v1_1_0;
break;
560 case Cogs::hash(
"1.1.1"): conf.version = WMSVersion::v1_1_1;
break;
561 case Cogs::hash(
"1.3.0"): conf.version = WMSVersion::v1_3_0;
break;
563 LOG_ERROR(logger,
"Unrecognized WMS version '%s'", Strings::getC(version));
568 if (
auto dataType = findStringMember(doc,
"ValueDataType",
false); dataType != NoString) {
569 switch (Strings::get(dataType).hash()) {
570 case Cogs::hash(
"Short"): conf.dataType = WMSValueDataType::Short;
break;
571 case Cogs::hash(
"UnsignedSHort"): conf.dataType = WMSValueDataType::UnsignedSHort;
break;
572 case Cogs::hash(
"Float"): conf.dataType = WMSValueDataType::Float;
break;
573 case Cogs::hash(
"Double"): conf.dataType = WMSValueDataType::Double;
break;
575 LOG_ERROR(logger,
"Unrecognized WMS value datatype '%s'", Strings::getC(dataType));
580 getBool(conf.serverIsLittleEndian, doc,
"IsLittleEndian",
false);
581 getBool(conf.retryFailedRequests, doc,
"Retry",
false);
582 if (!deserializeWMSLayerDescriptions(conf.layerDescriptions, doc))
return false;
583 if (!deserializeWMSOtherArguments(conf.otherArguments, doc))
return false;
588 bool serializeWMSRasterSource(rj::Document& doc,
const WMSConfig& conf,
bool include_credentials)
591 auto& allocator = doc.GetAllocator();
592 if (conf.version != confDefaults.version) {
593 switch (conf.version) {
594 case WMSVersion::v1_0_0: doc.AddMember(
"Version", rj::StringRef(
"1.0.0"), allocator);
break;
595 case WMSVersion::v1_1_0: doc.AddMember(
"Version", rj::StringRef(
"1.1.0"), allocator);
break;
596 case WMSVersion::v1_1_1: doc.AddMember(
"Version", rj::StringRef(
"1.1.1"), allocator);
break;
597 case WMSVersion::v1_3_0: doc.AddMember(
"Version", rj::StringRef(
"1.3.0"), allocator);
break;
598 default: LOG_ERROR(logger,
"Illegal WMS version");
return false;
601 if (conf.dataType != confDefaults.dataType) {
602 switch (conf.dataType) {
603 case WMSValueDataType::Short: doc.AddMember(
"ValueDataType", rj::StringRef(
"Short"), allocator);
break;
604 case WMSValueDataType::UnsignedSHort: doc.AddMember(
"ValueDataType", rj::StringRef(
"UnsignedSHort"), allocator);
break;
605 case WMSValueDataType::Float: doc.AddMember(
"ValueDataType", rj::StringRef(
"Float"), allocator);
break;
606 case WMSValueDataType::Double: doc.AddMember(
"ValueDataType", rj::StringRef(
"Double"), allocator);
break;
607 default: LOG_ERROR(logger,
"Illegal WMS dataType");
return false;
610 if (conf.serverIsLittleEndian != confDefaults.serverIsLittleEndian) {
611 doc.AddMember(
"IsLittleEndian", conf.serverIsLittleEndian, allocator);
613 if (conf.retryFailedRequests != confDefaults.retryFailedRequests) {
614 doc.AddMember(
"Retry", conf.retryFailedRequests, allocator);
616 if (!serializeWMSLayerDescriptions(doc, doc, conf.layerDescriptions))
return false;
617 if (!serializeWMSOtherArguments(doc, doc, conf.otherArguments))
return false;
618 return serializeHTTPConf(doc, conf, include_credentials);
621 std::unique_ptr<Cogs::Core::TerrainProvider::BaseConfig> deserializeConfig(rj::Document& doc)
623 auto rasterType = findStringMember(doc,
"RasterType");
624 if (rasterType == NoString)
return nullptr;
626 switch (Strings::get(rasterType).hash()) {
628 if (auto conf =
std::make_unique<
FloatConfig>(); deserializeFloatConf(*conf, doc)) {
633 if (auto conf =
std::make_unique<
ColorConfig>(); deserializeColorConf(*conf, doc)) {
638 if (auto conf =
std::make_unique<
WCSConfig>(); deserializeWCSConf(*conf, doc)) {
643 if (auto conf =
std::make_unique<
WMSConfig>(); deserializeWMSConf(*conf, doc)) {
649 LOG_ERROR(logger,
"Unrecognized rastertype %s", Strings::getC(rasterType));
658 if (providerConf->cacheKey != NoString) {
659 auto diskCache = std::make_unique<DiskCache>();
660 if (diskCache->init(context, providerConf, cacheRoot)) {
669std::unique_ptr<Cogs::Core::TerrainProvider::BaseConfig> Cogs::Core::TerrainProvider::deserializeRastersourceConfig(
Context* ,
const StringView json)
671 rapidjson::Document doc;
672 if (doc.Parse<rapidjson::kParseTrailingCommasFlag | rapidjson::kParseCommentsFlag | rapidjson::kParseNanAndInfFlag>(json.
data(), json.
size()).HasParseError()) {
675 if (!doc.IsObject()) {
676 LOG_ERROR(logger,
"conf json root is not an object");
680 return deserializeConfig(doc);
685 std::unique_ptr<BaseConfig> providerConf = deserializeRastersourceConfig(context, json);
686 if (!providerConf)
return nullptr;
688 if (providerConf->offline) {
689 auto cache = openCache(context, providerConf.get(), cacheRoot);
690 if (!cache)
return nullptr;
693 if (rastersource->init(*(providerConf.get()), std::move(cache))) {
694 LOG_DEBUG(logger,
"Created NullRasterSource");
699 else if (
auto* floatConf =
dynamic_cast<FloatConfig*
>(providerConf.get())) {
701 if (rastersource->init(*floatConf, std::make_unique<MemoryCache>())) {
702 LOG_DEBUG(logger,
"Created FloatRasterSource");
707 else if (
auto* colorConf =
dynamic_cast<ColorConfig*
>(providerConf.get())) {
709 if (rastersource->init(*colorConf, std::make_unique<MemoryCache>())) {
710 LOG_DEBUG(logger,
"Created ColorRasterSource");
715 else if (
auto* wcsConf =
dynamic_cast<WCSConfig*
>(providerConf.get())) {
716 auto cache = openCache(context, wcsConf, cacheRoot);
717 if (!cache)
return nullptr;
720 if (rastersource->init(*wcsConf, std::move(cache))) {
721 LOG_DEBUG(logger,
"Created WCSRasterSource");
726 else if (
auto* wmsConf =
dynamic_cast<WMSConfig*
>(providerConf.get())) {
727 auto cache = openCache(context, wmsConf, cacheRoot);
728 if (!cache)
return nullptr;
731 if (rastersource->init(*wmsConf, std::move(cache))) {
732 LOG_DEBUG(logger,
"Created WMSRasterSource");
738 LOG_ERROR(logger,
"Unsupported rastersource configuration");
746 if (conf ==
nullptr) {
747 LOG_ERROR(logger,
"Cannot serialzie null pointer");
751 rapidjson::Document doc;
752 auto& allocator = doc.GetAllocator();
755 if (
auto* frs =
dynamic_cast<const FloatConfig*
>(conf)) {
756 doc.AddMember(
"RasterType", rj::StringRef(
"FloatRasterSource"), allocator);
757 if (!serializeFloatRasterSource(doc, *frs))
return false;
759 else if (
auto* crs =
dynamic_cast<const ColorConfig*
>(conf)) {
760 doc.AddMember(
"RasterType", rj::StringRef(
"ColorRasterSource"), allocator);
761 if (!serializeColorRasterSource(doc, *crs))
return false;
763 else if (
auto* wcs =
dynamic_cast<const WCSConfig*
>(conf)) {
764 doc.AddMember(
"RasterType", rj::StringRef(
"WcsRasterSource"), allocator);
765 if (!serializeWCSRasterSource(doc, *wcs, include_credentials))
return false;
767 else if (
auto* wms =
dynamic_cast<const WMSConfig*
>(conf)) {
768 doc.AddMember(
"RasterType", rj::StringRef(
"WmsRasterSource"), allocator);
769 if (!serializeWMSRasterSource(doc, *wms, include_credentials))
return false;
772 LOG_ERROR(logger,
"Unrecognized raster source");
777 rapidjson::StringBuffer sb;
778 rapidjson::PrettyWriter<
decltype(sb),
781 rapidjson::CrtAllocator,
782 rapidjson::kWriteNanAndInfFlag> writer(sb);
786 buffer.resize(sb.GetSize(),
false);
787 std::memcpy(buffer.data(), sb.GetString(), sb.GetSize());
793 if (rasterSource ==
nullptr) {
794 LOG_ERROR(logger,
"Cannot serialzie null pointer");
798 rapidjson::Document doc;
799 auto& allocator = doc.GetAllocator();
803 doc.AddMember(
"RasterType", rj::StringRef(
"FloatRasterSource"), allocator);
805 frs->getConfig(conf);
806 if (!serializeFloatRasterSource(doc, conf))
return false;
809 doc.AddMember(
"RasterType", rj::StringRef(
"ColorRasterSource"), allocator);
811 crs->getConfig(conf);
812 if (!serializeColorRasterSource(doc, conf))
return false;
814 else if (
auto* wcs =
dynamic_cast<const WCSRasterSource*
>(rasterSource)) {
815 doc.AddMember(
"RasterType", rj::StringRef(
"WcsRasterSource"), allocator);
817 wcs->getConfig(conf);
818 if (!serializeWCSRasterSource(doc, conf, include_credentials))
return false;
820 else if (
auto* wms =
dynamic_cast<const WMSRasterSource*
>(rasterSource)) {
821 doc.AddMember(
"RasterType", rj::StringRef(
"WmsRasterSource"), allocator);
823 wms->getConfig(conf);
824 if (!serializeWMSRasterSource(doc, conf, include_credentials))
return false;
827 LOG_ERROR(logger,
"Unrecognized raster source");
832 rapidjson::StringBuffer sb;
833 rapidjson::PrettyWriter<
decltype(sb),
836 rapidjson::CrtAllocator,
837 rapidjson::kWriteNanAndInfFlag> writer(sb);
841 buffer.resize(sb.GetSize(),
false);
842 std::memcpy(buffer.data(), sb.GetString(), sb.GetSize());
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Log implementation class.
Provides a weakly referenced view over the contents of a string.
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
constexpr size_t size() const noexcept
Get the size of the string.
constexpr size_t length() const noexcept
Get the length of the string.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.