Merge branch 'lua_versions' into main/rendor-staging
[ryzomcore.git] / ryzom / tools / xml_packer / xml_packer.cpp
blob3261bb6828a1bffc496a7dc7ff62eb5371590d81
3 #include "nel/misc/types_nl.h"
4 #include "nel/misc/app_context.h"
5 #include "nel/misc/path.h"
6 #include "nel/misc/common.h"
7 #include "nel/misc/sstring.h"
8 #include "nel/misc/algo.h"
10 using namespace std;
11 using namespace NLMISC;
13 enum TAction
15 pack,
16 unpack,
17 undefined
20 const string DefaultExt("xml_pack");
21 const uint32 MaxLineSize = 16*1024;
23 const string ExcludeFiles(".#*;*.log;*.bin");
24 const string ExcludeDirs("CVS");
26 bool isExcludedFile(const std::string &fileName)
28 static vector<string> excludeFileVect;
29 static bool init = false;
31 if (!init)
33 explode(ExcludeFiles, ";", excludeFileVect, true);
34 init = true;
37 bool excluded = false;
39 for (uint i=0; i<excludeFileVect.size(); ++i)
41 if (testWildCard(fileName, excludeFileVect[i]))
43 excluded = true;
44 break;
48 return excluded;
51 bool isExcludedDir(const std::string &dirName)
53 static vector<string> excludeDirVect;
54 static bool init = false;
56 if (!init)
58 explode(ExcludeDirs, ";", excludeDirVect, true);
61 bool excluded = false;
63 for (uint i=0; i<excludeDirVect.size(); ++i)
65 if (testWildCard(dirName, excludeDirVect[i]))
67 excluded = true;
68 break;
72 return excluded;
75 string getLastDirName(const std::string &path)
77 string dirName;
78 string::size_type pos = path.size()-1;
80 // skip any terminal directory separator
81 if (pos > 0 && (path[pos] == '\\' || path[pos] == '/'))
82 --pos;
84 while(pos > 0 && path[pos] != '\\' && path[pos] != '/' )
85 dirName = path[pos--] + dirName;
87 return dirName;
90 int main(int argc, char *argv[])
92 printf("XML Packer/Unpacker V0.1\n(C) Nevrax 2006\n");
93 CApplicationContext appContext;
95 TAction action = undefined;
96 bool recursive = false;
98 // compute the current folder name
99 string currentPath = CPath::getCurrentPath();
100 string dirName = getLastDirName(currentPath);;
102 string filename = dirName + "."+DefaultExt;
104 // check the params to choose action
105 for (uint i=0; i<uint(argc); ++i)
107 if (strcmp(argv[i], "-p") == 0)
109 // pack the current folder
110 action = pack;
111 printf("Packing files\n");
113 else if (strcmp(argv[i], "-u") == 0)
115 // unpack the current folder
116 action = unpack;
117 printf("Unpacking files\n");
119 else if (strcmp(argv[i], "-r") == 0)
121 // unpack the current folder
122 recursive = true;
123 printf("Recursive mode\n");
125 // else if (strcmp(argv[i], "-f") == 0)
126 // {
127 // if (uint(argc) < i+i)
128 // {
129 // printf("Error : missing file name after -f\n");
130 // return -1;
131 // }
132 // // use the specified file archive instead of the directory name
133 // filename = argv[++i];
134 // }
137 if (action == undefined)
139 printf("Usage : %s -u|-p [-r] [-f <filename>]\n", argv[0]);
140 printf(" -p : pack the current folder\n");
141 printf(" -u : unpack the current folder\n");
142 printf(" -r : pack or unpack subdirectories recursively\n");
143 // printf(" -f <filename> : use the specified filename instead of current directory name\n");
145 return -1;
148 vector<string> dirStack;
150 printf("Current patch is '%s'\n", CPath::getCurrentPath().c_str());
152 // push the current directory to start the loop
153 dirStack.push_back(CPath::getCurrentPath());
156 while(!dirStack.empty())
158 string dirName = dirStack.back();
159 dirStack.pop_back();
160 string filename = dirName+"/"+getLastDirName(dirName) + "."+DefaultExt;
161 switch (action)
163 case pack:
165 printf("Packing directory '%s'...\n", dirName.c_str());
166 // string packFileName = dirName+"/tmp."+DefaultExt;
167 string packFileName = filename;
169 // get the current directory content
170 vector<string> files;
171 CPath::getPathContent(dirName, false, false, true, files);
173 vector<string> validFiles;
175 // first loop to build the list of valid file
176 for (uint i=0; i<files.size(); ++i)
178 if (files[i].find(DefaultExt) != string::npos)
179 continue;
181 string &subFileName = files[i];
183 // check exclude filter
184 if (isExcludedFile(subFileName))
186 continue;
189 // ok, this file is valid
190 validFiles.push_back(subFileName);
193 bool needRepack = true;
195 // if an xml pack already exist in the folder...
196 if (CFile::fileExists(packFileName))
198 uint32 packDate = CFile::getFileModificationDate(packFileName);
199 // loop to check for file time stamp
200 for (uint i=0; i<validFiles.size(); ++i)
202 uint32 fileDate = CFile::getFileModificationDate(validFiles[i]);
204 if (fileDate >= packDate)
205 // no more to check
206 break;
209 // all files are older than the pack file ! no repack needed
210 needRepack = false;
213 if (needRepack)
215 // open the pack file
216 // FILE *fp = nlfopen(filename, "wt");
217 FILE *fp = nlfopen(packFileName, "wt");
219 fprintf(fp, "<packed_xml>\n");
221 for (uint i=0; i<validFiles.size(); ++i)
223 string &subFileName = validFiles[i];
225 printf("Adding file '%s'...\n", CFile::getFilename(subFileName).c_str());
226 fprintf(fp, " <xml_file name=\"%s\">\n", CFile::getFilename(subFileName).c_str());
228 FILE *subFp = nlfopen(subFileName, "rt");
229 nlassert(subFp != NULL);
230 char buffer[MaxLineSize];
231 char *result;
232 bool needFinalReturn = false;
233 result = fgets(buffer, MaxLineSize, subFp);
234 needFinalReturn = result != NULL ? buffer[strlen(buffer)-1] != '\n' : true;
235 while(result != 0)
237 fputs(buffer, fp);
238 result = fgets(buffer, MaxLineSize, subFp);
239 needFinalReturn = result != NULL ? buffer[strlen(buffer)-1] != '\n' : needFinalReturn;
241 if (needFinalReturn)
243 char *finalReturn = "\n";
244 fputs(finalReturn, fp);
247 fclose(subFp);
249 fprintf(fp, " </nel:xml_file>\n");
252 fprintf(fp, "</nel:packed_xml>\n");
254 fclose(fp);
256 else
258 printf("Directory %s is up to date, no repack\n", dirName.c_str());
261 break;
262 case unpack:
264 printf("Unpacking directory '%s'...\n", dirName.c_str());
265 // open the pack file
266 // FILE *fp = nlfopen(dirName+"/tmp."+DefaultExt, "rt");
267 FILE *fp = nlfopen(filename, "rt");
268 nlassert(fp != NULL);
269 uint linecount = 0;
271 // read the first line
272 char buffer[MaxLineSize];
273 fgets(buffer, MaxLineSize, fp);
274 linecount++;
275 if (strcmp(buffer, "<nel:packed_xml>\n") != 0)
277 printf ("Error : invalid pack file '%s'\n", filename.c_str());
278 exit(-1);
281 char *result = NULL;
284 // read a file line
285 fgets(buffer, MaxLineSize, fp);
286 CSString parser(buffer);
287 linecount++;
288 if (parser.find(" <nel:xml_file name=") != 0)
290 if (parser.find("</nel:packed_xml>") == 0)
292 // end of pack file
293 fclose(fp);
294 break;
296 printf ("Error : invalid pack file '%s' at line %u", filename.c_str(), linecount);
297 exit(-1);
300 CSString subFileName = parser.leftCrop(sizeof(" <nel:xml_file name=")-1);
301 subFileName = subFileName.matchDelimiters(false, false, true, false);
302 subFileName = subFileName.unquoteIfQuoted();
303 subFileName = dirName+"/"+subFileName;
305 printf("Extracting file '%s'...\n", CFile::getFilename(subFileName).c_str());
306 // open the output file
307 FILE *output = nlfopen(subFileName, "wt");
308 if (output == NULL)
310 printf ("Error : can not open output file '%s' from pack file '%s'", subFileName.c_str(), filename.c_str());
311 exit(-1);
314 result = fgets(buffer, MaxLineSize, fp);
315 linecount++;
316 while (result != NULL && strcmp(buffer, " </nel:xml_file>\n") != 0)
318 fputs(result, output);
319 // read next line
320 result = fgets(buffer, MaxLineSize, fp);
321 linecount++;
324 fclose(output);
326 } while(result != NULL);
329 // break;
332 if (recursive)
334 vector<string> subDirs;
335 CPath::getPathContent(dirName, false, true, false, subDirs);
337 // filter the directories
338 for (uint i=subDirs.size(); i>0; --i)
340 if (!isExcludedDir(subDirs[i-1]))
341 dirStack.push_back(subDirs[i-1]);
345 return 0;