• R/O
  • SSH
  • HTTPS

eirsamples: Commit


Commit MetaInfo

Revision34 (tree)
Time2020-10-15 22:38:40
Authorquiret

Log Message

- added commandline interface to write RW chunks

Change Summary

Incremental Difference

--- rwchunk-writer/src/main.cpp (revision 33)
+++ rwchunk-writer/src/main.cpp (revision 34)
@@ -1,13 +1,84 @@
11 #include <renderware.h>
22
33 #include <iostream>
4+#include <string>
45
6+#include <sdk/NumericFormat.h>
7+
8+#include <sdk/UniChar.h>
9+#include <sdk/DataUtil.h>
10+#include <sdk/MemoryUtils.stream.h>
11+#include <sdk/FixedString.h>
12+
513 namespace rw
614 {
715
16+static rwStaticVector <eir::FixedString <char>> parse_cmdline( const std::string& cmdline )
17+{
18+ rwStaticVector <eir::FixedString <char>> args;
19+
20+ const char *chars = nullptr;
21+ size_t char_len = 0;
22+
23+ const char *cmdline_str = cmdline.c_str();
24+
25+ while ( *cmdline_str != '\0' )
26+ {
27+ char c = *cmdline_str;
28+
29+ if ( c == ' ' || c == '\t' )
30+ {
31+ if ( chars != nullptr )
32+ {
33+ args.AddToBack( std::move( eir::FixedString <char> ( chars, char_len ) ) );
34+
35+ chars = nullptr;
36+ char_len = 0;
37+ }
38+ }
39+ else
40+ {
41+ if ( chars == nullptr )
42+ {
43+ chars = cmdline_str;
44+ }
45+
46+ char_len++;
47+ }
48+
49+ cmdline_str++;
50+ }
51+
52+ if ( chars != nullptr )
53+ {
54+ args.AddToBack( std::move( eir::FixedString <char> ( chars, char_len ) ) );
55+ }
56+
57+ return args;
58+}
59+
60+template <size_t align_by>
61+AINLINE void byteAlignBlockProvider( BlockProvider *prov )
62+{
63+ static const char zeroes[align_by - 1] = { 0 };
64+
65+ int64 cur_seek = prov->tell();
66+
67+ size_t align_into = (size_t)( cur_seek % align_by );
68+
69+ if ( align_into == 0 )
70+ {
71+ return;
72+ }
73+
74+ size_t align_left = ( align_by - align_into );
75+
76+ prov->write( zeroes, align_left );
77+}
78+
879 LibraryVersion app_version( void )
980 {
10- return LibraryVersion( 3, 6, 0, 1 );
81+ return LibraryVersion( 3, 6, 0, 3 );
1182 }
1283
1384 int rwmain( rw::Interface *rwEngine )
@@ -16,6 +87,411 @@
1687 std::cout << "compiled on " __DATE__ << std::endl;
1788 std::cout << std::endl;
1889
90+ static rwStaticMap <rwStaticString <char>, uint32, lexical_string_comparator <false>> string_to_chunk_id =
91+ {
92+ { "struct", CHUNK_STRUCT },
93+ { "string", CHUNK_STRING },
94+ { "texture_native", CHUNK_TEXTURENATIVE },
95+ { "tex_native", CHUNK_TEXTURENATIVE }
96+ };
97+
98+ while ( true )
99+ {
100+ std::cout << "Enter a filename: ";
101+
102+ std::string filename;
103+
104+ std::cin >> filename;
105+
106+ if ( filename == "exit" )
107+ break;
108+
109+ // Create a file with that name.
110+ rw::streamConstructionFileParam_t fileparam( filename.c_str() );
111+
112+ rw::StreamPtr filestream = rwEngine->CreateStream( RWSTREAMTYPE_FILE, RWSTREAMMODE_CREATE, &fileparam );
113+
114+ if ( filestream.is_good() == false )
115+ {
116+ std::cout << "could not open file" << std::endl;
117+
118+ continue;
119+ }
120+
121+ rwStaticVector <BlockProvider> active_blocks;
122+
123+ BlockProvider current_block;
124+
125+ // For struct chunks we provide a bitstream API.
126+ size_t current_block_bit_offset = 0;
127+ BasicMemStream::basicMemStreamAllocMan <size_t> bufalloc;
128+ BasicMemStream::basicMemoryBufferStream <size_t> bitbuf( nullptr, 0, bufalloc );
129+
130+ // Configuration.
131+ bool enable_alignments = false;
132+
133+ auto flush_bits = [&]( void )
134+ {
135+ if ( current_block_bit_offset == 0 )
136+ return;
137+
138+ size_t bits_to_byte_bound = eir::getBitCountToByteBound( current_block_bit_offset - 1 );
139+
140+ eir::setBits( bitbuf.Data(), false, current_block_bit_offset, bits_to_byte_bound );
141+
142+ current_block.write( bitbuf.Data(), bitbuf.Size() );
143+ bitbuf.Truncate( 0 );
144+ current_block_bit_offset = 0;
145+ };
146+
147+ // Go into command-mode.
148+ while ( true )
149+ {
150+ std::string cmd;
151+
152+ std::getline( std::cin, cmd );
153+
154+ // Parse into tokens.
155+ auto tokens = parse_cmdline( cmd );
156+
157+ if ( tokens.GetCount() > 0 )
158+ {
159+ auto maincmd = std::move( tokens[0] );
160+
161+ bool recognized_cmd = false;
162+
163+ if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "exit", false ) )
164+ {
165+ std::cout << "exited file" << std::endl;
166+
167+ break;
168+ }
169+ else if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "enter", false ))
170+ {
171+ recognized_cmd = true;
172+
173+ rw::uint32 chunk_id;
174+
175+ if ( tokens.GetCount() == 1 )
176+ {
177+ chunk_id = CHUNK_STRUCT;
178+ }
179+ else if ( auto *idStringNode = string_to_chunk_id.Find( tokens[1] ) )
180+ {
181+ chunk_id = idStringNode->GetValue();
182+ }
183+ else
184+ {
185+ const auto& id_str = tokens[1];
186+
187+ chunk_id = eir::to_number_len <rw::uint32> ( id_str.GetConstString(), id_str.GetLength() );
188+ }
189+
190+ if ( chunk_id != 0 )
191+ {
192+ flush_bits();
193+
194+ BlockProvider *parentProvider = nullptr;
195+
196+ if ( current_block.inContext() )
197+ {
198+ active_blocks.AddToBack( std::move( current_block ) );
199+
200+ parentProvider = &active_blocks.GetBack();
201+ }
202+
203+ if ( parentProvider )
204+ {
205+ current_block = BlockProvider( blockprov_constr_no_ctx::DEFAULT, parentProvider );
206+ }
207+ else
208+ {
209+ current_block = BlockProvider( filestream, RWBLOCKMODE_WRITE );
210+ }
211+
212+ current_block.EstablishObjectContextDirect( chunk_id );
213+ }
214+ else
215+ {
216+ std::cout << "invalid chunk ID" << std::endl;
217+ }
218+ }
219+ else if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "leave", false ) )
220+ {
221+ recognized_cmd = true;
222+
223+ if ( current_block.inContext() == false )
224+ {
225+ std::cout << "no context to leave" << std::endl;
226+ }
227+ else
228+ {
229+ flush_bits();
230+
231+ size_t activeBlockCount = active_blocks.GetCount();
232+
233+ if ( activeBlockCount > 0 )
234+ {
235+ current_block = std::move( active_blocks.GetBack() );
236+
237+ active_blocks.Resize( activeBlockCount - 1 );
238+ }
239+ else
240+ {
241+ current_block = BlockProvider();
242+ }
243+ }
244+ }
245+ else if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "align", false ) )
246+ {
247+ recognized_cmd = true;
248+
249+ enable_alignments = !enable_alignments;
250+
251+ if ( enable_alignments )
252+ {
253+ std::cout << "enabled alignments" << std::endl;
254+ }
255+ else
256+ {
257+ std::cout << "disabled alignments" << std::endl;
258+ }
259+ }
260+ else if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "version", false ) )
261+ {
262+ recognized_cmd = true;
263+
264+ if ( tokens.GetCount() >= 2 )
265+ {
266+ uint8_t libMajor = eir::to_number_len <uint8_t> ( tokens[1].GetConstString(), tokens[1].GetLength() );
267+ uint8_t libMinor = ( tokens.GetCount() >= 3 ? eir::to_number_len <uint8_t> ( tokens[2].GetConstString(), tokens[2].GetLength() ) : 0u );
268+ uint8_t revMajor = ( tokens.GetCount() >= 4 ? eir::to_number_len <uint8_t> ( tokens[3].GetConstString(), tokens[3].GetLength() ) : 0u );
269+ uint8_t revMinor = ( tokens.GetCount() >= 5 ? eir::to_number_len <uint8_t> ( tokens[4].GetConstString(), tokens[4].GetLength() ) : 0u );
270+
271+ LibraryVersion ver( libMajor, libMinor, revMajor, revMinor );
272+
273+ current_block.setBlockVersion( ver );
274+
275+ rwEngine->SetVersion( ver );
276+ }
277+ else
278+ {
279+ std::cout << "not enough params" << std::endl;
280+ }
281+ }
282+ else if ( current_block.inContext() && current_block.getBlockID() == CHUNK_STRUCT )
283+ {
284+ if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "bits", false ) )
285+ {
286+ recognized_cmd = true;
287+
288+ if ( tokens.GetCount() >= 3 )
289+ {
290+ unsigned int num_bits = eir::to_number_len <unsigned int> ( tokens[1].GetConstString(), tokens[1].GetLength() );
291+
292+ if ( num_bits <= 64 )
293+ {
294+ uint64_t value = eir::to_number_len <uint64_t> ( tokens[2].GetConstString(), tokens[2].GetLength() );
295+
296+ // Make sure the buffer is big enough.
297+ size_t reqByteCount = CEIL_DIV( current_block_bit_offset + num_bits, 8u );
298+
299+ bitbuf.Truncate( reqByteCount );
300+
301+ eir::moveBits( bitbuf.Data(), &value, 0, current_block_bit_offset, num_bits );
302+
303+ current_block_bit_offset += num_bits;
304+
305+ }
306+ else
307+ {
308+ std::cout << "too many bits (max: 64)" << std::endl;
309+ }
310+ }
311+ else
312+ {
313+ std::cout << "invalid param count" << std::endl;
314+ }
315+ }
316+ else if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "uint8", false ) )
317+ {
318+ recognized_cmd = true;
319+
320+ if ( tokens.GetCount() >= 2 )
321+ {
322+ uint8_t value = eir::to_number_len <uint8_t> ( tokens[1].GetConstString(), tokens[1].GetLength() );
323+
324+ flush_bits();
325+
326+ current_block.writeUInt8( value );
327+ }
328+ else
329+ {
330+ std::cout << "invalid param count" << std::endl;
331+ }
332+ }
333+ else if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "uint16", false ) )
334+ {
335+ recognized_cmd = true;
336+
337+ if ( tokens.GetCount() >= 2 )
338+ {
339+ uint16_t value = eir::to_number_len <uint16_t> ( tokens[1].GetConstString(), tokens[1].GetLength() );
340+
341+ flush_bits();
342+
343+ if ( enable_alignments )
344+ {
345+ byteAlignBlockProvider <2> ( &current_block );
346+ }
347+
348+ current_block.writeUInt16( value );
349+ }
350+ else
351+ {
352+ std::cout << "invalid param count" << std::endl;
353+ }
354+ }
355+ else if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "uint32", false ) )
356+ {
357+ recognized_cmd = true;
358+
359+ if ( tokens.GetCount() >= 2 )
360+ {
361+ uint32_t value = eir::to_number_len <uint32_t> ( tokens[1].GetConstString(), tokens[1].GetLength() );
362+
363+ flush_bits();
364+
365+ if ( enable_alignments )
366+ {
367+ byteAlignBlockProvider <4> ( &current_block );
368+ }
369+
370+ current_block.writeUInt32( value );
371+ }
372+ else
373+ {
374+ std::cout << "invalid param count" << std::endl;
375+ }
376+ }
377+ else if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "uint64", false ) )
378+ {
379+ recognized_cmd = true;
380+
381+ if ( tokens.GetCount() >= 2 )
382+ {
383+ uint64_t value = eir::to_number_len <uint64_t> ( tokens[1].GetConstString(), tokens[1].GetLength() );
384+
385+ flush_bits();
386+
387+ if ( enable_alignments )
388+ {
389+ byteAlignBlockProvider <8> ( &current_block );
390+ }
391+
392+ current_block.writeUInt64( value );
393+ }
394+ else
395+ {
396+ std::cout << "invalid param count" << std::endl;
397+ }
398+ }
399+ else if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "fixchar", false ) )
400+ {
401+ recognized_cmd = true;
402+
403+ if ( tokens.GetCount() >= 3 )
404+ {
405+ flush_bits();
406+
407+ uint32 num_fixchar = eir::to_number_len <uint32> ( tokens[1].GetConstString(), tokens[1].GetLength() );
408+
409+ const char *writestr = tokens[2].GetConstString();
410+ size_t writecnt = std::min( (size_t)num_fixchar, strlen( writestr ) );
411+
412+ current_block.write( writestr, writecnt );
413+
414+ // Pad with zeroes.
415+ size_t padcnt = ( num_fixchar - writecnt );
416+
417+ while ( padcnt-- )
418+ {
419+ current_block.writeUInt8( 0 );
420+ }
421+ }
422+ else
423+ {
424+ std::cout << "invalid param count" << std::endl;
425+ }
426+ }
427+ else if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "byterep", false ) )
428+ {
429+ recognized_cmd = true;
430+
431+ if ( tokens.GetCount() >= 3 )
432+ {
433+ flush_bits();
434+
435+ uint8 byteval = eir::to_number_len <uint8> ( tokens[1].GetConstString(), tokens[1].GetLength() );
436+ uint32 repeat_count = eir::to_number_len <uint32> ( tokens[2].GetConstString(), tokens[2].GetLength() );
437+
438+ while ( repeat_count-- )
439+ {
440+ current_block.writeUInt8( byteval );
441+ }
442+ }
443+ else
444+ {
445+ std::cout << "invalid param count" << std::endl;
446+ }
447+ }
448+ else if ( BoundedStringEqual( maincmd.GetConstString(), maincmd.GetLength(), "bitrep", false ) )
449+ {
450+ recognized_cmd = true;
451+
452+ if ( tokens.GetCount() >= 4 )
453+ {
454+ uint8_t bitcnt = eir::to_number_len <uint8_t> ( tokens[1].GetConstString(), tokens[1].GetLength() );
455+
456+ if ( bitcnt <= 64 )
457+ {
458+ uint64_t value = eir::to_number_len <uint64_t> ( tokens[2].GetConstString(), tokens[2].GetLength() );
459+ uint32 repeat_count = eir::to_number_len <uint32> ( tokens[3].GetConstString(), tokens[3].GetLength() );
460+
461+ // Make sure the buffer is big enough.
462+ size_t reqByteCount = CEIL_DIV( current_block_bit_offset + bitcnt * repeat_count, 8u );
463+
464+ bitbuf.Truncate( reqByteCount );
465+
466+ while ( repeat_count-- )
467+ {
468+ eir::moveBits( bitbuf.Data(), &value, 0, current_block_bit_offset, bitcnt );
469+
470+ current_block_bit_offset += bitcnt;
471+ }
472+ }
473+ else
474+ {
475+ std::cout << "too many bits" << std::endl;
476+ }
477+ }
478+ else
479+ {
480+ std::cout << "invalid param count" << std::endl;
481+ }
482+ }
483+ }
484+
485+ if ( recognized_cmd == false )
486+ {
487+ std::cout << "unknown command" << std::endl;
488+ }
489+ }
490+ }
491+
492+ // File will be closed and flushed here.
493+ }
494+
19495 return 0;
20496 }
21497
Show on old repository browser