37 // cleanup |
36 // cleanup |
38 if (cache) |
37 if (cache) |
39 pt_cache_destroy(cache); |
38 pt_cache_destroy(cache); |
40 |
39 |
41 return -1; |
40 return -1; |
42 } |
|
43 |
|
44 int pt_cache_open (struct pt_cache **cache_ptr, const char *path, int mode) |
|
45 { |
|
46 struct pt_cache *cache; |
|
47 |
|
48 // alloc |
|
49 if (pt_cache_new(&cache, path, mode)) |
|
50 return -1; |
|
51 |
|
52 // ok |
|
53 *cache_ptr = cache; |
|
54 |
|
55 return 0; |
|
56 } |
41 } |
57 |
42 |
58 int pt_cache_status (struct pt_cache *cache, const char *img_path) |
43 int pt_cache_status (struct pt_cache *cache, const char *img_path) |
59 { |
44 { |
60 struct stat st_img, st_cache; |
45 struct stat st_img, st_cache; |
149 |
134 |
150 |
135 |
151 /** |
136 /** |
152 * Mmap the opened cache file using PT_CACHE_HEADER_SIZE plus the calculated size stored in cache->size |
137 * Mmap the opened cache file using PT_CACHE_HEADER_SIZE plus the calculated size stored in cache->size |
153 */ |
138 */ |
154 static int pt_cache_open_mmap (struct pt_cache *cache, void **addr_ptr) |
139 static int pt_cache_open_mmap (struct pt_cache *cache, void **addr_ptr, bool readonly) |
155 { |
140 { |
156 int prot = 0; |
141 int prot = 0; |
157 void *addr; |
142 void *addr; |
158 |
143 |
159 // determine prot |
144 // determine prot |
160 prot |= PROT_READ; |
145 prot |= PROT_READ; |
161 |
146 |
162 if (cache->mode & PT_IMG_WRITE) |
147 if (!readonly) { |
|
148 assert(cache->mode & PT_IMG_WRITE); |
|
149 |
163 prot |= PROT_WRITE; |
150 prot |= PROT_WRITE; |
|
151 } |
164 |
152 |
165 // perform mmap() from second page on |
153 // perform mmap() from second page on |
166 if ((addr = mmap(NULL, PT_CACHE_HEADER_SIZE + cache->size, prot, MAP_SHARED, cache->fd, 0)) == MAP_FAILED) |
154 if ((addr = mmap(NULL, PT_CACHE_HEADER_SIZE + cache->size, prot, MAP_SHARED, cache->fd, 0)) == MAP_FAILED) |
167 return -1; |
155 return -1; |
168 |
156 |
169 // ok |
157 // ok |
170 *addr_ptr = addr; |
158 *addr_ptr = addr; |
171 |
159 |
|
160 return 0; |
|
161 } |
|
162 |
|
163 /** |
|
164 * Read in the cache header from the open file |
|
165 */ |
|
166 static int pt_cache_read_header (struct pt_cache *cache, struct pt_cache_header *header) |
|
167 { |
|
168 size_t len = sizeof(*header); |
|
169 char *buf = (char *) header; |
|
170 |
|
171 // seek to start |
|
172 if (lseek(cache->fd, 0, SEEK_SET) != 0) |
|
173 return -1; |
|
174 |
|
175 // write out full header |
|
176 while (len) { |
|
177 ssize_t ret; |
|
178 |
|
179 // try and write out the header |
|
180 if ((ret = read(cache->fd, buf, len)) < 0) |
|
181 return -1; |
|
182 |
|
183 // update offset |
|
184 buf += ret; |
|
185 len -= ret; |
|
186 } |
|
187 |
|
188 // done |
172 return 0; |
189 return 0; |
173 } |
190 } |
174 |
191 |
175 /** |
192 /** |
176 * Write out the cache header into the opened file |
193 * Write out the cache header into the opened file |
224 // grow file |
241 // grow file |
225 if (ftruncate(cache->fd, PT_CACHE_HEADER_SIZE + cache->size) < 0) |
242 if (ftruncate(cache->fd, PT_CACHE_HEADER_SIZE + cache->size) < 0) |
226 goto error; |
243 goto error; |
227 |
244 |
228 // mmap header and data |
245 // mmap header and data |
229 if (pt_cache_open_mmap(cache, &base)) |
246 if (pt_cache_open_mmap(cache, &base, false)) |
230 goto error; |
247 goto error; |
231 |
248 |
232 cache->header = base; |
249 cache->header = base; |
233 cache->data = base + PT_CACHE_HEADER_SIZE; |
250 cache->data = base + PT_CACHE_HEADER_SIZE; |
234 |
251 |
264 |
281 |
265 // ok |
282 // ok |
266 return 0; |
283 return 0; |
267 } |
284 } |
268 |
285 |
|
286 int pt_cache_open (struct pt_cache *cache) |
|
287 { |
|
288 struct pt_cache_header header; |
|
289 void *base; |
|
290 |
|
291 // open the .cache |
|
292 if (pt_cache_open_read_fd(cache, &cache->fd)) |
|
293 return -1; |
|
294 |
|
295 // read in header |
|
296 if (pt_cache_read_header(cache, &header)) |
|
297 return -1; |
|
298 |
|
299 // calculate data size |
|
300 cache->size = sizeof(header) + header.height * header.row_bytes; |
|
301 |
|
302 // mmap header and data |
|
303 if (pt_cache_open_mmap(cache, &base, true)) |
|
304 goto error; |
|
305 |
|
306 cache->header = base; |
|
307 cache->data = base + PT_CACHE_HEADER_SIZE; |
|
308 |
|
309 // done |
|
310 return 0; |
|
311 |
|
312 error: |
|
313 // cleanup |
|
314 pt_cache_abort(cache); |
|
315 |
|
316 return -1; |
|
317 } |
|
318 |
269 int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info) |
319 int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info) |
270 { |
320 { |
271 struct pt_cache_header header; |
321 struct pt_cache_header header; |
272 |
322 |
273 // XXX: check cache_mode |
323 // XXX: check cache_mode |
274 // XXX: check image doesn't use any options we don't handle |
324 // XXX: check image doesn't use any options we don't handle |
|
325 // XXX: close any already-opened cache file |
275 |
326 |
276 memset(&header, 0, sizeof(header)); |
327 memset(&header, 0, sizeof(header)); |
277 |
328 |
278 // fill in basic info |
329 // fill in basic info |
279 header.width = png_get_image_width(png, info); |
330 header.width = png_get_image_width(png, info); |
283 |
334 |
284 log_debug("width=%u, height=%u, bit_depth=%u, color_type=%u", |
335 log_debug("width=%u, height=%u, bit_depth=%u, color_type=%u", |
285 header.width, header.height, header.bit_depth, header.color_type |
336 header.width, header.height, header.bit_depth, header.color_type |
286 ); |
337 ); |
287 |
338 |
|
339 // only pack 1 pixel per byte |
|
340 if (header.bit_depth < 8) |
|
341 png_set_packing(png); |
|
342 |
288 // fill in other info |
343 // fill in other info |
289 header.row_bytes = png_get_rowbytes(png, info); |
344 header.row_bytes = png_get_rowbytes(png, info); |
290 |
345 |
291 log_debug("row_bytes=%u", header.row_bytes); |
346 // calculate bpp as num_channels * bpc |
|
347 // XXX: this assumes the packed bit depth will be either 8 or 16 |
|
348 header.col_bytes = png_get_channels(png, info) * (header.bit_depth == 16 ? 2 : 1); |
|
349 |
|
350 log_debug("row_bytes=%u, col_bytes=%u", header.row_bytes, header.col_bytes); |
292 |
351 |
293 // palette etc. |
352 // palette etc. |
294 if (header.color_type == PNG_COLOR_TYPE_PALETTE) { |
353 if (header.color_type == PNG_COLOR_TYPE_PALETTE) { |
295 int num_palette; |
354 int num_palette; |
296 png_colorp palette; |
355 png_colorp palette; |
307 memcpy(&header.palette, palette, num_palette * sizeof(*palette)); |
366 memcpy(&header.palette, palette, num_palette * sizeof(*palette)); |
308 |
367 |
309 log_debug("num_palette=%u", num_palette); |
368 log_debug("num_palette=%u", num_palette); |
310 } |
369 } |
311 |
370 |
312 |
|
313 // create .tmp and write out header |
371 // create .tmp and write out header |
314 if (pt_cache_open_create(cache, &header)) |
372 if (pt_cache_open_create(cache, &header)) |
315 return -1; |
373 return -1; |
316 |
374 |
317 |
375 |
328 |
386 |
329 // done! |
387 // done! |
330 return 0; |
388 return 0; |
331 } |
389 } |
332 |
390 |
|
391 int pt_cache_tile_png (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_tile_info *ti) |
|
392 { |
|
393 if (!cache->data) { |
|
394 // not yet open |
|
395 if (pt_cache_open(cache)) |
|
396 return -1; |
|
397 } |
|
398 |
|
399 // set basic info |
|
400 png_set_IHDR(png, info, ti->width, ti->height, cache->header->bit_depth, cache->header->color_type, |
|
401 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT |
|
402 ); |
|
403 |
|
404 // set palette? |
|
405 if (cache->header->color_type == PNG_COLOR_TYPE_PALETTE) |
|
406 png_set_PLTE(png, info, cache->header->palette, cache->header->num_palette); |
|
407 |
|
408 // write meta-info |
|
409 png_write_info(png, info); |
|
410 |
|
411 // pixel data is packed into 1 pixel per byte |
|
412 png_set_packing(png); |
|
413 |
|
414 // write image data |
|
415 for (size_t row = ti->y; row < ti->y + ti->height; row++) { |
|
416 size_t col = ti->x; |
|
417 |
|
418 // XXX: fill out-of-range regions in some background color |
|
419 png_write_row(png, cache->data + (row * cache->header->row_bytes) + (col * cache->header->col_bytes)); |
|
420 } |
|
421 |
|
422 // done, flush remaining output |
|
423 png_write_flush(png); |
|
424 |
|
425 // ok |
|
426 return 0; |
|
427 } |
|
428 |
333 void pt_cache_destroy (struct pt_cache *cache) |
429 void pt_cache_destroy (struct pt_cache *cache) |
334 { |
430 { |
335 free(cache->path); |
431 free(cache->path); |
336 |
432 |
337 pt_cache_abort(cache); |
433 pt_cache_abort(cache); |