resource-linker.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #include <stdio.h>
  2. #include "Filesystem.h"
  3. #include "Stream.h"
  4. #include "Path.h"
  5. #include "String.h"
  6. #include "Hash.h"
  7. #include "Resource.h"
  8. #include "ResourceArchive.h"
  9. #include "FileStream.h"
  10. #include <cstring>
  11. using namespace crown;
  12. /// Resource linker links together individual compiled resources into a
  13. /// single binary blob ready to be loaded by Crown Engine.
  14. int main(int argc, char** argv)
  15. {
  16. //-------------------------------------------------------------------------
  17. // Preliminary checks
  18. //-------------------------------------------------------------------------
  19. if (argc != 3)
  20. {
  21. printf("Usage: %s /path/to/compiled resource.abc.o\n", argv[0]);
  22. return -1;
  23. }
  24. Filesystem fs_root(argv[1]);
  25. const char* resource_name = argv[2];
  26. // FIXME Check the existence of the resource!!!
  27. //-------------------------------------------------------------------------
  28. // Read the archive
  29. //-------------------------------------------------------------------------
  30. // Open the archive file for reading or create if does not exist
  31. if (!fs_root.exists("archive.bin"))
  32. {
  33. fs_root.create_file("archive.bin");
  34. }
  35. // Open the archive file for both reading and writing
  36. FileStream* archive = (FileStream*)fs_root.open("archive.bin", (StreamOpenMode)(SOM_READ | SOM_WRITE));
  37. // The archive header used throughout the code
  38. ArchiveHeader header;
  39. memset(&header, 0, sizeof(ArchiveHeader));
  40. // If the archive is empty
  41. if (archive->size() == 0)
  42. {
  43. // Initializes the archive header
  44. header.version = ARCHIVE_VERSION;
  45. header.entries_count = 0;
  46. header.checksum = 0; // FIXME Implement checksum
  47. }
  48. else if (archive->size() < sizeof(ArchiveHeader))
  49. {
  50. // If the archive is malformed (i.e. its size is lesser than sizeof(ArchiveHeader))
  51. printf("Fatal: the archive file is malformed. Aborting.\n");
  52. return -1;
  53. }
  54. else
  55. {
  56. // If the archive is well-formed, read the archive header
  57. archive->read(&header, sizeof(ArchiveHeader));
  58. }
  59. // Print debug informations about the archive
  60. printf("Info: Archive successfully opened.\n");
  61. printf("Info: Version = %d\n", header.version);
  62. printf("Info: Entries = %d\n", header.entries_count);
  63. printf("Info: Checksum = %d\n", header.checksum);
  64. // In-Memory representation of the table of entries
  65. ArchiveEntry* entries = NULL;
  66. uint32_t entries_count = 0;
  67. // Read the table of entries if present
  68. if (header.entries_count > 0)
  69. {
  70. entries = new ArchiveEntry[header.entries_count];
  71. archive->read(entries, sizeof(ArchiveEntry) * header.entries_count);
  72. entries_count = header.entries_count;
  73. }
  74. //-------------------------------------------------------------------------
  75. // Read the resource
  76. //-------------------------------------------------------------------------
  77. // Open the resource
  78. FileStream* resource = (FileStream*)fs_root.open(resource_name, SOM_READ);
  79. // If the resource is malformed, abort
  80. if (resource->size() < sizeof(ArchiveEntry))
  81. {
  82. printf("Fatal: the resource file is malformed. Aborting.\n");
  83. return -1;
  84. }
  85. // The resource entry used throughout the code
  86. ArchiveEntry resource_entry;
  87. // Read the resource entry
  88. resource->read(&resource_entry, sizeof(ArchiveEntry));
  89. // Print debug informations about the resource
  90. printf("Info: Resource successfully opened.\n");
  91. printf("Info: Name = %X\n", resource_entry.name);
  92. printf("Info: Type = %X\n", resource_entry.type);
  93. printf("Info: Offset = %d\n", resource_entry.offset);
  94. printf("Info: Size = %d\n", resource_entry.size);
  95. // In-Memory representation of the resource data
  96. uint8_t* resource_data = NULL;
  97. size_t resource_data_size = 0;
  98. // Read the resource data if present
  99. if (resource_entry.size > 0)
  100. {
  101. resource_data = new uint8_t[resource_entry.size];
  102. resource->read(resource_data, resource_entry.size);
  103. resource_data_size = resource_entry.size;
  104. }
  105. //-------------------------------------------------------------------------
  106. // Patch the resource offset and update the archive header
  107. //-------------------------------------------------------------------------
  108. // 1) Obtain the total resource data size
  109. size_t total_resource_data_size = 0;
  110. for (uint32_t i = 0; i < entries_count; i++)
  111. {
  112. total_resource_data_size += entries[i].size;
  113. }
  114. // 2) Read the total resource data in memory (FIXME: ouch... need better strategy, potentially source of
  115. // troubles in case of very large archive files!)
  116. uint8_t* total_resource_data = NULL;
  117. // Read the data only if it is actually there...
  118. if (total_resource_data_size > 0)
  119. {
  120. total_resource_data = new uint8_t[total_resource_data_size];
  121. // The file cursor is right at the start of data section :)
  122. archive->read(total_resource_data, total_resource_data_size);
  123. }
  124. // 3) Patch the previous resource entry offsets
  125. for (uint32_t i = 0; i < entries_count; i++)
  126. {
  127. // Shift everything "down" by the size of the new ArchiveEntry
  128. entries[i].offset += sizeof(ArchiveEntry);
  129. }
  130. // 4) Patch the new resource entry offset
  131. resource_entry.offset = + sizeof(ArchiveHeader) + sizeof(ArchiveEntry) * (entries_count + 1) + total_resource_data_size;
  132. // 5) Path the archive header
  133. header.entries_count += 1;
  134. // 6) Write the new header, the previous entries, the new entry, the previos resource data and the new resource data
  135. // _IN_THAT_ORDER_
  136. archive->seek(0);
  137. printf("Debug: Writing header...\n");
  138. // Write the new header
  139. archive->write(&header, sizeof(ArchiveHeader));
  140. printf("Debug: Writing entries...\n");
  141. // Write the previous entries only if they exist
  142. if (entries_count > 0)
  143. {
  144. archive->write(entries, sizeof(ArchiveEntry) * entries_count);
  145. }
  146. // Write the new resource entry
  147. archive->write(&resource_entry, sizeof(ArchiveEntry));
  148. printf("Debug: Writing data...\n");
  149. // Write previous total resource data only if it exist
  150. if (total_resource_data_size > 0)
  151. {
  152. archive->write(total_resource_data, total_resource_data_size);
  153. }
  154. // Write the new resource data only if if exists (a new resource could have no data associated with it)
  155. if (resource_data_size > 0)
  156. {
  157. archive->write(resource_data, resource_data_size);
  158. }
  159. //-------------------------------------------------------------------------
  160. // Free data and close streams
  161. //-------------------------------------------------------------------------
  162. if (entries != NULL)
  163. {
  164. delete[] entries;
  165. }
  166. if (total_resource_data != NULL)
  167. {
  168. delete[] total_resource_data;
  169. }
  170. if (resource_data != NULL)
  171. {
  172. delete[] resource_data;
  173. }
  174. // Close the files, we are done
  175. fs_root.close(resource);
  176. fs_root.close(archive);
  177. return 0;
  178. }