Added aqua_speed for rite geo 50 tryker
[ryzomcore.git] / nel / tools / misc / extract_filename / extract_filename.cpp
blob3dbf05b8d84ed6a87e423491e26777f142233102
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "nel/misc/file.h"
21 #include "nel/misc/config_file.h"
23 using namespace std;
24 using namespace NLMISC;
26 #ifdef NL_DEBUG
27 #define INFO nlinfo
28 #else // NL_DEBUG
29 # if defined(NL_COMP_VC) && NL_COMP_VC_VERSION >= 71
30 # define INFO __noop
31 # else
32 # define INFO 0&&
33 # endif
34 #endif // NL_DEBUG
36 bool readTheFile (const char *filename, vector<char> &fileArray)
38 // Open the file
39 CIFile file;
40 if (file.open (filename))
42 // Go to the end
43 file.seek (0, NLMISC::IStream::end);
45 // Get file size
46 sint32 size = file.getPos ();
48 // Resize the array
49 fileArray.resize (size);
51 // Go to the begin
52 file.seek (0, NLMISC::IStream::begin);
54 if (size)
56 // Read the file
57 NLMISC::IStream *stream = &file;
58 stream->serialBuffer ((uint8*)&fileArray[0], size);
61 return true;
63 else
65 // Error, can't open the file
66 nlwarning ("Can't open the file %s for reading.", filename);
68 return false;
72 inline bool isASCII (uint8 c)
74 return ( (c>=0x20 /*&& c<=0x7E*/) || (c == 0x09) || (c == 0x0A) || (c == 0x0D) );
77 bool isASCII(vector<char> &fileArray)
79 // Array size
80 uint size = (uint)fileArray.size();
82 if (size)
84 // Array pointer
85 const char *arrayPointer = &fileArray[0];
87 // Line count
88 uint line = 0;
90 for (uint c=0; c<size; c++)
92 if (!isASCII (arrayPointer[c]))
94 INFO ("Binary character: 0x%02x (line %d)", (uint)(uint8)arrayPointer[c], line);
95 return false;
97 if (arrayPointer[c] == '\n')
98 line++;
102 return true;
105 inline bool isStringChar (char c)
107 return ( ( (c>='a') && (c<='z') ) || ( (c>='A') && (c<='Z') ) || ( (c>='0') && (c<='9') ) || (c=='-') || (c=='_') || (c=='.') );
110 void removeBeginEndSpaces (string &str)
112 // Remove begin space
113 sint index=0;
114 while ( (index<(sint)str.length ()) && (str[index]==' ') )
115 index++;
116 if (index != 0)
117 str = str.substr (index, str.length ()-index);
119 // Remove end space
120 index=(sint)str.length ()-1;
121 while ( (index>0) && (str[index]==' ') )
122 index--;
123 str.resize (index+1);
126 void removeChar (string &str, char ch)
128 for (uint c=0; c<str.size (); c++)
130 if (str[c] == ch)
131 str.erase (c, 1);
135 void removeDirectory (string &str)
137 // Remove begin space
138 string::size_type pos = str.rfind ('\\');
139 string::size_type pos2 = str.rfind ('/');
141 if (pos == string::npos)
142 pos = pos2;
144 if (pos != string::npos)
145 str = str.substr (pos+1, str.size());
148 bool filterExtension (const char *str, const vector<string> &extensions)
150 // String size
151 uint size = (uint)strlen (str);
153 // For each filter
154 for (uint i=0; i<extensions.size(); i++)
156 if ( (str+(size - extensions[i].size())) == extensions[i])
157 return true;
160 // Not found
161 return false;
164 bool validateFilename (const char *str)
166 // Look for space
167 return (strchr (str, ' ') == NULL);
170 const char *getExtension (const char *filename)
172 return strrchr (filename, '.');
175 void removeExtension (string &filename)
177 string::size_type index = filename.rfind ('.');
178 filename.resize (index);
181 void extractStringsFromBinary (const vector<char> &fileArray, set<string> &filenameStrings, const vector<string> &extensions)
183 // Array size
184 uint size = (uint)fileArray.size();
186 // Array pointer
187 const char *arrayPointer = &fileArray[0];
189 // run through the data buffer looking for plausible looking strings
190 uint i,j;
191 for (i=0; (j=i+sizeof(uint))<size; i++)
193 // if we're pointing at a string the first 4 bytes ar the string length
194 uint len=*(uint *)(arrayPointer+i);
196 // if the string length could be valid
197 if (len>0 && len+i<=size)
199 uint k;
200 for (k=j; k<len+j && isASCII (arrayPointer[k]);k++);
201 if (k==len+j)
203 // build a string
204 string str;
206 // Resize the string
207 str.resize (len);
209 // Copy the string
210 for (k=0; k<len; k++)
211 str[k] = arrayPointer[j+k];
213 // Remove space
214 removeBeginEndSpaces (str);
216 // Not empty ?
217 if (str != "")
219 // Lower case
220 str = toLowerAscii (str);
222 // Filter extensions
223 if (filterExtension (str.c_str(), extensions))
225 // Remove directory
226 removeDirectory (str);
228 // Validate filename
229 if (validateFilename (str.c_str()))
231 // Add a string
232 filenameStrings.insert (str);
234 // Information
235 INFO ("Binary filename extracted: \"%s\" (0x%08x)", str.c_str(), j);
237 else
239 INFO ("Invalid filename: \"%s\" (0x%08x)", str.c_str(), j);
248 void extractStringsFromASCII (const vector<char> &fileArray, set<string> &filenameStrings, const vector<string> &extensions)
250 // Array size
251 uint size = (uint)fileArray.size();
252 if (size)
254 // Array pointer
255 const char *arrayPointer = &fileArray[0];
257 // Temp string
258 string temp;
260 // Begin of a valid string
261 const char *begin = arrayPointer;
262 while ((begin<arrayPointer) && (!isStringChar (*begin)))
263 begin++;
264 const char *end = begin;
265 while (end<arrayPointer+size)
267 // End char is ok ?
268 if (isStringChar (*end))
270 end++;
272 else
274 // Found a string ?
275 if (end != begin)
277 // String size
278 uint size = (uint)(end-begin);
279 temp.resize (size);
281 // Copy the string
282 for (uint c=0; c<size; c++)
283 temp[c] = begin[c];
285 // Lower case
286 temp = toLowerAscii (temp);
288 // Filter extensions
289 if (filterExtension (temp.c_str(), extensions))
291 // Remove directory
292 removeDirectory (temp);
294 // Validate filename
295 if (validateFilename (temp.c_str()))
297 // Add a string
298 filenameStrings.insert (temp);
300 // Information
301 INFO ("ASCII filename extracted: \"%s\"", temp.c_str());
303 else
305 INFO ("Invalid filename: \"%s\"", temp.c_str());
309 end++;
310 begin = end;
316 bool loadConfigFiles (const char *ext, const char *input_files, const char *available_files, vector<string> &extensions, set<string> &inputFiles, map<string, string> &availableFiles)
318 // Get a string
319 string temp;
320 string temp2;
322 // Extensions files
323 FILE *file = fopen (ext, "r");
324 if (file)
326 bool cont = true;
327 char name[512];
328 while (fgets (name, 512, file))
330 // To string and lower
331 temp = toLowerAscii (string(name));
333 // Remove return
334 removeChar (temp, '\n');
336 // Valid extension ?
337 if (temp.size() && temp[0] == '.')
338 // Add the extension
339 extensions.push_back (temp);
340 else
342 nlwarning ("ERROR extension %s must begin with a '.' character.", temp.c_str());
343 cont = false;
344 break;
348 // Close
349 fclose (file);
350 if (cont)
352 // Input files
353 file = fopen (input_files, "r");
354 if (file)
356 char name[512];
357 while (fgets (name, 512, file))
359 // To string
360 temp = name;
362 // Remove return
363 removeChar (temp, '\n');
365 // Add the extension
366 inputFiles.insert (temp);
369 // Close
370 fclose (file);
372 // Available files
373 file = fopen (available_files, "r");
374 if (file)
376 char name[512];
377 while (fgets (name, 512, file))
379 // To lower
380 temp = toLowerAscii (string(name));
381 temp2 = toLowerAscii (string(name));
383 // Remove space
384 removeBeginEndSpaces (temp);
385 removeBeginEndSpaces (temp2);
387 // Remove return
388 removeChar (temp, '\n');
389 removeChar (temp2, '\n');
391 // Remove directory
392 removeDirectory (temp);
394 // Good extension
395 if (filterExtension (temp.c_str (), extensions))
397 if (validateFilename (temp.c_str ()))
399 // Add the extension
400 if (!availableFiles.insert (map<string, string>::value_type (temp, temp2)).second)
402 fprintf (stderr, "DUBLING: %s %s\n", temp.c_str (), temp2.c_str());
405 else
407 fprintf (stderr, "INVALIDE NAME: %s\n", temp.c_str ());
410 else
412 fprintf (stderr, "INVALIDE EXT: %s\n", temp.c_str ());
416 // Close
417 fclose (file);
419 // Ok
420 return true;
422 else
424 nlwarning ("ERROR can't load available files %s", ext);
427 else
429 nlwarning ("ERROR can't load input files %s", ext);
433 else
435 nlwarning ("ERROR can't load extension file %s", ext);
438 return false;
442 #define BAR_LENGTH 21
444 const char *progressbar[BAR_LENGTH]=
446 "[ ]",
447 "[. ]",
448 "[.. ]",
449 "[... ]",
450 "[.... ]",
451 "[..... ]",
452 "[...... ]",
453 "[....... ]",
454 "[........ ]",
455 "[......... ]",
456 "[.......... ]",
457 "[........... ]",
458 "[............ ]",
459 "[............. ]",
460 "[.............. ]",
461 "[............... ]",
462 "[................ ]",
463 "[................. ]",
464 "[.................. ]",
465 "[................... ]",
466 "[....................]"
469 void progress (const char *message, float progress)
471 // Progress bar
472 char msg[512];
473 uint pgId= (uint)(progress*(float)BAR_LENGTH);
474 pgId= min(pgId, (uint)(BAR_LENGTH-1));
475 sprintf (msg, "\r%s %s", progressbar[pgId], message );
476 uint i;
477 for (i=(uint)strlen(msg); i<79; i++)
478 msg[i]=' ';
479 msg[i]=0;
480 printf ("%s", msg);
481 printf ("\r");
484 int main(int argc, char* argv[])
486 if (argc==4)
488 // Load the config file
489 printf ("Loading config files...");
491 // Extensions
492 vector<string> extensions;
494 // Extensions
495 map<string, string> alternateExtensions;
496 alternateExtensions.insert (map<string, string>::value_type (".tga", ".dds"));
498 // String array
499 set<string> inputFiles;
501 // String array
502 set<string> usedFiles;
504 // String array
505 map<string, string> availableFiles;
507 if (loadConfigFiles (argv[1], argv[2], argv[3], extensions, inputFiles, availableFiles))
509 // Load the config file
510 printf ("\rScaning files... \n");
512 uint size = 0;
513 uint maxSize = (uint)inputFiles.size();
514 set<string>::iterator ite = inputFiles.begin();
515 while (ite != inputFiles.end())
517 // Update
518 string label = ite->c_str();
520 // Remove directory
521 removeDirectory (label);
523 progress (label.c_str(), (float)size/(float)maxSize);
525 // String array
526 set<string> outputFilename;
528 // File array
529 vector<char> fileArray;
531 // Read the file
532 INFO ("Open file: %s", ite->c_str());
533 if (readTheFile (ite->c_str(), fileArray))
535 // Is it a ASCII file ?
536 if (isASCII (fileArray))
538 INFO ("ASCII mode");
540 // Extract strings
541 extractStringsFromASCII (fileArray, outputFilename, extensions);
543 else
545 INFO ("BINARY mode");
547 // Extract strings
548 extractStringsFromBinary (fileArray, outputFilename, extensions);
552 // Check this files exists
553 set<string>::iterator found = outputFilename.begin();
554 while (found != outputFilename.end())
556 // Look for this file
557 if (availableFiles.find (*found) == availableFiles.end())
559 // Found ?
560 bool foundIt = false;
562 // Try alternate extension
563 string ext = getExtension ((*found).c_str());
564 std::map<string, string>::iterator alternIte = alternateExtensions.find (ext);
565 if (alternIte != alternateExtensions.end ())
567 string name = *found;
568 removeExtension (name);
569 name += alternIte->second;
570 if (availableFiles.find (name) != availableFiles.end())
571 foundIt = true;
574 // Not found ?
575 if (!foundIt)
577 fprintf (stderr, "MISSING: %s (needed by file %s)\n", found->c_str(), ite->c_str());
580 else
582 // Add to used files
583 usedFiles.insert (*found);
586 // Next file found
587 found++;
590 size++;
592 // Next file
593 ite++;
596 // Look for unused files
597 map<string, string>::iterator available = availableFiles.begin();
598 while (available != availableFiles.end())
600 // It is used ?
601 if (usedFiles.find (available->first) == usedFiles.end())
603 string temp = toLowerAscii (available->second);
604 fprintf (stderr, "UNUSED: %s\n", temp.c_str());
607 // Next
608 available++;
611 // Ok
612 return 1;
615 else
617 printf ("extract_filename [extensions.txt] [inputFiles.txt] [availableFiles.txt]\n");
619 return 0;