1 /*
2 HawkNL cross platform network library
3 Copyright (C) 2000-2002 Phil Frisbie, Jr. (phil@hawksoft.com)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19
20 Or go to http://www.gnu.org/copyleft/lgpl.html
21 */
22
23 #ifndef NL_H
24 #define NL_H
25
26 #include <string.h> /* for strcpy, strlen, and memcpy in macros */
27
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31
32 #define NL_MAJOR_VERSION 1
33 #define NL_MINOR_VERSION 68
34 #define NL_VERSION_STRING "HawkNL 1.68"
35
36 /* define NL_SAFE_COPY for Sparc and other processors that do not allow non-aligned
37 memory access. Needed for read* and write* macros */
38 /* Always defined, because of Android */
39 #define NL_SAFE_COPY
40
41 /* undefine this to remove IPX code, Windows only */
42 // #define NL_INCLUDE_IPX
43
44 /* undefine this to remove loopback code */
45 #define NL_INCLUDE_LOOPBACK
46
47 /* undefine this to remove serial code */
48 #define NL_INCLUDE_SERIAL
49
50 /* undefine this to remove modem code */
51 #define NL_INCLUDE_MODEM
52
53 /* undefine this to remove parallel code */
54 #define NL_INCLUDE_PARALLEL
55
56 #if defined (WIN32) || defined (WIN64) || defined (_WIN32_WCE)
57 #define WINDOWS_APP
58 #endif
59
60 /* use native Windows threads and remove IPX support for WinCE */
61 /* also, many CE devices will not allow non-aligned memory access */
62 #if defined (_WIN32_WCE)
63 #define NL_WIN_THREADS
64 #undef NL_INCLUDE_IPX
65 #endif
66
67 #ifdef WINDOWS_APP
68 /* define NL_WIN_THREADS to use native Windows threads instead of pthreads */
69 #define NL_WIN_THREADS
70 #ifdef _MSC_VER
71 #pragma warning (disable:4514) /* disable "unreferenced inline function has been removed" warning */
72 #endif /* _MSC_VER */
73 /* The default build for Windows is as a DLL. */
74 /* If you want a static library, define WIN_STATIC_LIB. */
75 #ifdef WIN_STATIC_LIB
76 #define NL_EXP
77 #else
78 #if defined (__LCC__)
79 #define NL_EXP extern
80 #else
81 #define NL_EXP __declspec(dllexport)
82 #endif /* __LCC__ */
83 #endif /* WIN_STATIC_LIB */
84 #define NL_APIENTRY __stdcall
85 #define NL_CALLBACK __cdecl
86 #ifdef __GNUC__
87 #ifdef __MINGW32__
88 #define NL_INLINE static inline
89 #else
90 #define NL_INLINE extern __inline__
91 #endif
92 #else
93 #define NL_INLINE __inline
94 #endif /* __GNUC__ */
95 #else /* !WINDOWS_APP */
96 #define NL_EXP extern
97 #define NL_APIENTRY
98 #define NL_CALLBACK
99 #ifdef __GNUC__
100 #define NL_INLINE extern __inline__
101 #else
102 #define NL_INLINE inline /* assuming C99 compliant compiler */
103 #endif /* __GNUC__ */
104 #endif /* !WINDOWS_APP */
105
106 /* Any more needed here? */
107 #if defined WIN32 || defined WIN64 || defined __i386__ || defined __alpha__ || defined __mips__
108 #define NL_LITTLE_ENDIAN
109 #else
110 #define NL_BIG_ENDIAN
111 #endif
112
113 /* How do we detect Solaris 64 and Linux 64 bit? */
114 #if defined WIN64
115 #define IS_64_BIT
116 #endif
117
118 /* 8 bit */
119 typedef char NLbyte;
120 typedef unsigned char NLubyte;
121 typedef unsigned char NLboolean;
122 /* 16 bit */
123 typedef short NLshort;
124 typedef unsigned short NLushort;
125 /* 32 bit */
126 typedef float NLfloat;
127 #ifdef IS_64_BIT
128 typedef int NLlong; /* Longs are 64 bit on a 64 bit CPU, but integers are still 32 bit. */
129 typedef unsigned int NLulong; /* This is, of course, not true on Windows (yet another exception), */
130 /* but it does not hurt. */
131 #else
132 typedef long NLlong;
133 typedef unsigned long NLulong;
134 #endif
135 /* 64 bit */
136 typedef double NLdouble;
137 /* multithread */
138 typedef void *(*NLThreadFunc)(void *data);
139 typedef void *NLthreadID;
140 typedef struct nl_mutex_t *NLmutex;
141 typedef struct nl_cond_t *NLcond;
142 /* misc. */
143 typedef int NLint;
144 typedef unsigned int NLuint;
145 typedef unsigned long NLenum;
146 typedef void NLvoid;
147 typedef NLlong NLsocket;
148 /* NOTE: NLchar is only to be used for external strings
149 that might be unicode */
150 #if defined _UNICODE
151 typedef wchar_t NLchar;
152 #else
153 typedef char NLchar;
154 #endif
155
156 typedef struct _NLaddress
157 {
158 NLubyte addr[56]; /* large enough to hold IPv6 address = strlen("[ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:192.168.158.190]:12345") */
159 NLenum driver; /* driver type, not used yet */
160 NLboolean valid; /* set to NL_TRUE when address is valid */
161 } NLaddress;
162
163 /* for backwards compatability */
164 #if !defined(address_t)
165 typedef struct _NLaddress address_t;
166 #endif
167
168 typedef struct _NLtime
169 {
170 NLlong seconds; /* seconds since 12:00AM, 1 January, 1970 */
171 NLlong mseconds; /* milliseconds added to the seconds */
172 NLlong useconds; /* microseconds added to the seconds */
173 } NLtime;
174
175 /* max string size limited to 256 (255 plus NULL termination) for MacOS */
176 #define NL_MAX_STRING_LENGTH 256
177
178 /* max packet size for NL_UNRELIABLE and NL_RELIABLE_PACKETS */
179 #define NL_MAX_PACKET_LENGTH 16384
180
181 /* max number groups and sockets per group */
182 #define NL_MAX_GROUPS 128
183 #if defined (macintosh)
184 /* WARNING: Macs only allow up to 32K of local data, don't exceed 4096 */
185 /* Does NOT apply to Mac OSX */
186 #define NL_MAX_GROUP_SOCKETS 4096
187 #else
188 /* max number of sockets per group NL will handle */
189 #define NL_MAX_GROUP_SOCKETS 8192
190 #endif
191
192 #define NL_INVALID (-1)
193
194 /* Boolean values */
195 #define NL_FALSE ((NLboolean)(0))
196 #define NL_TRUE ((NLboolean)(1))
197
198 /* Network types */
199 /* Only one can be selected at a time */
200 #define NL_IP 0x0003 /* ipv6+ipv4 dual-stack socket */
201 //#define NL_IPV6 0x0004 /* not yet implemented, IPv6 address family */
202 #define NL_LOOP_BACK 0x0005 /* all platforms, for single player client/server emulation with no network */
203 #define NL_IPX 0x0006 /* Windows only */
204 #define NL_SERIAL 0x0007 /* not yet implemented, Windows and Linux only? */
205 #define NL_MODEM 0x0008 /* not yet implemented, Windows and Linux only? */
206 #define NL_PARALLEL 0x0009 /* not yet implemented, Windows and Linux only? */
207
208 /* Connection types */
209 #define NL_RELIABLE 0x0010 /* NL_IP (TCP), NL_IPX (SPX), NL_LOOP_BACK */
210 #define NL_UNRELIABLE 0x0011 /* NL_IP (UDP), NL_IPX, NL_LOOP_BACK */
211 #define NL_RELIABLE_PACKETS 0x0012 /* NL_IP (TCP), NL_IPX (SPX), NL_LOOP_BACK */
212 #define NL_BROADCAST 0x0013 /* NL_IP (UDP), NL_IPX, or NL_LOOP_BACK broadcast packets */
213 #define NL_UDP_MULTICAST 0x0014 /* NL_IP (UDP) multicast */
214 #define NL_RAW 0x0015 /* NL_SERIAL or NL_PARALLEL */
215 /* TCP/IP specific aliases for connection types */
216 #define NL_TCP NL_RELIABLE
217 #define NL_TCP_PACKETS NL_RELIABLE_PACKETS
218 #define NL_UDP NL_UNRELIABLE
219 #define NL_UDP_BROADCAST NL_BROADCAST
220 /* for backwards compatability */
221 #define NL_MULTICAST NL_UDP_MULTICAST
222
223 /* nlGetString */
224 #define NL_VERSION 0x0020 /* the version string */
225 #define NL_NETWORK_TYPES 0x0021 /* space delimited list of available network types */
226 #define NL_CONNECTION_TYPES 0x0022 /* space delimited list of available connection types */
227 /* only valid AFTER nlSelectNetwork */
228
229 /* nlGetInteger, nlGetSocketStat, nlClear */
230 #define NL_PACKETS_SENT 0x0030 /* total packets sent since last nlClear */
231 #define NL_BYTES_SENT 0x0031 /* total bytes sent since last nlClear */
232 #define NL_AVE_BYTES_SENT 0x0032 /* average bytes sent per second for the last 8 seconds */
233 #define NL_HIGH_BYTES_SENT 0x0033 /* highest bytes per second ever sent */
234 #define NL_PACKETS_RECEIVED 0x0034 /* total packets received since last nlClear */
235 #define NL_BYTES_RECEIVED 0x0035 /* total bytes received since last nlClear */
236 #define NL_AVE_BYTES_RECEIVED 0x0036 /* average bytes received per second for the last 8 seconds */
237 #define NL_HIGH_BYTES_RECEIVED 0x0037 /* highest bytes per second ever received */
238 #define NL_ALL_STATS 0x0038 /* nlClear only, clears out all counters */
239 #define NL_OPEN_SOCKETS 0x0039 /* number of open sockets */
240
241 /* nlEnable, nlDisable */
242 #define NL_BLOCKING_IO 0x0040 /* set IO to blocking, default is NL_FALSE for non-blocking IO */
243 #define NL_SOCKET_STATS 0x0041 /* enable collection of socket read/write statistics, default disabled */
244 #define NL_BIG_ENDIAN_DATA 0x0042 /* enable big endian data for nlSwap* and read/write macros, default enabled */
245 #define NL_LITTLE_ENDIAN_DATA 0x0043 /* enable little endian data for nlSwap* and read/write macros, default disabled */
246 #define NL_MULTIPLE_DRIVERS 0x0044 /* enable multiple drivers to be selected */
247
248 /* nlPollGroup */
249 #define NL_READ_STATUS 0x0050 /* poll the read status for all sockets in the group */
250 #define NL_WRITE_STATUS 0x0051 /* poll the write status for all sockets in the group */
251 #define NL_ERROR_STATUS 0x0052 /* poll the error status for all sockets in the group */
252
253 /* nlHint, advanced network settings for experienced developers */
254 #define NL_LISTEN_BACKLOG 0x0060 /* TCP, SPX: the backlog of connections for listen */
255 #define NL_MULTICAST_TTL 0x0061 /* UDP : The multicast TTL value. Default : 1 */
256 #define NL_REUSE_ADDRESS 0x0062 /* TCP, UDP : Allow IP address to be reused. Default : NL_FALSE */
257 #define NL_TCP_NO_DELAY 0x0063 /* TCP : disable Nagle algorithm, arg != 0 to disable, 0 to enable */
258
259 /* errors */
260 #define NL_NO_ERROR 0x0000 /* no error is stored */
261 #define NL_NO_NETWORK 0x0100 /* no network was found on init */
262 #define NL_OUT_OF_MEMORY 0x0101 /* out of memory */
263 #define NL_INVALID_ENUM 0x0102 /* function called with an invalid NLenum */
264 #define NL_INVALID_SOCKET 0x0103 /* socket is not valid, or has been terminated */
265 #define NL_INVALID_PORT 0x0104 /* the port could not be opened */
266 #define NL_INVALID_TYPE 0x0105 /* the network type is not available */
267 #define NL_SYSTEM_ERROR 0x0106 /* a system error occurred, call nlGetSystemError */
268 #define NL_SOCK_DISCONNECT 0x0107 /* the socket should be closed because of a connection loss or error */
269 #define NL_NOT_LISTEN 0x0108 /* the socket has not been set to listen */
270 #define NL_CON_REFUSED 0x0109 /* connection refused, or socket already connected */
271 #define NL_NO_PENDING 0x010a /* there are no pending connections to accept */
272 #define NL_BAD_ADDR 0x010b /* the address or port are not valid */
273 #define NL_MESSAGE_END 0x010c /* the end of a reliable stream (TCP) message has been reached */
274 #define NL_NULL_POINTER 0x010d /* a NULL pointer was passed to a function */
275 #define NL_INVALID_GROUP 0x010e /* the group is not valid, or has been destroyed */
276 #define NL_OUT_OF_GROUPS 0x010f /* out of internal group objects */
277 #define NL_OUT_OF_GROUP_SOCKETS 0x0110 /* the group has no more room for sockets */
278 #define NL_BUFFER_SIZE 0x0111 /* the buffer was too small to store the data, retry with a larger buffer */
279 #define NL_PACKET_SIZE 0x0112 /* the size of the packet exceeds NL_MAX_PACKET_LENGTH or the protocol max */
280 #define NL_WRONG_TYPE 0x0113 /* the function does not support the socket type */
281 #define NL_CON_PENDING 0x0114 /* a non-blocking connection is still pending */
282 #define NL_SELECT_NET_ERROR 0x0115 /* a network is already selected, and NL_MULTIPLE_DRIVERS is not enabled, call nlShutDown and nlInit first */
283 #define NL_PACKET_SYNC 0x0116 /* the NL_RELIABLE_PACKET stream is out of sync */
284 #define NL_TLS_ERROR 0x0117 /* thread local storage could not be created */
285 #define NL_TIMED_OUT 0x0118 /* the function timed out */
286 #define NL_SOCKET_NOT_FOUND 0x0119 /* the socket was not found in the group */
287 #define NL_STRING_OVER_RUN 0x011a /* the string is not null terminated, or is longer than NL_MAX_STRING_LENGTH */
288 #define NL_MUTEX_RECURSION 0x011b /* the mutex was recursivly locked */
289 #define NL_MUTEX_OWNER 0x011c /* the mutex is not owned by thread */
290 /* for backwards compatability */
291 #define NL_SOCKET_ERROR NL_SYSTEM_ERROR
292 #define NL_CON_TERM NL_SOCK_DISCONNECT
293
294 /* standard multicast TTL settings as recommended by the */
295 /* white paper at http://www.ipmulticast.com/community/whitepapers/howipmcworks.html */
296 #define NL_TTL_LOCAL 1 /* local LAN only */
297 #define NL_TTL_SITE 15 /* this site */
298 #define NL_TTL_REGION 63 /* this region */
299 #define NL_TTL_WORLD 127 /* the world */
300
301 /*
302
303 Low level API, a thin layer over Sockets or other network provider.
304
305 */
306
307 NL_EXP NLboolean NL_APIENTRY nlListen(NLsocket socket);
308
309 NL_EXP NLsocket NL_APIENTRY nlAcceptConnection(NLsocket socket);
310
311 NL_EXP NLsocket NL_APIENTRY nlOpen(NLushort port, NLenum type);
312
313 NL_EXP NLboolean NL_APIENTRY nlConnect(NLsocket socket, const NLaddress *address);
314
315 NL_EXP NLboolean NL_APIENTRY nlClose(NLsocket socket);
316
317 NL_EXP NLint NL_APIENTRY nlRead(NLsocket socket, /*@out@*/ NLvoid *buffer, NLint nbytes);
318
319 NL_EXP NLint NL_APIENTRY nlWrite(NLsocket socket, const NLvoid *buffer, NLint nbytes);
320
321 NL_EXP NLlong NL_APIENTRY nlGetSocketStat(NLsocket socket, NLenum name);
322
323 NL_EXP NLboolean NL_APIENTRY nlClearSocketStat(NLsocket socket, NLenum name);
324
325 NL_EXP NLint NL_APIENTRY nlPollGroup(NLint group, NLenum name, /*@out@*/ NLsocket *sockets, NLint number, NLint timeout);
326
327 NL_EXP NLboolean NL_APIENTRY nlHint(NLenum name, NLint arg);
328
329 /*
330
331 Address management API
332
333 */
334
335 NL_EXP /*@null@*/ NLchar* NL_APIENTRY nlAddrToString(const NLaddress *address, /*@returned@*/ /*@out@*/ NLchar *string);
336
337 NL_EXP NLboolean NL_APIENTRY nlStringToAddr(const NLchar *string, /*@out@*/ NLaddress *address);
338
339 NL_EXP NLboolean NL_APIENTRY nlGetRemoteAddr(NLsocket socket, /*@out@*/ NLaddress *address);
340
341 NL_EXP NLboolean NL_APIENTRY nlSetRemoteAddr(NLsocket socket, const NLaddress *address);
342
343 NL_EXP NLboolean NL_APIENTRY nlGetLocalAddr(NLsocket socket, /*@out@*/ NLaddress *address);
344
345 NL_EXP NLboolean NL_APIENTRY nlSetLocalAddr(const NLaddress *address);
346
347 NL_EXP NLboolean NL_APIENTRY nlAddrCompare(const NLaddress *address1, const NLaddress *address2);
348
349 NL_EXP NLushort NL_APIENTRY nlGetPortFromAddr(const NLaddress *address);
350
351 NL_EXP NLboolean NL_APIENTRY nlSetAddrPort(NLaddress *address, NLushort port);
352
353
354 /*
355
356 Group management API
357
358 */
359
360 NL_EXP NLint NL_APIENTRY nlGroupCreate(void);
361
362 NL_EXP NLboolean NL_APIENTRY nlGroupDestroy(NLint group);
363
364 NL_EXP NLboolean NL_APIENTRY nlGroupAddSocket(NLint group, NLsocket socket);
365
366 NL_EXP NLboolean NL_APIENTRY nlGroupGetSockets(NLint group, /*@out@*/ NLsocket *sockets, /*@in@*/ NLint *number);
367
368 NL_EXP NLboolean NL_APIENTRY nlGroupDeleteSocket(NLint group, NLsocket socket);
369
370 /*
371
372 Multithreading API
373
374 */
375
376 NL_EXP NLthreadID NL_APIENTRY nlThreadCreate(NLThreadFunc func, void *data, NLboolean joinable);
377
378 NL_EXP void NL_APIENTRY nlThreadYield(void);
379
380 NL_EXP NLboolean NL_APIENTRY nlThreadJoin(NLthreadID threadID, void **status);
381
382 NL_EXP NLboolean NL_APIENTRY nlMutexInit(NLmutex *mutex);
383
384 NL_EXP NLboolean NL_APIENTRY nlMutexLock(NLmutex *mutex);
385
386 NL_EXP NLboolean NL_APIENTRY nlMutexUnlock(NLmutex *mutex);
387
388 NL_EXP NLboolean NL_APIENTRY nlMutexDestroy(NLmutex *mutex);
389
390 NL_EXP NLboolean NL_APIENTRY nlCondInit(NLcond *cond);
391
392 NL_EXP NLboolean NL_APIENTRY nlCondWait(NLcond *cond, NLint timeout);
393
394 NL_EXP NLboolean NL_APIENTRY nlCondSignal(NLcond *cond);
395
396 NL_EXP NLboolean NL_APIENTRY nlCondBroadcast(NLcond *cond);
397
398 NL_EXP NLboolean NL_APIENTRY nlCondDestroy(NLcond *cond);
399
400 /*
401
402 Time API
403
404 */
405
406 NL_EXP NLboolean NL_APIENTRY nlTime(NLtime *ts);
407
408 /*
409
410 Misc. API
411
412 */
413
414 NL_EXP NLboolean NL_APIENTRY nlInit(void);
415
416 NL_EXP void NL_APIENTRY nlShutdown(void);
417
418 NL_EXP NLboolean NL_APIENTRY nlSelectNetwork(NLenum network);
419
420 NL_EXP const /*@observer@*//*@null@*/ NLchar* NL_APIENTRY nlGetString(NLenum name);
421
422 NL_EXP NLlong NL_APIENTRY nlGetInteger(NLenum name);
423
424 NL_EXP NLboolean NL_APIENTRY nlGetBoolean(NLenum name);
425
426 NL_EXP NLboolean NL_APIENTRY nlClear(NLenum name);
427
428 NL_EXP NLenum NL_APIENTRY nlGetError(void);
429
430 NL_EXP const /*@observer@*/ NLchar* NL_APIENTRY nlGetErrorStr(NLenum err);
431
432 NL_EXP NLint NL_APIENTRY nlGetSystemError(void);
433
434 NL_EXP const /*@observer@*/ NLchar* NL_APIENTRY nlGetSystemErrorStr(NLint err);
435
436 NL_EXP NLboolean NL_APIENTRY nlEnable(NLenum name);
437
438 NL_EXP NLboolean NL_APIENTRY nlDisable(NLenum name);
439
440 NL_EXP NLushort NL_APIENTRY nlGetCRC16(NLubyte *data, NLint len);
441
442 NL_EXP NLulong NL_APIENTRY nlGetCRC32(NLubyte *data, NLint len);
443
444 NL_EXP NLushort NL_APIENTRY nlSwaps(NLushort x);
445
446 NL_EXP NLulong NL_APIENTRY nlSwapl(NLulong x);
447
448 NL_EXP NLfloat NL_APIENTRY nlSwapf(NLfloat f);
449
450 NL_EXP NLdouble NL_APIENTRY nlSwapd(NLdouble d);
451
452
453 /* macros for writing/reading packet buffers */
454 /* NOTE: these also endian swap the data as needed */
455 /* write* or read* (buffer *, count, data [, length]) */
456
457 #ifdef NL_SAFE_COPY
458 #define writeShort(x, y, z) {NLushort nl_temps = nlSwaps(z); memcpy((char *)&x[y], (char *)&nl_temps, 2); y += 2;}
459 #define writeLong(x, y, z) {NLulong nl_templ = nlSwapl(z); memcpy((char *)&x[y], (char *)&nl_templ, 4); y += 4;}
460 #define writeFloat(x, y, z) {NLfloat nl_tempf = nlSwapf(z); memcpy((char *)&x[y], (char *)&nl_tempf, 4); y += 4;}
461 #define writeDouble(x, y, z) {NLdouble nl_tempd = nlSwapd(z); memcpy((char *)&x[y], (char *)&nl_tempd, 8); y += 8;}
462 #define readShort(x, y, z) {memcpy((char *)&z, (char *)&x[y], 2); z = nlSwaps(z); y += 2;}
463 #define readLong(x, y, z) {memcpy((char *)&z, (char *)&x[y], 4); z = nlSwapl(z); y += 4;}
464 #define readFloat(x, y, z) {memcpy((char *)&z, (char *)&x[y], 4); z = nlSwapf(z); y += 4;}
465 #define readDouble(x, y, z) {memcpy((char *)&z, (char *)&x[y], 8); z = nlSwapd(z); y += 8;}
466
467 #else /* !NL_SAFE_COPY */
468 #define writeShort(x, y, z) {*((NLushort *)((NLbyte *)&x[y])) = nlSwaps(z); y += 2;}
469 #define writeLong(x, y, z) {*((NLulong *)((NLbyte *)&x[y])) = nlSwapl(z); y += 4;}
470 #define writeFloat(x, y, z) {*((NLfloat *)((NLbyte *)&x[y])) = nlSwapf(z); y += 4;}
471 #define writeDouble(x, y, z) {*((NLdouble *)((NLbyte *)&x[y])) = nlSwapd(z); y += 8;}
472 #define readShort(x, y, z) {z = nlSwaps(*(NLushort *)((NLbyte *)&x[y])); y += 2;}
473 #define readLong(x, y, z) {z = nlSwapl(*(NLulong *)((NLbyte *)&x[y])); y += 4;}
474 #define readFloat(x, y, z) {z = nlSwapf(*(NLfloat *)((NLbyte *)&x[y])); y += 4;}
475 #define readDouble(x, y, z) {z = nlSwapd(*(NLdouble *)((NLbyte *)&x[y])); y += 8;}
476 #endif /* !NL_SAFE_COPY */
477
478 #define writeByte(x, y, z) (*(NLbyte *)&x[y++] = (NLbyte)z)
479 #define writeBlock(x, y, z, a) {memcpy((char *)&x[y], (char *)z, a);y += a;}
480 #define readByte(x, y, z) (z = *(NLbyte *)&x[y++])
481 #define readBlock(x, y, z, a) {memcpy((char *)z, (char *)&x[y], a);y += a;}
482
483 #ifdef _UNICODE
484 #include <stdlib.h>
485
486 #define writeString(x, y, z) writeStringWC(x, &y, z)
487 #define readString(x, y, z) readStringWC(x, &y, z)
488
writeStringWC(NLbyte * x,NLint * y,NLchar * z)489 NL_INLINE void writeStringWC(NLbyte *x, NLint *y, NLchar *z)
490 {
491 int len = (int)wcstombs(&x[*y], z, (size_t)NL_MAX_STRING_LENGTH);
492
493 if(len == NL_MAX_STRING_LENGTH)
494 {
495 /* must null terminate string */
496 x[*y + NL_MAX_STRING_LENGTH] = '\0';
497 *y += NL_MAX_STRING_LENGTH;
498 }
499 else if(len > 0)
500 {
501 *y += (len + 1);
502 }
503 else
504 {
505 /* there was an error in wcstombs, so just add a 0 length string to the buffer */
506 x[*y] = '\0';
507 *y++;
508 }
509 }
510
readStringWC(NLbyte * x,NLint * y,NLchar * z)511 NL_INLINE void readStringWC(NLbyte *x, NLint *y, NLchar *z)
512 {
513 int len = (int)mbstowcs(z, &x[*y], (size_t)NL_MAX_STRING_LENGTH);
514
515 if(len == NL_MAX_STRING_LENGTH)
516 {
517 /* must null terminate string */
518 z[NL_MAX_STRING_LENGTH] = L'\0';
519 }
520 else if(len < 0)
521 {
522 /* must null terminate string */
523 z[0] = L'\0';
524 }
525 *y += (strlen((char *)&x[*y]) + 1);
526 }
527
528 #else /* !_UNICODE */
529 #define writeString(x, y, z) {strcpy((char *)&x[y], (char *)z); y += (strlen((char *)z) + 1);}
530 #define readString(x, y, z) {strcpy((char *)z, (char *)&x[y]); y += (strlen((char *)z) + 1);}
531 #endif /* !_UNICODE */
532
533 #ifdef __cplusplus
534 } /* extern "C" */
535 #endif
536
537 #endif /* NL_H */
538
539