Fix game:addSpawnShapesByZone
[ryzomcore.git] / nel / tools / 3d / pipeline_max_rewrite_assets / main.cpp
blob1fdae49eec73c309b5d8acb89d148f78f65b8142
1 /*
2 * Copyright (C) 2012 by Jan Boon (Kaetemi)
4 * This file is part of RYZOM CORE PIPELINE.
5 * RYZOM CORE PIPELINE is free software: you can redistribute it
6 * and/or modify it under the terms of the GNU Affero General Public
7 * License as published by the Free Software Foundation, either
8 * version 3 of the License, or (at your option) any later version.
10 * RYZOM CORE PIPELINE is distributed in the hope that it will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
15 * You should have received a copy of the GNU Affero General Public
16 * License along with RYZOM CORE PIPELINE. If not, see
17 * <http://www.gnu.org/licenses/>.
20 #include <nel/misc/types_nl.h>
21 #include <nel/misc/common.h>
23 #include <gsf/gsf-outfile-msole.h>
24 #include <gsf/gsf-outfile.h>
25 #include <gsf/gsf-output-stdio.h>
26 #include <gsf/gsf-infile-msole.h>
27 #include <gsf/gsf-infile.h>
28 #include <gsf/gsf-input-stdio.h>
29 #include <gsf/gsf-utils.h>
30 #include <gsf/gsf-doc-meta-data.h>
31 #include <gsf/gsf-msole-utils.h>
32 #include <glib/gi18n.h>
33 #include <string.h>
34 #include <cstdio>
35 #include <iostream>
36 #include <fstream>
38 #include <vector>
39 #include <utility>
41 #include <nel/misc/file.h>
42 #include <nel/misc/vector.h>
43 #include "nel/misc/dynloadlib.h"
44 #include "nel/misc/debug.h"
45 #include "nel/misc/path.h"
46 #include "nel/misc/algo.h"
47 #include "nel/misc/file.h"
48 #include "nel/misc/mem_stream.h"
50 #include "../pipeline_max/storage_stream.h"
51 #include "../pipeline_max/storage_object.h"
52 #include "../pipeline_max/dll_directory.h"
53 #include "../pipeline_max/class_directory_3.h"
54 #include "../pipeline_max/class_data.h"
55 #include "../pipeline_max/config.h"
56 #include "../pipeline_max/scene.h"
57 #include "../pipeline_max/scene_class_registry.h"
59 // Testing
60 #include "../pipeline_max/builtin/builtin.h"
61 #include "../pipeline_max/update1/update1.h"
62 #include "../pipeline_max/epoly/epoly.h"
64 #include "../pipeline_max/builtin/storage/app_data.h"
65 #include "../pipeline_max/builtin/storage/geom_buffers.h"
66 #include "../pipeline_max/builtin/scene_impl.h"
67 #include "../pipeline_max/builtin/i_node.h"
68 #include "../pipeline_max/update1/editable_mesh.h"
69 #include "../pipeline_max/epoly/editable_poly.h"
71 #include <boost/algorithm/string.hpp>
72 using namespace std;
73 using namespace boost::algorithm;
75 using namespace PIPELINE::MAX;
76 using namespace PIPELINE::MAX::BUILTIN;
77 using namespace PIPELINE::MAX::BUILTIN::STORAGE;
78 using namespace PIPELINE::MAX::UPDATE1;
79 using namespace PIPELINE::MAX::EPOLY;
81 CSceneClassRegistry SceneClassRegistry;
83 // Never enable this
84 bool DebugParser = false;
86 bool DisplayStream = false;
87 bool DisplayReplaces = false;
89 bool ReplacePaths = true;
90 bool ReplaceMapExt = false;
92 bool WritePathChangesOnly = true;
93 bool WriteModified = true;
94 bool WriteDummy = false;
96 bool HaltOnIssue = false;
98 const char *DatabaseDirectory = "w:\\database\\";
99 const char *LinuxDatabaseDirectory = "/mnt/y/ryzom-assets/database/";
100 bool RunningLinux = true;
102 //const char *SrcDirectoryRecursive = "w:\\database\\interfaces\\";
103 //const char *SrcDirectoryRecursive = "w:\\database\\";
104 //const char *SrcDirectoryRecursive = "w:\\database\\stuff\\fyros\\city\\newpositionville\\";
105 const char *SrcDirectoryRecursiveInit = "w:\\database\\";
106 //const char *SrcDirectoryRecursiveHandle = "w:\\database\\stuff\\generique\\agents\\accessories\\";
107 //const char *SrcDirectoryRecursiveHandle = "w:\\database\\landscape\\ligo\\primes_racines\\max\\";
108 const char *SrcDirectoryRecursiveHandle = "w:\\database\\stuff\\fyros\\decors\\constructions\\";
110 bool UseFallbackTga = false;
111 const char *FallbackTga = "w:\\database\\stuff\\lod_actors\\texture_lod\\trame.png";
113 std::set<std::string> MissingFiles;
114 std::map<std::string, std::string> KnownFileCache;
116 std::string nativeDatabasePath(const std::string &standardizedPath)
118 if (RunningLinux)
120 std::string result = standardizedPath;
121 NLMISC::strFindReplace(result, DatabaseDirectory, LinuxDatabaseDirectory);
122 while (NLMISC::strFindReplace(result, "\\", "/")) { }
123 return result;
125 return standardizedPath;
128 std::string unnativeDatabasePath(const std::string &nativizedPath)
130 if (RunningLinux)
132 std::string result = nativizedPath;
133 NLMISC::strFindReplace(result, LinuxDatabaseDirectory, DatabaseDirectory);
134 while (NLMISC::strFindReplace(result, "/", "\\")) { }
135 return result;
137 return nativizedPath;
140 // COPY FROM PIPELINE_SERVICE.CPP WITH BACKSLASHES INSTEAD OF FORWARD SLASHES
141 std::string standardizePath(const std::string &path, bool addFinalSlash)
143 // check empty path
144 if (path.empty())
145 return "";
147 std::string newPath;
148 newPath.resize(path.size() + 1);
150 std::string::size_type j = 0;
151 for (std::string::size_type i = 0; i < path.size(); ++i)
153 if (path[i] == '\\' || path[i] == '/')
155 if (j <= 1 && path[i] == '\\')
157 // for windows network
158 newPath[j] = '\\';
159 ++j;
161 else if (j == 0 || newPath[j - 1] != '\\')
163 newPath[j] = '\\';
164 ++j;
167 else
169 newPath[j] = path[i];
170 ++j;
173 newPath[j] = 0;
174 newPath.resize(j);
176 // add terminal slash
177 if (addFinalSlash && newPath[newPath.size()-1] != '\\')
178 newPath += '\\';
180 return newPath;
183 inline bool isCharacter(char c0)
185 uint8 c = *(uint8 *)(void *)(&c0);
186 return (32 <= c /*&& c <= 127) || (161 <= c*/ /*&& c <= 255*/);
189 inline char stripFrenchLocale(char c0)
191 uint8 c = *(uint8 *)(void *)(&c0);
192 if (192 <= c && c <= 197) return 'a';
193 if (200 <= c && c <= 203) return 'e';
194 if (204 <= c && c <= 207) return 'i';
195 if (210 <= c && c <= 214) return 'o';
196 if (217 <= c && c <= 220) return 'u';
197 if (c == 221) return 'y';
198 if (224 <= c && c <= 229) return 'a';
199 if (232 <= c && c <= 235) return 'e';
200 if (236 <= c && c <= 239) return 'i';
201 if (242 <= c && c <= 246) return 'o';
202 if (249 <= c && c <= 252) return 'u';
203 if (c == 253 || c == 255) return 'y';
204 return c0;
207 std::string rewritePath(const std::string &path, const std::string &databaseDirectory)
209 // nldebug("Rewrite: %s", path.c_str());
211 static std::set<std::string> fileNameCache;
213 std::string stdPath = standardizePath(path, false);
214 for (std::string::size_type i = 0; i < stdPath.size(); ++i)
215 stdPath[i] = stripFrenchLocale(stdPath[i]);
216 stdPath = NLMISC::toLower(stdPath);
218 // TODO: remove ./stuff/caravan/agents/_textures/actors/trame.png
220 NLMISC::strFindReplace(stdPath, "w:\\database\\", databaseDirectory);
221 NLMISC::strFindReplace(stdPath, "\\\\amiga\\3d\\database\\", databaseDirectory);
222 NLMISC::strFindReplace(stdPath, "ma_hom_armor_01", "ma_hom_armor01");
223 NLMISC::strFindReplace(stdPath, "ma_hof_armor_01", "ma_hof_armor01");
224 NLMISC::strFindReplace(stdPath, "ma_hom_armor_00", "ma_hom_armor00");
225 NLMISC::strFindReplace(stdPath, "ma_hof_armor_00", "ma_hof_armor00");
226 NLMISC::strFindReplace(stdPath, "zo_hom_armor_00", "zo_hom_armor00");
227 NLMISC::strFindReplace(stdPath, "zo_hof_armor_00", "zo_hof_armor00");
228 NLMISC::strFindReplace(stdPath, "fy_hof_cheveux_shave01", "fy_hof_cheveux_shave");
230 NLMISC::strFindReplace(stdPath, "matis\\agents\\_textures\\actors\\ma_hom_underwear_avtbras", "tryker\\agents\\_textures\\actors\\tr_hom_underwear_avtbras");
231 NLMISC::strFindReplace(stdPath, "matis\\agents\\_textures\\actors\\ma_hom_underwear_epaule", "tryker\\agents\\_textures\\actors\\tr_hom_underwear_epaule");
232 NLMISC::strFindReplace(stdPath, "matis\\agents\\_textures\\actors\\ma_hom_underwear_hand-downside", "tryker\\agents\\_textures\\actors\\tr_hom_underwear_hand-downside");
233 NLMISC::strFindReplace(stdPath, "matis\\agents\\_textures\\actors\\ma_hom_underwear_hand-upside", "tryker\\agents\\_textures\\actors\\tr_hom_underwear_hand-upside");
234 NLMISC::strFindReplace(stdPath, "matis\\agents\\_textures\\actors\\ma_hom_underwear_molet", "tryker\\agents\\_textures\\actors\\tr_hom_underwear_molet");
235 NLMISC::strFindReplace(stdPath, "matis\\agents\\_textures\\actors\\ma_hof_underwear_hand-downside", "tryker\\agents\\_textures\\actors\\tr_hof_underwear_hand-downside");
236 NLMISC::strFindReplace(stdPath, "matis\\agents\\_textures\\actors\\ma_hof_underwear_hand-upside", "tryker\\agents\\_textures\\actors\\tr_hof_underwear_hand-upside");
238 NLMISC::strFindReplace(stdPath, "tr_hof_underwear_torso", "tr_hof_underwear_torse");
239 NLMISC::strFindReplace(stdPath, "tr_hof_underwear_hand-", "tr_hof_underwear_hand_");
241 NLMISC::strFindReplace(stdPath, "fy_hom_armor00_avbras.", "fy_hom_armor00_avbras_c1.");
242 NLMISC::strFindReplace(stdPath, "fy_hom_armor00_bottes.", "fy_hom_armor00_bottes_c1.");
243 NLMISC::strFindReplace(stdPath, "fy_hom_armor00_bras.", "fy_hom_armor00_bras_c1.");
244 NLMISC::strFindReplace(stdPath, "fy_hom_armor00_cuissear.", "fy_hom_armor00_cuissear_c1.");
245 NLMISC::strFindReplace(stdPath, "fy_hom_armor00_cuisseav.", "fy_hom_armor00_cuisseav_c1.");
246 NLMISC::strFindReplace(stdPath, "fy_hom_armor00_dos.", "fy_hom_armor00_dos_c1.");
247 NLMISC::strFindReplace(stdPath, "fy_hom_armor00_hand-downside.", "fy_hom_armor00_hand-downside_c1.");
248 NLMISC::strFindReplace(stdPath, "fy_hom_armor00_hand-upside.", "fy_hom_armor00_hand-upside_c1.");
249 NLMISC::strFindReplace(stdPath, "fy_hom_armor00_pieds.", "fy_hom_armor00_pieds_c1.");
250 NLMISC::strFindReplace(stdPath, "fy_hom_armor00_torse.", "fy_hom_armor00_torse_c1.");
252 NLMISC::strFindReplace(stdPath, "fy-hof-gilet02-dos", "fy_hof_gilet02_arriere_n");
253 NLMISC::strFindReplace(stdPath, "fy-hof-pantalon02-arriere", "fy_hof_pantalon02_arriere_n");
254 NLMISC::strFindReplace(stdPath, "fy-hof-pantalon02-avant", "fy_hof_pantalon02_avant_n");
255 NLMISC::strFindReplace(stdPath, "fy-hom-blouson02-avantbras", "fy_hom_blouson02_avbras_n");
256 NLMISC::strFindReplace(stdPath, "fy-hom-blouson02-bras", "fy_hom_blouson02_bras_n");
257 NLMISC::strFindReplace(stdPath, "fy-hom-blouson02-dos", "fy_hom_blouson02_arriere_n");
258 NLMISC::strFindReplace(stdPath, "fy-hom-blouson02-torse", "fy_hom_blouson02_avant_n");
259 NLMISC::strFindReplace(stdPath, "fy-hom-pantalon02-mollet", "fy_hom_pantalon02_mollet_n");
260 NLMISC::strFindReplace(stdPath, "fy-hom-shoes02", "fy_hom_shoes02_shoes_n");
261 NLMISC::strFindReplace(stdPath, "fyhof-gilet02-torse", "fy_hof_gilet02_torse_n");
263 NLMISC::strFindReplace(stdPath, "ge_hom_armor02_armpad", "ge_hom_armor02_avbras");
264 NLMISC::strFindReplace(stdPath, "ge_hom_armor02_bottes", "ge_hom_armor02_pied");
265 NLMISC::strFindReplace(stdPath, "ge_hom_armor02_cuisse-arr", "ge_hom_armor02_cuisse_arr");
266 NLMISC::strFindReplace(stdPath, "ge_hom_armor02_cuisse-avt", "ge_hom_armor02_cuisse_avt");
267 NLMISC::strFindReplace(stdPath, "ge_hom_armor02_hand-down", "ge_hom_armor02_hand_down");
268 NLMISC::strFindReplace(stdPath, "ge_hom_armor02_hand-up", "ge_hom_armor02_hand_up");
269 NLMISC::strFindReplace(stdPath, "ge_hom_armor02_torse", "ge_hom_armor02_torso");
271 NLMISC::strFindReplace(stdPath, "fy_lovejail.", "fy_lovejail_su.");
272 NLMISC::strFindReplace(stdPath, "\\caissebonusaction.", "\\g_caissebonus.");
273 NLMISC::strFindReplace(stdPath, "\\sactoile.", "\\g_sactoile.");
274 NLMISC::strFindReplace(stdPath, "\\ge_mission_stele_kami0.", "\\ge_mission_stele_kami.");
275 NLMISC::strFindReplace(stdPath, "\\ge_mission_reward_karavan_bigshield.", "\\ge_mission_reward_karavan_bigshield_c1.");
277 NLMISC::strFindReplace(stdPath, "\\tr_hom_underwear_cuisse_arr.", "\\tr_hom_underwear_cuisse-arr.");
278 NLMISC::strFindReplace(stdPath, "\\tr_hom_underwear_cuisse_avt.", "\\tr_hom_underwear_cuisse-avt.");
280 NLMISC::strFindReplace(stdPath, "interfaces_visage", "visage_interface");
282 if (stdPath.find("\\trame.") != std::string::npos)
283 stdPath = standardizePath(databaseDirectory + "/stuff/lod_actors/texture_lod/trame.png", false);
284 if (stdPath.find("\\tr_hof_visage_c1.") != std::string::npos)
285 stdPath = standardizePath(databaseDirectory + "/stuff/tryker/agents/_textures/actors/tr_hof_visage_c1.png", false);
286 if (stdPath.find("\\tr_hof_visage_c2.") != std::string::npos)
287 stdPath = standardizePath(databaseDirectory + "/stuff/tryker/agents/_textures/actors/tr_hof_visage_c2.png", false);
288 if (stdPath.find("\\tr_hof_visage_c3.") != std::string::npos)
289 stdPath = standardizePath(databaseDirectory + "/stuff/tryker/agents/_textures/actors/tr_hof_visage_c3.png", false);
290 if (stdPath.find("\\ma_hof_cheveux_medium02.") != std::string::npos)
291 stdPath = standardizePath(databaseDirectory + "/stuff/matis/agents/_textures/actors/ma_hof_cheveux_medium02.png", false);
293 /*if (stdPath.size() > path.size())
295 nlwarning("Path size becomes too large: '%s' -> '%s'", path.c_str(), stdPath.c_str());
296 return path;
299 if (NLMISC::CFile::getFilename(stdPath) == stdPath)
301 breakable
303 if (fileNameCache.find(stdPath) == fileNameCache.end() || KnownFileCache.find(stdPath) == KnownFileCache.end())
305 if (stdPath[stdPath.size() - 3] == 't' && stdPath[stdPath.size() - 2] == 'g' && stdPath[stdPath.size() - 1] == 'a')
307 stdPath[stdPath.size() - 3] = 'p';
308 stdPath[stdPath.size() - 2] = 'n';
309 stdPath[stdPath.size() - 1] = 'g';
310 if (fileNameCache.find(stdPath) != fileNameCache.end())
311 break;
313 //#nlwarning("File name not known: '%s' ('%s')", path.c_str(), stdPath.c_str());
314 // MissingFiles.insert(path);
315 return stdPath;
318 return stdPath;
320 else
322 if (stdPath.find(databaseDirectory) == std::string::npos)
324 if (stdPath[1] == ':' || (stdPath[0] == '\\' && stdPath[1] == '\\'))
326 if (KnownFileCache.find(NLMISC::CFile::getFilename(stdPath)) != KnownFileCache.end())
327 return KnownFileCache[NLMISC::CFile::getFilename(stdPath)];
329 if (stdPath[stdPath.size() - 3] == 't' && stdPath[stdPath.size() - 2] == 'g' && stdPath[stdPath.size() - 1] == 'a')
330 { stdPath[stdPath.size() - 3] = 'p'; stdPath[stdPath.size() - 2] = 'n'; stdPath[stdPath.size() - 1] = 'g'; }
331 if (KnownFileCache.find(NLMISC::CFile::getFilename(stdPath)) != KnownFileCache.end())
332 return KnownFileCache[NLMISC::CFile::getFilename(stdPath)];
334 if (stdPath[stdPath.size() - 3] == 'p' && stdPath[stdPath.size() - 2] == 'n' && stdPath[stdPath.size() - 1] == 'g')
335 { stdPath[stdPath.size() - 3] = 't'; stdPath[stdPath.size() - 2] = 'g'; stdPath[stdPath.size() - 1] = 'a'; }
336 if (KnownFileCache.find(NLMISC::CFile::getFilename(stdPath)) != KnownFileCache.end())
337 return KnownFileCache[NLMISC::CFile::getFilename(stdPath)];
339 //#nlwarning("Path not in database: '%s' ('%s')", path.c_str(), stdPath.c_str());
340 MissingFiles.insert(path);
341 return stdPath;
343 else
345 // invalid path, don't care too much
346 return stdPath;
350 breakable
352 if (!NLMISC::CFile::fileExists(nativeDatabasePath(stdPath)))
354 if (stdPath[stdPath.size() - 3] == 't' && stdPath[stdPath.size() - 2] == 'g' && stdPath[stdPath.size() - 1] == 'a')
356 stdPath[stdPath.size() - 3] = 'p';
357 stdPath[stdPath.size() - 2] = 'n';
358 stdPath[stdPath.size() - 1] = 'g';
359 if (NLMISC::CFile::fileExists(nativeDatabasePath(stdPath)))
360 break;
363 std::string stdPathVv2 = standardizePath(NLMISC::CFile::getPath(stdPath) + "/vv2/" + NLMISC::CFile::getFilename(stdPath), false);
364 bool vv2works = false;
365 if (NLMISC::CFile::fileExists(nativeDatabasePath(stdPathVv2)))
367 vv2works = true;
369 else
371 if (stdPathVv2[stdPathVv2.size() - 3] == 'p' && stdPathVv2[stdPathVv2.size() - 2] == 'n' && stdPathVv2[stdPathVv2.size() - 1] == 'g')
373 stdPathVv2[stdPathVv2.size() - 3] = 't';
374 stdPathVv2[stdPathVv2.size() - 2] = 'g';
375 stdPathVv2[stdPathVv2.size() - 1] = 'a';
376 if (NLMISC::CFile::fileExists(nativeDatabasePath(stdPathVv2)))
378 vv2works = true;
382 if (vv2works)
384 // try with vv2
385 /*if (stdPathVv2.size() > path.size())
387 nlwarning("Path with vv2 size becomes too large: '%s' -> '%s'", path.c_str(), stdPathVv2.c_str());
388 return stdPath;
390 else
392 stdPath = stdPathVv2;
393 break;
397 // try find
398 if (KnownFileCache.find(NLMISC::CFile::getFilename(stdPath)) != KnownFileCache.end())
399 return KnownFileCache[NLMISC::CFile::getFilename(stdPath)];
401 if (stdPath[stdPath.size() - 3] == 't' && stdPath[stdPath.size() - 2] == 'g' && stdPath[stdPath.size() - 1] == 'a')
402 { stdPath[stdPath.size() - 3] = 'p'; stdPath[stdPath.size() - 2] = 'n'; stdPath[stdPath.size() - 1] = 'g'; }
403 if (KnownFileCache.find(NLMISC::CFile::getFilename(stdPath)) != KnownFileCache.end())
404 return KnownFileCache[NLMISC::CFile::getFilename(stdPath)];
406 if (stdPath[stdPath.size() - 3] == 'p' && stdPath[stdPath.size() - 2] == 'n' && stdPath[stdPath.size() - 1] == 'g')
407 { stdPath[stdPath.size() - 3] = 't'; stdPath[stdPath.size() - 2] = 'g'; stdPath[stdPath.size() - 1] = 'a'; }
408 if (KnownFileCache.find(NLMISC::CFile::getFilename(stdPath)) != KnownFileCache.end())
409 return KnownFileCache[NLMISC::CFile::getFilename(stdPath)];
411 //#nlwarning("Path file does not exist: '%s' ('%s')", path.c_str(), stdPath.c_str());
412 MissingFiles.insert(path);
413 return stdPath;
418 fileNameCache.insert(NLMISC::CFile::getFilename(stdPath));
419 return stdPath;
422 void doFileInitialize(const std::string &filePath)
424 // nldebug("File: '%s'", filePath.c_str());
425 // nldebug("Native: '%s'", nativeDatabasePath(filePath).c_str());
427 KnownFileCache[NLMISC::CFile::getFilename(filePath)] = standardizePath(filePath, false);
430 // maxRewritePaths R:/graphics/interfaces/anims_max
432 void doDirectoryInitialize(const std::string &directoryPath)
434 nldebug("Directory: '%s'", directoryPath.c_str());
436 std::string dirPath = standardizePath(directoryPath, true);
437 std::vector<std::string> dirContents;
439 NLMISC::CPath::getPathContent(nativeDatabasePath(dirPath), false, true, true, dirContents);
441 // nldebug("Native: '%s'", nativeDatabasePath(dirPath).c_str());
442 // nldebug("Contents: %i", dirContents.size());
444 for (std::vector<std::string>::iterator it = dirContents.begin(), end = dirContents.end(); it != end; ++it)
446 std::string subPath = standardizePath(unnativeDatabasePath(*it), false);
447 // nldebug("Path: '%s'", subPath.c_str());
448 // nldebug("Native: '%s'", nativeDatabasePath(subPath + " ").c_str());
450 if (NLMISC::CFile::isDirectory(nativeDatabasePath(subPath)))
452 if (subPath.find("\\.") == std::string::npos)
453 doDirectoryInitialize(subPath);
455 else
456 doFileInitialize(subPath);
460 void runInitialize()
462 nlinfo("DatabaseDirectory: '%s'", DatabaseDirectory);
464 doDirectoryInitialize(std::string(SrcDirectoryRecursiveInit));
467 // Scary stuff
468 void doFileScanner(const std::string &filePath)
470 if (filePath[filePath.size() - 3] == 'm' && filePath[filePath.size() - 2] == 'a' && filePath[filePath.size() - 1] == 'x')
472 nldebug("File: '%s'", filePath.c_str());
474 std::vector<char> buffer;
475 buffer.resize(NLMISC::CFile::getFileSize(nativeDatabasePath(filePath)));
477 // read
479 NLMISC::CIFile ifile;
480 ifile.open(nativeDatabasePath(filePath), false);
481 ifile.serialBuffer((uint8 *)(&buffer[0]), buffer.size());
482 ifile.close();
485 // find paths
486 for (std::vector<char>::size_type i = 256; i < buffer.size(); ++i) // skip the first 256 lol :)
488 if (((NLMISC::toLower(buffer[i - 1]) == 'x' && NLMISC::toLower(buffer [i - 2]) == 'a' && NLMISC::toLower(buffer[i - 3]) == 'm')
489 || (NLMISC::toLower(buffer[i - 1]) == 'a' && NLMISC::toLower(buffer [i - 2]) == 'g' && NLMISC::toLower(buffer[i - 3]) == 't')
490 || (NLMISC::toLower(buffer[i - 1]) == 'g' && NLMISC::toLower(buffer [i - 2]) == 'n' && NLMISC::toLower(buffer[i - 3]) == 'p'))
491 && (NLMISC::toLower(buffer[i - 4]) == '.'))
493 // buffer[i] is the character after the path! :)
494 std::vector<char>::size_type beginPath = 0;
495 for (std::vector<char>::size_type j = i - 4; j > 0; --j)
497 if (!isCharacter(buffer[j]))
499 if ((buffer[j + 1] == '\\' && buffer[j + 2] == '\\') || buffer[j] == 0)
501 beginPath = j + 1;
502 break;
504 // nlwarning("Invalid characters '%i' in path at %i, len %i!", (uint32)buffer[j], (uint32)j, (uint32)(i - j));
505 // beginPath = j + 1; // test
506 break;
508 if (buffer[j] == ':')
510 beginPath = j - 1;
511 break;
514 if (beginPath != 0)
516 std::vector<char>::size_type sizePath = i - beginPath;
517 std::string foundPath = std::string(&buffer[beginPath], sizePath); //std::string(buffer.at(beginPath), buffer.at(i));
518 //nldebug("Found path: '%s' from %i to %i", foundPath.c_str(), (uint32)beginPath, (uint32)i);
519 std::string fixedPath = rewritePath(foundPath, DatabaseDirectory);
520 //nldebug("Rewrite to: '%s'", fixedPath.c_str());
525 //NLMISC::CFile::re
527 // ...
531 void doDirectoryScanner(const std::string &directoryPath)
533 nldebug("Directory: '%s'", directoryPath.c_str());
535 std::string dirPath = standardizePath(directoryPath, true);
536 std::vector<std::string> dirContents;
538 NLMISC::CPath::getPathContent(nativeDatabasePath(dirPath), false, true, true, dirContents);
540 for (std::vector<std::string>::iterator it = dirContents.begin(), end = dirContents.end(); it != end; ++it)
542 std::string subPath = standardizePath(unnativeDatabasePath(*it), false);
544 if (NLMISC::CFile::isDirectory(nativeDatabasePath(subPath)))
546 if (subPath.find("\\.") == std::string::npos)
547 doDirectoryScanner(subPath);
549 else
550 doFileScanner(subPath);
554 void runScanner()
556 nlinfo("DatabaseDirectory: '%s'", DatabaseDirectory);
558 doDirectoryScanner(SrcDirectoryRecursiveHandle);
560 for (std::set<std::string>::iterator it = MissingFiles.begin(), end = MissingFiles.end(); it != end; ++it)
561 nlinfo("Missing: '%s'", (*it).c_str());
564 void handleFile(const std::string &path);
566 void doFileHandler(const std::string &filePath)
568 if (filePath[filePath.size() - 3] == 'm' && filePath[filePath.size() - 2] == 'a' && filePath[filePath.size() - 1] == 'x')
570 nldebug("File: '%s'", filePath.c_str());
572 handleFile(nativeDatabasePath(filePath));
576 void doDirectoryHandler(const std::string &directoryPath)
578 nldebug("Directory: '%s'", directoryPath.c_str());
580 std::string dirPath = standardizePath(directoryPath, true);
581 std::vector<std::string> dirContents;
583 NLMISC::CPath::getPathContent(nativeDatabasePath(dirPath), false, true, true, dirContents);
585 for (std::vector<std::string>::iterator it = dirContents.begin(), end = dirContents.end(); it != end; ++it)
587 std::string subPath = standardizePath(unnativeDatabasePath(*it), false);
589 if (NLMISC::CFile::isDirectory(nativeDatabasePath(subPath)))
591 if (subPath.find("\\.") == std::string::npos)
592 doDirectoryHandler(subPath);
594 else
595 doFileHandler(subPath);
599 void runHandler()
601 nlinfo("DatabaseDirectory: '%s'", DatabaseDirectory);
603 doDirectoryHandler(SrcDirectoryRecursiveHandle);
606 void serializeStorageContainer(PIPELINE::MAX::CStorageContainer *storageContainer, GsfInfile *infile, const char *streamName)
608 GsfInput *input = gsf_infile_child_by_name(infile, streamName);
609 if (!input)
611 nlerror("GSF Could not read stream %s", streamName);
612 return;
615 PIPELINE::MAX::CStorageStream instream(input);
616 storageContainer->serial(instream);
618 g_object_unref(input);
621 void serializeStorageContainer(PIPELINE::MAX::CStorageContainer *storageContainer, GsfOutfile *outfile, const char *streamName)
623 //nldebug("write");
624 GsfOutput *output = GSF_OUTPUT(gsf_outfile_new_child(outfile, streamName, false));
625 if (!output)
627 nlerror("GSF Could not write stream %s", streamName);
628 return;
631 PIPELINE::MAX::CStorageStream outstream(output);
632 storageContainer->serial(outstream);
634 gsf_output_close(output);
635 g_object_unref(G_OBJECT(output));
638 void serializeRaw(std::vector<uint8> &rawOutput, GsfInfile *infile, const char *streamName)
640 GsfInput *input = gsf_infile_child_by_name(infile, streamName);
641 if (!input)
643 nlerror("GSF Could not read stream %s", streamName);
644 return;
647 PIPELINE::MAX::CStorageStream instream(input);
648 rawOutput.resize(instream.size());
649 instream.serialBuffer(&rawOutput[0], rawOutput.size());
651 g_object_unref(input);
654 void serializeRaw(std::vector<uint8> &rawOutput, GsfOutfile *outfile, const char *streamName)
656 GsfOutput *output = GSF_OUTPUT(gsf_outfile_new_child(outfile, streamName, false));
657 if (!output)
659 nlerror("GSF Could not write stream %s", streamName);
660 return;
663 PIPELINE::MAX::CStorageStream outstream(output);
664 outstream.serialBuffer(&rawOutput[0], rawOutput.size());
666 gsf_output_close(output);
667 g_object_unref(G_OBJECT(output));
670 std::string cleanString(const std::string &str)
672 std::string res = str;
673 trim(res);
674 // \\Amiga\3D (10 chars)
675 if (res.size() > 10)
677 if (res.substr(res.size() - 10) == "\\\\Amiga\\3D")
678 res = res.substr(0, res.size() - 10);
680 if (res.size() > 1)
682 if (res.substr(res.size() - 1) == "0")
683 res = res.substr(0, res.size() - 1);
685 if (res.size() > 4 && res[res.size() - 1] == '.')
687 if (res.substr(res.size() - 4) == "max.") // fix a stupid typo
688 res = res.substr(0, res.size() - 1);
690 return res;
693 std::string rewritePathFinal(const std::string &str)
695 std::string strtrimmed = cleanString(str);
696 std::string result = rewritePath(strtrimmed, DatabaseDirectory);
697 if (NLMISC::CFile::getFilename(result) != result && !NLMISC::CFile::fileExists(nativeDatabasePath(result)) &&
698 ((result[result.size() - 3] == 't' && result[result.size() - 2] == 'g' && result[result.size() - 1] == 'a') || (result[result.size() - 3] == 'p' && result[result.size() - 2] == 'n' && result[result.size() - 1] == 'g'))
701 // nlwarning("Replacing missing '%s' with '%s'", result.c_str(), FallbackTga);
702 if (UseFallbackTga)
704 return FallbackTga;
706 else
708 return NLMISC::CFile::getFilename(result);
711 if (DisplayReplaces)
713 nldebug("Replacing '%s' with '%s'", str.c_str(), result.c_str());
715 return result;
718 bool isImportantFilePath(const std::string &str)
720 // nldebug("Is important? %s", str.c_str());
722 std::string strtrimmed = cleanString(str);
723 if (strtrimmed.size() >= 4)
725 std::string strlw = NLMISC::toLower(strtrimmed);
726 return (strlw[strlw.size() - 3] == 'm' && strlw[strlw.size() - 2] == 'a' && strlw[strlw.size() - 1] == 'x')
727 || (strlw[strlw.size() - 3] == 't' && strlw[strlw.size() - 2] == 'g' && strlw[strlw.size() - 1] == 'a')
728 || (strlw[strlw.size() - 3] == 'p' && strlw[strlw.size() - 2] == 'n' && strlw[strlw.size() - 1] == 'g');
730 return false;
733 bool hasImportantFilePath(CStorageRaw *raw)
735 if (raw->Value.size() >= 4)
737 // Find any occurences of .max, .png or .tga in ascii or utf16
738 for (uint i = 0; i < raw->Value.size() - 3; ++i)
740 if (NLMISC::toLower(((char *)&raw->Value[0])[i]) == '.'
741 && NLMISC::toLower(((char *)&raw->Value[0])[i + 1]) == 'm'
742 && NLMISC::toLower(((char *)&raw->Value[0])[i + 2]) == 'a'
743 && NLMISC::toLower(((char *)&raw->Value[0])[i + 3]) == 'x')
744 return true;
745 if (NLMISC::toLower(((char *)&raw->Value[0])[i]) == '.'
746 && NLMISC::toLower(((char *)&raw->Value[0])[i + 1]) == 't'
747 && NLMISC::toLower(((char *)&raw->Value[0])[i + 2]) == 'g'
748 && NLMISC::toLower(((char *)&raw->Value[0])[i + 3]) == 'a')
749 return true;
750 if (NLMISC::toLower(((char *)&raw->Value[0])[i]) == '.'
751 && NLMISC::toLower(((char *)&raw->Value[0])[i + 1]) == 'p'
752 && NLMISC::toLower(((char *)&raw->Value[0])[i + 2]) == 'n'
753 && NLMISC::toLower(((char *)&raw->Value[0])[i + 3]) == 'g')
754 return true;
757 if (raw->Value.size() >= 6)
759 for (uint i = 0; i < raw->Value.size() - 6; ++i)
761 if (NLMISC::toLower(((char *)&raw->Value[0])[i]) == '.'
762 && NLMISC::toLower(((char *)&raw->Value[0])[i + 2]) == 'm'
763 && NLMISC::toLower(((char *)&raw->Value[0])[i + 4]) == 'a'
764 && NLMISC::toLower(((char *)&raw->Value[0])[i + 6]) == 'x')
765 return true;
766 if (NLMISC::toLower(((char *)&raw->Value[0])[i]) == '.'
767 && NLMISC::toLower(((char *)&raw->Value[0])[i + 2]) == 't'
768 && NLMISC::toLower(((char *)&raw->Value[0])[i + 4]) == 'g'
769 && NLMISC::toLower(((char *)&raw->Value[0])[i + 6]) == 'a')
770 return true;
771 if (NLMISC::toLower(((char *)&raw->Value[0])[i]) == '.'
772 && NLMISC::toLower(((char *)&raw->Value[0])[i + 2]) == 'p'
773 && NLMISC::toLower(((char *)&raw->Value[0])[i + 4]) == 'n'
774 && NLMISC::toLower(((char *)&raw->Value[0])[i + 6]) == 'g')
775 return true;
778 return false;
781 bool fixChunk(uint16 id, IStorageObject *chunk)
783 if (id == 4656)
785 // nldebug("testing 4656: %s", chunk->toString().c_str());
787 bool changed = false;
788 CStorageValue<std::string> *asString = dynamic_cast<CStorageValue<std::string> *>(chunk);
789 if (asString)
791 // nldebug("String: %s", asString->Value.c_str());
792 if (isImportantFilePath(asString->Value))
794 std::string rewritten = rewritePathFinal(asString->Value);
795 if (rewritten != asString->Value)
797 asString->Value = rewritten;
798 changed = true;
801 return changed;
803 CStorageValue<ucstring> *asUCString = dynamic_cast<CStorageValue<ucstring> *>(chunk);
804 if (asUCString)
806 // nldebug("UCString: %s", asUCString->Value.toUtf8().c_str());
807 if (isImportantFilePath(asUCString->Value.toString()))
809 std::string rewritten = rewritePathFinal(asUCString->Value.toString());
810 if (rewritten != asUCString->Value.toString())
812 asUCString->Value.fromUtf8(rewritten);
813 changed = true;
816 return changed;
818 CStorageRaw *asRaw = dynamic_cast<CStorageRaw *>(chunk);
819 if (asRaw)
821 switch (id)
823 case 4656:
824 // nldebug("4656: %s", chunk->toString().c_str());
825 case 256:
826 case 16385:
827 case 288: // .max xref in classdata
828 if (hasImportantFilePath(asRaw))
830 // generic ucstring really
831 nlassert(asRaw->Value.size() % 2 == 0);
832 ucstring str;
833 str.resize(asRaw->Value.size() / 2);
834 memcpy(&str[0], &asRaw->Value[0], asRaw->Value.size());
835 // nldebug("[%s]", str.toString().c_str());
836 nlassert(isImportantFilePath(str.toString()));
837 std::string rewritten = rewritePathFinal(str.toString());
838 if (rewritten != str.toString())
840 str.fromUtf8(rewritten);
841 asRaw->Value.resize(str.size() * 2);
842 memcpy(&asRaw->Value[0], &str[0], asRaw->Value.size());
843 changed = true;
845 break;
847 case 10:
848 if (hasImportantFilePath(asRaw))
850 // 10 00 08 00 00 00 02 00 80 00 40 // 11 bytes O_O
851 // 4d 00 00 00
852 // 57 3a 5c 44 61 74 61 62 61 73
853 // 65 5c 73 74 75 66 66 5c 74 72
854 // 79 6b 65 72 5c 61 67 65 6e 74
855 // 73 5c 5f 74 65 78 74 75 72 65
856 // 73 5c 61 63 74 6f 72 73 5c 54
857 // 52 5f 48 4f 46 5f 63 69 76 69
858 // 6c 30 31 5f 74 6f 72 73 6f 5f
859 // 43 31 2e 74 67 61 00
860 bool overrideFF = true; // Patch for some ligo max files
861 if (overrideFF && asRaw->Value.size() > 4 && asRaw->Value[asRaw->Value.size() - 4] == 0xFF)
863 nlwarning("0xFFFFFFFF");
865 else if (!(asRaw->Value[asRaw->Value.size() - 1] == 0))
867 nlinfo("Id: %i, size: %i", (uint32)id, asRaw->Value.size());
868 asRaw->toString(std::cout);
869 nldebug("x");
870 nlwarning("not null term");
871 if (HaltOnIssue)
873 std::string x;
874 std::cin >> x;
876 break;
878 uint32 size = ((uint32 *)&asRaw->Value[11])[0];
879 if (!(asRaw->Value.size() == size + 4 + 11))
881 nlinfo("Id: %i, size: %i", (uint32)id, asRaw->Value.size());
882 asRaw->toString(std::cout);
883 nldebug("x");
884 nlwarning("size '%i' does not match '%i', use different algo :)", size, asRaw->Value.size() - 4 - 11);
885 uint8 nonsense[11];
886 uint32 counter;
887 std::vector<std::string> strings;
889 NLMISC::CMemStream mem;
890 asRaw->serial(mem);
891 mem.invert();
892 mem.serialBuffer(nonsense, 11);
893 mem.serial(counter);
894 uint i = 0;
895 while ((sint)mem.getPos() != (sint)mem.size())
897 //nldebug("pos %i", mem.getPos());
898 //nldebug("size %i", mem.size());
899 char funny;
900 mem.serial(funny);
901 nlassert(funny == '@');
902 sint32 size;
903 mem.serial(size);
904 //nldebug("size %i", size);
905 if (!overrideFF && size == -1)
907 nldebug("size %i", size);
908 nlwarning("bad size");
909 if (HaltOnIssue)
911 std::string x;
912 std::cin >> x;
914 return changed;
916 std::string v;
917 if (overrideFF && size == -1)
919 v.resize(1);
920 *(uint8 *)&v[0] = 0;
922 else
924 v.resize(size);
925 mem.serialBuffer((uint8 *)&v[0], size);
927 if (!(v[v.size() - 1] == 0))
929 nlinfo("Id: %i, size: %i", (uint32)id, asRaw->Value.size());
930 asRaw->toString(std::cout);
931 nldebug("x");
932 nlwarning("not null term inside array stuff %i '%s'", i, v.c_str());
933 if (HaltOnIssue)
935 std::string x;
936 std::cin >> x;
938 return changed;
940 v.resize(v.size() - 1);
941 // nldebug("%s", v.c_str());
942 strings.push_back(v);
943 ++i;
944 // nldebug("ok");
946 nlassert(strings.size() == counter);
947 asRaw->Value.resize(0);
949 bool foundone = false;
950 for (uint i = 0; i < strings.size(); ++i)
952 if (isImportantFilePath(strings[i]))
954 foundone = true;
955 std::string rewritten = rewritePathFinal(strings[i]);
956 if (rewritten != strings[i])
958 strings[i] = rewritten;
959 changed = true;
963 nlassert(foundone);
965 //nldebug("go");
966 NLMISC::CMemStream mem;
967 mem.serialBuffer(nonsense, 11);
968 mem.serial(counter);
969 for (uint i = 0; i < strings.size(); ++i)
971 //nldebug("one");
972 char funny = '@';
973 mem.serial(funny);
974 strings[i].resize(strings[i].size() + 1);
975 strings[i][strings[i].size() - 1] = 0;
976 uint32 size = strings[i].size();
977 mem.serial(size);
978 mem.serialBuffer((uint8 *)&strings[i][0], size);
980 asRaw->setSize(mem.getPos());
981 mem.invert();
982 asRaw->serial(mem);
984 //std::string x;
985 //std::cin >> x;
986 return changed;
988 std::string str;
989 str.resize(size - 1);
990 memcpy(&str[0], &asRaw->Value[15], str.size());
991 // nldebug("test '%s'", str.c_str());
992 // asRaw->toString(std::cout);
993 if (!isImportantFilePath(str))
995 nlinfo("Id: %i, size: %i", (uint32)id, asRaw->Value.size());
996 asRaw->toString(std::cout);
997 nldebug("x");
998 nlwarning("not important");
999 if (HaltOnIssue)
1001 std::string x;
1002 std::cin >> x;
1004 break;
1006 std::string rewritten = rewritePathFinal(str);
1007 if (rewritten != str)
1009 str = rewritten;
1010 asRaw->Value.resize(str.size() + 11 + 4 + 1);
1011 memcpy(&asRaw->Value[15], &str[0], str.size());
1012 ((uint32 *)&asRaw->Value[11])[0] = str.size() + 1;
1013 asRaw->Value[asRaw->Value.size() - 1] = 0;
1014 changed = true;
1016 break;
1018 case 304:
1019 if (hasImportantFilePath(asRaw))
1021 // null term c string
1022 nlassert(asRaw->Value[asRaw->Value.size() - 1] == 0);
1023 std::string str;
1024 str.resize(asRaw->Value.size() - 1);
1025 memcpy(&str[0], &asRaw->Value[0], str.size());
1026 if (!isImportantFilePath(str))
1028 nlinfo("Id: %i", (uint32)id);
1029 asRaw->toString(std::cout);
1030 nlerror("not important");
1032 std::string rewritten = rewritePathFinal(str);
1033 if (rewritten != str)
1035 str = rewritten;
1036 asRaw->Value.resize(str.size() + 1);
1037 memcpy(&asRaw->Value[0], &str[0], str.size());
1038 asRaw->Value[asRaw->Value.size() - 1] = 0;
1039 changed = true;
1041 break;
1043 case 9730:
1044 if (asRaw->Value.size() > 0 && asRaw->Value[0] == 'I')
1046 // ignore Init.max
1047 break;
1049 default:
1050 if (hasImportantFilePath(asRaw))
1052 nlinfo("Id: %i", (uint32)id);
1053 asRaw->toString(std::cout);
1054 nlwarning("Found important file path");
1055 if (HaltOnIssue)
1057 std::string x;
1058 std::cin >> x;
1060 return changed;
1062 break;
1065 return changed;
1068 bool fixChunks(CStorageContainer *container)
1070 bool changed = false;
1071 for (CStorageContainer::TStorageObjectConstIt it = container->chunks().begin(), end = container->chunks().end(); it != end; ++it)
1073 if (it->second->isContainer())
1075 changed = (changed || fixChunks(static_cast<CStorageContainer *>(it->second)));
1077 else
1079 changed = (changed || fixChunk(it->first, it->second));
1082 return changed;
1085 void handleFile(const std::string &path)
1087 GError *err = NULL;
1089 GsfDocMetaData *metadata = gsf_doc_meta_data_new();
1090 nlassert(metadata);
1092 GsfInput *src = gsf_input_stdio_new(path.c_str(), &err);
1093 if (err) { nlerror("GSF Failed to open %s", path.c_str()); return; }
1095 GsfInfile *infile = gsf_infile_msole_new(src, NULL);
1096 if (!infile) { nlerror("GSF Failed to recognize %s", path.c_str()); return; }
1097 g_object_unref(src);
1099 uint8 classId[16];
1100 if (!gsf_infile_msole_get_class_id((GsfInfileMSOle *)infile, classId))
1101 nlerror("GSF Did not find classId");
1103 PIPELINE::MAX::CStorageContainer videoPostQueue;
1104 serializeStorageContainer(&videoPostQueue, infile, "VideoPostQueue");
1105 PIPELINE::MAX::CStorageContainer config;
1106 serializeStorageContainer(&config, infile, "Config");
1107 PIPELINE::MAX::CStorageContainer classData;
1108 serializeStorageContainer(&classData, infile, "ClassData");
1110 std::vector<uint8> summaryInformation;
1111 serializeRaw(summaryInformation, infile, "\05SummaryInformation");
1113 std::vector<uint8> documentSummaryInformation;
1114 serializeRaw(documentSummaryInformation, infile, "\05DocumentSummaryInformation"); // Can't read this, don't care.
1116 PIPELINE::MAX::CDllDirectory dllDirectory;
1117 serializeStorageContainer(&dllDirectory, infile, "DllDirectory");
1118 dllDirectory.parse(VersionUnknown);
1120 PIPELINE::MAX::CClassDirectory3 classDirectory3(&dllDirectory);
1121 serializeStorageContainer(&classDirectory3, infile, "ClassDirectory3");
1122 classDirectory3.parse(VersionUnknown);
1124 PIPELINE::MAX::CScene scene(&SceneClassRegistry, &dllDirectory, &classDirectory3);
1125 serializeStorageContainer(&scene, infile, "Scene");
1127 if (DebugParser)
1129 // Not parsing the scene for this function.
1130 scene.parse(VersionUnknown);
1131 scene.clean();
1135 PIPELINE::MAX::CStorageContainer dllDirectory;
1136 serializeStorageContainer(&dllDirectory, infile, "DllDirectory");
1138 PIPELINE::MAX::CStorageContainer classDirectory3;
1139 serializeStorageContainer(&classDirectory3, infile, "ClassDirectory3");
1141 PIPELINE::MAX::CStorageContainer scene;
1142 serializeStorageContainer(&scene, infile, "Scene");
1145 if (DisplayStream)
1147 videoPostQueue.toString(std::cout);
1148 config.toString(std::cout);
1149 classData.toString(std::cout);
1150 dllDirectory.toString(std::cout);
1151 classDirectory3.toString(std::cout);
1152 scene.toString(std::cout);
1155 if (DebugParser)
1157 // Not parsing the scene for this function.
1158 scene.build(VersionUnknown);
1159 scene.disown();
1162 g_object_unref(infile);
1164 bool pathsChanged = !WritePathChangesOnly;
1165 if (ReplacePaths)
1167 pathsChanged = pathsChanged || fixChunks(&classData);
1168 pathsChanged = pathsChanged || fixChunks(&scene);
1171 if (ReplaceMapExt)
1173 // Parse the scene
1174 scene.parse(VersionUnknown);
1175 NLMISC::CClassId editMeshClassId = NLMISC::CClassId(0x00000050, 0x00000000);
1176 NLMISC::CClassId editableMeshClassId = NLMISC::CClassId(0xe44f10b3, 0x00000000);
1177 // from: (0x2ec82081, 0x045a6271)
1178 NLMISC::CClassId fromClassId = NLMISC::CClassId(0x2ec82081, 0x045a6271);
1179 // Find all object space modifier derived containing map extender
1180 for (CStorageContainer::TStorageObjectConstIt it = scene.container()->chunks().begin(), end = scene.container()->chunks().end(); it != end; ++it)
1182 if (it->first == 0x2032) // Derived Object
1184 // nldebug("Found derived object");
1185 CReferenceMaker *derivedObject = dynamic_cast<CReferenceMaker *>(it->second);
1186 nlassert(derivedObject);
1188 // Find map extender in the modifier stack
1189 uint mapExtenderIndex = 0;
1190 CReferenceMaker *mapExtender = NULL;
1191 for (uint i = 0; i < derivedObject->nbReferences(); ++i)
1193 if (derivedObject->getReference(i) && derivedObject->getReference(i)->classDesc()->classId() == fromClassId)
1195 nldebug("Found map extender at '%i' / '%i'!", i, derivedObject->nbReferences());
1196 mapExtenderIndex = i;
1197 mapExtender = derivedObject->getReference(i);
1199 bool deleteDerivedGeom = false;
1200 CStorageContainer *derivedData = dynamic_cast<CStorageContainer *>(derivedObject->findStorageObject(0x2500, mapExtenderIndex));
1201 nlassert(derivedData);
1202 CStorageContainer *derivedGeom = dynamic_cast<CStorageContainer *>(derivedData->findStorageObject(0x2512));
1203 if (!derivedGeom)
1205 CStorageRaw *derivedGeomRaw = dynamic_cast<CStorageRaw *>(derivedData->findStorageObject(0x2512));
1206 if (derivedGeomRaw)
1208 nlwarning("Derived geometry raw instead of as container");
1209 NLMISC::CMemStream memGeom;
1210 derivedGeomRaw->serial(memGeom);
1211 uint size = memGeom.getPos();
1212 memGeom.invert();
1213 derivedGeom = new CStorageContainer();
1214 deleteDerivedGeom = true;
1215 derivedGeom->serial(memGeom, size);
1217 else
1219 derivedData->toString(std::cout);
1220 nlwarning("derived geometry missing!!!");
1221 if (HaltOnIssue)
1223 std::string x;
1224 std::cin >> x;
1226 continue;
1229 CStorageRaw *derivedVertices = dynamic_cast<CStorageRaw *>(derivedGeom->findStorageObject(0x03e9));
1230 if (!derivedVertices)
1232 derivedGeom->toString(std::cout);
1233 nlwarning("derived vertices missing!!!");
1234 if (HaltOnIssue)
1236 std::string x;
1237 std::cin >> x;
1239 continue;
1241 CStorageRaw *derivedIndices = dynamic_cast<CStorageRaw *>(derivedGeom->findStorageObject(0x03eb));
1242 if (!derivedIndices)
1244 derivedGeom->toString(std::cout);
1245 nlwarning("derived indices missing!!!");
1246 if (HaltOnIssue)
1248 std::string x;
1249 std::cin >> x;
1251 continue;
1254 CStorageContainer::TStorageObjectContainer &mapChunks = const_cast<CStorageContainer::TStorageObjectContainer &>(mapExtender->chunks());
1256 // CStorageContainer::TStorageObjectWithId
1258 nlassert(derivedVertices->Value.size() % 12 == 0);
1259 nlassert(derivedIndices->Value.size() % 12 == 0);
1260 uint32 nbVertices = derivedVertices->Value.size() / 12;
1261 uint32 nbFaces = derivedIndices->Value.size() / 12;
1262 nldebug("Vertices: %i", nbVertices);
1263 nldebug("Faces: %i", nbFaces);
1265 // Write vertex chunks
1266 CStorageValue<uint32> *chunkVertCount = new CStorageValue<uint32>();
1267 chunkVertCount->Value = nbVertices;
1268 mapChunks.push_back(CStorageContainer::TStorageObjectWithId(0x0100, chunkVertCount));
1270 CStorageRaw *chunkVerts = new CStorageRaw();
1271 NLMISC::CMemStream memVerts;
1272 derivedVertices->serial(memVerts);
1273 chunkVerts->setSize(memVerts.getPos());
1274 memVerts.invert();
1275 chunkVerts->serial(memVerts);
1276 mapChunks.push_back(CStorageContainer::TStorageObjectWithId(0x0110, chunkVerts));
1278 // Write face chunks
1279 CStorageValue<uint32> *chunkFaceCount = new CStorageValue<uint32>();
1280 chunkFaceCount->Value = nbFaces;
1281 mapChunks.push_back(CStorageContainer::TStorageObjectWithId(0x0230, chunkFaceCount));
1283 CStorageRaw *chunkFaces = new CStorageRaw();
1284 NLMISC::CMemStream memFaces;
1285 derivedIndices->serial(memFaces);
1286 chunkFaces->setSize(memFaces.getPos());
1287 memFaces.invert();
1288 chunkFaces->serial(memFaces);
1289 mapChunks.push_back(CStorageContainer::TStorageObjectWithId(0x0240, chunkFaces));
1291 // Write geom points
1292 CStorageValue<uint32> *chunkGeomPointCount = new CStorageValue<uint32>();
1293 chunkGeomPointCount->Value = nbVertices; // derived vertices?
1294 mapChunks.push_back(CStorageContainer::TStorageObjectWithId(0x0320, chunkGeomPointCount));
1296 CStorageRaw *chunkGeomPoints = new CStorageRaw();
1297 NLMISC::CMemStream memGeomPoints;
1298 derivedVertices->serial(memGeomPoints); // derived vertices?
1299 chunkGeomPoints->setSize(memGeomPoints.getPos());
1300 memGeomPoints.invert();
1301 chunkGeomPoints->serial(memGeomPoints);
1302 mapChunks.push_back(CStorageContainer::TStorageObjectWithId(0x0330, chunkGeomPoints));
1304 if (deleteDerivedGeom)
1305 delete derivedGeom;
1307 // /*break;*/
1308 nldebug("Converted!");
1312 if (mapExtender)
1314 uint editMeshIndex;
1315 CReferenceMaker *editMesh = NULL;
1316 for (uint i = 0; i < derivedObject->nbReferences(); ++i)
1318 if (derivedObject->getReference(i) && derivedObject->getReference(i)->classDesc()->classId() == editMeshClassId)
1320 nldebug("Found edit mesh at '%i' / '%i'!", i, derivedObject->nbReferences());
1321 editMeshIndex = i;
1322 editMesh = derivedObject->getReference(i);
1324 // Ensure no selection
1326 CStorageContainer::TStorageObjectContainer &meshChunks = const_cast<CStorageContainer::TStorageObjectContainer &>(editMesh->chunks());
1328 // Ensure no selection
1329 for (CStorageContainer::TStorageObjectIterator it = meshChunks.begin(), end = meshChunks.end(); it != end; )
1331 CStorageContainer::TStorageObjectIterator next = it; ++next;
1332 switch (it->first)
1334 case 0x2800:
1335 nldebug("Override selection");
1337 delete it->second;
1338 CStorageValue<uint16> *v = new CStorageValue<uint16>();
1339 v->Value = 0;
1340 it->second = v;
1342 break;
1344 it = next;
1347 // /*break;*/
1351 uint editableMeshIndex;
1352 CReferenceMaker *editableMesh = NULL;
1353 for (uint i = 0; i < derivedObject->nbReferences(); ++i)
1355 if (derivedObject->getReference(i) && derivedObject->getReference(i)->classDesc()->classId() == editableMeshClassId)
1357 nldebug("Found editable mesh at '%i' / '%i'!", i, derivedObject->nbReferences());
1358 editableMeshIndex = i;
1359 editableMesh = derivedObject->getReference(i);
1361 CStorageContainer::TStorageObjectContainer &meshChunks = const_cast<CStorageContainer::TStorageObjectContainer &>(editableMesh->chunks());
1363 // Ensure no selection
1364 for (CStorageContainer::TStorageObjectIterator it = meshChunks.begin(), end = meshChunks.end(); it != end; )
1366 CStorageContainer::TStorageObjectIterator next = it; ++next;
1367 switch (it->first)
1369 case 0x2845:
1370 case 0x2846:
1371 case 0x2847:
1372 case 0x2849:
1373 case 0x2850:
1374 case 0x3001:
1375 case 0x3003:
1376 case 0x3004:
1377 nldebug("Erase selection");
1378 meshChunks.erase(it);
1379 break;
1380 case 0x4038:
1381 nldebug("Override selection");
1383 delete it->second;
1384 CStorageValue<uint32> *v = new CStorageValue<uint32>();
1385 v->Value = 0;
1386 it->second = v;
1388 break;
1390 it = next;
1393 // /*break;*/
1397 if (editableMesh && editableMeshIndex + 1 != derivedObject->nbReferences())
1399 nlwarning("Editable mesh not at bottom of the stack, this is unpossible!");
1400 std::string x;
1401 std::cin >> x;
1402 continue;
1405 if (editableMesh == NULL || editMesh == NULL)
1407 derivedObject->toString(std::cout);
1408 nlwarning("editable mesh or edit mesh not found");
1409 std::string x;
1410 std::cin >> x;
1411 continue;
1415 //derivedObject->toString(std::cout);
1416 //editableMesh->toString(std::cout);
1418 // derivedObject -> 0x2500 -> 0x2512 -> 0x03e9 / 0x03eb
1419 // editableMesh -> 0x08fe (geom) -> 0x0916 / 0x0918
1421 CStorageContainer *editableMeshGeometry = dynamic_cast<CStorageContainer *>(editableMesh->findStorageObject(0x08fe));
1422 // nlassert(editableMeshGeometry);
1423 if (!editableMeshGeometry)
1425 nlwarning("broken");
1426 std::string x;
1427 std::cin >> x;
1428 continue;
1430 CStorageRaw *editableVertices = dynamic_cast<CStorageRaw *>(editableMeshGeometry->findStorageObject(0x0916));
1431 nlassert(editableVertices);
1432 CStorageRaw *editableIndices = dynamic_cast<CStorageRaw *>(editableMeshGeometry->findStorageObject(0x0918));
1433 nlassert(editableIndices);
1435 //return new CStorageArraySizePre<NLMISC::CVector>();
1436 if (derivedIndices->Value.size() != editableIndices->Value.size())
1438 editableMesh->toString(std::cout);
1439 derivedObject->toString(std::cout);
1440 nlwarning("size mismatch");
1441 std::string x;
1442 std::cin >> x;
1443 continue;
1446 editableVertices->Value.clear();
1447 editableIndices->Value.clear();
1449 nlassert(derivedVertices->Value.size() % 12 == 0);
1450 uint32 nbVertices = derivedVertices->Value.size() / 12;
1451 NLMISC::CMemStream memVertices;
1452 memVertices.serial(nbVertices);
1453 derivedVertices->serial(memVertices);
1454 memVertices.invert();
1455 editableVertices->setSize(derivedVertices->Value.size() + 4);
1456 editableVertices->serial(memVertices);
1458 NLMISC::CMemStream memIndices;
1459 derivedIndices->serial(memIndices);
1460 memIndices.invert();
1461 editableIndices->setSize(derivedIndices->Value.size());
1462 editableIndices->serial(memIndices);
1463 nldebug("ok!");*/
1467 // to: (0x02df2e3a, 0x72ba4e1f)
1468 NLMISC::CClassId toClassId = NLMISC::CClassId(0x02df2e3a, 0x72ba4e1f); // uvw unwrap
1469 // NLMISC::CClassId toClassId = NLMISC::CClassId(0x5c5b50f7,0x60397ca1); // converttomesh :|
1470 // NLMISC::CClassId toClassId = NLMISC::CClassId(0x31f9c666, 0x03b4a577); // uvw mapping add
1471 // dllname to: uvwunwrap.dlm
1472 for (CStorageContainer::TStorageObjectConstIt it = classDirectory3.chunks().begin(), end = classDirectory3.chunks().end(); it != end; ++it)
1474 CClassEntry *classEntry = dynamic_cast<CClassEntry *>(it->second);
1475 if (classEntry)
1477 //nldebug("class entry %s", classEntry->classId().toString().c_str());
1478 if (classEntry->classId() == fromClassId)
1480 nldebug("Found class id to replace!");
1481 classEntry->overrideClassId(toClassId);
1482 CDllEntry *dllEntry = const_cast<CDllEntry *>(dllDirectory.get(classEntry->dllIndex()));
1483 dllEntry->overrideDllFilename(ucstring("uvwunwrap.dlm"));
1486 //else nldebug("not class entry");
1488 // Disown the scene
1489 scene.disown();
1492 dllDirectory.disown();
1493 classDirectory3.disown();
1494 if (WriteModified && (ReplaceMapExt || pathsChanged))
1496 const char *outpath = (WriteDummy ? "testdummy.max" : path.c_str());
1497 GsfOutput *output;
1498 GsfOutfile *outfile;
1500 output = gsf_output_stdio_new(outpath, &err);
1501 if (err) { nlerror("GSF Failed to create %s", outpath); return; }
1502 outfile = gsf_outfile_msole_new(output);
1503 g_object_unref(G_OBJECT(output));
1505 serializeStorageContainer(&videoPostQueue, outfile, "VideoPostQueue");
1506 serializeStorageContainer(&scene, outfile, "Scene");
1507 serializeStorageContainer(&dllDirectory, outfile, "DllDirectory");
1508 serializeStorageContainer(&config, outfile, "Config");
1509 serializeStorageContainer(&classDirectory3, outfile, "ClassDirectory3");
1510 serializeStorageContainer(&classData, outfile, "ClassData");
1511 serializeRaw(summaryInformation, outfile, "\05SummaryInformation");
1512 serializeRaw(documentSummaryInformation, outfile, "\05DocumentSummaryInformation");
1514 if (!gsf_outfile_msole_set_class_id((GsfOutfileMSOle *)outfile, classId))
1515 nlerror("GSF Cannot write class id");
1517 gsf_output_close(GSF_OUTPUT(outfile));
1518 g_object_unref(G_OBJECT(outfile));
1520 if (WriteDummy)
1522 nlinfo("Dummy written, press key for next");
1523 std::string x;
1524 std::cin >> x;
1528 g_object_unref(metadata);
1531 // int __stdcall WinMain(void *, void *, void *, int)
1532 int main(int argc, char **argv)
1534 // Initialise gsf
1535 printf("Pipeline Max Rewrite Assets\n");
1536 char const *me = (argv[0] ? argv[0] : "pipeline_max_rewrite_assets");
1537 g_set_prgname(me);
1538 gsf_init();
1540 // Register all plugin classes
1541 CBuiltin::registerClasses(&SceneClassRegistry);
1542 CUpdate1::registerClasses(&SceneClassRegistry);
1543 CEPoly::registerClasses(&SceneClassRegistry);
1545 //handleFile("/srv/work/database/interfaces/anims_max/cp_fy_hof_species.max");
1546 runInitialize();
1547 runHandler();
1548 //handleFile(nativeDatabasePath("w:\\database\\landscape\\ligo\\desert\\max\\zonematerial-converted-brandon.max")); // overrideFF
1549 //handleFile(nativeDatabasePath("w:\\database\\landscape\\ligo\\desert\\max\\zonematerial-converted-154_dz.max")); // overrideFF
1550 //handleFile(nativeDatabasePath("w:\\database\\landscape\\ligo\\lacustre\\max\\zonematerial-converted-village_a.max"));
1551 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\ge_mission_reward_karavan_bigshield.max"));
1552 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\ge_acc_pick_o.max"));
1553 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\ge_zo_wea_trib_masse1m.max"));
1554 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\ge_fy_wea_trib_grand_bouclier.max"));
1555 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\ge_mission_entrepot.max"));
1556 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\mesh_wip\\all_trib_weapons.max"));
1557 //handleFile(nativeDatabasePath("w:\\database\\stuff\\fyros\\decors\\constructions\\fy_cn_smokehouse.max"));
1558 //handleFile("/srv/work/database/landscape/ligo/jungle/pipeline_max/zonematerial-foret-ruine_boss.max");
1559 //handleFile("/srv/work/database/stuff/fyros/agents/actors/male/animation/anims_non_utilisees/fy_hom_assis_boire_verre.max");
1560 //handleFile("/home/kaetemi/3dsMax/scenes/test_clear_add_uvw.max");
1561 //runScanner();
1563 for (std::set<std::string>::iterator it = MissingFiles.begin(), end = MissingFiles.end(); it != end; ++it)
1564 nlinfo("Missing: '%s'", (*it).c_str());
1566 gsf_shutdown();
1568 return 0;