/** =====================================================================================** 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 1024typedef 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; }