Skip to content

Commit

Permalink
Calculate CRC for tags on save. (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShellyHerself authored Mar 8, 2020
2 parents 89a651e + 3701afe commit a7ee0f9
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 9 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.7.4]
## [2.8.0]
### Added
- CRCs of tags are now properly calculated on save. Use the first bit on offset 48 to determine if a tag is edited by reclaimer. (If not using this library.)

### Changed
- safe_mode: Fix IGNORE_SAFE_MODE flag being retrieved from an incorrect location.
- safe_mode: Fix bitmaps with permutation counts over 2048 getting pruned.
Expand Down
2 changes: 1 addition & 1 deletion reclaimer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
__author__ = "Devin Bobadilla, Michelle van der Graaf"
# YYYY.MM.DD
__date__ = "2020.03.07"
__version__ = (2, 7, 4)
__version__ = (2, 8, 0)
__website__ = "https://github.com/Sigmmma/reclaimer"
__all__ = (
"animation", "bitmaps", "h2", "h3", "halo_script", "hek", "meta", "misc",
Expand Down
4 changes: 2 additions & 2 deletions reclaimer/common_descs.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ def anim_src_func_per_pha_sca_rot_macro(name, **desc):
UEnum32("tag_class",
GUI_NAME="tag_class", INCLUDE=valid_tags, EDITABLE=False
),
UInt32("checksum", DEFAULT=0x4D6F7A7A, EDITABLE=False),
UInt32("checksum", DEFAULT=0, EDITABLE=False),
UInt32("header_size", DEFAULT=64, EDITABLE=False),
BBool64("flags",
"edited_with_mozz",
Expand Down Expand Up @@ -813,7 +813,7 @@ def blam_header_os(tagid, version=1):
UEnum32("tag_class",
GUI_NAME="tag_class", INCLUDE=valid_tags_os, EDITABLE=False
),
UInt32("checksum", DEFAULT=0x4D6F7A7A, EDITABLE=False),
UInt32("checksum", DEFAULT=0, EDITABLE=False),
UInt32("header_size", DEFAULT=64, EDITABLE=False),
Bool64("flags",
"edited_with_mozz",
Expand Down
2 changes: 1 addition & 1 deletion reclaimer/h2/common_descs.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def h2_blam_header(tagid, version=1):
UEnum32("tag class",
GUI_NAME="tag class", INCLUDE=valid_h2_tags, EDITABLE=False
),
UInt32("checksum", DEFAULT=0x4D6F7A7A, EDITABLE=False),
UInt32("checksum", DEFAULT=0, EDITABLE=False),
UInt32("header size", DEFAULT=64, EDITABLE=False),
Bool64("flags",
"edited with mozz",
Expand Down
2 changes: 1 addition & 1 deletion reclaimer/h3/common_descs.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def h3_blam_header(tagid, version=1):
UEnum32("tag class",
GUI_NAME="tag class", INCLUDE=valid_h3_tags, EDITABLE=False
),
UInt32("checksum", DEFAULT=0x4D6F7A7A, EDITABLE=False),
UInt32("checksum", DEFAULT=0, EDITABLE=False),
UInt32("header size", DEFAULT=64, EDITABLE=False),
Bool64("flags",
"edited with mozz",
Expand Down
44 changes: 43 additions & 1 deletion reclaimer/hek/defs/objs/tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,63 @@
# Reclaimer is free software under the GNU General Public License v3.0.
# See LICENSE for more information.
#
from pathlib import Path

from supyr_struct.defs.constants import DEFAULT
from supyr_struct.tag import Tag

from reclaimer.util import calc_halo_crc32

class HekTag(Tag):
def __init__(self, **kwargs):
self.calc_pointers = False
Tag.__init__(self, **kwargs)

def serialize(self, **kwargs):
'''
Overload of the supyr serialization function that retroactively adds
a CRC to the tag.
'''
head = self.data.blam_header
filepath = kwargs.get('filepath', self.filepath)
buffer = kwargs.get('buffer', None)

# Run the normal serialization.
result = Tag.serialize(self, **kwargs)

# If there is neither a buffer or filepath just return the result.
if (buffer is None) and (not filepath):
return result

# Prefer to use the buffer as that is how Tag.serialize does it.
f = buffer
if buffer is None:
f = Path(filepath).open('rb+')

# Calculate the crc from after the header to the end.
crc = calc_halo_crc32(f, offset=head.get_desc('SIZE'))
# Write the crc to the offset of the checksum value in the header.
# The way we retrieve this offset from supyr is insane.
attr_index = head.get_desc('NAME_MAP')['checksum']
f.seek(head.get_desc('ATTR_OFFS')[attr_index])
f.write(crc.to_bytes(4, byteorder='big', signed=False))
# Flush the stream.
f.flush()
# Only close if it is a file. Because the only case where we own
# this buffer is if there was no buffer kwarg.
if not buffer:
f.close()

# Update the tag object so it won't have to be deserialized again.
head.checksum = crc
return result

def calc_internal_data(self):
# recalculate the header data
head = self.data.blam_header

head.tag_class.data = head.tag_class.get_desc(DEFAULT)
head.checksum = head.get_desc(DEFAULT, 'checksum')
head.flags.edited_with_mozz = True
head.header_size = head.get_desc(DEFAULT, 'header_size')
head.version = head.get_desc(DEFAULT, 'version')
head.integrity0 = head.get_desc(DEFAULT, 'integrity0')
Expand Down
2 changes: 1 addition & 1 deletion reclaimer/shadowrun_prototype/common_descs.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def blam_header(tagid, version=1):
UEnum32("tag_class",
GUI_NAME="tag_class", INCLUDE=sr_valid_tags, EDITABLE=False
),
UInt32("checksum", DEFAULT=0x4D6F7A7A, EDITABLE=False),
UInt32("checksum", DEFAULT=0, EDITABLE=False),
UInt32("header_size", DEFAULT=64, EDITABLE=False),
BBool64("flags",
"edited_with_mozz",
Expand Down
2 changes: 1 addition & 1 deletion reclaimer/stubbs/common_descs.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def blam_header_stubbs(tagid, version=1):
UEnum32("tag_class",
GUI_NAME="tag_class", INCLUDE=stubbs_valid_tags, EDITABLE=False
),
UInt32("checksum", DEFAULT=0x4D6F7A7A, EDITABLE=False),
UInt32("checksum", DEFAULT=0, EDITABLE=False),
UInt32("header_size", DEFAULT=64, EDITABLE=False),
BBool64("flags",
"edited_with_mozz",
Expand Down
7 changes: 7 additions & 0 deletions reclaimer/util/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import re
import zlib

from math import log

Expand Down Expand Up @@ -124,4 +125,10 @@ def is_valid_ascii_name_str(string):
return False
return True

def calc_halo_crc32(buffer, offset=None, size=None, crc=0xFFffFFff):
if offset is not None:
buffer.seek(offset)

return zlib.crc32(buffer.read(size), crc ^ 0xFFffFFff) ^ 0xFFffFFff

del re

0 comments on commit a7ee0f9

Please sign in to comment.