unlha.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*
  2. * unlha.cpp
  3. * ---------
  4. * Purpose: Implementation file for extracting modules from .lha archives, making use of lhasa
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "unlha.h"
  11. #ifdef MPT_WITH_LHASA
  12. #include "lhasa.h"
  13. #endif // MPT_WITH_LHASA
  14. OPENMPT_NAMESPACE_BEGIN
  15. #ifdef MPT_WITH_LHASA
  16. static int LHAreadFileReader(void *handle, void *buf, size_t buf_len)
  17. {
  18. FileReader *f = reinterpret_cast<FileReader*>(handle);
  19. int read_len = mpt::saturate_cast<int>(buf_len);
  20. int result = mpt::saturate_cast<int>(f->ReadRaw(mpt::span(mpt::void_cast<std::byte*>(buf), read_len)).size());
  21. if(result == 0)
  22. {
  23. return -1;
  24. }
  25. return result;
  26. }
  27. static int LHAskipFileReader(void *handle, size_t bytes)
  28. {
  29. FileReader *f = reinterpret_cast<FileReader*>(handle);
  30. if(f->CanRead(bytes))
  31. {
  32. f->Skip(bytes);
  33. return 1;
  34. }
  35. return 0;
  36. }
  37. static void LHAcloseFileReader(void * /*handle*/)
  38. {
  39. return;
  40. }
  41. static LHAInputStreamType vtable =
  42. {
  43. LHAreadFileReader,
  44. LHAskipFileReader,
  45. LHAcloseFileReader
  46. };
  47. CLhaArchive::CLhaArchive(FileReader &file) : ArchiveBase(file), inputstream(nullptr), reader(nullptr), firstfile(nullptr)
  48. {
  49. OpenArchive();
  50. for(LHAFileHeader *fileheader = firstfile; fileheader; fileheader = lha_reader_next_file(reader))
  51. {
  52. ArchiveFileInfo info;
  53. info.name = mpt::PathString::FromUnicode(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, fileheader->filename));
  54. info.size = fileheader->length;
  55. info.type = ArchiveFileType::Normal;
  56. contents.push_back(info);
  57. }
  58. CloseArchive();
  59. }
  60. CLhaArchive::~CLhaArchive()
  61. {
  62. return;
  63. }
  64. void CLhaArchive::OpenArchive()
  65. {
  66. inFile.Rewind();
  67. inputstream = lha_input_stream_new(&vtable, &inFile);
  68. if(inputstream)
  69. {
  70. reader = lha_reader_new(inputstream);
  71. }
  72. if(reader)
  73. {
  74. lha_reader_set_dir_policy(reader, LHA_READER_DIR_END_OF_DIR);
  75. firstfile = lha_reader_next_file(reader);
  76. }
  77. }
  78. void CLhaArchive::CloseArchive()
  79. {
  80. if(reader)
  81. {
  82. lha_reader_free(reader);
  83. reader = nullptr;
  84. }
  85. if(inputstream)
  86. {
  87. lha_input_stream_free(inputstream);
  88. inputstream = nullptr;
  89. }
  90. }
  91. bool CLhaArchive::ExtractFile(std::size_t index)
  92. {
  93. if(index >= contents.size())
  94. {
  95. return false;
  96. }
  97. data.clear();
  98. OpenArchive();
  99. const std::size_t bufSize = 4096;
  100. std::size_t i = 0;
  101. for(LHAFileHeader *fileheader = firstfile; fileheader; fileheader = lha_reader_next_file(reader))
  102. {
  103. if(index == i)
  104. {
  105. data.clear();
  106. std::size_t countRead = 0;
  107. do
  108. {
  109. try
  110. {
  111. data.resize(data.size() + bufSize);
  112. } catch(...)
  113. {
  114. CloseArchive();
  115. return false;
  116. }
  117. countRead = lha_reader_read(reader, &data[data.size() - bufSize], bufSize);
  118. if(countRead < bufSize)
  119. {
  120. try
  121. {
  122. data.resize(data.size() - (bufSize - countRead));
  123. } catch(...)
  124. {
  125. CloseArchive();
  126. return false;
  127. }
  128. }
  129. } while(countRead > 0);
  130. }
  131. ++i;
  132. }
  133. CloseArchive();
  134. return data.size() > 0;
  135. }
  136. #endif // MPT_WITH_LHASA
  137. OPENMPT_NAMESPACE_END