mightymandel v16

GPU-based Mandelbrot set explorer

parse_png.c
Go to the documentation of this file.
1 // mightymandel -- GPU-based Mandelbrot Set explorer
2 // Copyright (C) 2012,2013,2014,2015 Claude Heiland-Allen
3 // License GPL3+ http://www.gnu.org/licenses/gpl.html
4 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <mpfr.h>
14 
15 #include "parse.h"
16 #include "parse_png.h"
17 #include "logging.h"
18 #include "utility.h"
19 #include "crc.h"
20 
21 bool parse_png(const char *source, int length, mpfr_t cx, mpfr_t cy, mpfr_t cz) {
22  assert(source);
23  const unsigned char *s = (const unsigned char *) source;
24  // PNG signature http://www.w3.org/TR/PNG/#5PNG-file-signature
25  const unsigned char signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
26  if (! (length >= 8 && 0 == memcmp(s, signature, 8))) {
27  return false; // not PNG
28  }
29  s += 8;
30  // networkk byte order http://www.w3.org/TR/PNG/#7Integers-and-byte-order
31 #define INT ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3])); s+= 4
32  // tEXt chunk http://www.w3.org/TR/PNG/#11tEXt
33  const unsigned int tEXt = (116 << 24) | (69 << 16) | (88 << 8) | (116);
34  // keyowrds http://www.w3.org/TR/PNG/#11keywords
35  // Software used to create the image
36  const unsigned char *software = (const unsigned char *) "Software";
37  const int software_length = 9; // including null terminator
38  // Short (one line) title or caption for image
39  const unsigned char *title = (const unsigned char *) "Title";
40  const int title_length = 6; // including null terminator
41  // Software text string for mightymandel
42  const unsigned char *mightymandel = (const unsigned char *) "mightymandel";
43  const int mightymandel_length = 12; // NOT including null terminator
44  // search through the chunks
45  bool have_mightymandel = false;
46  char *have_title = 0;
47  while (s + 4 <= (const unsigned char *) source + length) {
48  // PNG chunks http://www.w3.org/TR/PNG/#5Chunk-layout
49  unsigned int chunk_length = INT;
50  if (! (s + chunk_length + 4 <= (const unsigned char *) source + length)) {
51  log_message(LOG_WARN, "PNG truncated?\n");
52  break;
53  }
54  unsigned long chunk_data_crc = crc(s, 4 + chunk_length);
55  unsigned int type = INT;
56  debug_message("parse_png type = %08x (want %08x)\n", type, tEXt);
57  if (type == tEXt) {
58  // Software mightymandel
59  if (! have_mightymandel && 0 == memcmp(s, software, software_length)) {
60  debug_message("parse_png Software\n");
61  s += software_length;
62  chunk_length -= software_length;
63  if ((int) chunk_length == mightymandel_length && 0 == memcmp(s, mightymandel, mightymandel_length)) {
64  debug_message("parse_png Software mightymandel\n");
65  have_mightymandel = true;
66  }
67  }
68  // Title -0.75 + 0.0 i @ 1.5
69  if (! have_title && 0 == memcmp(s, title, title_length)) {
70  debug_message("parse_png Title\n");
71  s += title_length;
72  chunk_length -= title_length;
73  have_title = malloc(chunk_length + 1);
74  memcpy(have_title, s, chunk_length);
75  have_title[chunk_length] = 0;
76  debug_message("parse_png Title '%s'\n", have_title);
77  }
78  }
79  s += chunk_length;
80  unsigned long chunk_crc = INT;
81  if ((chunk_data_crc & 0xFFffFFff) != (chunk_crc & 0xFFffFFff)) {
82  log_message(LOG_WARN, "PNG CRC mismatch: %08x %08x\n", chunk_data_crc, chunk_crc);
83  }
84  // we only care about two keywords in tEXt chunks
85  if (have_mightymandel && have_title) {
86  debug_message("parse_png Software mightymandel + Title\n");
87  bool retval = false;
88  // surely long enough for each substring
89  int len = strlen(have_title) + 1;
90  char *sx = malloc(len); sx[0] = 0;
91  char *sy = malloc(len); sy[0] = 0;
92  char *sz = malloc(len); sz[0] = 0;
93  // parse title
94  if (3 == sscanf(have_title, "%s + %s i @ %s", sx, sy, sz)) {
95  debug_message("parse_png sx '%s'\n", sx);
96  debug_message("parse_png sy '%s'\n", sy);
97  debug_message("parse_png sz '%s'\n", sz);
98  mpfr_set_prec(cz, 53);
99  mpfr_set_str(cz, sz, 10, MPFR_RNDN);
100  if (radius_is_valid(cz)) {
101  mpfr_prec_t p = precision_for_radius(cz);
102  mpfr_set_prec(cx, p);
103  mpfr_set_prec(cy, p);
104  mpfr_set_str(cx, sx, 10, MPFR_RNDN);
105  mpfr_set_str(cy, sy, 10, MPFR_RNDN);
106  retval = true;
107  }
108  }
109  // cleanup
110  free(sx);
111  free(sy);
112  free(sz);
113  free(have_title);
114  return retval;
115  }
116  }
117  // cleanup, might have found some other title unrelated to mightymandel
118  if (have_title) {
119  free(have_title);
120  }
121  return false;
122 #undef INT
123 }