-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsimple-raw.cpp
156 lines (149 loc) · 4.75 KB
/
simple-raw.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "simple-raw.h"
#include "lib-common.h"
#if defined(__linux__)
# include <arpa/inet.h>
# include <endian.h>
# define ntohll(x) be64toh(x)
# define htonll(x) htobe64(x)
#elif defined(__FreeBSD__) || defined(__NetBSD__)
# include <arpa/inet.h>
# include <sys/endian.h>
# define ntohll(x) be64toh(x)
# define htonll(x) htobe64(x)
#elif defined(__OpenBSD__)
# include <sys/types.h>
# define ntohll(x) betoh64(x)
# define htonll(x) htobe64(x)
#elif defined(__APPLE__)
# include <arpa/inet.h>
#elif defined(_WIN32) || defined(__CYGWIN__)
#define IS_LITTLE_ENDIAN (((struct { union { unsigned int x; unsigned char c; }}){1}).c)
#define LITTLE_ENDIAN 1234
#define BIG_ENDIAN 4321
#ifdef IS_LITTLE_ENDIAN
#define BYTE_ORDER LITTLE_ENDIAN
#else
#define BYTE_ORDER BIG_ENDIAN
#endif
# if BYTE_ORDER == LITTLE_ENDIAN
# define ntohs(x) _byteswap_ushort(x)
# define htons(x) _byteswap_ushort(x)
# define ntohl(x) _byteswap_ulong(x)
# define htonl(x) _byteswap_ulong(x)
# define ntohll(x) _byteswap_uint64(x)
# define htonll(x) _byteswap_uint64(x)
# else
# define ntohs(x) (x)
# define htons(x) (x)
# define ntohl(x) (x)
# define htonl(x) (x)
# define ntohll(x) (x)
# define htonll(x) (x)
# endif
#else
# warning "no 64-bits ntoh/hton byte operations"
#endif
#include <stdio.h>
#include <unistd.h>
[[nodiscard]] size_t SafeWrite(int fd, const char* ptr, size_t size) {
size_t retval = 0;
while (size > 0) {
//std::cerr << "SafeWrite: size=" << size << " retval=" << retval << std::endl;
#ifdef WIN32
auto bytes = write(fd, ptr, uint32_t(size));
#else
auto bytes = write(fd, ptr, size);
#endif
if (bytes == 0)
break;
if (bytes < 0) {
if (errno == EINTR)
continue;
break;
}
ptr += bytes;
size -= size_t(bytes);
retval += size_t(bytes);
}
//std::cerr << "SafeWrite: size=" << size << " retval=" << retval << std::endl;
return retval;
}
[[nodiscard]] std::pair<size_t,int> SafeRead(int fd, char* ptr, size_t size) {
size_t retval = 0;
while (size > 0) {
errno = 0;
//std::cerr << "SafeRead: size=" << size << " retval=" << retval << std::endl;
#ifdef WIN32
auto bytes = read(fd, ptr, uint32_t(size));
#else
auto bytes = read(fd, ptr, size);
#endif
if (bytes == 0)
break;
if (bytes < 0) {
if (errno == EINTR)
continue;
break;
}
ptr += bytes;
size -= size_t(bytes);
retval += size_t(bytes);
}
//std::cerr << "SafeRead: size=" << size << " retval=" << retval << std::endl;
return {retval, errno};
}
bool WriteBinary(int out, uint8_t number) {
return sizeof(number) == SafeWrite(out, reinterpret_cast<char*>(&number), sizeof(number));
}
bool WriteBinary(int out, uint32_t number) {
number = htonl(number);
return sizeof(number) == SafeWrite(out, reinterpret_cast<char*>(&number), sizeof(number));
}
bool WriteBinary(int out, uint64_t number) {
number = htonll(number);
return sizeof(number) == SafeWrite(out, reinterpret_cast<char*>(&number), sizeof(number));
}
bool WriteBinary(int out, const char* str, uint32_t length) {
if (!WriteBinary(out, uint32_t(length)))
return false;
return length == SafeWrite(out, str, length);
}
uint8_t ReadBinary(int in, uint8_t defaultValue, bool& good) {
uint8_t number = 0;
auto [bytes,err] = SafeRead(in, reinterpret_cast<char*>(&number), sizeof(number));
return (good = (good && err == 0 && bytes == sizeof(number))) ? number : defaultValue;
}
uint32_t ReadBinary(int in, uint32_t defaultValue, bool& good) {
uint32_t number = 0;
auto [bytes,err] = SafeRead(in, reinterpret_cast<char*>(&number), sizeof(number));
//std::cerr << "Read32: " << number << std::endl;
return (good = (good && err == 0 && bytes == sizeof(number))) ? ntohl(number) : defaultValue;
}
uint64_t ReadBinary(int in, uint64_t defaultValue, bool& good) {
uint64_t number = 0;
auto [bytes,err] = SafeRead(in, reinterpret_cast<char*>(&number), sizeof(number));
//std::cerr << "Read64 " << number << std::endl;
return (good = (good && err == 0 && bytes == sizeof(number))) ? ntohll(number) : defaultValue;
}
std::string ReadBinary(int in, const std::string& defaultValue, bool& good) {
uint32_t length = ReadBinary(in, uint32_t(0), good);
//std::cerr << "ReadString " << length << std::endl;
if (!good)
return defaultValue;
std::string retval (length, '\0');
auto [bytes,err] = SafeRead(in, retval.data(), length);
//std::cerr << "readBinary(String " << length << ") -> " << bytes << std::endl;
return (good = (good && err == 0 && bytes == length)) ? retval : defaultValue;
}
uint8_t ntoh(uint8_t n) {
return n;
}
uint16_t ntoh(uint16_t n) {
return OLD_STYLE_CAST(ntohs(n));
}
uint32_t ntoh(uint32_t n) {
return OLD_STYLE_CAST(ntohl(n));
}
uint64_t ntoh(uint64_t n) {
return OLD_STYLE_CAST(ntohll(n));
}