Bringing vpdf from vendor/MorphOS-OSS/current into main branch.
[AROS-Contrib.git] / vpdf / poppler / poppler / CachedFile.cc
blob393383006b074573aea9b8dc713884d7b3417d54
1 //========================================================================
2 //
3 // CachedFile.cc
4 //
5 // This file is licensed under the GPLv2 or later
6 //
7 // Copyright 2009 Stefan Thomas <thomas@eload24.com>
8 // Copyright 2010, 2011 Hib Eris <hib@hiberis.nl>
9 // Copyright 2010 Albert Astals Cid <aacid@kde.org>
11 //========================================================================
13 #include <config.h>
14 #include "CachedFile.h"
16 //------------------------------------------------------------------------
17 // CachedFile
18 //------------------------------------------------------------------------
20 CachedFile::CachedFile(CachedFileLoader *cachedFileLoaderA, GooString *uriA)
22 uri = uriA;
23 loader = cachedFileLoaderA;
25 streamPos = 0;
26 chunks = new std::vector<Chunk>();
27 length = 0;
29 length = loader->init(uri, this);
30 refCnt = 1;
32 if (length != ((size_t) -1)) {
33 chunks->resize(length/CachedFileChunkSize + 1);
35 else {
36 error(-1, "Failed to initialize file cache for '%s'.", uri->getCString());
37 chunks->resize(0);
41 CachedFile::~CachedFile()
43 delete uri;
44 delete loader;
45 delete chunks;
48 void CachedFile::incRefCnt() {
49 refCnt++;
52 void CachedFile::decRefCnt() {
53 if (--refCnt == 0)
54 delete this;
57 long int CachedFile::tell() {
58 return streamPos;
61 int CachedFile::seek(long int offset, int origin)
63 if (origin == SEEK_SET) {
64 streamPos = offset;
65 } else if (origin == SEEK_CUR) {
66 streamPos += offset;
67 } else {
68 streamPos = length + offset;
71 if (streamPos > length) {
72 streamPos = 0;
73 return 1;
76 return 0;
79 int CachedFile::cache(const std::vector<ByteRange> &origRanges)
81 std::vector<int> loadChunks;
82 int numChunks = length/CachedFileChunkSize + 1;
83 std::vector<bool> chunkNeeded(numChunks);
84 int startChunk, endChunk;
85 std::vector<ByteRange> chunk_ranges, all;
86 ByteRange range;
87 const std::vector<ByteRange> *ranges = &origRanges;
89 if (ranges->empty()) {
90 range.offset = 0;
91 range.length = length;
92 all.push_back(range);
93 ranges = &all;
96 for (int i = 0; i < numChunks; ++i)
97 chunkNeeded[i] = false;
98 for (size_t i = 0; i < ranges->size(); i++) {
100 if ((*ranges)[i].length == 0) continue;
101 if ((*ranges)[i].offset >= length) continue;
103 size_t start = (*ranges)[i].offset;
104 size_t end = start + (*ranges)[i].length - 1;
105 if (end >= length) end = length - 1;
107 startChunk = start / CachedFileChunkSize;
108 endChunk = end / CachedFileChunkSize;
109 for (int chunk = startChunk; chunk <= endChunk; chunk++) {
110 if ((*chunks)[chunk].state == chunkStateNew) {
111 chunkNeeded[chunk] = true;
116 int chunk = 0;
117 while (chunk < numChunks) {
118 while (!chunkNeeded[chunk] && (++chunk != numChunks)) ;
119 if (chunk == numChunks) break;
120 startChunk = chunk;
121 loadChunks.push_back(chunk);
123 while ((++chunk != numChunks) && chunkNeeded[chunk]) {
124 loadChunks.push_back(chunk);
126 endChunk = chunk - 1;
128 range.offset = startChunk * CachedFileChunkSize;
129 range.length = (endChunk - startChunk + 1) * CachedFileChunkSize;
131 chunk_ranges.push_back(range);
134 if (chunk_ranges.size() > 0) {
135 CachedFileWriter writer =
136 CachedFileWriter(this, &loadChunks);
137 return loader->load(chunk_ranges, &writer);
140 return 0;
143 size_t CachedFile::read(void *ptr, size_t unitsize, size_t count)
145 size_t bytes = unitsize*count;
146 if (length < (streamPos + bytes)) {
147 bytes = length - streamPos;
150 if (bytes == 0) return 0;
152 // Load data
153 if (cache(streamPos, bytes) != 0) return 0;
155 // Copy data to buffer
156 size_t toCopy = bytes;
157 while (toCopy) {
158 int chunk = streamPos / CachedFileChunkSize;
159 int offset = streamPos % CachedFileChunkSize;
160 size_t len = CachedFileChunkSize-offset;
162 if (len > toCopy)
163 len = toCopy;
165 memcpy(ptr, (*chunks)[chunk].data + offset, len);
166 streamPos += len;
167 toCopy -= len;
168 ptr = (char*)ptr + len;
171 return bytes;
174 int CachedFile::cache(size_t offset, size_t length)
176 std::vector<ByteRange> r;
177 ByteRange range;
178 range.offset = offset;
179 range.length = length;
180 r.push_back(range);
181 return cache(r);
184 //------------------------------------------------------------------------
185 // CachedFileWriter
186 //------------------------------------------------------------------------
188 CachedFileWriter::CachedFileWriter(CachedFile *cachedFileA, std::vector<int> *chunksA)
190 cachedFile = cachedFileA;
191 chunks = chunksA;
193 if (chunks) {
194 offset = 0;
195 it = (*chunks).begin();
199 CachedFileWriter::~CachedFileWriter()
203 size_t CachedFileWriter::write(const char *ptr, size_t size)
205 const char *cp = ptr;
206 size_t len = size;
207 size_t nfree, ncopy;
208 size_t written = 0;
209 size_t chunk;
211 if (!len) return 0;
213 while (len) {
214 if (chunks) {
215 if (offset == CachedFileChunkSize) {
216 it++;
217 if (it == (*chunks).end()) return written;
218 offset = 0;
220 chunk = *it;
221 } else {
222 offset = cachedFile->length % CachedFileChunkSize;
223 chunk = cachedFile->length / CachedFileChunkSize;
226 if (chunk >= cachedFile->chunks->size()) {
227 cachedFile->chunks->resize(chunk + 1);
230 nfree = CachedFileChunkSize - offset;
231 ncopy = (len >= nfree) ? nfree : len;
232 memcpy(&((*cachedFile->chunks)[chunk].data[offset]), cp, ncopy);
233 len -= ncopy;
234 cp += ncopy;
235 offset += ncopy;
236 written += ncopy;
238 if (!chunks) {
239 cachedFile->length += ncopy;
242 if (offset == CachedFileChunkSize) {
243 (*cachedFile->chunks)[chunk].state = CachedFile::chunkStateLoaded;
247 if ((chunk == (cachedFile->length / CachedFileChunkSize)) &&
248 (offset == (cachedFile->length % CachedFileChunkSize))) {
249 (*cachedFile->chunks)[chunk].state = CachedFile::chunkStateLoaded;
252 return written;
255 //------------------------------------------------------------------------