source: trunk/poppler/mypoppler/poppler/CachedFile.cc @ 461

Last change on this file since 461 was 461, checked in by Silvan Scherrer, 11 years ago

poppler update to 0.14.2

File size: 5.6 KB
Line 
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 Hib Eris <hib@hiberis.nl>
9// Copyright 2010 Albert Astals Cid <aacid@kde.org>
10//
11//========================================================================
12
13#include <config.h>
14#include "CachedFile.h"
15
16//------------------------------------------------------------------------
17// CachedFile
18//------------------------------------------------------------------------
19
20CachedFile::CachedFile(CachedFileLoader *cachedFileLoaderA, GooString *uriA)
21{
22  uri = uriA;
23  loader = cachedFileLoaderA;
24
25  streamPos = 0;
26  chunks = new GooVector<Chunk>();
27  length = 0;
28
29  length = loader->init(uri, this);
30  refCnt = 1;
31
32  chunks->resize(length/CachedFileChunkSize + 1);
33}
34
35CachedFile::~CachedFile()
36{
37  delete uri;
38  delete loader;
39  delete chunks;
40}
41
42void CachedFile::incRefCnt() {
43  refCnt++;
44}
45
46void CachedFile::decRefCnt() {
47  if (--refCnt == 0)
48    delete this;
49}
50
51long int CachedFile::tell() {
52  return streamPos;
53}
54
55int CachedFile::seek(long int offset, int origin)
56{
57  if (origin == SEEK_SET) {
58    streamPos = offset;
59  } else if (origin == SEEK_CUR) {
60    streamPos += offset;
61  } else {
62    streamPos = length + offset;
63  }
64
65  if (streamPos > length) {
66    streamPos = 0;
67    return 1;
68  }
69
70  return 0;
71}
72
73int CachedFile::cache(const GooVector<ByteRange> &origRanges)
74{
75  GooVector<int> loadChunks;
76  int numChunks = length/CachedFileChunkSize + 1;
77  GooVector<bool> chunkNeeded(numChunks);
78  int startChunk, endChunk;
79  GooVector<ByteRange> chunk_ranges, all;
80  ByteRange range;
81  const GooVector<ByteRange> *ranges = &origRanges;
82
83  if (ranges->empty()) {
84    range.offset = 0;
85    range.length = length;
86    all.push_back(range);
87    ranges = &all;
88  }
89
90  memset(&chunkNeeded[0], 0, sizeof(bool) * numChunks);
91  for (size_t i = 0; i < ranges->size(); i++) {
92
93    if ((*ranges)[i].length == 0) continue;
94    if ((*ranges)[i].offset >= length) continue;
95
96    size_t start = (*ranges)[i].offset;
97    size_t end = start + (*ranges)[i].length - 1;
98    if (end >= length) end = length - 1;
99
100    startChunk = start / CachedFileChunkSize;
101    endChunk = end / CachedFileChunkSize;
102    for (int chunk = startChunk; chunk <= endChunk; chunk++) {
103      if ((*chunks)[chunk].state == chunkStateNew) {
104           chunkNeeded[chunk] = true;
105      }
106    }
107  }
108
109  int chunk = 0;
110  while (chunk < numChunks) {
111    while (!chunkNeeded[chunk] && (++chunk != numChunks)) ;
112    if (chunk == numChunks) break;
113    startChunk = chunk;
114    loadChunks.push_back(chunk);
115
116    while ((++chunk != numChunks) && chunkNeeded[chunk]) {
117      loadChunks.push_back(chunk);
118    }
119    endChunk = chunk - 1;
120
121    range.offset = startChunk * CachedFileChunkSize;
122    range.length = (endChunk - startChunk + 1) * CachedFileChunkSize;
123
124    chunk_ranges.push_back(range);
125  }
126
127  if (chunk_ranges.size() > 0) {
128    CachedFileWriter writer =
129        CachedFileWriter(this, &loadChunks);
130    return loader->load(chunk_ranges, &writer);
131  }
132
133  return 0;
134}
135
136size_t CachedFile::read(void *ptr, size_t unitsize, size_t count)
137{
138  size_t bytes = unitsize*count;
139  if (length < (streamPos + bytes)) {
140    bytes = length - streamPos;
141  }
142
143  if (bytes == 0) return 0;
144
145  // Load data
146  if (cache(streamPos, bytes) != 0) return 0;
147
148  // Copy data to buffer
149  size_t toCopy = bytes;
150  while (toCopy) {
151    int chunk = streamPos / CachedFileChunkSize;
152    int offset = streamPos % CachedFileChunkSize;
153    size_t len = CachedFileChunkSize-offset;
154
155    if (len > toCopy)
156      len = toCopy;
157
158    memcpy(ptr, (*chunks)[chunk].data + offset, len);
159    streamPos += len;
160    toCopy -= len;
161    ptr = (char*)ptr + len;
162  }
163
164  return bytes;
165}
166
167int CachedFile::cache(size_t offset, size_t length)
168{
169  GooVector<ByteRange> r;
170  ByteRange range;
171  range.offset = offset;
172  range.length = length;
173  r.push_back(range);
174  return cache(r);
175}
176
177//------------------------------------------------------------------------
178// CachedFileWriter
179//------------------------------------------------------------------------
180
181CachedFileWriter::CachedFileWriter(CachedFile *cachedFileA, GooVector<int> *chunksA)
182{
183   cachedFile = cachedFileA;
184   chunks = chunksA;
185
186   if (chunks) {
187     offset = 0;
188     it = (*chunks).begin();
189   }
190}
191
192CachedFileWriter::~CachedFileWriter()
193{
194}
195
196size_t CachedFileWriter::write(const char *ptr, size_t size)
197{
198  const char *cp = ptr;
199  size_t len = size;
200  size_t nfree, ncopy;
201  size_t written = 0;
202  size_t chunk;
203
204  if (!len) return 0;
205
206  while (len) {
207    if (chunks) {
208      if (offset == CachedFileChunkSize) {
209         it++;
210         if (it == (*chunks).end()) return written;
211         offset = 0;
212      }
213      chunk = *it;
214    } else {
215      offset = cachedFile->length % CachedFileChunkSize;
216      chunk = cachedFile->length / CachedFileChunkSize;
217    }
218
219    if (chunk >= cachedFile->chunks->size()) {
220       cachedFile->chunks->resize(chunk + 1);
221    }
222
223    nfree = CachedFileChunkSize - offset;
224    ncopy = (len >= nfree) ? nfree : len;
225    memcpy(&((*cachedFile->chunks)[chunk].data[offset]), cp, ncopy);
226    len -= ncopy;
227    cp += ncopy;
228    offset += ncopy;
229    written += ncopy;
230
231    if (!chunks) {
232      cachedFile->length += ncopy;
233    }
234
235    if (offset == CachedFileChunkSize) {
236       (*cachedFile->chunks)[chunk].state = CachedFile::chunkStateLoaded;
237    }
238  }
239
240  if ((chunk == (cachedFile->length / CachedFileChunkSize)) &&
241      (offset == (cachedFile->length % CachedFileChunkSize))) {
242     (*cachedFile->chunks)[chunk].state = CachedFile::chunkStateLoaded;
243  }
244
245  return written;
246}
247
248//------------------------------------------------------------------------
249
Note: See TracBrowser for help on using the repository browser.