recovery图片资源的再分析

来源:互联网 发布:python 记录日志 编辑:程序博客网 时间:2024/05/21 11:08

1. 概述

为了进一步分析recovery系统使用资源png文件的过程,我们把相关代码剥离出来,作成小例子进行分析。


2. 正向分析的代码

这个小例子的第一步是能够遍历出png中所有locale的图片信息。


2.1 代码

代码如下:

/* * gcc png_example.c -Iinclude -lpng * * The original code is based android_4.4.2_r2 branch. */#include <stdlib.h>#include <unistd.h>#include <stdio.h>#include <sys/types.h>#include <png.h>#include <pixelflinger/pixelflinger.h> // android/system/core/include/pixelfligner/pixelflinger.h// copy from minui.htypedef struct {    int width;    int height;    int row_bytes;    int pixel_bytes;    unsigned char* data;} GRSurface;typedef GRSurface* gr_surface;#define SURFACE_DATA_ALIGNMENT 8static gr_surface malloc_surface(size_t data_size) {    unsigned char* temp = malloc(sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT);    if (temp == NULL) return NULL;    gr_surface surface = (gr_surface) temp;    surface->data = temp + sizeof(GRSurface) +        (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT));    return surface;}static int open_png(const char* file_name, png_structp* png_ptr, png_infop* info_ptr,                    png_uint_32* width, png_uint_32* height, png_byte* channels) {    unsigned char header[8];    int result = 0;    FILE* fp = fopen(file_name, "rb");    if (fp == NULL) {        result = -1;        goto exit;    }    size_t bytesRead = fread(header, 1, sizeof(header), fp);    if (bytesRead != sizeof(header)) {        result = -2;        goto exit;    }    if (png_sig_cmp(header, 0, sizeof(header))) {        result = -3;        goto exit;    }    *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);    if (!*png_ptr) {        result = -4;        goto exit;    }    *info_ptr = png_create_info_struct(*png_ptr);    if (!*info_ptr) {        result = -5;        goto exit;    }    if (setjmp(png_jmpbuf(*png_ptr))) {        result = -6;        goto exit;    }    png_init_io(*png_ptr, fp);    png_set_sig_bytes(*png_ptr, sizeof(header));    png_read_info(*png_ptr, *info_ptr);    int color_type, bit_depth;    png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth,            &color_type, NULL, NULL, NULL);    *channels = png_get_channels(*png_ptr, *info_ptr);    if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) {        // 8-bit RGB images: great, nothing to do.    } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) {        // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray.        png_set_expand_gray_1_2_4_to_8(*png_ptr);    } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) {        // paletted images: expand to 8-bit RGB.  Note that we DON'T        // currently expand the tRNS chunk (if any) to an alpha        // channel, because minui doesn't support alpha channels in        // general.        png_set_palette_to_rgb(*png_ptr);        *channels = 3;    } else {        fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n",                bit_depth, *channels, color_type);        result = -7;        goto exit;    }    return result;  exit:    if (result < 0) {        png_destroy_read_struct(png_ptr, info_ptr, NULL);    }    if (fp != NULL) {        fclose(fp);    }    return result;}static int matches_locale(const char* loc, const char* locale) {    if (locale == NULL) return 0;    if (strcmp(loc, locale) == 0) return 1;    // if loc does *not* have an underscore, and it matches the start    // of locale, and the next character in locale *is* an underscore,    // that's a match.  For instance, loc == "en" matches locale ==    // "en_US".    int i;    for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);    if (loc[i] == '_') return 0;    return (strncmp(locale, loc, i) == 0 && locale[i] == '_');}int read_png(const char* file_name, const char* locale/*,                                    gr_surface* pSurface*/) {    gr_surface surface = NULL;    int result = 0;    png_structp png_ptr = NULL;    png_infop info_ptr = NULL;    png_uint_32 width, height;    png_byte channels;    //*pSurface = NULL;    if (locale == NULL) {        surface = malloc_surface(0);        surface->width = 0;        surface->height = 0;        surface->row_bytes = 0;        surface->pixel_bytes = 1;        goto exit;    }    result = open_png(file_name, &png_ptr, &info_ptr, &width, &height, &channels);    if (result < 0) return result;    if (channels != 1) {        result = -7;        goto exit;    }    unsigned char* row = malloc(width);    png_uint_32 y;    for (y = 0; y < height; ++y) {        png_read_row(png_ptr, row, NULL);        int w = (row[1] << 8) | row[0];        int h = (row[3] << 8) | row[2];        int len = row[4];        char* loc = (char*)row+5;        printf("  %20s: %s (%d x %d @ %lu)\n", file_name, loc, w, h, y);        if (y+1+h >= height || matches_locale(loc, locale)) {            surface = malloc_surface(w*h);            if (surface == NULL) {                result = -8;                goto exit;            }            surface->width = w;            surface->height = h;            surface->row_bytes = w;            surface->pixel_bytes = 1;            int i;            for (i = 0; i < h; ++i, ++y) {                png_read_row(png_ptr, row, NULL);                memcpy(surface->data + i*w, row, w);            }            //*pSurface = (gr_surface) surface;            break;        } else {            int i;            for (i = 0; i < h; ++i, ++y) {                png_read_row(png_ptr, row, NULL);            }        }    }exit:    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);    if (result < 0 && surface != NULL) free(surface);    return result;}int main(int argc, const char* argv[]) {if (argc != 3) {printf("Usage: ./a.out file_name locale\n");exit(1);}read_png(argv[1], argv[2]);return 0;}

2.2 运行结果

如果机器上还没有安装png库,则需要先做这个准备工作。其实这一步只需要一条命令即可:

sudo apt-get install libpng-dev

因为是小例子,就没有makefile,直接用gcc命令来完成编译&链接的事情。命令在代码一开始的注释中给出了,下面是运行的效果:

flying-bird@flyingbird:~/examples/png$ gcc png_example.c -Iinclude -lpngflying-bird@flyingbird:~/examples/png$ ./a.out ./res/installing_text.png en_GB  ./res/installing_text.png: ar (305 x 38 @ 0)  ./res/installing_text.png: bg (384 x 71 @ 39)  ./res/installing_text.png: ca (429 x 71 @ 111)  ./res/installing_text.png: cs (398 x 38 @ 183)  ./res/installing_text.png: da (414 x 38 @ 222)  ./res/installing_text.png: de (382 x 38 @ 261)  ./res/installing_text.png: el (338 x 71 @ 300)  ./res/installing_text.png: en_GB (324 x 38 @ 372)flying-bird@flyingbird:~/examples/png$ ./a.out ./res/installing_text.png en  ./res/installing_text.png: ar (305 x 38 @ 0)  ./res/installing_text.png: bg (384 x 71 @ 39)  ./res/installing_text.png: ca (429 x 71 @ 111)  ./res/installing_text.png: cs (398 x 38 @ 183)  ./res/installing_text.png: da (414 x 38 @ 222)  ./res/installing_text.png: de (382 x 38 @ 261)  ./res/installing_text.png: el (338 x 71 @ 300)  ./res/installing_text.png: en_GB (324 x 38 @ 372)  ./res/installing_text.png: en (324 x 38 @ 411)flying-bird@flyingbird:~/examples/png$ ./a.out ./res/installing_text.png xy_GB  ./res/installing_text.png: ar (305 x 38 @ 0)  ./res/installing_text.png: bg (384 x 71 @ 39)  ./res/installing_text.png: ca (429 x 71 @ 111)  ./res/installing_text.png: cs (398 x 38 @ 183)  ./res/installing_text.png: da (414 x 38 @ 222)  ./res/installing_text.png: de (382 x 38 @ 261)  ./res/installing_text.png: el (338 x 71 @ 300)  ./res/installing_text.png: en_GB (324 x 38 @ 372)  ./res/installing_text.png: en (324 x 38 @ 411)  ./res/installing_text.png: es_ES (474 x 38 @ 450)  ./res/installing_text.png: es (474 x 38 @ 489)  ./res/installing_text.png: fa (416 x 38 @ 528)  ./res/installing_text.png: fi (438 x 38 @ 567)  ./res/installing_text.png: fr (388 x 71 @ 606)  ./res/installing_text.png: hr (393 x 38 @ 678)  ./res/installing_text.png: hu (370 x 38 @ 717)  ./res/installing_text.png: in (397 x 38 @ 756)  ./res/installing_text.png: it (384 x 71 @ 795)  ./res/installing_text.png: iw (245 x 38 @ 867)  ./res/installing_text.png: ja (474 x 71 @ 906)  ./res/installing_text.png: ko (317 x 38 @ 978)  ./res/installing_text.png: lt (384 x 38 @ 1017)  ./res/installing_text.png: lv (385 x 71 @ 1056)  ./res/installing_text.png: nb (434 x 38 @ 1128)  ./res/installing_text.png: nl (350 x 38 @ 1167)  ./res/installing_text.png: pl (394 x 38 @ 1206)  ./res/installing_text.png: pt_BR (449 x 38 @ 1245)  ./res/installing_text.png: pt (459 x 38 @ 1284)  ./res/installing_text.png: ro (472 x 38 @ 1323)  ./res/installing_text.png: ru (446 x 38 @ 1362)  ./res/installing_text.png: sk (392 x 71 @ 1401)  ./res/installing_text.png: sl (439 x 38 @ 1473)  ./res/installing_text.png: sr (336 x 71 @ 1512)  ./res/installing_text.png: sv (404 x 38 @ 1584)  ./res/installing_text.png: th (334 x 38 @ 1623)  ./res/installing_text.png: tl (419 x 38 @ 1662)  ./res/installing_text.png: tr (414 x 38 @ 1701)  ./res/installing_text.png: uk (471 x 38 @ 1740)  ./res/installing_text.png: vi (462 x 38 @ 1779)  ./res/installing_text.png: zh_CN (240 x 38 @ 1818)  ./res/installing_text.png: zh (240 x 38 @ 1857)  ./res/installing_text.png:  (1 x 1 @ 1896)flying-bird@flyingbird:~/examples/png$  ./a.out ./res/installing_text.png en_ES  ./res/installing_text.png: ar (305 x 38 @ 0)  ./res/installing_text.png: bg (384 x 71 @ 39)  ./res/installing_text.png: ca (429 x 71 @ 111)  ./res/installing_text.png: cs (398 x 38 @ 183)  ./res/installing_text.png: da (414 x 38 @ 222)  ./res/installing_text.png: de (382 x 38 @ 261)  ./res/installing_text.png: el (338 x 71 @ 300)  ./res/installing_text.png: en_GB (324 x 38 @ 372)  ./res/installing_text.png: en (324 x 38 @ 411)flying-bird@flyingbird:~/examples/png$ 

2.3 locale匹配规则

locale匹配的规则在Android源代码中有详细的说明(下面代码中间的一段注释),另外通过代码也可以分析出来。为了阅读方便,再copy&paste这个函数:

static int matches_locale(const char* loc, const char* locale) {    if (locale == NULL) return 0;    if (strcmp(loc, locale) == 0) return 1;    // if loc does *not* have an underscore, and it matches the start    // of locale, and the next character in locale *is* an underscore,    // that's a match.  For instance, loc == "en" matches locale ==    // "en_US".    int i;    for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);    if (loc[i] == '_') return 0;    return (strncmp(locale, loc, i) == 0 && locale[i] == '_');}

参数中第一个loc是从png文件中读取出来的字符串,第二个locale是目标字符串。运行时输入了几种参数进行对比运行,其中最后一个en_ES是非法代码,并没有西班牙英语微笑



3. 图片规则

3.1 每个图片的width & height

进一步地,通过打印信息,可以看出每种locale的图片高度和宽度并不一样。——@ xxx这个数据无需关注,通常仅用于调试用,验证是否地区某个locale的图片at实现放置的位置。(此仅为猜测微笑


3.2 色彩深度等

通过Android的各个分支代码的对比分析,可以看到Android准备支持越来越多的图片格式。至于目前,我们仅关注如下规则:

  1. bit_depth == 8
  2. channels == 1
  3. color_type == PNG_COLOR_TYPE_GRAY



2 0