1381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* gzguts.h -- zlib internal header definitions for gz* operations 27291b8caf18844362881750df5cebd045d672c43Leon Scroggins III * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler 3381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes * For conditions of distribution and use, see copyright notice in zlib.h 4381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes */ 5381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 6381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#ifdef _LARGEFILE64_SOURCE 7381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# ifndef _LARGEFILE_SOURCE 8381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# define _LARGEFILE_SOURCE 1 9381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# endif 10381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# ifdef _FILE_OFFSET_BITS 11381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# undef _FILE_OFFSET_BITS 12381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# endif 13381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#endif 14381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 1509eb358bbbb9aad3fe48dd3368c8a7a481cbda1cElliott Hughes#ifdef HAVE_HIDDEN 16381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) 17381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#else 18381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# define ZLIB_INTERNAL 19381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#endif 20381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 21381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#include <stdio.h> 22381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#include "zlib.h" 23381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#ifdef STDC 24381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# include <string.h> 25381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# include <stdlib.h> 26381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# include <limits.h> 27381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#endif 287291b8caf18844362881750df5cebd045d672c43Leon Scroggins III 297291b8caf18844362881750df5cebd045d672c43Leon Scroggins III#ifndef _POSIX_SOURCE 307291b8caf18844362881750df5cebd045d672c43Leon Scroggins III# define _POSIX_SOURCE 317291b8caf18844362881750df5cebd045d672c43Leon Scroggins III#endif 32381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#include <fcntl.h> 33381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 3409eb358bbbb9aad3fe48dd3368c8a7a481cbda1cElliott Hughes#ifdef _WIN32 3509eb358bbbb9aad3fe48dd3368c8a7a481cbda1cElliott Hughes# include <stddef.h> 3609eb358bbbb9aad3fe48dd3368c8a7a481cbda1cElliott Hughes#endif 3709eb358bbbb9aad3fe48dd3368c8a7a481cbda1cElliott Hughes 3809eb358bbbb9aad3fe48dd3368c8a7a481cbda1cElliott Hughes#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) 39ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# include <io.h> 40ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#endif 41ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 427291b8caf18844362881750df5cebd045d672c43Leon Scroggins III#if defined(_WIN32) || defined(__CYGWIN__) 437291b8caf18844362881750df5cebd045d672c43Leon Scroggins III# define WIDECHAR 447291b8caf18844362881750df5cebd045d672c43Leon Scroggins III#endif 457291b8caf18844362881750df5cebd045d672c43Leon Scroggins III 4604351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes#ifdef WINAPI_FAMILY 4704351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes# define open _open 4804351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes# define read _read 4904351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes# define write _write 5004351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes# define close _close 5104351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes#endif 5204351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes 53381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#ifdef NO_DEFLATE /* for compatibility with old definition */ 54381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# define NO_GZCOMPRESS 55381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#endif 56381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 57ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) 58ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# ifndef HAVE_VSNPRINTF 59ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define HAVE_VSNPRINTF 60ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 61ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#endif 62ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 63ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#if defined(__CYGWIN__) 64ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# ifndef HAVE_VSNPRINTF 65ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define HAVE_VSNPRINTF 66ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 67ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#endif 68ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 69ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) 70ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# ifndef HAVE_VSNPRINTF 71ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define HAVE_VSNPRINTF 72ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 73ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#endif 74ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 75ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#ifndef HAVE_VSNPRINTF 76ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# ifdef MSDOS 77ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), 7804351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes but for now we just assume it doesn't. */ 79ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define NO_vsnprintf 80ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 81ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# ifdef __TURBOC__ 82ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define NO_vsnprintf 83ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 84ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# ifdef WIN32 85ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ 86ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# if !defined(vsnprintf) && !defined(NO_vsnprintf) 87ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) 88ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define vsnprintf _vsnprintf 89ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 90ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 91ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 92ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# ifdef __SASC 93ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define NO_vsnprintf 94ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 95ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# ifdef VMS 96ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define NO_vsnprintf 97ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 98ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# ifdef __OS400__ 99ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define NO_vsnprintf 100ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 101ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# ifdef __MVS__ 102ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define NO_vsnprintf 103ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# endif 104381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#endif 105381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 1067291b8caf18844362881750df5cebd045d672c43Leon Scroggins III/* unlike snprintf (which is required in C99), _snprintf does not guarantee 1077291b8caf18844362881750df5cebd045d672c43Leon Scroggins III null termination of the result -- however this is only used in gzlib.c where 10804351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes the result is assured to fit in the space provided */ 1097291b8caf18844362881750df5cebd045d672c43Leon Scroggins III#if defined(_MSC_VER) && _MSC_VER < 1900 11004351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes# define snprintf _snprintf 11104351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes#endif 11204351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes 113381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#ifndef local 114381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# define local static 115381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#endif 1167291b8caf18844362881750df5cebd045d672c43Leon Scroggins III/* since "static" is used to mean two completely different things in C, we 1177291b8caf18844362881750df5cebd045d672c43Leon Scroggins III define "local" for the non-static meaning of "static", for readability 1187291b8caf18844362881750df5cebd045d672c43Leon Scroggins III (compile with -Dlocal if your debugger can't find static symbols) */ 119381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 120381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* gz* functions always use library allocation functions */ 121381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#ifndef STDC 122381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes extern voidp malloc OF((uInt size)); 123381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes extern void free OF((voidpf ptr)); 124381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#endif 125381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 126381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* get errno and strerror definition */ 127381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#if defined UNDER_CE 128381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# include <windows.h> 129381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# define zstrerror() gz_strwinerror((DWORD)GetLastError()) 130381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#else 13109eb358bbbb9aad3fe48dd3368c8a7a481cbda1cElliott Hughes# ifndef NO_STRERROR 132381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# include <errno.h> 133381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# define zstrerror() strerror(errno) 134381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# else 135381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# define zstrerror() "stdio error (consult errno)" 136381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# endif 137381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#endif 138381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 139381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* provide prototypes for these when building zlib without LFS */ 140381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 141381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); 142381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); 143381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); 144381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); 145381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#endif 146381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 147ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes/* default memLevel */ 148ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#if MAX_MEM_LEVEL >= 8 149ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define DEF_MEM_LEVEL 8 150ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#else 151ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes# define DEF_MEM_LEVEL MAX_MEM_LEVEL 152ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes#endif 153ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes 15404351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes/* default i/o buffer size -- double this for output when reading (this and 15504351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes twice this must be able to fit in an unsigned type) */ 156381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#define GZBUFSIZE 8192 157381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 158381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* gzip modes, also provide a little integrity check on the passed structure */ 159381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#define GZ_NONE 0 160381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#define GZ_READ 7247 161381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#define GZ_WRITE 31153 162381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ 163381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 164381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* values for gz_state how */ 165381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#define LOOK 0 /* look for a gzip header */ 166381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#define COPY 1 /* copy input directly */ 167381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#define GZIP 2 /* decompress a gzip stream */ 168381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 169381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* internal gzip file state data structure */ 170381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughestypedef struct { 171ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes /* exposed contents for gzgetc() macro */ 172ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes struct gzFile_s x; /* "x" for exposed */ 173ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes /* x.have: number of bytes available at x.next */ 174ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes /* x.next: next output data to deliver or write */ 175ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes /* x.pos: current position in uncompressed data */ 176381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes /* used for both reading and writing */ 177381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes int mode; /* see gzip modes above */ 178381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes int fd; /* file descriptor */ 179381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes char *path; /* path or fd for error messages */ 180381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes unsigned size; /* buffer size, zero if not allocated yet */ 181381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes unsigned want; /* requested buffer size, default is GZBUFSIZE */ 1827291b8caf18844362881750df5cebd045d672c43Leon Scroggins III unsigned char *in; /* input buffer (double-sized when writing) */ 183381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes unsigned char *out; /* output buffer (double-sized when reading) */ 184ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes int direct; /* 0 if processing gzip, 1 if transparent */ 185381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes /* just for reading */ 186381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes int how; /* 0: get header, 1: copy, 2: decompress */ 187ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes z_off64_t start; /* where the gzip data started, for rewinding */ 188ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes int eof; /* true if end of input file reached */ 189ee9e11d0d4e3361533860bf04896abb86a291bfbElliott Hughes int past; /* true if read requested past end */ 190381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes /* just for writing */ 191381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes int level; /* compression level */ 192381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes int strategy; /* compression strategy */ 193381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes /* seek request */ 194381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes z_off64_t skip; /* amount to skip (already rewound if backwards) */ 195381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes int seek; /* true if seek request pending */ 196381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes /* error information */ 197381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes int err; /* error code */ 198381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes char *msg; /* error message */ 199381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes /* zlib inflate or deflate stream */ 200381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes z_stream strm; /* stream structure in-place (not a pointer) */ 201381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes} gz_state; 202381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughestypedef gz_state FAR *gz_statep; 203381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 204381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* shared functions */ 205381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughesvoid ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); 206381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#if defined UNDER_CE 207381716e9396b55b1adb8235b020c37344f60ab07Elliott Hugheschar ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); 208381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#endif 209381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes 210381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t 211381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes value -- needed when comparing unsigned to z_off64_t, which is signed 212381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes (possible z_off64_t types off_t, off64_t, and long are all signed) */ 213381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#ifdef INT_MAX 214381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) 215381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#else 216381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughesunsigned ZLIB_INTERNAL gz_intmax OF((void)); 217381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) 218381716e9396b55b1adb8235b020c37344f60ab07Elliott Hughes#endif 219