recovery图片资源的又分析
recovery图片资源的再分析
1. 概述
2. 正向分析的代码
参数中第一个loc是从png文件中读取出来的字符串,第二个locale是目标字符串。运行时输入了几种参数进行对比运行,其中最后一个en_ES是非法代码,并没有西班牙英语
3.1 每个图片的width & height
附录 TODO
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.h typedef struct { int width; int height; int row_bytes; int pixel_bytes; unsigned char* data; } GRSurface; typedef GRSurface* gr_surface; #define SURFACE_DATA_ALIGNMENT 8 static 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 -lpng flying-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是非法代码,并没有西班牙英语
以上信息姑且认为是Recovery模式下的文本显示一文的补充。
3. 图片规则
3.1 每个图片的width & height
进一步地,通过打印信息,可以看出每种locale的图片高度和宽度并不一样。——@ xxx这个数据无需关注,通常仅用于调试用,验证是否地区某个locale的图片at实现放置的位置。(此仅为猜测)
3.2 色彩深度等
通过Android的各个分支代码的对比分析,可以看到Android准备支持越来越多的图片格式。至于目前,我们仅关注如下规则:
- bit_depth == 8
- channels == 1
- color_type == PNG_COLOR_TYPE_GRAY
4. 绘制一个小图片
准备工具;
画图;
调整参数
5. 利用png读取图片
附录 TODO
- 利用绘图工具绘制一个符合上述要求的图片;
- 用png库读取该文件;
- 增加类似locale的信息到图片中(IDAT部分);
- 绘制多个图片;;
- 自动把多个图片转换成一个符合recovery解析规则的png文件。
- 是否可以自动把文本串转换出png???
- CRC32源码
- 1楼u013344915前天 19:28
- 文中使用的代码&资源文件以上传,方便大家调试。http://download.****.net/detail/u013344915/7103357