Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
assetcull.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
20// $File: //depot/GeneralsMD/Staging/code/Tools/assetcull/assetcull.cpp $
21// $Author: mhoffe $
22// $Revision: #1 $
23// $DateTime: 2003/07/28 14:54:04 $
24//
25// ©2003 Electronic Arts
26//
27// simple recursive directory compare tool for asset culling
29#include <string>
30#include <vector>
31#include <sys/stat.h>
32#include <stdio.h>
33#include <io.h>
34
35/*
36 Usage: assetcull <dir1> <dir2> <bat-file>
37
38 Description:
39 All files in <dir1> and <dir2> (and subdirectories) are compared
40 binary. If an identical file exists it is removed from <dir1>
41 and a corresponding DEL line is written to the given batch file.
42*/
43
44static bool filesEqual(const char *fn1, const char *fn2)
45{
46 // make sure both files exist and are of same size
47 struct _stat s1,s2;
48 if (_stat(fn1,&s1)||
49 _stat(fn2,&s2))
50 return false;
51 if (s1.st_size!=s2.st_size)
52 return false;
53
54 // must compare byte-by-byte
55 FILE *f1=fopen(fn1,"rb");
56 if (!f1)
57 return false;
58 FILE *f2=fopen(fn2,"rb");
59 if (!f2)
60 return false;
61
62 static char buf1[16384],buf2[16384];
63 for (unsigned k=0;k<s1.st_size;)
64 {
65 unsigned cur=s1.st_size-k;
66 if (cur>sizeof(buf1))
67 cur=sizeof(buf1);
68 if (fread(buf1,cur,1,f1)!=1||
69 fread(buf2,cur,1,f2)!=1)
70 break;
71 if (memcmp(buf1,buf2,cur))
72 break;
73 k+=cur;
74 }
75 fclose(f1);
76 fclose(f2);
77 return k==s1.st_size;
78}
79
80static int recursiveCull(FILE *batchFile,
81 const char *dir1, const char *dir2,
82 const char *relDir)
83{
84 // sub directory must exist both in dir1 and dir2
85 // (but we're walking dir2 only later)
86 std::string work;
87 work=dir1; work+=relDir; work+="*.*";
88 _finddata_t fd;
89 long h=_findfirst(work.c_str(),&fd);
90 if (h==-1)
91 return 0;
92 _findclose(h);
93
94 work=dir2; work+=relDir; work+="*.*";
95 h=_findfirst(work.c_str(),&fd);
96 if (h==-1)
97 return 0;
98
99 // walk dir2, collect sub directories and check for duplicate
100 // files
101 std::vector<std::string> subdir,dupfiles;
102 int deleted=0;
103 for (;;)
104 {
105 if (fd.attrib&_A_SUBDIR)
106 {
107 if (strcmp(fd.name,".")&&
108 strcmp(fd.name,".."))
109 subdir.push_back(fd.name);
110 }
111 else
112 {
113 std::string work1,work2;
114 work1=dir1; work1+=relDir; work1+=fd.name;
115 work2=dir2; work2+=relDir; work2+=fd.name;
116 if (filesEqual(work1.c_str(),work2.c_str()))
117 dupfiles.push_back(fd.name);
118 }
119 if (_findnext(h,&fd))
120 break;
121 }
122 _findclose(h);
123
124 // remove duplicate files, at to batch file
125 // (we can't just delete them inside the find loop because - at
126 // least theoretically - that could screw up that find process...)
127 for (std::vector<std::string>::iterator i=dupfiles.begin();i!=dupfiles.end();++i)
128 {
129 std::string work;
130 work=dir1; work+=relDir; work+=*i;
131 _chmod(work.c_str(),_S_IREAD|_S_IWRITE);
132 if (_unlink(work.c_str()))
133 fprintf(stderr,"Error: Can't delete %s\n",work.c_str());
134 else
135 deleted++;
136 fprintf(batchFile,"attrib -r \"%s\"\n",work.c_str());
137 fprintf(batchFile,"del -r \"%s\"\n",work.c_str());
138 }
139
140 // walk subdirectories
141 for (i=subdir.begin();i!=subdir.end();++i)
142 {
143 std::string work;
144 work=relDir;
145 work+=*i;
146 work+="\\";
147 deleted+=recursiveCull(batchFile,dir1,dir2,work.c_str());
148 }
149
150 // done!
151 return deleted;
152}
153
154int main(int argc, char *argv[])
155{
156 if (argc!=4)
157 {
158 printf("Usage: assetcull <dir1> <dir2> <bat-file>\n\n"
159 "Description:\n"
160 " All files in <dir1> and <dir2> (and subdirectories) are compared\n"
161 " binary. If an identical file exists it is removed from <dir1>\n"
162 " and a corresponding DEL line is written to the given batch file.\n"
163 );
164 return 10;
165 }
166
167 FILE *f=fopen(argv[3],"wt");
168 if (!f)
169 {
170 printf("Error: Can't create %s\n",argv[3]);
171 return 10;
172 }
173
174 int n=recursiveCull(f,argv[1],argv[2],"\\.\\");
175 fclose(f);
176 printf("assetcull: %i files culled.\n",n);
177
178 return 0;
179}
void main(void)
Definition test1.cpp:47