Merge pull request #3 from Bai-Mirror/codex/analyze-samsung_apple_compatible.heic-issue-0gnqzk

Preserve optional content type strings in infe boxes
This commit is contained in:
Nymiro
2025-10-20 21:29:56 +13:00
committed by GitHub
+50 -1
View File
@@ -3,7 +3,7 @@
import struct import struct
from base import Box, FullBox from base import Box, FullBox
from io import BytesIO from io import BytesIO
from typing import List # <-- 添加 List 导入 from typing import List, Optional # <-- 添加 List, Optional 导入
# --- 帮助函数 --- # --- 帮助函数 ---
@@ -212,6 +212,8 @@ class ItemInfoEntryBox(FullBox):
self.item_protection_index: int = 0 self.item_protection_index: int = 0
self.item_type: str = "" # 4-char code self.item_type: str = "" # 4-char code
self.item_name: str = "" # UTF-8 string self.item_name: str = "" # UTF-8 string
self.content_type: Optional[str] = None
self.content_encoding: Optional[str] = None
super().__init__(size, box_type, offset, raw_data) super().__init__(size, box_type, offset, raw_data)
def _post_parse_initialization(self): def _post_parse_initialization(self):
@@ -229,6 +231,19 @@ class ItemInfoEntryBox(FullBox):
name_end = stream.find(b'\x00', pos) name_end = stream.find(b'\x00', pos)
if name_end == -1: name_end = len(stream) if name_end == -1: name_end = len(stream)
self.item_name = stream[pos:name_end].decode('utf-8', errors='ignore') self.item_name = stream[pos:name_end].decode('utf-8', errors='ignore')
pos = min(name_end + 1, len(stream))
if pos < len(stream):
ctype_end = stream.find(b'\x00', pos)
if ctype_end == -1: ctype_end = len(stream)
self.content_type = stream[pos:ctype_end].decode('utf-8', errors='ignore')
pos = min(ctype_end + 1, len(stream))
if pos < len(stream):
cenc_end = stream.find(b'\x00', pos)
if cenc_end == -1: cenc_end = len(stream)
self.content_encoding = stream[pos:cenc_end].decode('utf-8', errors='ignore')
pos = min(cenc_end + 1, len(stream))
elif self.version == 2: elif self.version == 2:
self.item_id = struct.unpack('>I', stream[pos:pos+4])[0] self.item_id = struct.unpack('>I', stream[pos:pos+4])[0]
@@ -264,6 +279,19 @@ class ItemInfoEntryBox(FullBox):
name_end = stream.find(b'\x00', pos) name_end = stream.find(b'\x00', pos)
if name_end == -1: name_end = len(stream) if name_end == -1: name_end = len(stream)
self.item_name = stream[pos:name_end].decode('utf-8', errors='ignore') self.item_name = stream[pos:name_end].decode('utf-8', errors='ignore')
pos = min(name_end + 1, len(stream))
if pos < len(stream):
ctype_end = stream.find(b'\x00', pos)
if ctype_end == -1: ctype_end = len(stream)
self.content_type = stream[pos:ctype_end].decode('utf-8', errors='ignore')
pos = min(ctype_end + 1, len(stream))
if pos < len(stream):
cenc_end = stream.find(b'\x00', pos)
if cenc_end == -1: cenc_end = len(stream)
self.content_encoding = stream[pos:cenc_end].decode('utf-8', errors='ignore')
pos = min(cenc_end + 1, len(stream))
elif self.version == 3: elif self.version == 3:
self.item_id = struct.unpack('>H', stream[pos:pos+2])[0] self.item_id = struct.unpack('>H', stream[pos:pos+2])[0]
@@ -275,6 +303,19 @@ class ItemInfoEntryBox(FullBox):
name_end = stream.find(b'\x00', pos) name_end = stream.find(b'\x00', pos)
if name_end == -1: name_end = len(stream) if name_end == -1: name_end = len(stream)
self.item_name = stream[pos:name_end].decode('utf-8', errors='ignore') self.item_name = stream[pos:name_end].decode('utf-8', errors='ignore')
pos = min(name_end + 1, len(stream))
if pos < len(stream):
ctype_end = stream.find(b'\x00', pos)
if ctype_end == -1: ctype_end = len(stream)
self.content_type = stream[pos:ctype_end].decode('utf-8', errors='ignore')
pos = min(ctype_end + 1, len(stream))
if pos < len(stream):
cenc_end = stream.find(b'\x00', pos)
if cenc_end == -1: cenc_end = len(stream)
self.content_encoding = stream[pos:cenc_end].decode('utf-8', errors='ignore')
pos = min(cenc_end + 1, len(stream))
except (struct.error, IndexError) as e: except (struct.error, IndexError) as e:
print(f"Warning: Failed to parse 'infe' box (v{self.version}). Content may be truncated. Error: {e}") print(f"Warning: Failed to parse 'infe' box (v{self.version}). Content may be truncated. Error: {e}")
@@ -299,12 +340,20 @@ class ItemInfoEntryBox(FullBox):
# item_type 必须是 4 字节的 4CC,若不足则以 NUL 填充 # item_type 必须是 4 字节的 4CC,若不足则以 NUL 填充
content.write(self.item_type.encode('ascii', errors='ignore')[:4].ljust(4, b'\x00')) content.write(self.item_type.encode('ascii', errors='ignore')[:4].ljust(4, b'\x00'))
content.write(item_name_bytes_to_write) content.write(item_name_bytes_to_write)
if self.content_type is not None:
content.write(self.content_type.encode('utf-8') + b'\x00')
if self.content_encoding is not None:
content.write(self.content_encoding.encode('utf-8') + b'\x00')
elif self.version == 3: elif self.version == 3:
content.write(struct.pack('>H', self.item_id)) content.write(struct.pack('>H', self.item_id))
content.write(struct.pack('>H', self.item_protection_index)) content.write(struct.pack('>H', self.item_protection_index))
content.write(self.item_type.encode('ascii').ljust(4, b'\x00')) content.write(self.item_type.encode('ascii').ljust(4, b'\x00'))
content.write(item_name_bytes_to_write) content.write(item_name_bytes_to_write)
if self.content_type is not None:
content.write(self.content_type.encode('utf-8') + b'\x00')
if self.content_encoding is not None:
content.write(self.content_encoding.encode('utf-8') + b'\x00')
return content.getvalue() return content.getvalue()