ird.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. # -*- coding: utf8 -*-
  2. # libray - Libre Blu-Ray PS3 ISO Tool
  3. # Copyright © 2018 - 2024 Nichlas Severinsen
  4. #
  5. # This file is part of libray.
  6. #
  7. # libray is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # libray 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 General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with libray. If not, see <https://www.gnu.org/licenses/>.
  19. import os
  20. import sys
  21. import zlib
  22. import shutil
  23. try:
  24. from libray import core
  25. except ImportError:
  26. import core
  27. class IRD:
  28. """Class for handling .ird files
  29. Attributes:
  30. version: IRD version number
  31. game_id: PS3 game identifier
  32. game_name: Name of PS3 game
  33. update_version: PS3 firmware update version
  34. game_version: PS3 game version
  35. app_version: PS3 app version
  36. region_count: How many encrypted regions are in the .iso
  37. file_count: How many files are supposed to be in the .iso
  38. data1: Encryption key
  39. """
  40. ORDER = 'little'
  41. TEMP_FILE = 'ird'
  42. MAGIC_STRING = b'3IRD'
  43. def __init__(self, ird_path, verbose=False):
  44. """IRD constructor using args from argparse."""
  45. self.uncompress(ird_path) # TODO: Try/Except?
  46. self.size = core.size(self.TEMP_FILE)
  47. if not self.size:
  48. core.error('IRD file is empty!')
  49. with open(self.TEMP_FILE, 'rb') as input_ird:
  50. if input_ird.read(4) != self.MAGIC_STRING:
  51. core.error('Either not an IRD file, corruped IRD file, or unknown IRD format')
  52. self.version = core.to_int(input_ird.read(1), self.ORDER)
  53. self.game_id = input_ird.read(9)
  54. name_length = core.read_seven_bit_encoded_int(input_ird, self.ORDER)
  55. self.game_name = input_ird.read(name_length).decode('utf8')
  56. self.update_version = input_ird.read(4)
  57. self.game_version = input_ird.read(5)
  58. self.app_version = input_ird.read(5)
  59. if self.version == 7:
  60. self.identifier = input_ird.read(4)
  61. header_length = (core.to_int(input_ird.read(4), self.ORDER))
  62. self.header = input_ird.read(header_length)
  63. footer_length = (core.to_int(input_ird.read(4), self.ORDER))
  64. self.footer = input_ird.read(footer_length)
  65. self.region_count = core.to_int(input_ird.read(1), self.ORDER)
  66. self.region_hashes = []
  67. for _ in range(0, self.region_count):
  68. self.region_hashes.append(input_ird.read(16))
  69. self.file_count = core.to_int(input_ird.read(4), self.ORDER)
  70. self.file_hashes = []
  71. for _ in range(0, self.file_count):
  72. key = core.to_int(input_ird.read(8), self.ORDER)
  73. val = input_ird.read(16)
  74. self.file_hashes.append({'key': key, 'val': val})
  75. if self.version >= 9:
  76. self.pic = input_ird.read(115)
  77. input_ird.seek(input_ird.tell() + 4) # ?
  78. self.data1 = input_ird.read(16)
  79. self.data2 = input_ird.read(16)
  80. if self.version < 9:
  81. self.pic = input_ird.read(115)
  82. if self.version < 7:
  83. self.uid = core.to_int(input_ird.read(4), self.ORDER)
  84. if verbose:
  85. self.print_info()
  86. os.remove(self.TEMP_FILE)
  87. def uncompress(self, filename):
  88. """Uncompress IRD. Assumes given .ird file is not compressed, but then tries to decompress it with zlib/gzfile if it was not uncompressed."""
  89. uncompress = False
  90. with open(filename, 'rb') as input_ird:
  91. if input_ird.read(4) != self.MAGIC_STRING:
  92. uncompress = True
  93. if uncompress:
  94. with open(filename, 'rb') as gzfile:
  95. with open(self.TEMP_FILE, 'wb') as tmpfile:
  96. tmpfile.write(zlib.decompress(gzfile.read(), zlib.MAX_WBITS | 16))
  97. else:
  98. shutil.copyfile(filename, self.TEMP_FILE)
  99. def print_info(self, regions=False):
  100. # TODO: This could probably have been a __str__? Who cares?
  101. """Print some info about the IRD."""
  102. print('Info from IRD:')
  103. print('Version: %s' % self.version)
  104. print('Game ID: %s' % self.game_id)
  105. print('Game Name: %s' % self.game_name)
  106. print('Update Version: %s' % self.update_version)
  107. print('Game Version: %s' % self.game_version)
  108. print('App Version: %s' % self.app_version)
  109. print('Region Count: %s' % self.region_count)
  110. if regions:
  111. for i, region_hash in enumerate(self.region_hashes):
  112. print('\tRegion Hash %s: %s' % (i, region_hash.hex()))
  113. print('File Count: %s' % self.file_count)
  114. print('Data1: %s' % self.data1.hex())
  115. print('Data2: %s' % self.data2.hex())