/*
* =====================================================================================
*
* Filename: szbtool.c
*
* Description: 联想手机szb格式的制作工具,部分开源代码(仅提供程序思想);
*
* Version: 1.0
* Created: 2013年03月25日 01时46分16秒
* Revision: none
* Compiler: gcc
*
* Author: linkscue (scue),
* Organization:
*
* =====================================================================================
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
extern char *optarg;
extern int optind;
extern int opterr;
extern int optopt;
#define u8 unsigned char
#define u32 unsigned int
#define u16 unsigned short
#define INFOSIZE 256
#define BUFFER_SIZE 1024
typedef struct {
/*
* 保密信息:szb文件0~12字节
* */
}szb_header_t;
typedef struct {
/*
* 保密信息:szb文件12~256字节
*/
}szb_head_t;
typedef struct {
/*
* 保密信息:szb文件的结构体
*/
}szb_info;
typedef struct{
/*
*保密信息:存放image信息的结构体
* */
}szb_images_t;
/*获取文件长度*/
long getSize( FILE *fp )
{
long int save_pos; /* 保存当前文件指针 */
long size_of_file; /* 保存文件的大小 */
save_pos = ftell( fp ); /* 暂存当前文件指针位置 */
fseek( fp, 0L, SEEK_END ); /* 从文件开始位置移动至文件结尾 */
size_of_file = ftell( fp ); /* 获取文件指针位置 */
fseek( fp, save_pos, SEEK_SET ); /* 还原之前的文件指针位置 */
return( size_of_file ); /* 返回文件大小数值 */
}
unsigned int getSzbSum(char *file){
/*
*保密信息:获取szb文件校验码
* */
return sum;
}
/*计算一个文件的CRC校验*/
unsigned int getSum(FILE *fp)
{
/*
*保密信息:获取image文件校验码
* */
return sum; /* 这里的检验和的值是正确的 */
}
/* 分解szb函数 */
void splitFile(char *file){
FILE *fd = NULL;
FILE *ft = NULL;
int i;
get_szb_info(file); /* 显示szb文件信息 */
if ( (fd=fopen(file,"rb")) == NULL ) { /* 打开文件进行操作 */
printf ( "Extract szb file, open %s failure!\n", file );
exit(1);
}
fseek( fd, 0, SEEK_SET ); /* 重新定向文件指针位置 */
u32 imagecount = 0;
fseek( fd, 84, SEEK_SET ); /* 略过前边的84字节 */
fscanf( fd,"%4c", &imagecount ); /* 获取镜像文件个数 */
fseek( fd, 168, SEEK_CUR ); /* 总共略过前边的256字节的Header信息 */
szb_images_t images[10];
memset(images,0x00,sizeof(images));
for ( i=0; i < imagecount ; i++ ){
fscanf(fd,"%64c",&images[i].filename); /* 获取得文件名称 */
fscanf(fd,"%32c",&images[i].partname);
fscanf(fd,"%4c",&images[i].checksum);
fscanf(fd,"%4c",&images[i].timestamp);
fscanf(fd,"%4c",&images[i].imageoffset); /* 获取偏移位置 */
fscanf(fd,"%4c",&images[i].imagesize); /* 获取镜像文件的大小 */
fscanf(fd,"%4c",&images[i].eraseflag);
fscanf(fd,"%4c",&images[i].writeflag);
fscanf(fd,"%136c",&images[i].reserve);
}
//开始分解数据;
int size,n,offset,fp_local,end;
unsigned char imagename[32]="";
unsigned char buffer[BUFFER_SIZE]; /* 创建缓冲区 */
strncpy(buffer,"",sizeof(buffer)); /* 清空缓冲区内容 */
for( i=0; i < imagecount ; i++ ){
strncpy(imagename, images[i].filename, sizeof(imagename));
offset=images[i].imageoffset;
size=images[i].imagesize;
end=(offset+size);
if ( size != 0 ) {
if ( ( ft=fopen(imagename,"wb") ) == NULL ){
printf("Extract szb file, open %s failure!\n",imagename);
}
fseek( fd, offset, SEEK_SET); /* 跳转至数据段 */
printf("Extract %s..\n",imagename);
while ( fp_local != end ) {
n = fread(buffer,1, sizeof(buffer), fd);
fwrite(buffer, n, 1, ft);
fp_local=ftell(fd);
}
}
}
fclose(fd);
printf("Extract szb file done!\n");
}
/* 在尾部追加二进制文件(cat a >> b) */
void appendFile(char *fp, char *body) {
int n=0;
FILE *in,*out;
u8 buffer[BUFFER_SIZE];
if ( (in = fopen(fp, "rb")) == NULL){
printf ( "Open in file failure!\n" );
exit(1);
}
if ( (out=fopen( body , "ab")) == NULL ){
printf ( "Open out file failure!\n" );
exit(1);
}
while (!feof(in)) {
n = fread(buffer, 1, BUFFER_SIZE, in);
fwrite(buffer, 1, n, out);
}
fclose(in);
fclose(out);
}
/* 复制一个文件至另一个文件位置 */
//void copyFile(char *from, char *to){
// FILE * outfile, *infile;
// infile = fopen(from, "rb");
// outfile = fopen(to, "wb" );
// unsigned char buf[BUFFER_SIZE];
// if( outfile == NULL || infile == NULL )
// {
// printf("Copy file failure!");
// exit(1);
// }
// int rc;
// while( (rc = fread(buf,sizeof(unsigned char), BUFFER_SIZE ,infile)) != 0 )
// {
// fwrite( buf, sizeof( unsigned char ), rc, outfile );
// }
//// sleep(0.1);
// fclose(infile);
// fclose(outfile);
//}
/* 合并两个文件至一个文件 (cat a b > c) */
//void mergeFile(char *fp1,char *fp2,char *name){
// FILE *fd1,*fd2,*fp3;
// unsigned char buf[BUFFER_SIZE];
// char filename[100];
// strncpy(filename,name,sizeof(filename));
// int rc1,rc2;
// fd1 = fopen(fp1,"rb");
// fd2 = fopen(fp2,"rb");
// fp3 = fopen(filename, "wb" );
// while( (rc1 = fread(buf,sizeof(unsigned char), BUFFER_SIZE,fd1)) != 0 )
// {
// fwrite( buf, sizeof( unsigned char ), rc1, fp3 );
// }
// while( (rc2 = fread(buf,sizeof(unsigned char), BUFFER_SIZE,fd2)) != 0 )
// {
// fwrite( buf, sizeof( unsigned char ), rc2, fp3 );
// }
// sleep(0.1);
// fclose(fd1);
// fclose(fd2);
// fclose(fp3);
//}
/* appendImage(szb文件, image文件,文件名称,分区位置,偏移量,索引位置) */
u32 appendImage(char *szb, char *file, char *filename, char *partname, u32 offset, int index){
FILE *fp,*fb;
if((fp=fopen(file,"rb")) == NULL){
printf ( "Open %s failure!\n",filename );
exit(1);
}
szb_images_t image;
strncpy(image.filename, filename, sizeof(image.filename));
strncpy(image.partname, partname, sizeof(image.partname));
strncpy(image.reserve, "", sizeof(image.reserve));
time(&image.timestamp);
image.imageoffset=offset;
image.imagesize=getSize(fp);
image.checksum=getSum(fp);
image.eraseflag=1;
image.writeflag=1;
fclose(fp);
printf("Adding: %-12sOffset: 0x%08x Checksum: 0x%08x\n",image.partname, image.imageoffset, image.checksum);
if ( (fb=fopen(szb, "rb+")) == NULL) {
printf(" append %s to szb file, open szb file failure!\n", file);
exit(1);
}
fseek( fb, ( index * INFOSIZE ), SEEK_SET ); /* 移动文件指针的位置 */
fwrite(&image.filename, sizeof(image.filename), 1, fb); /* 向szb文件写入Image的相关信息 */
fwrite(&image.partname, sizeof(image.partname), 1, fb); /* 向szb文件写入Image的相关信息 */
fwrite(&image.checksum, sizeof(image.checksum), 1, fb); /* 向szb文件写入Image的相关信息 */
fwrite(&image.timestamp, sizeof(image.timestamp), 1, fb); /* 向szb文件写入Image的相关信息 */
fwrite(&image.imageoffset, sizeof(image.imageoffset), 1, fb); /* 向szb文件写入Image的相关信息 */
fwrite(&image.imagesize, sizeof(image.imagesize), 1, fb); /* 向szb文件写入Image的相关信息 */
fwrite(&image.eraseflag, sizeof(image.eraseflag), 1, fb); /* 向szb文件写入Image的相关信息 */
fwrite(&image.writeflag, sizeof(image.writeflag), 1, fb); /* 向szb文件写入Image的相关信息 */
fwrite(&image.reserve, sizeof(image.reserve), 1, fb); /* 向szb文件写入Image的相关信息 */
fclose(fb); /* 向szb文件写完Image信息后关闭 */
appendFile(file, szb); /* 向szb文件的尾部添加image数据 */
return (image.imagesize+image.imageoffset); /* 返回一个偏移数据,方便之后的判断 */
}
void get_szb_info(char *file){
FILE *fp;
int i,count;
szb_info info;
if ( (fp=fopen(file, "rb")) == NULL ) {
/* code */
}
fscanf(fp,"%8c",&info.magic);
/*
*保密信息: 获取szb头部信息
* */
fscanf(fp,"%136c",&info.reserve);
u8 magic[]="LmSzBfMt";
if ( strstr(info.magic,magic) == NULL ){
printf ( "This file not in szb format, abort!\n" );
exit(1);
}
struct tm *ptr; /* 格式化时间输出 */
time_t lt;
unsigned int times=info.timestamp;
char str[80];
lt=times;
ptr=localtime(<);
strftime(str,100,"%F%X",ptr);
printf ( "\n" );
printf ( "Header:\n" );
printf ( "Checksum:\t0x%08x\n",info.checksum );
printf ( "Size:\t\t0x%08x\n",info.filesize );
printf ( "Author:\t\t%s\n",info.author );
printf ( "Version:\t%s\n",info.version );
printf ( "Times:\t\t%s\n",str );
printf ( "Counts:\t\t0x%x\n",info.imagecount );
count=info.imagecount;
szb_images_t images[10];
printf ( "\n" );
printf ( "Images:\n" );
for ( i=0; i < info.imagecount ; i++ ){
fscanf(fp,"%64c",&images[i].filename);
fscanf(fp,"%32c",&images[i].partname);
fscanf(fp,"%4c",&images[i].checksum);
fscanf(fp,"%4c",&images[i].timestamp);
fscanf(fp,"%4c",&images[i].imageoffset);
fscanf(fp,"%4c",&images[i].imagesize);
fscanf(fp,"%4c",&images[i].eraseflag);
fscanf(fp,"%4c",&images[i].writeflag);
fscanf(fp,"%136c",&images[i].reserve);
if ( strlen(images[i].filename) != 0 ){
printf ( "Position: %-10sOffset: 0x%08x Checksum: 0x%08x\n",images[i].partname, images[i].imageoffset, images[i].checksum );}
else{
printf ( "Earse: %-10sCaution!\n",images[i].partname);
}
}
printf ( "\n" );
fclose(fp);
}
/* 显示szbtool作者信息 */
void author_info(){
printf ( "\n" );
printf ( "===============================================================\n" );
printf ( " Welcome to use Lenovo K860/K860i szbtool! \n" );
printf ( "\n" );
printf ( " -- version: 0.14 \n" );
printf ( " -- author: linkscue \n" );
printf ( "===============================================================\n" );
}
/* 显示使用帮助 */
void usage(){
printf ( "\n" );
printf ( "---------------------------------------------------------------\n" );
printf ( "usage:\n" );
printf ( "szbtool -b uboot # add uboot.bin\n" );
printf ( "szbtool -k boot # add boot.img\n" );
printf ( "szbtool -r recovery # add recovery.img\n" );
printf ( "szbtool -s system # add system.img\n" );
printf ( "szbtool -c cpimage # add cpimage.img\n" );
printf ( "szbtool -p preload # add preload.img\n" );
printf ( "szbtool -d userdata # add userdata.img\n" );
printf ( "szbtool -e erase # erase data & cache space\n" );
printf ( "szbtool -a author # specify author\n" );
printf ( "szbtool -v version # specify version\n" );
printf ( "szbtool -i szb # szb information\n" );
printf ( "szbtool -x szb # extract szb \n" );
printf ( "szbtool -h # help\n" );
printf ( "---------------------------------------------------------------\n" );
printf ( "e.g. szbtool -k boot.img -s system.img -a scue@Link -v Link.szb\n" );
printf ( "\n" );
}
/*主函数*/
int main ( int argc, char *argv[] )
{
FILE *fp,*fp1,*fp2,*fd1,*fd2,*sub_image;
char *file=NULL;
u8 magic[8];
u8 imagename[64];
u8 partname[32];
u8 version[32];
u8 author[32];
u32 filesize;
u32 offset=8192; /* 初始的偏移量 */
char opt; /* 获取输入的选项 */
int index=0; /* 判断szb中的分区索引数量 */
int DO_NOTHING=0; /* 依据此变量判断是否执行 */
int ERASE_DATA=0; /* 依据此变量判断是否擦除数据 */
//清空变量
memset(version,0x00,sizeof(version));
memset(imagename,0x00,sizeof(imagename));
memset(partname,0x00,sizeof(partname));
strncpy(author,"scue@Link",sizeof(author));
//显示作者信息
author_info();
//检测输入参数
if(argc == 1)
{
usage(); /* 显示使用手册 */
exit(0);
}
//判断选项中是否有版本
int i;
char tmp1[32]="";
char tmp2[32]="";
strncpy(tmp2,"-v",sizeof(tmp2));
for (i = 0; i < argc; i++) {
strncpy(tmp1,argv[i],sizeof(tmp1));
if ( strcmp(tmp1,tmp2) == 0 ) {
strncpy(version,argv[i+1],sizeof(version));
}
if ( strcmp(tmp1,"-x") == 0 || strcmp(tmp1,"-i")==0 ) {
DO_NOTHING = 1;
}
}
if ( strlen(version) == 0 && DO_NOTHING !=1 ){
printf ( "\n" );
printf ( "Please use -v to specify a version name!\n" );
usage();
exit(1);
}
if (DO_NOTHING != 1) { /* 当发现有事可做的时候... */
//创建文件
remove(version); /* delete the old szb file */
if ( (fp=fopen(version,"wb+")) == NULL ) {
printf ( "Create version file %s failure!\n",version);
exit(1);
}
u8 header_buffer[INFOSIZE*32];
strncpy(header_buffer, "LmSzBfMt", sizeof(header_buffer));
fwrite(header_buffer, sizeof(header_buffer) , 1, fp); /* 向其中写8192字节后退出 */
index++;
fclose(fp);
}
//开始获取选项信息
opterr=0; /* 不显示错误的选项信息 */
while ((opt = getopt(argc, argv, "b:k:r:s:c:p:d:x:i:v:a:e")) != -1)
switch (opt) {
case 'v':
strncpy(version,optarg,sizeof(version));
break;
case 'b':
file=optarg;
strncpy(partname,"bootloader",sizeof(partname));
strncpy(imagename,"uboot.bin",sizeof(imagename));
offset=appendImage(version, file, imagename, partname, offset, index);
index++;
break;
case 'k':
file=optarg;
strncpy(partname,"boot",sizeof(partname));
strncpy(imagename,"boot.img",sizeof(imagename));
offset=appendImage(version, file, imagename, partname, offset, index);
index++;
break;
case 'r':
file=optarg;
strncpy(partname,"recovery",sizeof(partname));
strncpy(imagename,"recovery.img",sizeof(imagename));
offset=appendImage(version, file, imagename, partname, offset, index);
index++;
break;
case 's':
file=optarg;
strncpy(partname,"system",sizeof(partname));
strncpy(imagename,"system.img",sizeof(imagename));
offset=appendImage(version, file, imagename, partname, offset, index);
index++;
break;
case 'c':
file=optarg;
strncpy(partname,"cpimage",sizeof(partname));
strncpy(imagename,"cpimage.img",sizeof(imagename));
offset=appendImage(version, file, imagename, partname, offset, index);
index++;
break;
case 'p':
file=optarg;
strncpy(partname,"preload",sizeof(partname));
strncpy(imagename,"preload.img",sizeof(imagename));
offset=appendImage(version, file, imagename, partname, offset, index);
index++;
break;
case 'd':
file=optarg;
strncpy(partname,"userdata",sizeof(partname));
strncpy(imagename,"userdata.img",sizeof(imagename));
offset=appendImage(version, file, imagename, partname, offset, index);
index++;
break;
case 'e':
ERASE_DATA=1;
break;
case 'a':
strncpy(author,optarg,sizeof(author));
break;
case 'x':
DO_NOTHING=1;
file=optarg;
splitFile(file);
break;
case 'i':
DO_NOTHING=1;
file=optarg;
get_szb_info(file);
break;
default:
DO_NOTHING=1;
usage();
}
argv += optind;
//开始执行制作szb文件
if ( DO_NOTHING != 1 ){
//检查是否输入格式名
if ( strlen(version) == 0 ){
DO_NOTHING = 1;
printf ( "\n" );
printf ( "Please use -v to specify a version name!\n" );
usage();
exit(1);
}
// 双清功能
if ( ERASE_DATA == 1) { /* 判断是否有“双清功能” */
u8 erase_data[32];
u8 erase_cache[32];
strncpy(erase_data, "userdata", sizeof(erase_data));
strncpy(erase_cache, "cache", sizeof(erase_data));
if ( (fp=fopen(version, "rb+")) == NULL ) {
printf("Add erase features, open file %s failure!\n", version);
exit(1);
}
fseek( fp, (INFOSIZE * index + 64 ), SEEK_SET ); /* erase userdata */
fwrite(erase_data, sizeof(erase_data), 1, fp);
index++;
fseek( fp, (INFOSIZE * index + 64 ), SEEK_SET ); /* erase cache */
fwrite(erase_cache, sizeof(erase_cache), 1, fp);
index++;
fclose(fp);
}
//制作SZB格式文件头部(256-12)部分
szb_head_t head;
if ( (fp=fopen(version,"rb+")) ==NULL ){
printf("Calculate file size, open file %s failure!\n", version);
exit(1);
}
head.filesize=getSize(fp); /* get szb file size */
/*
* 保密信息:向szb文件写入数据
* */
time(&head.timestamp); /* 写入时间信息 */
/*
* 保密信息:向szb文件写入数据
* */
fseek( fp, 12, SEEK_SET );
fwrite(&head,sizeof(szb_head_t),1,fp); /* 写入256-12字节部分 */
fclose(fp);
u32 szb_checksum;
szb_checksum=getSzbSum(version);
if ( (fp=fopen(version,"rb+")) ==NULL ){
printf("Calculate file size, open file %s failure!\n", version);
exit(1);
}
fseek(fp, 8, SEEK_SET);
fwrite(&szb_checksum,sizeof(szb_checksum),1,fp); /* 写入总的验证码字节部分 */
fclose(fp);
get_szb_info(version);
printf ( ">> Congratulations! The Official ROM %s done!\n",version);
printf ( "\n" );
}
return 0;
}