the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "FileHeader.h"
3
4//#define _DEBUG_FILE_HEADER
5
6FileHeader::FileHeader()
7{
8 lastFile = NULL;
9 m_saveVersion = 0;
10
11 // New saves should have an original version set to the latest version. This will be overridden when we load a save
12 m_originalSaveVersion = SAVE_FILE_VERSION_NUMBER;
13 m_savePlatform = SAVE_FILE_PLATFORM_LOCAL;
14 m_saveEndian = m_localEndian;
15}
16
17FileHeader::~FileHeader()
18{
19 for( unsigned int i = 0; i < fileTable.size(); ++i )
20 {
21 delete fileTable[i];
22 }
23}
24
25FileEntry *FileHeader::AddFile( const wstring &name, unsigned int length /* = 0 */ )
26{
27 assert( name.length() < 64 );
28
29 wchar_t filename[64];
30 memset( &filename, 0, sizeof( wchar_t ) * 64 );
31 memcpy( &filename, name.c_str(), min( sizeof( wchar_t ) * 64, sizeof( wchar_t ) * name.length() ) );
32
33 // Would a map be more efficient? Our file tables probably won't be very big so better to avoid hashing all the time?
34 // Does the file exist?
35 for( unsigned int i = 0; i < fileTable.size(); ++i )
36 {
37 if( wcscmp( fileTable[i]->data.filename, filename ) == 0 )
38 {
39 // If so, return it
40 return fileTable[i];
41 }
42 }
43
44 // Else, add it to our file table
45 fileTable.push_back( new FileEntry( filename, length, GetStartOfNextData() ) );
46 lastFile = fileTable[ fileTable.size() - 1 ];
47 return lastFile;
48}
49
50void FileHeader::RemoveFile( FileEntry *file )
51{
52 if( file == NULL ) return;
53
54 AdjustStartOffsets(file, file->getFileSize(), true);
55
56 AUTO_VAR(it, find(fileTable.begin(), fileTable.end(),file));
57
58 if( it < fileTable.end() )
59 {
60 fileTable.erase( it );
61 }
62
63#ifndef _CONTENT_PACKAGE
64 wprintf(L"Removed file %ls\n", file->data.filename);
65#endif
66
67 delete file;
68}
69
70void FileHeader::WriteHeader( LPVOID saveMem )
71{
72 unsigned int headerOffset = GetStartOfNextData();
73
74 // 4J Changed for save version 2 to be the number of files rather than the size in bytes
75 unsigned int headerSize = (int)(fileTable.size());
76
77 //DWORD numberOfBytesWritten = 0;
78
79 // Write the offset of the header
80 //assert(numberOfBytesWritten == 4);
81 int *begin = (int *)saveMem;
82#ifdef __PSVITA__
83 VirtualCopyTo(begin, &headerOffset, sizeof(headerOffset));
84#else
85 *begin = headerOffset;
86#endif
87
88 // Write the size of the header
89 //assert(numberOfBytesWritten == 4);
90#ifdef __PSVITA__
91 VirtualCopyTo(begin + 1, &headerSize, sizeof(headerSize));
92#else
93 *(begin + 1) = headerSize;
94#endif
95
96 short *versions = (short *)(begin + 2);
97 // Write the original version number
98#ifdef __PSVITA__
99 VirtualCopyTo(versions, &m_originalSaveVersion, sizeof(m_originalSaveVersion));
100#else
101 *versions = m_originalSaveVersion;
102#endif
103
104 // Write the version number
105 short versionNumber = SAVE_FILE_VERSION_NUMBER;
106 //assert(numberOfBytesWritten == 4);
107 //*(begin + 2) = versionNumber;
108#ifdef __PSVITA__
109 VirtualCopyTo(versions + 1, &versionNumber, sizeof(versionNumber));
110#else
111 *(versions + 1) = versionNumber;
112#endif
113
114#ifdef _DEBUG_FILE_HEADER
115 app.DebugPrintf("Write save file with original version: %d, and current version %d\n", m_originalSaveVersion, versionNumber);
116#endif
117
118 char *headerPosition = (char *)saveMem + headerOffset;
119
120#ifdef _DEBUG_FILE_HEADER
121 app.DebugPrintf("\n\nWrite file Header: Offset = %d, Size = %d\n", headerOffset, headerSize);
122#endif
123
124 // Write the header
125 for( unsigned int i = 0; i < fileTable.size(); ++i )
126 {
127 //wprintf(L"File: %ls, Start = %d, Length = %d, End = %d\n", fileTable[i]->data.filename, fileTable[i]->data.startOffset, fileTable[i]->data.length, fileTable[i]->data.startOffset + fileTable[i]->data.length);
128#ifdef __PSVITA__
129 VirtualCopyTo((void *)headerPosition, &fileTable[i]->data, sizeof(FileEntrySaveData));
130#else
131 memcpy( (void *)headerPosition, &fileTable[i]->data, sizeof(FileEntrySaveData) );
132#endif
133 //assert(numberOfBytesWritten == sizeof(FileEntrySaveData));
134 headerPosition += sizeof(FileEntrySaveData);
135 }
136}
137
138void FileHeader::ReadHeader( LPVOID saveMem, ESavePlatform plat /*= SAVE_FILE_PLATFORM_LOCAL */ )
139{
140 unsigned int headerOffset;
141 unsigned int headerSize;
142
143 m_savePlatform = plat;
144
145 switch(m_savePlatform)
146 {
147 case SAVE_FILE_PLATFORM_X360:
148 case SAVE_FILE_PLATFORM_PS3:
149 m_saveEndian = BIGENDIAN;
150 break;
151 case SAVE_FILE_PLATFORM_XBONE:
152 case SAVE_FILE_PLATFORM_WIN64:
153 case SAVE_FILE_PLATFORM_PS4:
154 case SAVE_FILE_PLATFORM_PSVITA:
155 m_saveEndian = LITTLEENDIAN;
156 break;
157 default:
158 assert(0);
159 m_savePlatform = SAVE_FILE_PLATFORM_LOCAL;
160 m_saveEndian = m_localEndian;
161 break;
162 }
163
164
165 // Read the offset of the header
166 //assert(numberOfBytesRead == 4);
167 int *begin = (int *)saveMem;
168#ifdef __PSVITA__
169 VirtualCopyFrom(&headerOffset, begin, sizeof(headerOffset));
170#else
171 headerOffset = *begin;
172#endif
173 if(isSaveEndianDifferent()) System::ReverseULONG(&headerOffset);
174
175 // Read the size of the header
176 //assert(numberOfBytesRead == 4);
177#ifdef __PSVITA__
178 VirtualCopyFrom(&headerSize, begin + 1, sizeof(headerSize));
179#else
180 headerSize = *(begin + 1);
181#endif
182 if(isSaveEndianDifferent()) System::ReverseULONG(&headerSize);
183
184
185 short *versions = (short *)(begin + 2);
186 // Read the original save version number
187#ifdef __PSVITA__
188 VirtualCopyFrom(&m_originalSaveVersion, versions, sizeof(m_originalSaveVersion));
189#else
190 m_originalSaveVersion = *(versions);
191#endif
192 if(isSaveEndianDifferent()) System::ReverseSHORT(&m_originalSaveVersion);
193
194 // Read the save version number
195 //m_saveVersion = *(begin + 2);
196#ifdef __PSVITA__
197 VirtualCopyFrom(&m_saveVersion, versions + 1, sizeof(m_saveVersion));
198#else
199 m_saveVersion = *(versions + 1);
200#endif
201 if(isSaveEndianDifferent()) System::ReverseSHORT(&m_saveVersion);
202
203#ifdef _DEBUG_FILE_HEADER
204 app.DebugPrintf("Read save file with orignal version: %d, and current version %d\n", m_originalSaveVersion, m_saveVersion);
205 app.DebugPrintf("\n\nRead file Header: Offset = %d, Size = %d\n", headerOffset, headerSize);
206#endif
207
208 char *headerPosition = (char *)saveMem + headerOffset;
209
210 switch( m_saveVersion )
211 {
212 //case SAVE_FILE_VERSION_NUMBER:
213 //case 8: // 4J Stu - SAVE_FILE_VERSION_NUMBER 2,3,4,5,6,7,8 are the same, but:
214 // : Bumped it to 3 in TU5 to force older builds (ie 0062) to generate a new world when trying to load new saves
215 // : Bumped it to 4 in TU9 to delete versions of The End that were generated in builds prior to TU9
216 // : Bumped it to 5 in TU9 to update the map data that was only using 1 bit to determine dimension
217 // : Bumped it to 6 for PS3 v1 to update map data mappings to use larger PlayerUID
218 // : Bumped it to 7 for Durango v1 to update map data mappings to use string based PlayerUID
219 // : Bumped it to 8 for Durango v1 when to save the chunks in a different compressed format
220 case SAVE_FILE_VERSION_CHUNK_INHABITED_TIME:
221 case SAVE_FILE_VERSION_COMPRESSED_CHUNK_STORAGE:
222 case SAVE_FILE_VERSION_DURANGO_CHANGE_MAP_DATA_MAPPING_SIZE:
223 case SAVE_FILE_VERSION_CHANGE_MAP_DATA_MAPPING_SIZE:
224 case SAVE_FILE_VERSION_MOVED_STRONGHOLD:
225 case SAVE_FILE_VERSION_NEW_END:
226 case SAVE_FILE_VERSION_POST_LAUNCH:
227 case SAVE_FILE_VERSION_LAUNCH:
228 {
229 // Changes for save file version 2:
230 // headerSize is now a count of elements rather than a count of bytes
231 // The FileEntrySaveData struct has a lastModifiedTime member
232
233 // Read the header
234 FileEntrySaveData *fesdHeaderPosition = (FileEntrySaveData *)headerPosition;
235 for(unsigned int i = 0; i < headerSize; ++i)
236 {
237 FileEntry *entry = new FileEntry();
238 //assert(numberOfBytesRead == sizeof(FileEntrySaveData));
239
240#ifdef __PSVITA__
241 VirtualCopyFrom( &entry->data, fesdHeaderPosition, sizeof(FileEntrySaveData) );
242#else
243 memcpy( &entry->data, fesdHeaderPosition, sizeof(FileEntrySaveData) );
244#endif
245
246 if(isSaveEndianDifferent())
247 {
248 // Reverse bytes
249 System::ReverseWCHARA(entry->data.filename,64);
250 System::ReverseULONG(&entry->data.length);
251 System::ReverseULONG(&entry->data.startOffset);
252 System::ReverseULONGLONG(&entry->data.lastModifiedTime);
253 }
254
255
256 entry->currentFilePointer = entry->data.startOffset;
257 lastFile = entry;
258 fileTable.push_back( entry );
259#ifdef _DEBUG_FILE_HEADER
260 app.DebugPrintf("File: %ls, Start = %d, Length = %d, End = %d, Timestamp = %lld\n", entry->data.filename, entry->data.startOffset, entry->data.length, entry->data.startOffset + entry->data.length, entry->data.lastModifiedTime);
261#endif
262
263 fesdHeaderPosition++;
264 }
265 }
266 break;
267
268 // Legacy save versions, with updated code to convert the FileEntrySaveData to the latest version
269 // 4J Stu - At time of writing, the tutorial save is V1 so need to keep this for compatibility
270 case SAVE_FILE_VERSION_PRE_LAUNCH:
271 {
272 // Read the header
273 // We can then make headerPosition a FileEntrySaveData pointer and just increment by one up to the number
274 unsigned int i = 0;
275 while( i < headerSize )
276 {
277 FileEntry *entry = new FileEntry();
278 //assert(numberOfBytesRead == sizeof(FileEntrySaveData));
279
280#ifdef __PSVITA__
281 VirtualCopyFrom( &entry->data, headerPosition, sizeof(FileEntrySaveDataV1) );
282#else
283 memcpy( &entry->data, headerPosition, sizeof(FileEntrySaveDataV1) );
284#endif
285
286 entry->currentFilePointer = entry->data.startOffset;
287 lastFile = entry;
288 fileTable.push_back( entry );
289#ifdef _DEBUG_FILE_HEADER
290 app.DebugPrintf("File: %ls, Start = %d, Length = %d, End = %d\n", entry->data.filename, entry->data.startOffset, entry->data.length, entry->data.startOffset + entry->data.length);
291#endif
292
293 i += sizeof(FileEntrySaveDataV1);
294 headerPosition += sizeof(FileEntrySaveDataV1);
295 }
296 }
297 break;
298 default:
299#ifndef _CONTENT_PACKAGE
300 app.DebugPrintf("********** Invalid save version %d\n",m_saveVersion);
301 __debugbreak();
302#endif
303 break;
304 }
305}
306
307unsigned int FileHeader::GetStartOfNextData()
308{
309 // The first 4 bytes is the location of the header (the header itself is at the end of the file)
310 // Then 4 bytes for the size of the header
311 // Then 2 bytes for the version number at which this save was first generated
312 // Then 2 bytes for the version number that the save should now be at
313 unsigned int totalBytesSoFar = SAVE_FILE_HEADER_SIZE;
314 for( unsigned int i = 0; i < fileTable.size(); ++i )
315 {
316 if( fileTable[i]->getFileSize() > 0 )
317 totalBytesSoFar += fileTable[i]->getFileSize();
318 }
319 return totalBytesSoFar;
320}
321
322unsigned int FileHeader::GetFileSize()
323{
324 return GetStartOfNextData() + ( sizeof(FileEntrySaveData) * (unsigned int)fileTable.size() );
325}
326
327void FileHeader::AdjustStartOffsets(FileEntry *file, DWORD nNumberOfBytesToWrite, bool subtract /*= false*/)
328{
329 bool found = false;
330 for( unsigned int i = 0; i < fileTable.size(); ++i )
331 {
332 if( found == true )
333 {
334 if(subtract)
335 {
336 fileTable[i]->data.startOffset -= nNumberOfBytesToWrite;
337 fileTable[i]->currentFilePointer -= nNumberOfBytesToWrite;
338 }
339 else
340 {
341 fileTable[i]->data.startOffset += nNumberOfBytesToWrite;
342 fileTable[i]->currentFilePointer += nNumberOfBytesToWrite;
343 }
344 }
345 else if( fileTable[i] == file )
346 {
347 found = true;
348 }
349 }
350}
351
352bool FileHeader::fileExists( const wstring &name )
353{
354 for( unsigned int i = 0; i < fileTable.size(); ++i )
355 {
356 if( wcscmp( fileTable[i]->data.filename, name.c_str() ) == 0 )
357 {
358 // If so, return it
359 return true;
360 }
361 }
362 return false;
363}
364
365vector<FileEntry *> *FileHeader::getFilesWithPrefix(const wstring &prefix)
366{
367 vector<FileEntry *> *files = NULL;
368
369 for( unsigned int i = 0; i < fileTable.size(); ++i )
370 {
371 if( wcsncmp( fileTable[i]->data.filename, prefix.c_str(), prefix.size() ) == 0 )
372 {
373 if( files == NULL )
374 {
375 files = new vector<FileEntry *>();
376 }
377
378 files->push_back(fileTable[i]);
379 }
380 }
381
382 return files;
383}
384
385#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
386
387static bool isHexChar(wchar_t wc)
388{
389 if(wc >= L'0' && wc <= L'9')
390 return true;
391 if(wc >= L'a' && wc <= L'f')
392 return true;
393 return false;
394}
395static bool isHexString(wchar_t* ws, int size)
396{
397 for(int i=0;i<size;i++)
398 {
399 if(!isHexChar(ws[i]))
400 return false;
401 }
402 return true;
403}
404static bool isDecimalChar(wchar_t wc)
405{
406 if(wc >= L'0' && wc <= L'9')
407 return true;
408 return false;
409}
410static bool isDecimalString(wchar_t* ws, int size)
411{
412 for(int i=0;i<size;i++)
413 {
414 if(!isDecimalChar(ws[i]))
415 return false;
416 }
417 return true;
418}
419static wchar_t* findFilenameStart(wchar_t* str)
420{
421 // find the last forward slash in the filename, and return the pointer to the following character
422 wchar_t* filenameStart= str;
423 int len = wcslen(str);
424 for(int i=0;i<len;i++)
425 if(str[i] == L'/')
426 filenameStart = &str[i+1];
427 return filenameStart;
428}
429
430wstring FileHeader::getPlayerDataFilenameForLoad(const PlayerUID& pUID)
431{
432 wstring retVal = L"";
433 vector<FileEntry*>* pFiles = getDatFilesWithOnlineID(pUID);
434 if(!pFiles)
435 {
436 // we didn't find a matching online dat file, so look for an offline version
437 pFiles = getDatFilesWithMacAndUserID(pUID);
438 }
439 if(!pFiles)
440 {
441 // and we didn't find an offline file, so check if we're the primary user, and grab the primary file if we are
442 if(pUID.isPrimaryUser())
443 {
444 pFiles= getDatFilesWithPrimaryUser();
445 }
446 }
447 if(pFiles)
448 {
449 // we've got something to load
450// assert(pFiles->size() == 1);
451 retVal = pFiles->at(0)->data.filename;
452 delete pFiles;
453 }
454 return retVal;
455}
456
457wstring FileHeader::getPlayerDataFilenameForSave(const PlayerUID& pUID)
458{
459 // check if we're online first
460 if(pUID.isSignedIntoPSN() == false)
461 {
462 // OK, we're not online, see if we can find another data file with matching mac and userID
463 vector<FileEntry*>* pFiles = getDatFilesWithMacAndUserID(pUID);
464 if(pFiles)
465 {
466 // we've found a previous save, use the filename from it, as it might have the online part too
467// assert(pFiles->size() == 1);
468 wstring retVal = pFiles->at(0)->data.filename;
469 delete pFiles;
470 return retVal;
471 }
472 }
473
474 // we're either online, or we can't find a previous save, so use the standard filename
475 wstring retVal = pUID.toString() + L".dat";
476 return retVal;
477}
478
479
480vector<FileEntry *> *FileHeader::getValidPlayerDatFiles()
481{
482 vector<FileEntry *> *files = NULL;
483
484 // find filenames that match this pattern
485 // P_5e7ff8372ea9_00000004_Mark_4J
486
487 for( unsigned int i = 0; i < fileTable.size(); ++i )
488 {
489 wchar_t* filenameOnly = findFilenameStart(fileTable[i]->data.filename);
490
491 int nameLen = wcslen(filenameOnly);
492 if(nameLen <= 4)
493 continue;
494
495 // make sure it's a ".dat" file
496 if( wcsncmp( &filenameOnly[nameLen-4], L".dat", 4 ) != 0 )
497 continue;
498 // make sure we start with "P_" or "N_"
499 if( ( wcsncmp(&filenameOnly[0], L"P_", 2) != 0 ) && ( wcsncmp( &filenameOnly[0], L"N_", 2 ) != 0 ) )
500 continue;
501 //check the next 12 chars are hex
502 if(!isHexString(&filenameOnly[2], 12))
503 continue;
504 // make sure character 14 is '_'
505 if(filenameOnly[14] != L'_')
506 continue;
507 //check the next 8 chars are decimal
508 if(!isDecimalString(&filenameOnly[15], 8))
509 continue;
510
511 // if we get here, it must be a valid filename
512 if( files == NULL )
513 {
514 files = new vector<FileEntry *>();
515 }
516 files->push_back(fileTable[i]);
517 }
518
519 return files;
520}
521
522
523
524vector<FileEntry *> *FileHeader::getDatFilesWithOnlineID(const PlayerUID& pUID)
525{
526 if(pUID.isSignedIntoPSN() == false)
527 return NULL;
528
529 vector<FileEntry *>* datFiles = getValidPlayerDatFiles();
530 if(datFiles == NULL)
531 return NULL;
532
533 // we're looking for the online name from the pUID in these types of filenames -
534 // P_5e7ff8372ea9_00000004_Mark_4J
535 wchar_t onlineIDW[64];
536 mbstowcs(onlineIDW, pUID.getOnlineID(), 64);
537
538 vector<FileEntry *> *files = NULL;
539 int onlineIDSize = wcslen(onlineIDW);
540 if(onlineIDSize == 0)
541 return NULL;
542
543 wcscat(onlineIDW, L".dat");
544
545#ifdef __ORBIS__
546 onlineIDSize = wcslen(onlineIDW);
547#else
548 static const int onlineIDStart = 24; // 24 characters into the filename
549#endif
550
551 char tempStr[128];
552 for( unsigned int i = 0; i < datFiles->size(); ++i )
553 {
554 wchar_t* filenameOnly = findFilenameStart(datFiles->at(i)->data.filename);
555 wcstombs(tempStr,filenameOnly, 128);
556 app.DebugPrintf("file : %s\n", tempStr);
557
558#ifdef __ORBIS__
559 int onlineIDStart = wcslen(filenameOnly) - onlineIDSize;
560 if(onlineIDStart > 0)
561#else
562 if(wcslen(filenameOnly) > onlineIDStart)
563#endif
564 {
565 if(wcsncmp(&filenameOnly[onlineIDStart], onlineIDW, onlineIDSize) == 0)
566 {
567 if( files == NULL )
568 {
569 files = new vector<FileEntry *>();
570 }
571 files->push_back(datFiles->at(i));
572 }
573 }
574 }
575 delete datFiles;
576
577 if(files) sort(files->begin(), files->end(), FileEntry::newestFirst );
578 return files;
579}
580
581vector<FileEntry *> *FileHeader::getDatFilesWithMacAndUserID(const PlayerUID& pUID)
582{
583
584 vector<FileEntry *>* datFiles = getValidPlayerDatFiles();
585 if(datFiles == NULL)
586 return NULL;
587
588 // we're looking for the mac address and userIDfrom the pUID in these types of filenames -
589 // P_5e7ff8372ea9_00000004_Mark_4J
590 std::wstring macStr = pUID.macAddressStr();
591 std::wstring userStr = pUID.userIDStr();
592 const wchar_t* pMacStr = macStr.c_str();
593 const wchar_t* pUserStr = userStr.c_str();
594
595 vector<FileEntry *> *files = NULL;
596 static const int macAddrStart = 2; // 2 characters into the filename
597 static const int userIDStart = 15; // 15 characters into the filename
598
599 char tempStr[128];
600 for( unsigned int i = 0; i < datFiles->size(); ++i )
601 {
602 wchar_t* filenameOnly = findFilenameStart(datFiles->at(i)->data.filename);
603 wcstombs(tempStr,filenameOnly, 128);
604 app.DebugPrintf("file : %s\n", tempStr);
605
606 // check the mac address matches
607 if(wcsncmp(&filenameOnly[macAddrStart], pMacStr, macStr.size()) == 0)
608 {
609 // check the userID matches
610 if(wcsncmp(&filenameOnly[userIDStart], pUserStr, userStr.size()) == 0)
611 {
612 if( files == NULL )
613 {
614 files = new vector<FileEntry *>();
615 }
616 files->push_back(datFiles->at(i));
617 }
618 }
619 }
620 delete datFiles;
621 if(files) sort(files->begin(), files->end(), FileEntry::newestFirst );
622 return files;
623}
624
625
626vector<FileEntry *> *FileHeader::getDatFilesWithPrimaryUser()
627{
628
629 vector<FileEntry *>* datFiles = getValidPlayerDatFiles();
630 if(datFiles == NULL)
631 return NULL;
632
633 // we're just looking for filenames starting with "P_" in these types of filenames -
634 // P_5e7ff8372ea9_00000004_Mark_4J
635 vector<FileEntry *> *files = NULL;
636
637 char tempStr[128];
638 for( unsigned int i = 0; i < datFiles->size(); ++i )
639 {
640 wchar_t* filenameOnly = findFilenameStart(datFiles->at(i)->data.filename);
641 wcstombs(tempStr,filenameOnly, 128);
642 app.DebugPrintf("file : %s\n", tempStr);
643
644 // check for "P_" prefix
645 if(wcsncmp(&filenameOnly[0], L"P_", 2) == 0)
646 {
647 if( files == NULL )
648 {
649 files = new vector<FileEntry *>();
650 }
651 files->push_back(datFiles->at(i));
652 }
653 }
654 delete datFiles;
655 if(files) sort(files->begin(), files->end(), FileEntry::newestFirst );
656 return files;
657}
658#endif // __PS3__ || __ORBIS__
659
660ByteOrder FileHeader::getEndian( ESavePlatform plat )
661{
662 ByteOrder platEndian;
663 switch(plat)
664 {
665 case SAVE_FILE_PLATFORM_X360:
666 case SAVE_FILE_PLATFORM_PS3:
667 return BIGENDIAN;
668 break;
669
670 case SAVE_FILE_PLATFORM_NONE:
671 case SAVE_FILE_PLATFORM_XBONE:
672 case SAVE_FILE_PLATFORM_PS4:
673 case SAVE_FILE_PLATFORM_PSVITA:
674 case SAVE_FILE_PLATFORM_WIN64:
675 return LITTLEENDIAN;
676 break;
677 default:
678 assert(0);
679 break;
680 }
681 return LITTLEENDIAN;
682}