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