Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
stream.c
Go to the documentation of this file.
1 /* Copyright 2015 the unarr project authors (see AUTHORS file).
2  License: LGPLv3 */
3 
4 #include "unarr-imp.h"
5 
7 {
8  ar_stream *stream = malloc(sizeof(ar_stream));
9  if (!stream) {
10  close(data);
11  return NULL;
12  }
13  stream->data = data;
14  stream->close = close;
15  stream->read = read;
16  stream->seek = seek;
17  stream->tell = tell;
18  return stream;
19 }
20 
21 void ar_close(ar_stream *stream)
22 {
23  if (stream)
24  stream->close(stream->data);
25  free(stream);
26 }
27 
28 size_t ar_read(ar_stream *stream, void *buffer, size_t count)
29 {
30  return stream->read(stream->data, buffer, count);
31 }
32 
33 bool ar_seek(ar_stream *stream, off64_t offset, int origin)
34 {
35  return stream->seek(stream->data, offset, origin);
36 }
37 
38 bool ar_skip(ar_stream *stream, off64_t count)
39 {
40  return stream->seek(stream->data, count, SEEK_CUR);
41 }
42 
44 {
45  return stream->tell(stream->data);
46 }
47 
48 /***** stream based on FILE *****/
49 
50 static void file_close(void *data)
51 {
52  fclose(data);
53 }
54 
55 static size_t file_read(void *data, void *buffer, size_t count)
56 {
57  return fread(buffer, 1, count, data);
58 }
59 
60 static bool file_seek(void *data, off64_t offset, int origin)
61 {
62 #ifdef _MSC_VER
63  return _fseeki64(data, offset, origin) == 0;
64 #else
65 #if _POSIX_C_SOURCE >= 200112L
66  if (sizeof(off_t) == 8)
67  return fseeko(data, offset, origin) == 0;
68 #endif
69  if (offset > INT32_MAX || offset < INT32_MIN)
70  return false;
71  return fseek(data, (long)offset, origin) == 0;
72 #endif
73 }
74 
75 static off64_t file_tell(void *data)
76 {
77 #ifdef _MSC_VER
78  return _ftelli64(data);
79 #elif _POSIX_C_SOURCE >= 200112L
80  return ftello(data);
81 #else
82  return ftell(data);
83 #endif
84 }
85 
86 ar_stream *ar_open_file(const char *path)
87 {
88  FILE *f = path ? fopen(path, "rb") : NULL;
89  if (!f)
90  return NULL;
92 }
93 
94 #ifdef _WIN32
95 ar_stream *ar_open_file_w(const wchar_t *path)
96 {
97  FILE *f = path ? _wfopen(path, L"rb") : NULL;
98  if (!f)
99  return NULL;
101 }
102 #endif
103 
104 /***** stream based on preallocated memory *****/
105 
106 struct MemoryStream {
107  const uint8_t *data;
108  size_t length;
109  size_t offset;
110 };
111 
112 static void memory_close(void *data)
113 {
114  struct MemoryStream *stm = data;
115  free(stm);
116 }
117 
118 static size_t memory_read(void *data, void *buffer, size_t count)
119 {
120  struct MemoryStream *stm = data;
121  if (count > stm->length - stm->offset)
122  count = stm->length - stm->offset;
123  memcpy(buffer, stm->data + stm->offset, count);
124  stm->offset += count;
125  return count;
126 }
127 
128 static bool memory_seek(void *data, off64_t offset, int origin)
129 {
130  struct MemoryStream *stm = data;
131  if (origin == SEEK_CUR)
132  offset += stm->offset;
133  else if (origin == SEEK_END)
134  offset += stm->length;
135  if (offset < 0 || offset > (off64_t)stm->length || (size_t)offset > stm->length)
136  return false;
137  stm->offset = (size_t)offset;
138  return true;
139 }
140 
141 static off64_t memory_tell(void *data)
142 {
143  struct MemoryStream *stm = data;
144  return stm->offset;
145 }
146 
147 ar_stream *ar_open_memory(const void *data, size_t datalen)
148 {
149  struct MemoryStream *stm = malloc(sizeof(struct MemoryStream));
150  if (!stm)
151  return NULL;
152  stm->data = data;
153  stm->length = datalen;
154  stm->offset = 0;
156 }
157 
158 #ifdef _WIN32
159 /***** stream based on IStream *****/
160 
161 #define COBJMACROS
162 #include <windows.h>
163 
164 static void stream_close(void *data)
165 {
166  IUnknown_Release((IStream *)data);
167 }
168 
169 static size_t stream_read(void *data, void *buffer, size_t count)
170 {
171  size_t read = 0;
172  HRESULT res;
173  ULONG cbRead;
174 #ifdef _WIN64
175  while (count > ULONG_MAX) {
176  res = IStream_Read((IStream *)data, buffer, ULONG_MAX, &cbRead);
177  if (FAILED(res))
178  return read;
179  read += cbRead;
180  buffer = (BYTE *)buffer + ULONG_MAX;
181  count -= ULONG_MAX;
182  }
183 #endif
184  res = IStream_Read((IStream *)data, buffer, (ULONG)count, &cbRead);
185  if (SUCCEEDED(res))
186  read += cbRead;
187  return read;
188 }
189 
190 static bool stream_seek(void *data, off64_t offset, int origin)
191 {
192  LARGE_INTEGER off;
193  ULARGE_INTEGER n;
194  HRESULT res;
195  off.QuadPart = offset;
196  res = IStream_Seek((IStream *)data, off, origin, &n);
197  return SUCCEEDED(res);
198 }
199 
200 static off64_t stream_tell(void *data)
201 {
202  LARGE_INTEGER zero = { 0 };
203  ULARGE_INTEGER n = { 0 };
204  IStream_Seek((IStream *)data, zero, SEEK_CUR, &n);
205  return (off64_t)n.QuadPart;
206 }
207 
208 ar_stream *ar_open_istream(IStream *stream)
209 {
210  LARGE_INTEGER zero = { 0 };
211  HRESULT res = IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
212  if (FAILED(res))
213  return NULL;
214  IUnknown_AddRef(stream);
215  return ar_open_stream(stream, stream_close, stream_read, stream_seek, stream_tell);
216 }
217 #endif