📄 pack.cpp
字号:
#pragma warning(disable :4786)
#include "stdafx.h"
#include "windows.h"
//#include "shlwapi.h"
#include "shlobj.h"
#include "objbase.h"
#include <assert.h>
#include <stdlib.h>
#include <assert.h>
#include <string>
#include <iostream>
#include <vector>
#include "estdio.h"
using namespace std;
extern "C"{
HRESULT ResolveIt(HWND hwnd, LPCSTR lpszLinkFile, LPSTR lpszPath) ;
}
struct PakEntry{
unsigned long nameHash; // hashValue of fileName.
unsigned long start; //*4 is the start address.
unsigned long len;
};
struct Pak{
long nPak;
struct PakEntry aPak[0];
//..
//file1.
//file2.
} *pak;
/* giving a file name, return a unique long to represent it. (a string hash function)
* if 2 string has the same hash value, please change your file name( sorry :) )
*/
unsigned long NameHash(const char* s)
{
unsigned long h=0;
const char *p;
for(p = s; *p ; p ++)
h = ( h << 5 ) - h + *p;
return h;
}
/* check if 2 string of a strings set has the same hash value,
* if so , please change your file name
*/
void IsCollision(vector<string>& names)
{
int collision = 0;
vector<string>::iterator i;
for(i= names.begin(); i!=names.end(); i++){
unsigned int nameHash = NameHash((*i).c_str());
for(vector<string>::iterator j = names.begin(); j!= i; j++){
if(nameHash == NameHash((*j).c_str())){
cout << "Hash collision: "<< *i <<'\t' <<*j <<'\n';
collision = 1;
}
}
}
if(collision)
exit(-1);
}
/* in BREW, the file name are relative. convert absolute path name to relative name( relate to root)
* for example, if root is F:\\brewPrj\\brew\\san\\
* name is F:\\brewPrj\\brew\\san\\res\\a.dat
* then the result is res\\a.dat
*/
string CalcRelativePath(string name ,string root)
{
//the relative name. convert F:\\brewPrj\\brew\\san\\res\\a.dat to res\\a.dat
string::size_type pos = name.find(root);
if(pos == string::npos ){
cout << "Cann't find root:"<< root <<" in "<< name <<'\n';
assert(0);
exit(-1);
}
return name.substr(root.length(),name.length() - root.length());
}
/* giving a filename, return it's start offset in packaged file
*/
int FindHash(struct Pak* pak, string s,vector<string>& names,const char *root )
{
struct PakEntry *p;
for(p = pak->aPak;p- pak->aPak < pak->nPak; p++){
string r = CalcRelativePath(s,root);
if(p->nameHash == NameHash(r.c_str()))
return p->start;
}
assert(0);
return 0;
}
/* packing all file in names to a big file.
* store name relate to root,
* for each name
* compute name's hash value
* if conflict with previous have value
* prompt user to change name, exit
* start = temp.pak's len +3 &~3;
* len = name.len
* copy /b name to temp.pak
* aPak[i] ={nameHash, start/4,len}
* write pak to name.pak
* append temp.pak to name.pak
* remove temp.pak
*
* NOTE: name rules:
* the name used to calculte hash value is relate to root, and have no .lzo posix,
* so other module call fopen("res\\a.dat") will read res\\a.dat if not packaged,
* and will read res\\a.dat.lzo if packaged.
*/
void package(vector<string>& names, const char *root, const char *fileName)
{
string rt(root);
vector<string>::iterator i;
int size = sizeof(pak) + names.size() * sizeof(struct PakEntry);
pak = (struct Pak*)malloc(size);
pak->nPak = names.size();
struct PakEntry *p;
int start = size;
FILE *log = efopen((string(fileName)+".txt").c_str(),"wt");
//concate all file to tmp.pak
FILE *tmp = efopen("tmp.pak","wb");
for(p = pak->aPak,i= names.begin() ; i!=names.end(); p++, i++){
long len;
char *block;
if( string::npos != (*i).find("_linkTo_") ){
p->nameHash = 0;
continue;
}
block = BinRead((*i+".lzo").c_str(), &len) ;
p->len = len;
len = (len+3)&~3; //align to long
efwrite(block,1,len,tmp); //write length should align to long
string r = CalcRelativePath(*i,root);
p->nameHash = NameHash(r.c_str());
p->start = start>>2;
fprintf(log, "%08x\t%d\t%d\t%s\n",p->nameHash, p->start<<2, p->len, (r+".lzo").c_str());
start += len;
free(block);
}
for(p = pak->aPak,i= names.begin() ; i!=names.end(); p++, i++){
if(p->nameHash != 0) continue;
/* adding support for shortcuts
* if *i is A_linkTo_B
*
*
* p->nameHash = NameHash( RelativePath(A));
* p->start = B's start ( s must already in NameHash. )
* so the first loop process all non link file, second loop process linked ones
*/
string r = CalcRelativePath(*i,root);
string A = r;
int pos = A.find("_linkTo_");
assert(pos != string::npos);
A[pos] = 0;
p->nameHash = NameHash(A.c_str());
string B = r.substr(pos+strlen("_linkTo_"));
pos = (*i).find_last_of("\\");
assert(pos != string::npos);
string C=(*i).substr(0, pos+1);
C += B;
p->start = FindHash(pak,C,names,root);
fprintf(log,"%s link To %s\n",A.c_str(), B.c_str());
}
fclose(tmp);
fclose(log);
//insert pak at the begin of tmp.pak
FILE *out = efopen(fileName,"wb");
efwrite(pak,1,size,out);
long tmplen;
char *buff = BinRead("tmp.pak",&tmplen);
efwrite(buff,1,tmplen,out);
fclose(out);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -