[C语言] 联想手机szb格式的制作工具,部分开源代码(仅提供程序思想);

/*
 * =====================================================================================
 *
 *       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(&lt);
    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;
}

 

posted @ 2013-03-28 22:01  scue  阅读(1167)  评论(1编辑  收藏  举报