File indexing completed on 2025-02-02 04:25:58
0001 /* Copyright 2015 the unarr project authors (see AUTHORS file). 0002 License: LGPLv3 */ 0003 0004 #include "unarr-imp.h" 0005 #ifdef WIN32 0006 #define COBJMACROS 0007 #include <Objidl.h> 0008 #include <Unknwn.h> 0009 #endif 0010 0011 ar_stream *ar_open_stream(void *data, ar_stream_close_fn close, ar_stream_read_fn read, ar_stream_seek_fn seek, ar_stream_tell_fn tell) 0012 { 0013 ar_stream *stream = malloc(sizeof(ar_stream)); 0014 if (!stream) { 0015 close(data); 0016 return NULL; 0017 } 0018 stream->data = data; 0019 stream->close = close; 0020 stream->read = read; 0021 stream->seek = seek; 0022 stream->tell = tell; 0023 return stream; 0024 } 0025 0026 void ar_close(ar_stream *stream) 0027 { 0028 if (stream) 0029 stream->close(stream->data); 0030 free(stream); 0031 } 0032 0033 size_t ar_read(ar_stream *stream, void *buffer, size_t count) 0034 { 0035 return stream->read(stream->data, buffer, count); 0036 } 0037 0038 bool ar_seek(ar_stream *stream, off64_t offset, int origin) 0039 { 0040 return stream->seek(stream->data, offset, origin); 0041 } 0042 0043 bool ar_skip(ar_stream *stream, off64_t count) 0044 { 0045 return stream->seek(stream->data, count, SEEK_CUR); 0046 } 0047 0048 off64_t ar_tell(ar_stream *stream) 0049 { 0050 return stream->tell(stream->data); 0051 } 0052 0053 /***** stream based on FILE *****/ 0054 0055 static void file_close(void *data) 0056 { 0057 fclose(data); 0058 } 0059 0060 static size_t file_read(void *data, void *buffer, size_t count) 0061 { 0062 return fread(buffer, 1, count, data); 0063 } 0064 0065 static bool file_seek(void *data, off64_t offset, int origin) 0066 { 0067 #ifdef _MSC_VER 0068 return _fseeki64(data, offset, origin) == 0; 0069 #else 0070 #if _POSIX_C_SOURCE >= 200112L 0071 if (sizeof(off_t) == 8) 0072 return fseeko(data, offset, origin) == 0; 0073 #endif 0074 if (offset > INT32_MAX || offset < INT32_MIN) 0075 return false; 0076 return fseek(data, (long)offset, origin) == 0; 0077 #endif 0078 } 0079 0080 static off64_t file_tell(void *data) 0081 { 0082 #ifdef _MSC_VER 0083 return _ftelli64(data); 0084 #elif _POSIX_C_SOURCE >= 200112L 0085 return ftello(data); 0086 #else 0087 return ftell(data); 0088 #endif 0089 } 0090 0091 ar_stream *ar_open_file(const char *path) 0092 { 0093 FILE *f = path ? fopen(path, "rb") : NULL; 0094 if (!f) 0095 return NULL; 0096 return ar_open_stream(f, file_close, file_read, file_seek, file_tell); 0097 } 0098 0099 #ifdef _WIN32 0100 ar_stream *ar_open_file_w(const wchar_t *path) 0101 { 0102 FILE *f = path ? _wfopen(path, L"rb") : NULL; 0103 if (!f) 0104 return NULL; 0105 return ar_open_stream(f, file_close, file_read, file_seek, file_tell); 0106 } 0107 #endif 0108 0109 /***** stream based on preallocated memory *****/ 0110 0111 struct MemoryStream { 0112 const uint8_t *data; 0113 size_t length; 0114 size_t offset; 0115 }; 0116 0117 static void memory_close(void *data) 0118 { 0119 struct MemoryStream *stm = data; 0120 free(stm); 0121 } 0122 0123 static size_t memory_read(void *data, void *buffer, size_t count) 0124 { 0125 struct MemoryStream *stm = data; 0126 if (count > stm->length - stm->offset) 0127 count = stm->length - stm->offset; 0128 memcpy(buffer, stm->data + stm->offset, count); 0129 stm->offset += count; 0130 return count; 0131 } 0132 0133 static bool memory_seek(void *data, off64_t offset, int origin) 0134 { 0135 struct MemoryStream *stm = data; 0136 if (origin == SEEK_CUR) 0137 offset += stm->offset; 0138 else if (origin == SEEK_END) 0139 offset += stm->length; 0140 if (offset < 0 || offset > (off64_t)stm->length || (size_t)offset > stm->length) 0141 return false; 0142 stm->offset = (size_t)offset; 0143 return true; 0144 } 0145 0146 static off64_t memory_tell(void *data) 0147 { 0148 struct MemoryStream *stm = data; 0149 return stm->offset; 0150 } 0151 0152 ar_stream *ar_open_memory(const void *data, size_t datalen) 0153 { 0154 struct MemoryStream *stm = malloc(sizeof(struct MemoryStream)); 0155 if (!stm) 0156 return NULL; 0157 stm->data = data; 0158 stm->length = datalen; 0159 stm->offset = 0; 0160 return ar_open_stream(stm, memory_close, memory_read, memory_seek, memory_tell); 0161 } 0162 0163 #ifdef _WIN32 0164 /***** stream based on IStream *****/ 0165 0166 #define COBJMACROS 0167 #include <windows.h> 0168 0169 static void stream_close(void *data) 0170 { 0171 IUnknown_Release((IStream *)data); 0172 } 0173 0174 static size_t stream_read(void *data, void *buffer, size_t count) 0175 { 0176 size_t read = 0; 0177 HRESULT res; 0178 ULONG cbRead; 0179 #ifdef _WIN64 0180 while (count > ULONG_MAX) { 0181 res = IStream_Read((IStream *)data, buffer, ULONG_MAX, &cbRead); 0182 if (FAILED(res)) 0183 return read; 0184 read += cbRead; 0185 buffer = (BYTE *)buffer + ULONG_MAX; 0186 count -= ULONG_MAX; 0187 } 0188 #endif 0189 res = IStream_Read((IStream *)data, buffer, (ULONG)count, &cbRead); 0190 if (SUCCEEDED(res)) 0191 read += cbRead; 0192 return read; 0193 } 0194 0195 static bool stream_seek(void *data, off64_t offset, int origin) 0196 { 0197 LARGE_INTEGER off; 0198 ULARGE_INTEGER n; 0199 HRESULT res; 0200 off.QuadPart = offset; 0201 res = IStream_Seek((IStream *)data, off, origin, &n); 0202 return SUCCEEDED(res); 0203 } 0204 0205 static off64_t stream_tell(void *data) 0206 { 0207 LARGE_INTEGER zero = { 0 }; 0208 ULARGE_INTEGER n = { 0 }; 0209 IStream_Seek((IStream *)data, zero, SEEK_CUR, &n); 0210 return (off64_t)n.QuadPart; 0211 } 0212 0213 ar_stream *ar_open_istream(IStream *stream) 0214 { 0215 LARGE_INTEGER zero = { 0 }; 0216 HRESULT res = IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL); 0217 if (FAILED(res)) 0218 return NULL; 0219 IUnknown_AddRef(stream); 0220 return ar_open_stream(stream, stream_close, stream_read, stream_seek, stream_tell); 0221 } 0222 #endif