1 | /* poppler-cached-file-loader.h: glib interface to poppler |
2 | * |
3 | * Copyright (C) 2012 Carlos Garcia Campos <carlosgc@gnome.org> |
4 | * Copyright (C) 2022 Albert Astals Cid <aacid@kde.org> |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2, or (at your option) |
9 | * any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
19 | */ |
20 | |
21 | #include "config.h" |
22 | #include "poppler-cached-file-loader.h" |
23 | |
24 | PopplerCachedFileLoader::PopplerCachedFileLoader(GInputStream *inputStreamA, GCancellable *cancellableA, goffset lengthA) |
25 | { |
26 | inputStream = (GInputStream *)g_object_ref(inputStreamA); |
27 | cancellable = cancellableA ? (GCancellable *)g_object_ref(cancellableA) : nullptr; |
28 | length = lengthA; |
29 | cachedFile = nullptr; |
30 | } |
31 | |
32 | PopplerCachedFileLoader::~PopplerCachedFileLoader() |
33 | { |
34 | g_object_unref(object: inputStream); |
35 | if (cancellable) { |
36 | g_object_unref(object: cancellable); |
37 | } |
38 | } |
39 | |
40 | size_t PopplerCachedFileLoader::init(CachedFile *cachedFileA) |
41 | { |
42 | size_t size; |
43 | gssize bytesRead; |
44 | char buf[CachedFileChunkSize]; |
45 | |
46 | cachedFile = cachedFileA; |
47 | |
48 | if (length != (goffset)-1) { |
49 | return length; |
50 | } |
51 | |
52 | if (G_IS_FILE_INPUT_STREAM(inputStream)) { |
53 | GFileInfo *info; |
54 | |
55 | info = g_file_input_stream_query_info(G_FILE_INPUT_STREAM(inputStream), G_FILE_ATTRIBUTE_STANDARD_SIZE, cancellable, error: nullptr); |
56 | if (!info) { |
57 | error(category: errInternal, pos: -1, msg: "Failed to get size." ); |
58 | return (size_t)-1; |
59 | } |
60 | |
61 | length = g_file_info_get_size(info); |
62 | g_object_unref(object: info); |
63 | |
64 | return length; |
65 | } |
66 | |
67 | // Unknown stream length, read the whole stream and return the size. |
68 | CachedFileWriter writer = CachedFileWriter(cachedFile, nullptr); |
69 | size = 0; |
70 | do { |
71 | bytesRead = g_input_stream_read(stream: inputStream, buffer: buf, CachedFileChunkSize, cancellable, error: nullptr); |
72 | if (bytesRead == -1) { |
73 | break; |
74 | } |
75 | |
76 | writer.write(ptr: buf, size: bytesRead); |
77 | size += bytesRead; |
78 | } while (bytesRead > 0); |
79 | |
80 | return size; |
81 | } |
82 | |
83 | int PopplerCachedFileLoader::load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer) |
84 | { |
85 | char buf[CachedFileChunkSize]; |
86 | gssize bytesRead; |
87 | size_t rangeBytesRead, bytesToRead; |
88 | |
89 | if (length == (goffset)-1) { |
90 | return 0; |
91 | } |
92 | |
93 | for (const ByteRange &range : ranges) { |
94 | bytesToRead = MIN(CachedFileChunkSize, range.length); |
95 | rangeBytesRead = 0; |
96 | g_seekable_seek(G_SEEKABLE(inputStream), offset: range.offset, type: G_SEEK_SET, cancellable, error: nullptr); |
97 | do { |
98 | bytesRead = g_input_stream_read(stream: inputStream, buffer: buf, count: bytesToRead, cancellable, error: nullptr); |
99 | if (bytesRead == -1) { |
100 | return -1; |
101 | } |
102 | |
103 | writer->write(ptr: buf, size: bytesRead); |
104 | rangeBytesRead += bytesRead; |
105 | bytesToRead = range.length - rangeBytesRead; |
106 | } while (bytesRead > 0 && bytesToRead > 0); |
107 | } |
108 | |
109 | return 0; |
110 | } |
111 | |