beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / poppler / CachedFile.cc
blobb0ae8388113cafa1277346eed1cd733bbfc2c635
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>
10 // Copyright (C) 2013 Julien Nabet <serval2412@yahoo.fr>
12 //========================================================================
14 #include <config.h>
15 #include "CachedFile.h"
17 //------------------------------------------------------------------------
18 // CachedFile
19 //------------------------------------------------------------------------
21 CachedFile::CachedFile(CachedFileLoader *cachedFileLoaderA, GooString *uriA)
23 uri = uriA;
24 loader = cachedFileLoaderA;
26 streamPos = 0;
27 chunks = new std::vector<Chunk>();
28 length = 0;
30 length = loader->init(uri, this);
31 refCnt = 1;
33 if (length != ((size_t) -1)) {
34 chunks->resize(length/CachedFileChunkSize + 1);
36 else {
37 error(errInternal, -1, "Failed to initialize file cache for '{0:t}'.", uri);
38 chunks->resize(0);
42 CachedFile::~CachedFile()
44 delete uri;
45 delete loader;
46 delete chunks;
49 void CachedFile::incRefCnt() {
50 refCnt++;
53 void CachedFile::decRefCnt() {
54 if (--refCnt == 0)
55 delete this;
58 long int CachedFile::tell() {
59 return streamPos;
62 int CachedFile::seek(long int offset, int origin)
64 if (origin == SEEK_SET) {
65 streamPos = offset;
66 } else if (origin == SEEK_CUR) {
67 streamPos += offset;
68 } else {
69 streamPos = length + offset;
72 if (streamPos > length) {
73 streamPos = 0;
74 return 1;
77 return 0;
80 int CachedFile::cache(const std::vector<ByteRange> &origRanges)
82 std::vector<int> loadChunks;
83 int numChunks = length/CachedFileChunkSize + 1;
84 std::vector<bool> chunkNeeded(numChunks);
85 int startChunk, endChunk;
86 std::vector<ByteRange> chunk_ranges, all;
87 ByteRange range;
88 const std::vector<ByteRange> *ranges = &origRanges;
90 if (ranges->empty()) {
91 range.offset = 0;
92 range.length = length;
93 all.push_back(range);
94 ranges = &all;
97 for (int i = 0; i < numChunks; ++i)
98 chunkNeeded[i] = false;
99 for (size_t i = 0; i < ranges->size(); i++) {
101 if ((*ranges)[i].length == 0) continue;
102 if ((*ranges)[i].offset >= length) continue;
104 size_t start = (*ranges)[i].offset;
105 size_t end = start + (*ranges)[i].length - 1;
106 if (end >= length) end = length - 1;
108 startChunk = start / CachedFileChunkSize;
109 endChunk = end / CachedFileChunkSize;
110 for (int chunk = startChunk; chunk <= endChunk; chunk++) {
111 if ((*chunks)[chunk].state == chunkStateNew) {
112 chunkNeeded[chunk] = true;
117 int chunk = 0;
118 while (chunk < numChunks) {
119 while (!chunkNeeded[chunk] && (++chunk != numChunks)) ;
120 if (chunk == numChunks) break;
121 startChunk = chunk;
122 loadChunks.push_back(chunk);
124 while ((++chunk != numChunks) && chunkNeeded[chunk]) {
125 loadChunks.push_back(chunk);
127 endChunk = chunk - 1;
129 range.offset = startChunk * CachedFileChunkSize;
130 range.length = (endChunk - startChunk + 1) * CachedFileChunkSize;
132 chunk_ranges.push_back(range);
135 if (chunk_ranges.size() > 0) {
136 CachedFileWriter writer =
137 CachedFileWriter(this, &loadChunks);
138 return loader->load(chunk_ranges, &writer);
141 return 0;
144 size_t CachedFile::read(void *ptr, size_t unitsize, size_t count)
146 size_t bytes = unitsize*count;
147 if (length < (streamPos + bytes)) {
148 bytes = length - streamPos;
151 if (bytes == 0) return 0;
153 // Load data
154 if (cache(streamPos, bytes) != 0) return 0;
156 // Copy data to buffer
157 size_t toCopy = bytes;
158 while (toCopy) {
159 int chunk = streamPos / CachedFileChunkSize;
160 int offset = streamPos % CachedFileChunkSize;
161 size_t len = CachedFileChunkSize-offset;
163 if (len > toCopy)
164 len = toCopy;
166 memcpy(ptr, (*chunks)[chunk].data + offset, len);
167 streamPos += len;
168 toCopy -= len;
169 ptr = (char*)ptr + len;
172 return bytes;
175 int CachedFile::cache(size_t offset, size_t length)
177 std::vector<ByteRange> r;
178 ByteRange range;
179 range.offset = offset;
180 range.length = length;
181 r.push_back(range);
182 return cache(r);
185 //------------------------------------------------------------------------
186 // CachedFileWriter
187 //------------------------------------------------------------------------
189 CachedFileWriter::CachedFileWriter(CachedFile *cachedFileA, std::vector<int> *chunksA)
191 cachedFile = cachedFileA;
192 chunks = chunksA;
194 if (chunks) {
195 offset = 0;
196 it = (*chunks).begin();
200 CachedFileWriter::~CachedFileWriter()
204 size_t CachedFileWriter::write(const char *ptr, size_t size)
206 const char *cp = ptr;
207 size_t len = size;
208 size_t nfree, ncopy;
209 size_t written = 0;
210 size_t chunk;
212 if (!len) return 0;
214 while (len) {
215 if (chunks) {
216 if (offset == CachedFileChunkSize) {
217 ++it;
218 if (it == (*chunks).end()) return written;
219 offset = 0;
221 chunk = *it;
222 } else {
223 offset = cachedFile->length % CachedFileChunkSize;
224 chunk = cachedFile->length / CachedFileChunkSize;
227 if (chunk >= cachedFile->chunks->size()) {
228 cachedFile->chunks->resize(chunk + 1);
231 nfree = CachedFileChunkSize - offset;
232 ncopy = (len >= nfree) ? nfree : len;
233 memcpy(&((*cachedFile->chunks)[chunk].data[offset]), cp, ncopy);
234 len -= ncopy;
235 cp += ncopy;
236 offset += ncopy;
237 written += ncopy;
239 if (!chunks) {
240 cachedFile->length += ncopy;
243 if (offset == CachedFileChunkSize) {
244 (*cachedFile->chunks)[chunk].state = CachedFile::chunkStateLoaded;
248 if ((chunk == (cachedFile->length / CachedFileChunkSize)) &&
249 (offset == (cachedFile->length % CachedFileChunkSize))) {
250 (*cachedFile->chunks)[chunk].state = CachedFile::chunkStateLoaded;
253 return written;
256 //------------------------------------------------------------------------