1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/types_nl.h"
33 #include "nel/misc/debug.h"
34 #include "nel/misc/file.h"
35 #include "nel/misc/path.h"
36 #include "nel/misc/algo.h"
37 #include "nel/misc/common.h"
38 #include "nel/misc/big_file.h"
39 #include "nel/misc/cmd_args.h"
43 using namespace NLMISC
;
45 // ---------------------------------------------------------------------------
53 std::vector
<CWildCard
> WildCards
;
55 // ---------------------------------------------------------------------------
57 bool keepFile (const std::string
&fileName
)
60 bool ifPresent
= false;
62 string file
= toLowerAscii(CFile::getFilename (fileName
));
63 for (i
=0; i
<WildCards
.size(); i
++)
67 // One ifnot condition met and the file is not added
68 if (testWildCard(file
, WildCards
[i
].Expression
))
74 ifTrue
|= testWildCard(file
, WildCards
[i
].Expression
);
78 return !ifPresent
|| ifTrue
;
81 // ---------------------------------------------------------------------------
83 NLMISC::CBigFile::BNP gBNPHeader
;
85 // ---------------------------------------------------------------------------
86 bool i_comp(const string
&s0
, const string
&s1
)
88 return nlstricmp (CFile::getFilename(s0
).c_str(), CFile::getFilename(s1
).c_str()) < 0;
91 bool packSubRecurse(const std::string
&srcDirectory
)
93 vector
<string
> pathContent
;
95 printf ("Treating directory: %s\n", srcDirectory
.c_str());
96 CPath::getPathContent(srcDirectory
, true, false, true, pathContent
);
98 if (pathContent
.empty()) return true;
101 sort (pathContent
.begin(), pathContent
.end(), i_comp
);
103 // check for files with same name
104 for(uint i
= 1, len
= pathContent
.size(); i
< len
; ++i
)
106 if (toLowerAscii(CFile::getFilename(pathContent
[i
-1])) == toLowerAscii(CFile::getFilename(pathContent
[i
])))
108 nlwarning("File %s is not unique in BNP!", CFile::getFilename(pathContent
[i
]).c_str());
113 for (uint i
=0; i
<pathContent
.size(); ++i
)
115 if (keepFile(pathContent
[i
]))
117 if (gBNPHeader
.appendFile(pathContent
[i
]))
119 printf("Adding %s\n", pathContent
[i
].c_str());
123 printf("Error: cannot open %s\n", pathContent
[i
].c_str());
131 // ---------------------------------------------------------------------------
132 int main(int argc
, char **argv
)
134 NLMISC::CApplicationContext myApplicationContext
;
136 NLMISC::CCmdArgs args
;
138 args
.addArg("p", "pack", "", "Pack the directory to a BNP file");
139 args
.addArg("u", "unpack", "", "Unpack the BNP file to a directory");
140 args
.addArg("l", "list", "", "List the files contained in the BNP file");
141 args
.addArg("o", "output", "destination", "Output directory or file");
142 args
.addArg("i", "if", "wildcard", "Add the file if it matches the wilcard (at least one 'if' conditions must be met for a file to be adding)", false);
143 args
.addArg("n", "ifnot", "wildcard", "Add the file if it doesn't match the wilcard (all the 'ifnot' conditions must be met for a file to be adding)", false);
144 args
.addArg("", "list-verbose", "", "List files using 'pos size name' format");
145 args
.addArg("", "extract", "name", "Extract file(s) from BNP into --output");
146 args
.addAdditionalArg("input", "Input directory or BNP file depending on command");
148 if (!args
.parse(argc
, argv
)) return 1;
150 if (args
.haveArg("p"))
152 std::vector
<std::string
> filters
;
155 filters
= args
.getLongArg("if");
157 for (uint i
= 0; i
< filters
.size(); ++i
)
160 card
.Expression
= toLowerAscii(filters
[i
]);
162 WildCards
.push_back(card
);
166 filters
= args
.getLongArg("ifnot");
168 for (uint i
= 0; i
< filters
.size(); ++i
)
171 card
.Expression
= toLowerAscii(filters
[i
]);
173 WildCards
.push_back(card
);
177 std::string srcDirectory
= args
.getAdditionalArg("input").front();
179 if (!CFile::isDirectory(srcDirectory
) || !CFile::isExists(srcDirectory
))
181 nlwarning("Error: %s doesn't exist or is not a directory!", srcDirectory
.c_str());
184 // Output directory or filename
185 if (args
.haveArg("o"))
187 gBNPHeader
.BigFileName
= args
.getArg("o").front();
189 if (CFile::isDirectory(gBNPHeader
.BigFileName
))
191 gBNPHeader
.BigFileName
= CPath::standardizePath(gBNPHeader
.BigFileName
) + CFile::getFilename(srcDirectory
);
196 gBNPHeader
.BigFileName
= CFile::getFilename(srcDirectory
);
199 if (CFile::getExtension(gBNPHeader
.BigFileName
) != "bnp")
200 gBNPHeader
.BigFileName
+= ".bnp";
202 CFile::deleteFile(gBNPHeader
.BigFileName
);
204 if (!packSubRecurse(srcDirectory
)) return 1;
206 return gBNPHeader
.appendHeader() ? 0:-1;
209 if (args
.haveArg("u"))
211 gBNPHeader
.BigFileName
= args
.getAdditionalArg("input").front();
215 // Output directory or filename
216 if (args
.haveArg("o"))
218 dirName
= args
.getArg("o").front();
222 dirName
= CFile::getFilenameWithoutExtension(gBNPHeader
.BigFileName
);
226 return gBNPHeader
.unpack(dirName
) ? 0:-1;
229 if (args
.haveArg("l"))
231 gBNPHeader
.BigFileName
= args
.getAdditionalArg("input").front();
233 // Read header of BNP file
234 if (!gBNPHeader
.readHeader()) return -1;
236 for (uint i
= 0; i
< gBNPHeader
.SFiles
.size(); ++i
)
238 printf("%s\n", gBNPHeader
.SFiles
[i
].Name
.c_str());
244 if (args
.haveLongArg("list-verbose"))
246 gBNPHeader
.BigFileName
= args
.getAdditionalArg("input").front();
248 // Read header of BNP file
249 if (!gBNPHeader
.readHeader()) return -1;
251 for (uint i
= 0; i
< gBNPHeader
.SFiles
.size(); ++i
)
253 printf("%u %u %s\n", gBNPHeader
.SFiles
[i
].Pos
, gBNPHeader
.SFiles
[i
].Size
, gBNPHeader
.SFiles
[i
].Name
.c_str());
260 if (args
.haveLongArg("extract") && !args
.getLongArg("extract").empty())
262 std::string bnpName
= args
.getAdditionalArg("input").front();
263 CBigFile::getInstance().add(bnpName
, BF_ALWAYS_OPENED
);
265 // Output directory or filename
266 if (!args
.haveArg("o") || args
.getArg("o").empty())
268 nlerror("Output file or directory not set");
271 std::string srcName
= args
.getLongArg("extract").front();
272 std::string dstName
= args
.getArg("o").front();
273 if (CFile::fileExists(dstName
) && CFile::isDirectory(dstName
))
275 dstName
+= "/" + srcName
;
279 // bnpName without path
280 if (!inFile
.open(CFile::getFilename(bnpName
) + "@" + srcName
))
282 nlerror("Unable to open '%s' for reading", inFile
.getStreamName().c_str());
286 if (!outFile
.open(dstName
))
288 nlerror("Unable to open '%s' for writing", outFile
.getStreamName().c_str());
293 outFile
.serialBuffer((uint8
*)&buf
[0], buf
.size());