Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/api
diff options
context:
space:
mode:
authorYury Melnichek <melnichek@gmail.com>2013-03-21 02:28:22 +0400
committerAlex Zolotarev <alex@maps.me>2015-09-23 01:52:07 +0300
commit8446dd06829050ba5d8a0ebc12bf34e134ba9875 (patch)
tree50bfc181d484d59ee60860e3ae9662532ddde697 /api
parent3faba8bfece62e8903b5eef4996318b137255b45 (diff)
MapsWithMe_GenShortShowMapUrl
Diffstat (limited to 'api')
-rw-r--r--api/src/c/api-client.c111
-rw-r--r--api/tests/c/api-client-test.c174
2 files changed, 282 insertions, 3 deletions
diff --git a/api/src/c/api-client.c b/api/src/c/api-client.c
index 5045050c46..fc545ea3ba 100644
--- a/api/src/c/api-client.c
+++ b/api/src/c/api-client.c
@@ -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;
}
diff --git a/api/tests/c/api-client-test.c b/api/tests/c/api-client-test.c
index ba74e164c1..49c7960eef 100644
--- a/api/tests/c/api-client-test.c
+++ b/api/tests/c/api-client-test.c
@@ -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();