曾经,有个项目,资源文件过大,mod+所有资源+sig+mif文件超过1.5MB(日本kddi有这方面限制),又不允许使用mod压缩的方法(该方法有些非常非常小的缺陷),他们说,随着mod附带一部分资源,剩下的资源文件在线下载吧。
听起来很简单,不就是把资源文件分割掉,放到网上去么,事实的情况是:程序中要知道随着mod附带了多少资源;总共有多少的资源包没有下载;下载了的资源包是否有损坏;网络通讯中间是否有错误;网络下载是否当天超过了6MB;本程序当天下载是否超过了3MB,(3MB和6MB等都是kddi的规定);下载完成之后,中间某个资源包错误之后,程序需要判断是哪一个,并且重新下载;包的分割多大为合适(用户不会希望等半天都没有进度显示);程序需要计算剩余多少没有下载。
一句话引发了一场灾难,我的项目都是使用make来编译的,资源使用make来整理的,如果make能帮我自动计算并分割,那我将会省很多事情。我很庆幸自己用命令行的方式,如果用IDE的方式,每次的更改将会是一场灾难。于是就写了下面的makefile:
OBJ=test.bin SPLIT_SIZE=262144 OUT_DIR=out DIST_DIR?=ready_packet OUTFILE?= SKIP_SIZE?=0 SIZE?=0 CRC?=0 IN_FILE?= PACKAGE_SIZE?=1572864 POSITION?= LENGTH?= H_FILE=../project/source/cpp/spdata/download_data.h ZIP=../../Tool/7z.exe FILE_SIZE=$(word 5, $(shell ls -l $(OBJ) )) cutfile= $($(call mvfile, $(3), $(4) ) && $(shell dd if=$(3) of=$(4) bs=1 count=$(call exprsize, $(2), -, $(1) ) skip=$(1) ) ) all: rm -drf $(DIST_DIR) mkdir -p $(DIST_DIR) make do_all # rm -drf $(OBJ) clean: rm -drf $(OUT_DIR) otherres1: rm -drf $(OUT_DIR) mkdir -p $(OUT_DIR) @echo do all INDEX=0;PACKAGE_SIZE=$(PACKAGE_SIZE);NAME=0;SKIP_SIZE=0;while [[ "$$SKIP_SIZE" -lt $(FILE_SIZE) ]]; \ do \ echo "skip_size=$$SKIP_SIZE"; \ let "skip_block=NAME";\ make split1 OUTFILE="$(OUT_DIR)/$(basename $(OBJ))_"$$NAME".bin" SKIP_SIZE=$$skip_block;\ let "SKIP_SIZE+=$(SPLIT_SIZE)"; \ echo "skip_size=$$SKIP_SIZE"; \ let "NAME+=1";\ done;\ let "PACKAGE_SIZE-=`cksum \"$(OUT_DIR)/res.bin\"|gawk '{print $$2}'`"; \ while [[ "$$INDEX" -lt "$$NAME" ]]; \ do \ let "PACKAGE_SIZE-=`cksum \"$(OUT_DIR)/$(basename $(OBJ))_\"$$INDEX\".bin\"|gawk '{print $$2}'`"; \ if [[ "$$PACKAGE_SIZE" -lt 0 ]]; \ then \ break; \ fi; \ cat "$(OUT_DIR)/$(basename $(OBJ))_"$$INDEX".bin" >> $(OUT_DIR)/res.bin; \ let "INDEX+=1"; \ done;\ mkdir -p $(DIST_DIR) # cp -f $(OUT_DIR)/res.bin $(DIST_DIR)/res.bin cp -f $(OBJ) $(DIST_DIR)/res.bin otherres: rm -drf $(OUT_DIR) mkdir -p $(OUT_DIR) @echo do all INDEX=0;PACKAGE_SIZE=$(PACKAGE_SIZE);NAME=0;SKIP_SIZE=0;while [[ "$$SKIP_SIZE" -lt $(FILE_SIZE) ]]; \ do \ echo "skip_size=$$SKIP_SIZE"; \ let "skip_block=NAME";\ make split1 OUTFILE="$(OUT_DIR)/$(basename $(OBJ))_"$$NAME".bin" SKIP_SIZE=$$skip_block;\ let "SKIP_SIZE+=$(SPLIT_SIZE)"; \ echo "skip_size=$$SKIP_SIZE"; \ let "NAME+=1";\ done;\ let "PACKAGE_SIZE-=`cksum \"$(OUT_DIR)/res.bin\"|gawk '{print $$2}'`"; \ while [[ "$$INDEX" -lt "$$NAME" ]]; \ do \ let "PACKAGE_SIZE-=`cksum \"$(OUT_DIR)/$(basename $(OBJ))_\"$$INDEX\".bin\"|gawk '{print $$2}'`"; \ if [[ "$$PACKAGE_SIZE" -lt 0 ]]; \ then \ break; \ fi; \ cat "$(OUT_DIR)/$(basename $(OBJ))_"$$INDEX".bin" >> $(OUT_DIR)/res.bin; \ let "INDEX+=1"; \ done;\ mkdir -p $(DIST_DIR) cp -f $(OUT_DIR)/res.bin $(DIST_DIR)/res.bin # cp -f $(OBJ) $(DIST_DIR)/res.bin split1: @echo "split1 from $(SKIP_SIZE) size=$(SPLIT_SIZE)" dd if=$(OBJ) of=$(OUTFILE).tmp bs=$(SPLIT_SIZE) count=1 skip=$(SKIP_SIZE) # $(ZIP) -tgzip a $(OUTFILE).tmp1 $(OUTFILE).tmp # rm -f $(OUTFILE).tmp1 make insert1 OUTFILE=$(OUTFILE) IN_FILE=$(OUTFILE).tmp POSITION=$(SKIP_SIZE) `cksum $(OUTFILE).tmp|gawk '{print "CRC="$$1,"SIZE="$$2}'` rm -f $(OUTFILE).tmp insert1: @echo "make insert1 $(OUTFILE) $(IN_FILE) $(CRC) $(SIZE) $(POSITION)" # make writehex OUTFILE=$(OUT_DIR)/res.bin SIZE=$(POSITION) # make writehex OUTFILE=$(OUT_DIR)/res.bin SIZE=$(SIZE) # make writehex OUTFILE=$(OUT_DIR)/res.bin SIZE=$(CRC) cat $(IN_FILE) >> $(OUTFILE) do_all: @echo do all cd res/data && make clean && make mv stdata_sd.bin ready_packet/res.bin echo -e "#include \"define.h\"\nstatic _CONST_ int FILE_ARRAY[]= {" > $(H_FILE); NAME=0;SKIP_SIZE=0;while [[ "$$SKIP_SIZE" -lt $(FILE_SIZE) ]]; \ do \ echo "skip_size=$$SKIP_SIZE"; \ let "skip_block=NAME";\ make split OUTFILE="$(DIST_DIR)/$(basename $(OBJ))_"$$NAME".bin" SKIP_SIZE=$$skip_block;\ let "SKIP_SIZE+=$(SPLIT_SIZE)"; \ echo "skip_size=$$SKIP_SIZE"; \ let "NAME+=1";\ done; \ echo -e "};\n#define NET_ALL_FILE_NUM $$NAME\n#define BLOCK_SIZE $(SPLIT_SIZE)\n#define FILE_SIZE $(FILE_SIZE)" >> $(H_FILE) split: @echo "split from $(SKIP_SIZE) size=$(SPLIT_SIZE)" dd if=$(OBJ) of=$(OUTFILE).tmp bs=$(SPLIT_SIZE) count=1 skip=$(SKIP_SIZE) # $(ZIP) -tgzip a $(OUTFILE).tmp1 $(OUTFILE).tmp # rm -f $(OUTFILE).tmp1 make insert OUTFILE=$(OUTFILE) IN_FILE=$(OUTFILE).tmp `cksum $(OUTFILE).tmp|gawk '{print "CRC="$$1,"SIZE="$$2}'` rm -f $(OUTFILE).tmp insert: @echo "make insert $(OUTFILE) $(IN_FILE) $(CRC) $(SIZE)" make writehex OUTFILE=$(OUTFILE) SIZE=$(SIZE) make writehex OUTFILE=$(OUTFILE) SIZE=$(CRC) cat $(IN_FILE) >> $(OUTFILE) echo -e " $(SIZE), $(CRC)," >> $(H_FILE) writehex: COUNT=4;_SIZE=$(SIZE);while [[ "$$COUNT" -gt 0 ]];\ do \ let "_OUT=_SIZE%256";\ let "_SIZE=_SIZE/256";\ let "COUNT-=1";\ TST=(`echo $$_OUT|gawk '{printf "%x", $$0}'`); \ OUT="\\x$$TST"; \ printf $$OUT >> $(OUTFILE);\ done;
上面的代码应该是可以运行的,记忆有些模糊,因为最终,他们又同意mod压缩方法了,上面的代码就完全白费了。只能感叹,中国的人力资源真便宜。
实际上,在调用的时候要调用上面的makefile文件两次,第一次是在代码编译之前,生成.h文件。使用
make DIST_DIR=net
的方式调用。
第二次的调用在代码编译之后,打包资源的时候,需要计算剩余可用的容量,然后打包整理,我是这样调用的:
PACKAGE_SIZE=0; for i in $(RES) ; \ do \ echo "i=$$i"; \ let "PACKAGE_SIZE+=`cksum \"$(RESDIR)/$$i\"|gawk '{print $$2}'`"; \ done; \ let "PACKAGE_SIZE+=`cksum \"$(RELEASE_DIR)/$(PLAT)/$(P)/$(TARGET)/$(TARGET).$(MODULE)\"|gawk '{print $$2}'`"; \ let "PACKAGE_SIZE+=`cksum \"$(RELEASE_DIR)/$(PLAT)/$(P)/$(TARGET).mif\"|gawk '{print $$2}'`"; \ let "PACKAGE_SIZE+=4096"; \ let "PACKAGE_SIZE=$(MAX_SIZE)-PACKAGE_SIZE"; \ cd resource && make otherres PACKAGE_SIZE=$$PACKAGE_SIZE && make clean cp -f $(RESDIR)/res.bin $(RELEASE_DIR)/$(PLAT)/$(P)/$(TARGET)/res.bin
测试这边,在国内没办法使用网络下载,所以,我顺便又调用那个makefile一次,生成测试那边可以用的资源,就像他们已经下载完成了那样:
cd resource && make otherres1 PACKAGE_SIZE=20971520 DIST_DIR=smc && make clean
上面的脚本执行起来比较慢,没有30分钟是搞不定的。但如果手动的话,即使快,又没办法做到自动,况且还需要添加crc校验,长度校验,因此,我个人认为,这个是可以接受的。不幸的是,项目中最后完全没有用到,不过,最后却又省了很多麻烦事,何况,自己写的代码到最后没有用处的也不在少数。
专业性好强啊~