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>
10 // Copyright (C) 2013 Julien Nabet <serval2412@yahoo.fr>
12 //========================================================================
15 #include "CachedFile.h"
17 //------------------------------------------------------------------------
19 //------------------------------------------------------------------------
21 CachedFile::CachedFile(CachedFileLoader
*cachedFileLoaderA
, GooString
*uriA
)
24 loader
= cachedFileLoaderA
;
27 chunks
= new std::vector
<Chunk
>();
30 length
= loader
->init(uri
, this);
33 if (length
!= ((size_t) -1)) {
34 chunks
->resize(length
/CachedFileChunkSize
+ 1);
37 error(errInternal
, -1, "Failed to initialize file cache for '{0:t}'.", uri
);
42 CachedFile::~CachedFile()
49 void CachedFile::incRefCnt() {
53 void CachedFile::decRefCnt() {
58 long int CachedFile::tell() {
62 int CachedFile::seek(long int offset
, int origin
)
64 if (origin
== SEEK_SET
) {
66 } else if (origin
== SEEK_CUR
) {
69 streamPos
= length
+ offset
;
72 if (streamPos
> length
) {
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
;
88 const std::vector
<ByteRange
> *ranges
= &origRanges
;
90 if (ranges
->empty()) {
92 range
.length
= length
;
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;
118 while (chunk
< numChunks
) {
119 while (!chunkNeeded
[chunk
] && (++chunk
!= numChunks
)) ;
120 if (chunk
== numChunks
) break;
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
);
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;
154 if (cache(streamPos
, bytes
) != 0) return 0;
156 // Copy data to buffer
157 size_t toCopy
= bytes
;
159 int chunk
= streamPos
/ CachedFileChunkSize
;
160 int offset
= streamPos
% CachedFileChunkSize
;
161 size_t len
= CachedFileChunkSize
-offset
;
166 memcpy(ptr
, (*chunks
)[chunk
].data
+ offset
, len
);
169 ptr
= (char*)ptr
+ len
;
175 int CachedFile::cache(size_t offset
, size_t length
)
177 std::vector
<ByteRange
> r
;
179 range
.offset
= offset
;
180 range
.length
= length
;
185 //------------------------------------------------------------------------
187 //------------------------------------------------------------------------
189 CachedFileWriter::CachedFileWriter(CachedFile
*cachedFileA
, std::vector
<int> *chunksA
)
191 cachedFile
= cachedFileA
;
196 it
= (*chunks
).begin();
200 CachedFileWriter::~CachedFileWriter()
204 size_t CachedFileWriter::write(const char *ptr
, size_t size
)
206 const char *cp
= ptr
;
216 if (offset
== CachedFileChunkSize
) {
218 if (it
== (*chunks
).end()) return written
;
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
);
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
;
256 //------------------------------------------------------------------------