1 /*
2   Copyright (c) DataStax, Inc.
3 
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7 
8   http://www.apache.org/licenses/LICENSE-2.0
9 
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15 */
16 
17 #ifndef DATASTAX_ENTERPRISE_INTERNAL_SERIALIZATION_HPP
18 #define DATASTAX_ENTERPRISE_INTERNAL_SERIALIZATION_HPP
19 
20 #include "dse.h"
21 
22 #include "macros.hpp"
23 #include "serialization.hpp"
24 #include "vector.hpp"
25 
26 #include <assert.h>
27 #include <stdint.h>
28 #include <string.h>
29 
30 #define DSE_POINT_TYPE "org.apache.cassandra.db.marshal.PointType"
31 #define DSE_LINE_STRING_TYPE "org.apache.cassandra.db.marshal.LineStringType"
32 #define DSE_POLYGON_TYPE "org.apache.cassandra.db.marshal.PolygonType"
33 #define DSE_DATE_RANGE_TYPE "org.apache.cassandra.db.marshal.DateRangeType"
34 
35 #define WKB_HEADER_SIZE (sizeof(cass_uint8_t) + sizeof(cass_uint32_t))        // Endian + Type
36 #define WKB_POLYGON_HEADER_SIZE (WKB_HEADER_SIZE + sizeof(cass_uint32_t))     // Header + Num rings
37 #define WKB_LINE_STRING_HEADER_SIZE (WKB_HEADER_SIZE + sizeof(cass_uint32_t)) // Header + Num points
38 
39 namespace datastax { namespace internal { namespace enterprise {
40 
41 enum DateRangeBoundType {
42   DATE_RANGE_BOUND_TYPE_SINGLE_DATE = 0,
43   DATE_RANGE_BOUND_TYPE_CLOSED_RANGE = 1,
44   DATE_RANGE_BOUND_TYPE_OPEN_RANGE_HIGH = 2,
45   DATE_RANGE_BOUND_TYPE_OPEN_RANGE_LOW = 3,
46   DATE_RANGE_BOUND_TYPE_BOTH_OPEN_RANGE = 4,
47   DATE_RANGE_BOUND_TYPE_SINGLE_DATE_OPEN = 5
48 };
49 
50 enum WkbGeometryType {
51   WKB_GEOMETRY_TYPE_POINT = 1,
52   WKB_GEOMETRY_TYPE_LINESTRING = 2,
53   WKB_GEOMETRY_TYPE_POLYGON = 3,
54   WKB_GEOMETRY_TYPE_MULTIPOINT = 4,
55   WKB_GEOMETRY_TYPE_MULTILINESTRING = 5,
56   WKB_GEOMETRY_TYPE_MULTIPOLYGON = 6,
57   WKB_GEOMETRY_TYPE_GEOMETRYCOLLECTION = 7
58 };
59 
60 enum WkbByteOrder { WKB_BYTE_ORDER_BIG_ENDIAN = 0, WKB_BYTE_ORDER_LITTLE_ENDIAN = 1 };
61 
62 #if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || \
63     defined(__x86_64__) || defined(__amd64__)
native_byte_order()64 inline WkbByteOrder native_byte_order() { return WKB_BYTE_ORDER_LITTLE_ENDIAN; }
65 #elif defined(__BYTE_ORDER__)
native_byte_order()66 inline WkbByteOrder native_byte_order() {
67   return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? WKB_BYTE_ORDER_BIG_ENDIAN
68                                                 : WKB_BYTE_ORDER_LITTLE_ENDIAN;
69 }
70 #else
native_byte_order()71 inline WkbByteOrder native_byte_order() {
72   const uint32_t native_byte_order = 0x01020304;
73   return reinterpret_cast<const cass_uint8_t*>(&NATIVE_ORDER)[0] == 0x01
74              ? WKB_BYTE_ORDER_BIG_ENDIAN
75              : WKB_BYTE_ORDER_LITTLE_ENDIAN;
76 }
77 #endif
78 
79 typedef Vector<cass_byte_t> Bytes;
80 
81 #if defined(HAVE_BUILTIN_BSWAP32) && defined(HAVE_BUILTIN_BSWAP64)
swap_uint32(cass_uint32_t value)82 inline cass_uint32_t swap_uint32(cass_uint32_t value) { return __builtin_bswap32(value); }
83 
swap_uint64(cass_uint64_t value)84 inline cass_uint64_t swap_uint64(cass_uint64_t value) { return __builtin_bswap64(value); }
85 #elif defined(_MSC_VER)
swap_uint32(cass_uint32_t value)86 inline cass_uint32_t swap_uint32(cass_uint32_t value) {
87   STATIC_ASSERT(sizeof(cass_uint32_t) == sizeof(unsigned long));
88   return _byteswap_ulong(value);
89 }
90 
swap_uint64(cass_uint64_t value)91 inline cass_uint64_t swap_uint64(cass_uint64_t value) { return _byteswap_uint64(value); }
92 #else
swap_uint32(cass_uint32_t value)93 inline cass_uint32_t swap_uint32(cass_uint32_t value) {
94   value = ((value << 8) & 0xFF00FF00) | ((value >> 8) & 0xFF00FF);
95   return (value << 16) | (value >> 16);
96 }
97 
swap_uint64(cass_uint64_t value)98 inline cass_uint64_t swap_uint64(cass_uint64_t value) {
99   value = ((value << 8) & 0xFF00FF00FF00FF00ULL) | ((value >> 8) & 0x00FF00FF00FF00FFULL);
100   value = ((value << 16) & 0xFFFF0000FFFF0000ULL) | ((value >> 16) & 0x0000FFFF0000FFFFULL);
101   return (value << 32) | (value >> 32);
102 }
103 #endif
104 
105 template <class T>
encode(T value,size_t index,Bytes & bytes)106 inline void encode(T value, size_t index, Bytes& bytes) {
107   assert(bytes.size() >= index + sizeof(T));
108   memcpy(&bytes[index], &value, sizeof(T));
109 }
110 
111 template <class T>
encode_append(T value,Bytes & bytes)112 inline void encode_append(T value, Bytes& bytes) {
113   cass_uint8_t* data = reinterpret_cast<cass_uint8_t*>(&value);
114   for (size_t i = 0; i < sizeof(T); ++i) {
115     bytes.push_back(data[i]);
116   }
117 }
118 
encode_header_append(WkbGeometryType type,Bytes & bytes)119 inline void encode_header_append(WkbGeometryType type, Bytes& bytes) {
120   bytes.push_back(native_byte_order());
121   encode_append(static_cast<cass_uint32_t>(type), bytes);
122 }
123 
decode_double(const cass_byte_t * bytes,WkbByteOrder byte_order)124 inline cass_double_t decode_double(const cass_byte_t* bytes, WkbByteOrder byte_order) {
125   STATIC_ASSERT(sizeof(cass_double_t) == sizeof(cass_uint64_t));
126   cass_double_t value;
127   if (byte_order != native_byte_order()) {
128     cass_uint64_t temp;
129     memcpy(&temp, bytes, sizeof(cass_uint64_t));
130     swap_uint64(temp);
131     memcpy(&value, &temp, sizeof(cass_uint64_t));
132   } else {
133     memcpy(&value, bytes, sizeof(cass_uint64_t));
134   }
135   return value;
136 }
137 
decode_uint32(const cass_byte_t * bytes,WkbByteOrder byte_order)138 inline cass_uint32_t decode_uint32(const cass_byte_t* bytes, WkbByteOrder byte_order) {
139   cass_uint32_t value;
140   memcpy(&value, bytes, sizeof(cass_uint32_t));
141   if (byte_order != native_byte_order()) {
142     swap_uint32(value);
143   }
144   return value;
145 }
146 
decode_header(const cass_byte_t * bytes,WkbByteOrder * byte_order)147 inline WkbGeometryType decode_header(const cass_byte_t* bytes, WkbByteOrder* byte_order) {
148   *byte_order = static_cast<WkbByteOrder>(bytes[0]);
149   return static_cast<WkbGeometryType>(decode_uint32(bytes + 1, *byte_order));
150 }
151 
152 }}} // namespace datastax::internal::enterprise
153 
154 #endif
155