forked from organicmaps/organicmaps
MapsWithMe_GenShortShowMapUrl
This commit is contained in:
parent
3faba8bfec
commit
8446dd0682
2 changed files with 282 additions and 3 deletions
|
@ -1,6 +1,8 @@
|
|||
#include "api-client.h"
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Max number of base64 bytes to encode a geo point.
|
||||
#define MAPSWITHME_MAX_POINT_BYTES 10
|
||||
|
@ -70,10 +72,113 @@ void MapsWithMe_LatLonToString(double lat, double lon, char * s, int nBytes)
|
|||
}
|
||||
}
|
||||
|
||||
int MapsWithMe_GenShortShowMapUrl(double lat, double lon, double zoomLevel, char const * name, char * buf, int bufSize)
|
||||
// Do special URL Encoding:
|
||||
// URL restricted / unsafe / unwise characters are %-encoded.
|
||||
// See rfc3986, rfc1738, rfc2396.
|
||||
// ' ' is replaced with '_'
|
||||
// '_' is replaces with %-encoded space, i.e. %20
|
||||
int MapsWithMe_UrlEncodeString(char const * s, int size, char ** res)
|
||||
{
|
||||
*res = malloc(size * 3 + 1);
|
||||
char * out = *res;
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
unsigned char c = (unsigned char)(s[i]);
|
||||
switch (c)
|
||||
{
|
||||
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
|
||||
case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F:
|
||||
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
|
||||
case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F:
|
||||
case 0x7F:
|
||||
case '<':
|
||||
case '>':
|
||||
case '#':
|
||||
case '%':
|
||||
case '"':
|
||||
case '!':
|
||||
case '*':
|
||||
case '\'':
|
||||
case '(':
|
||||
case ')':
|
||||
case ';':
|
||||
case ':':
|
||||
case '@':
|
||||
case '&':
|
||||
case '=':
|
||||
case '+':
|
||||
case '$':
|
||||
case ',':
|
||||
case '/':
|
||||
case '?':
|
||||
case '[':
|
||||
case ']':
|
||||
case '{':
|
||||
case '}':
|
||||
case '|':
|
||||
case '^':
|
||||
case '`':
|
||||
*(out++) = '%';
|
||||
*(out++) = "0123456789ABCDEF"[c >> 4];
|
||||
*(out++) = "0123456789ABCDEF"[c & 15];
|
||||
break;
|
||||
case ' ':
|
||||
*(out++) = '_';
|
||||
break;
|
||||
case '_':
|
||||
*(out++) = '%'; *(out++) = '2'; *(out++) = '0';
|
||||
break;
|
||||
default:
|
||||
*(out++) = s[i];
|
||||
}
|
||||
}
|
||||
*(out++) = 0;
|
||||
return out - *res - 1;
|
||||
}
|
||||
|
||||
void MapsWithMe_AppendString(char * buf, int bufSize, int * bytesAppended, char const * s, int size)
|
||||
{
|
||||
int const bytesAvailable = bufSize - *bytesAppended;
|
||||
if (bytesAvailable > 0)
|
||||
memcpy(buf + *bytesAppended, s, size < bytesAvailable ? size : bytesAvailable);
|
||||
|
||||
*bytesAppended += size;
|
||||
}
|
||||
|
||||
int MapsWithMe_GenShortShowMapUrl(double lat, double lon, double zoom, char const * name, char * buf, int bufSize)
|
||||
{
|
||||
// @TODO: Implement MapsWithMe_GenShortShowMapUrl().
|
||||
// @TODO: Escape URL-unfriendly characters: ! * ' ( ) ; : @ & = + $ , / ? % # [ ]
|
||||
|
||||
return 0;
|
||||
// URL format:
|
||||
//
|
||||
// +------------------ 1 byte: zoom level
|
||||
// |+-------+--------- 9 bytes: lat,lon
|
||||
// || | +--+---- Variable number of bytes: point name
|
||||
// || | | |
|
||||
// ge0://ZCoordba64/Name
|
||||
|
||||
int fullUrlSize = 0;
|
||||
|
||||
char urlPrefix[] = "ge0://ZCoord6789";
|
||||
|
||||
int const zoomI = (zoom <= 4 ? 0 : (zoom >= 19.75 ? 63 : (int) ((zoom - 4) * 4)));
|
||||
urlPrefix[6] = MapsWithMe_Base64Char(zoomI);
|
||||
|
||||
MapsWithMe_LatLonToString(lat, lon, urlPrefix + 7, 9);
|
||||
|
||||
MapsWithMe_AppendString(buf, bufSize, &fullUrlSize, urlPrefix, 16);
|
||||
|
||||
if (name != 0 && name[0] != 0)
|
||||
{
|
||||
MapsWithMe_AppendString(buf, bufSize, &fullUrlSize, "/", 1);
|
||||
|
||||
char * encName;
|
||||
int const encNameSize = MapsWithMe_UrlEncodeString(name, strlen(name), &encName);
|
||||
|
||||
MapsWithMe_AppendString(buf, bufSize, &fullUrlSize, encName, encNameSize);
|
||||
|
||||
free(encName);
|
||||
}
|
||||
|
||||
return fullUrlSize;
|
||||
}
|
||||
|
|
|
@ -249,5 +249,179 @@ FCT_BGN()
|
|||
fct_chk((max2 - min2) * 1.0 / max2 < 0.05);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_SmokeTest)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, "Name", buf, 100);
|
||||
fct_chk_eq_str("ge0://8wAAAAAAAA/Name", buf);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_NameIsNull)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, 0, buf, 100);
|
||||
fct_chk_eq_str("ge0://8wAAAAAAAA", buf);
|
||||
fct_chk_eq_int(16, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_NameIsEmpty)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, "", buf, 100);
|
||||
fct_chk_eq_str("ge0://8wAAAAAAAA", buf);
|
||||
fct_chk_eq_int(16, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_ZoomVerySmall)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 2, "Name", buf, 100);
|
||||
fct_chk_eq_str("ge0://AwAAAAAAAA/Name", buf);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_ZoomNegative)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, -5, "Name", buf, 100);
|
||||
fct_chk_eq_str("ge0://AwAAAAAAAA/Name", buf);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_ZoomLarge)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 20, "Name", buf, 100);
|
||||
fct_chk_eq_str("ge0://_wAAAAAAAA/Name", buf);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_ZoomVeryLarge)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 2000000000, "Name", buf, 100);
|
||||
fct_chk_eq_str("ge0://_wAAAAAAAA/Name", buf);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_FractionalZoom)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 8.25, "Name", buf, 100);
|
||||
fct_chk_eq_str("ge0://RwAAAAAAAA/Name", buf);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_FractionalZoomRoundsDown)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 8.499, "Name", buf, 100);
|
||||
fct_chk_eq_str("ge0://RwAAAAAAAA/Name", buf);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_FractionalZoomNextStep)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 8.5, "Name", buf, 100);
|
||||
fct_chk_eq_str("ge0://SwAAAAAAAA/Name", buf);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_SpaceIsReplacedWithUnderscore)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, "Hello World", buf, 100);
|
||||
fct_chk_eq_str("ge0://8wAAAAAAAA/Hello_World", buf);
|
||||
fct_chk_eq_int(28, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_NamesAreEscaped)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, "'Hello,World!%$", buf, 100);
|
||||
fct_chk_eq_str("ge0://8wAAAAAAAA/%27Hello%2CWorld%21%25%24", buf);
|
||||
fct_chk_eq_int(42, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_UnderscoreIsReplacedWith%20)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, "Hello_World", buf, 100);
|
||||
fct_chk_eq_str("ge0://8wAAAAAAAA/Hello%20World", buf);
|
||||
fct_chk_eq_int(30, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_ControlCharsAreEscaped)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, "Hello\tWorld\n", buf, 100);
|
||||
fct_chk_eq_str("ge0://8wAAAAAAAA/Hello%09World%0A", buf);
|
||||
fct_chk_eq_int(33, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_BufferNullAndEmpty)
|
||||
{
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, "Name", 0, 0);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_BufferNotNullAndEmpty)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, "Name", buf, 0);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_TerminatingNullIsNotWritten)
|
||||
{
|
||||
char buf[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, "Name", buf, 27);
|
||||
fct_chk_eq_str("ge0://8wAAAAAAAA/Namexxxxxx", buf);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_BufferIs1Byte)
|
||||
{
|
||||
char buf;
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, "Name", &buf, 1);
|
||||
fct_chk_eq_int('g', buf);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
FCT_QTEST_BGN(MapsWithMe_GenShortShowMapUrl_BufferTooSmall)
|
||||
{
|
||||
for (int bufSize = 1; bufSize <= 21; ++bufSize)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
int res = MapsWithMe_GenShortShowMapUrl(0, 0, 19, "Name", buf, bufSize);
|
||||
char expected[] = "ge0://8wAAAAAAAA/Name";
|
||||
expected[bufSize] = 0;
|
||||
fct_chk_eq_str(expected, buf);
|
||||
fct_chk_eq_int(21, res);
|
||||
}
|
||||
}
|
||||
FCT_QTEST_END();
|
||||
|
||||
}
|
||||
FCT_END();
|
||||
|
|
Loading…
Add table
Reference in a new issue