1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2007 The Android Open Source Project
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Licensed under the Apache License, Version 2.0 (the "License");
5*4882a593Smuzhiyun * you may not use this file except in compliance with the License.
6*4882a593Smuzhiyun * You may obtain a copy of the License at
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * http://www.apache.org/licenses/LICENSE-2.0
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Unless required by applicable law or agreed to in writing, software
11*4882a593Smuzhiyun * distributed under the License is distributed on an "AS IS" BASIS,
12*4882a593Smuzhiyun * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4882a593Smuzhiyun * See the License for the specific language governing permissions and
14*4882a593Smuzhiyun * limitations under the License.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <stdlib.h>
18*4882a593Smuzhiyun #include <unistd.h>
19*4882a593Smuzhiyun #include <string.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <fcntl.h>
22*4882a593Smuzhiyun #include <stdio.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include <sys/ioctl.h>
25*4882a593Smuzhiyun #include <sys/mman.h>
26*4882a593Smuzhiyun #include <sys/types.h>
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <linux/fb.h>
29*4882a593Smuzhiyun #include <linux/kd.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include <png.h>
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #include "minui.h"
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun extern char* locale;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define SURFACE_DATA_ALIGNMENT 8
38*4882a593Smuzhiyun
malloc_surface(size_t data_size)39*4882a593Smuzhiyun static gr_surface malloc_surface(size_t data_size) {
40*4882a593Smuzhiyun unsigned char* temp = malloc(sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT);
41*4882a593Smuzhiyun if (temp == NULL) return NULL;
42*4882a593Smuzhiyun gr_surface surface = (gr_surface) temp;
43*4882a593Smuzhiyun surface->data = temp + sizeof(GRSurface) +
44*4882a593Smuzhiyun (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT));
45*4882a593Smuzhiyun return surface;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun
open_png(const char * name,png_structp * png_ptr,png_infop * info_ptr,png_uint_32 * width,png_uint_32 * height,png_byte * channels)48*4882a593Smuzhiyun static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr,
49*4882a593Smuzhiyun png_uint_32* width, png_uint_32* height, png_byte* channels) {
50*4882a593Smuzhiyun char resPath[256];
51*4882a593Smuzhiyun unsigned char header[8];
52*4882a593Smuzhiyun int result = 0;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
55*4882a593Smuzhiyun resPath[sizeof(resPath)-1] = '\0';
56*4882a593Smuzhiyun FILE* fp = fopen(resPath, "rb");
57*4882a593Smuzhiyun if (fp == NULL) {
58*4882a593Smuzhiyun result = -1;
59*4882a593Smuzhiyun goto exit;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun size_t bytesRead = fread(header, 1, sizeof(header), fp);
63*4882a593Smuzhiyun if (bytesRead != sizeof(header)) {
64*4882a593Smuzhiyun result = -2;
65*4882a593Smuzhiyun goto exit;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun if (png_sig_cmp(header, 0, sizeof(header))) {
69*4882a593Smuzhiyun result = -3;
70*4882a593Smuzhiyun goto exit;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
74*4882a593Smuzhiyun if (!*png_ptr) {
75*4882a593Smuzhiyun result = -4;
76*4882a593Smuzhiyun goto exit;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun *info_ptr = png_create_info_struct(*png_ptr);
80*4882a593Smuzhiyun if (!*info_ptr) {
81*4882a593Smuzhiyun result = -5;
82*4882a593Smuzhiyun goto exit;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (setjmp(png_jmpbuf(*png_ptr))) {
86*4882a593Smuzhiyun result = -6;
87*4882a593Smuzhiyun goto exit;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun png_init_io(*png_ptr, fp);
91*4882a593Smuzhiyun png_set_sig_bytes(*png_ptr, sizeof(header));
92*4882a593Smuzhiyun png_read_info(*png_ptr, *info_ptr);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun int color_type, bit_depth;
95*4882a593Smuzhiyun png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth,
96*4882a593Smuzhiyun &color_type, NULL, NULL, NULL);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun *channels = png_get_channels(*png_ptr, *info_ptr);
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) {
101*4882a593Smuzhiyun // 8-bit RGB images: great, nothing to do.
102*4882a593Smuzhiyun } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) {
103*4882a593Smuzhiyun // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray.
104*4882a593Smuzhiyun png_set_expand_gray_1_2_4_to_8(*png_ptr);
105*4882a593Smuzhiyun } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) {
106*4882a593Smuzhiyun // paletted images: expand to 8-bit RGB. Note that we DON'T
107*4882a593Smuzhiyun // currently expand the tRNS chunk (if any) to an alpha
108*4882a593Smuzhiyun // channel, because minui doesn't support alpha channels in
109*4882a593Smuzhiyun // general.
110*4882a593Smuzhiyun png_set_palette_to_rgb(*png_ptr);
111*4882a593Smuzhiyun *channels = 3;
112*4882a593Smuzhiyun } else {
113*4882a593Smuzhiyun fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n",
114*4882a593Smuzhiyun bit_depth, *channels, color_type);
115*4882a593Smuzhiyun result = -7;
116*4882a593Smuzhiyun goto exit;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun return result;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun exit:
122*4882a593Smuzhiyun if (result < 0) {
123*4882a593Smuzhiyun png_destroy_read_struct(png_ptr, info_ptr, NULL);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun if (fp != NULL) {
126*4882a593Smuzhiyun fclose(fp);
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun return result;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun // "display" surfaces are transformed into the framebuffer's required
133*4882a593Smuzhiyun // pixel format (currently only RGBX is supported) at load time, so
134*4882a593Smuzhiyun // gr_blit() can be nothing more than a memcpy() for each row. The
135*4882a593Smuzhiyun // next two functions are the only ones that know anything about the
136*4882a593Smuzhiyun // framebuffer pixel format; they need to be modified if the
137*4882a593Smuzhiyun // framebuffer format changes (but nothing else should).
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun // Allocate and return a gr_surface sufficient for storing an image of
140*4882a593Smuzhiyun // the indicated size in the framebuffer pixel format.
init_display_surface(png_uint_32 width,png_uint_32 height)141*4882a593Smuzhiyun static gr_surface init_display_surface(png_uint_32 width, png_uint_32 height) {
142*4882a593Smuzhiyun gr_surface surface;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun surface = malloc_surface(width * height * 4);
145*4882a593Smuzhiyun if (surface == NULL) return NULL;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun surface->width = width;
148*4882a593Smuzhiyun surface->height = height;
149*4882a593Smuzhiyun surface->row_bytes = width * 4;
150*4882a593Smuzhiyun surface->pixel_bytes = 4;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun return surface;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun // Copy 'input_row' to 'output_row', transforming it to the
156*4882a593Smuzhiyun // framebuffer pixel format. The input format depends on the value of
157*4882a593Smuzhiyun // 'channels':
158*4882a593Smuzhiyun //
159*4882a593Smuzhiyun // 1 - input is 8-bit grayscale
160*4882a593Smuzhiyun // 3 - input is 24-bit RGB
161*4882a593Smuzhiyun // 4 - input is 32-bit RGBA/RGBX
162*4882a593Smuzhiyun //
163*4882a593Smuzhiyun // 'width' is the number of pixels in the row.
transform_rgb_to_draw(unsigned char * input_row,unsigned char * output_row,int channels,int width)164*4882a593Smuzhiyun static void transform_rgb_to_draw(unsigned char* input_row,
165*4882a593Smuzhiyun unsigned char* output_row,
166*4882a593Smuzhiyun int channels, int width) {
167*4882a593Smuzhiyun int x;
168*4882a593Smuzhiyun unsigned char* ip = input_row;
169*4882a593Smuzhiyun unsigned char* op = output_row;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun switch (channels) {
172*4882a593Smuzhiyun case 1:
173*4882a593Smuzhiyun // expand gray level to RGBX
174*4882a593Smuzhiyun for (x = 0; x < width; ++x) {
175*4882a593Smuzhiyun *op++ = *ip;
176*4882a593Smuzhiyun *op++ = *ip;
177*4882a593Smuzhiyun *op++ = *ip;
178*4882a593Smuzhiyun *op++ = 0xff;
179*4882a593Smuzhiyun ip++;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun break;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun case 3:
184*4882a593Smuzhiyun // expand RGBA to RGBX
185*4882a593Smuzhiyun for (x = 0; x < width; ++x) {
186*4882a593Smuzhiyun *op++ = *ip++;
187*4882a593Smuzhiyun *op++ = *ip++;
188*4882a593Smuzhiyun *op++ = *ip++;
189*4882a593Smuzhiyun *op++ = 0xff;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun break;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun case 4:
194*4882a593Smuzhiyun // copy RGBA to RGBX
195*4882a593Smuzhiyun memcpy(output_row, input_row, width*4);
196*4882a593Smuzhiyun break;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
res_create_display_surface(const char * name,gr_surface * pSurface)200*4882a593Smuzhiyun int res_create_display_surface(const char* name, gr_surface* pSurface) {
201*4882a593Smuzhiyun gr_surface surface = NULL;
202*4882a593Smuzhiyun int result = 0;
203*4882a593Smuzhiyun png_structp png_ptr = NULL;
204*4882a593Smuzhiyun png_infop info_ptr = NULL;
205*4882a593Smuzhiyun png_uint_32 width, height;
206*4882a593Smuzhiyun png_byte channels;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun *pSurface = NULL;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
211*4882a593Smuzhiyun if (result < 0) return result;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun surface = init_display_surface(width, height);
214*4882a593Smuzhiyun if (surface == NULL) {
215*4882a593Smuzhiyun result = -8;
216*4882a593Smuzhiyun goto exit;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun unsigned char* p_row = malloc(width * 4);
220*4882a593Smuzhiyun unsigned int y;
221*4882a593Smuzhiyun for (y = 0; y < height; ++y) {
222*4882a593Smuzhiyun png_read_row(png_ptr, p_row, NULL);
223*4882a593Smuzhiyun transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width);
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun free(p_row);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun *pSurface = surface;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun exit:
230*4882a593Smuzhiyun png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
231*4882a593Smuzhiyun if (result < 0 && surface != NULL) free(surface);
232*4882a593Smuzhiyun return result;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
res_create_multi_display_surface(const char * name,int * frames,gr_surface ** pSurface)235*4882a593Smuzhiyun int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface) {
236*4882a593Smuzhiyun gr_surface* surface = NULL;
237*4882a593Smuzhiyun int result = 0;
238*4882a593Smuzhiyun png_structp png_ptr = NULL;
239*4882a593Smuzhiyun png_infop info_ptr = NULL;
240*4882a593Smuzhiyun png_uint_32 width, height;
241*4882a593Smuzhiyun png_byte channels;
242*4882a593Smuzhiyun int i;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun *pSurface = NULL;
245*4882a593Smuzhiyun *frames = -1;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
248*4882a593Smuzhiyun if (result < 0) return result;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun *frames = 1;
251*4882a593Smuzhiyun png_textp text;
252*4882a593Smuzhiyun int num_text;
253*4882a593Smuzhiyun if (png_get_text(png_ptr, info_ptr, &text, &num_text)) {
254*4882a593Smuzhiyun for (i = 0; i < num_text; ++i) {
255*4882a593Smuzhiyun if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) {
256*4882a593Smuzhiyun *frames = atoi(text[i].text);
257*4882a593Smuzhiyun break;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun printf(" found frames = %d\n", *frames);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun if (height % *frames != 0) {
264*4882a593Smuzhiyun printf("bad height (%d) for frame count (%d)\n", height, *frames);
265*4882a593Smuzhiyun result = -9;
266*4882a593Smuzhiyun goto exit;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun surface = malloc(*frames * sizeof(gr_surface));
270*4882a593Smuzhiyun if (surface == NULL) {
271*4882a593Smuzhiyun result = -8;
272*4882a593Smuzhiyun goto exit;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun for (i = 0; i < *frames; ++i) {
275*4882a593Smuzhiyun surface[i] = init_display_surface(width, height / *frames);
276*4882a593Smuzhiyun if (surface[i] == NULL) {
277*4882a593Smuzhiyun result = -8;
278*4882a593Smuzhiyun goto exit;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun unsigned char* p_row = malloc(width * 4);
283*4882a593Smuzhiyun unsigned int y;
284*4882a593Smuzhiyun for (y = 0; y < height; ++y) {
285*4882a593Smuzhiyun png_read_row(png_ptr, p_row, NULL);
286*4882a593Smuzhiyun int frame = y % *frames;
287*4882a593Smuzhiyun unsigned char* out_row = surface[frame]->data +
288*4882a593Smuzhiyun (y / *frames) * surface[frame]->row_bytes;
289*4882a593Smuzhiyun transform_rgb_to_draw(p_row, out_row, channels, width);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun free(p_row);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun *pSurface = (gr_surface*) surface;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun exit:
296*4882a593Smuzhiyun png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun if (result < 0) {
299*4882a593Smuzhiyun if (surface) {
300*4882a593Smuzhiyun for (i = 0; i < *frames; ++i) {
301*4882a593Smuzhiyun if (surface[i]) free(surface[i]);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun free(surface);
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun return result;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
res_create_alpha_surface(const char * name,gr_surface * pSurface)309*4882a593Smuzhiyun int res_create_alpha_surface(const char* name, gr_surface* pSurface) {
310*4882a593Smuzhiyun gr_surface surface = NULL;
311*4882a593Smuzhiyun int result = 0;
312*4882a593Smuzhiyun png_structp png_ptr = NULL;
313*4882a593Smuzhiyun png_infop info_ptr = NULL;
314*4882a593Smuzhiyun png_uint_32 width, height;
315*4882a593Smuzhiyun png_byte channels;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun *pSurface = NULL;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
320*4882a593Smuzhiyun if (result < 0) return result;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if (channels != 1) {
323*4882a593Smuzhiyun result = -7;
324*4882a593Smuzhiyun goto exit;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun surface = malloc_surface(width * height);
328*4882a593Smuzhiyun if (surface == NULL) {
329*4882a593Smuzhiyun result = -8;
330*4882a593Smuzhiyun goto exit;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun surface->width = width;
333*4882a593Smuzhiyun surface->height = height;
334*4882a593Smuzhiyun surface->row_bytes = width;
335*4882a593Smuzhiyun surface->pixel_bytes = 1;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun unsigned char* p_row;
338*4882a593Smuzhiyun unsigned int y;
339*4882a593Smuzhiyun for (y = 0; y < height; ++y) {
340*4882a593Smuzhiyun p_row = surface->data + y * surface->row_bytes;
341*4882a593Smuzhiyun png_read_row(png_ptr, p_row, NULL);
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun *pSurface = surface;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun exit:
347*4882a593Smuzhiyun png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
348*4882a593Smuzhiyun if (result < 0 && surface != NULL) free(surface);
349*4882a593Smuzhiyun return result;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun
matches_locale(const char * loc,const char * locale)352*4882a593Smuzhiyun static int matches_locale(const char* loc, const char* locale) {
353*4882a593Smuzhiyun if (locale == NULL) return 0;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun if (strcmp(loc, locale) == 0) return 1;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun // if loc does *not* have an underscore, and it matches the start
358*4882a593Smuzhiyun // of locale, and the next character in locale *is* an underscore,
359*4882a593Smuzhiyun // that's a match. For instance, loc == "en" matches locale ==
360*4882a593Smuzhiyun // "en_US".
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun int i;
363*4882a593Smuzhiyun for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);
364*4882a593Smuzhiyun if (loc[i] == '_') return 0;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun return (strncmp(locale, loc, i) == 0 && locale[i] == '_');
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
res_create_localized_alpha_surface(const char * name,const char * locale,gr_surface * pSurface)369*4882a593Smuzhiyun int res_create_localized_alpha_surface(const char* name,
370*4882a593Smuzhiyun const char* locale,
371*4882a593Smuzhiyun gr_surface* pSurface) {
372*4882a593Smuzhiyun gr_surface surface = NULL;
373*4882a593Smuzhiyun int result = 0;
374*4882a593Smuzhiyun png_structp png_ptr = NULL;
375*4882a593Smuzhiyun png_infop info_ptr = NULL;
376*4882a593Smuzhiyun png_uint_32 width, height;
377*4882a593Smuzhiyun png_byte channels;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun *pSurface = NULL;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun if (locale == NULL) {
382*4882a593Smuzhiyun surface = malloc_surface(0);
383*4882a593Smuzhiyun surface->width = 0;
384*4882a593Smuzhiyun surface->height = 0;
385*4882a593Smuzhiyun surface->row_bytes = 0;
386*4882a593Smuzhiyun surface->pixel_bytes = 1;
387*4882a593Smuzhiyun goto exit;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
391*4882a593Smuzhiyun if (result < 0) return result;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun if (channels != 1) {
394*4882a593Smuzhiyun result = -7;
395*4882a593Smuzhiyun goto exit;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun unsigned char* row = malloc(width);
399*4882a593Smuzhiyun png_uint_32 y;
400*4882a593Smuzhiyun for (y = 0; y < height; ++y) {
401*4882a593Smuzhiyun png_read_row(png_ptr, row, NULL);
402*4882a593Smuzhiyun int w = (row[1] << 8) | row[0];
403*4882a593Smuzhiyun int h = (row[3] << 8) | row[2];
404*4882a593Smuzhiyun int len = row[4];
405*4882a593Smuzhiyun char* loc = (char*)row+5;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun if (y+1+h >= height || matches_locale(loc, locale)) {
408*4882a593Smuzhiyun printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun surface = malloc_surface(w*h);
411*4882a593Smuzhiyun if (surface == NULL) {
412*4882a593Smuzhiyun result = -8;
413*4882a593Smuzhiyun goto exit;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun surface->width = w;
416*4882a593Smuzhiyun surface->height = h;
417*4882a593Smuzhiyun surface->row_bytes = w;
418*4882a593Smuzhiyun surface->pixel_bytes = 1;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun int i;
421*4882a593Smuzhiyun for (i = 0; i < h; ++i, ++y) {
422*4882a593Smuzhiyun png_read_row(png_ptr, row, NULL);
423*4882a593Smuzhiyun memcpy(surface->data + i*w, row, w);
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun *pSurface = (gr_surface) surface;
427*4882a593Smuzhiyun break;
428*4882a593Smuzhiyun } else {
429*4882a593Smuzhiyun int i;
430*4882a593Smuzhiyun for (i = 0; i < h; ++i, ++y) {
431*4882a593Smuzhiyun png_read_row(png_ptr, row, NULL);
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun exit:
437*4882a593Smuzhiyun png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
438*4882a593Smuzhiyun if (result < 0 && surface != NULL) free(surface);
439*4882a593Smuzhiyun return result;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
res_free_surface(gr_surface surface)442*4882a593Smuzhiyun void res_free_surface(gr_surface surface) {
443*4882a593Smuzhiyun free(surface);
444*4882a593Smuzhiyun }
445