1//========================================================================
2//
3// InMemoryFile.cc
4//
5// Represents a file in-memory with GNU's stdio wrappers.
6// NOTE as of this writing, open() depends on the glibc 'fopencookie'
7// extension and is not supported on other platforms. The
8// HAVE_IN_MEMORY_FILE macro is intended to reflect whether this class is
9// usable.
10//
11// This file is licensed under the GPLv2 or later
12//
13// Copyright (C) 2018, 2019 Greg Knight <lyngvi@gmail.com>
14// Copyright (C) 2020 Albert Astals Cid <aacid@kde.org>
15//
16//========================================================================
17
18#include "InMemoryFile.h"
19
20#include <cstring>
21#include <sstream>
22
23InMemoryFile::InMemoryFile() = default;
24
25#ifdef HAVE_IN_MEMORY_FILE_FOPENCOOKIE
26ssize_t InMemoryFile::_read(char *buf, size_t sz)
27{
28 auto toRead = std::min<size_t>(a: data.size() - iohead, b: sz);
29 memcpy(dest: &buf[0], src: &data[iohead], n: toRead);
30 iohead += toRead;
31 return toRead;
32}
33
34ssize_t InMemoryFile::_write(const char *buf, size_t sz)
35{
36 if (iohead + sz > data.size()) {
37 data.resize(new_size: iohead + sz);
38 }
39 memcpy(dest: &data[iohead], src: buf, n: sz);
40 iohead += sz;
41 return sz;
42}
43
44int InMemoryFile::_seek(off64_t *offset, int whence)
45{
46 switch (whence) {
47 case SEEK_SET:
48 iohead = (*offset);
49 break;
50 case SEEK_CUR:
51 iohead += (*offset);
52 break;
53 case SEEK_END:
54 iohead -= (*offset);
55 break;
56 }
57 (*offset) = std::min<off64_t>(a: std::max<off64_t>(a: iohead, b: 0l), b: data.size());
58 iohead = static_cast<size_t>(*offset);
59 return 0;
60}
61#endif // def HAVE_IN_MEMORY_FILE_FOPENCOOKIE
62
63FILE *InMemoryFile::open(const char *mode)
64{
65#ifdef HAVE_IN_MEMORY_FILE_FOPENCOOKIE
66 if (fptr != nullptr) {
67 fprintf(stderr, format: "InMemoryFile: BUG: Why is this opened more than once?");
68 return nullptr; // maybe there's some legit reason for it, whoever comes up with one can remove this line
69 }
70 static const cookie_io_functions_t methods = {
71 /* .read = */ [](void *self, char *buf, size_t sz) { return ((InMemoryFile *)self)->_read(buf, sz); },
72 /* .write = */ [](void *self, const char *buf, size_t sz) { return ((InMemoryFile *)self)->_write(buf, sz); },
73 /* .seek = */ [](void *self, off64_t *offset, int whence) { return ((InMemoryFile *)self)->_seek(offset, whence); },
74 /* .close = */
75 [](void *self) {
76 ((InMemoryFile *)self)->fptr = nullptr;
77 return 0;
78 },
79 };
80 return fptr = fopencookie(magic_cookie: this, modes: mode, io_funcs: methods);
81#else
82 fprintf(stderr, "If you can read this, your platform does not support the features necessary to achieve your goals.");
83 return nullptr;
84#endif
85}
86

source code of poppler/utils/InMemoryFile.cc