1 //========================================================================
5 // This file is licensed under the GPLv2 or later
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 //========================================================================
14 #include "CachedFile.h"
16 //------------------------------------------------------------------------
18 //------------------------------------------------------------------------
20 CachedFile::CachedFile(CachedFileLoader
*cachedFileLoaderA
, GooString
*uriA
)
23 loader
= cachedFileLoaderA
;
26 chunks
= new std::vector
<Chunk
>();
29 length
= loader
->init(uri
, this);
32 if (length
!= ((size_t) -1)) {
33 chunks
->resize(length
/CachedFileChunkSize
+ 1);
36 error(-1, "Failed to initialize file cache for '%s'.", uri
->getCString());
41 CachedFile::~CachedFile()
48 void CachedFile::incRefCnt() {
52 void CachedFile::decRefCnt() {
57 long int CachedFile::tell() {
61 int CachedFile::seek(long int offset
, int origin
)
63 if (origin
== SEEK_SET
) {
65 } else if (origin
== SEEK_CUR
) {
68 streamPos
= length
+ offset
;
71 if (streamPos
> length
) {
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
;
87 const std::vector
<ByteRange
> *ranges
= &origRanges
;
89 if (ranges
->empty()) {
91 range
.length
= length
;
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;
117 while (chunk
< numChunks
) {
118 while (!chunkNeeded
[chunk
] && (++chunk
!= numChunks
)) ;
119 if (chunk
== numChunks
) break;
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
);
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;
153 if (cache(streamPos
, bytes
) != 0) return 0;
155 // Copy data to buffer
156 size_t toCopy
= bytes
;
158 int chunk
= streamPos
/ CachedFileChunkSize
;
159 int offset
= streamPos
% CachedFileChunkSize
;
160 size_t len
= CachedFileChunkSize
-offset
;
165 memcpy(ptr
, (*chunks
)[chunk
].data
+ offset
, len
);
168 ptr
= (char*)ptr
+ len
;
174 int CachedFile::cache(size_t offset
, size_t length
)
176 std::vector
<ByteRange
> r
;
178 range
.offset
= offset
;
179 range
.length
= length
;
184 //------------------------------------------------------------------------
186 //------------------------------------------------------------------------
188 CachedFileWriter::CachedFileWriter(CachedFile
*cachedFileA
, std::vector
<int> *chunksA
)
190 cachedFile
= cachedFileA
;
195 it
= (*chunks
).begin();
199 CachedFileWriter::~CachedFileWriter()
203 size_t CachedFileWriter::write(const char *ptr
, size_t size
)
205 const char *cp
= ptr
;
215 if (offset
== CachedFileChunkSize
) {
217 if (it
== (*chunks
).end()) return written
;
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
);
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
;
255 //------------------------------------------------------------------------