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