Skip to content

Commit

Permalink
Merge pull request #24 from adq/main
Browse files Browse the repository at this point in the history
Add support for new blocks: 0x0D SceneInfo and 0x08 SceneTombstoneItemBlock

Add support for `move_id` field on some SceneLineItems
  • Loading branch information
ricklupton authored May 26, 2024
2 parents fbab627 + 67575d2 commit 7331e6d
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 8 deletions.
2 changes: 2 additions & 0 deletions src/rmscene/scene_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class Line(SceneItem):
points: list[Point]
thickness_scale: float
starting_length: float
move_id: tp.Optional[CrdtId] = None


## Text
Expand All @@ -144,6 +145,7 @@ class ParagraphStyle(enum.IntEnum):
BOLD = 3
BULLET = 4
BULLET2 = 5
CHECKBOX = 6


END_MARKER = CrdtId(0, 0)
Expand Down
62 changes: 58 additions & 4 deletions src/rmscene/scene_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,34 @@ def to_stream(self, writer: TaggedBlockWriter):
writer.data.write_bytes(self.data)


@dataclass
class SceneInfo(Block):
BLOCK_TYPE: tp.ClassVar = 0x0D

def version_info(self, _) -> tuple[int, int]:
"""Return (min_version, current_version) to use when writing."""
return (0, 1)

current_layer: LwwValue[CrdtId]
background_visible: LwwValue[bool]
root_document_visible: LwwValue[bool]

@classmethod
def from_stream(cls, stream: TaggedBlockReader) -> SceneInfo:
current_layer = stream.read_lww_id(1)
background_visible = stream.read_lww_bool(2)
root_document_visible = stream.read_lww_bool(3)

return SceneInfo(current_layer=current_layer,
background_visible=background_visible,
root_document_visible=root_document_visible)

def to_stream(self, writer: TaggedBlockWriter):
writer.write_lww_id(1, self.current_layer)
writer.write_lww_bool(2, self.background_visible)
writer.write_lww_bool(3, self.root_document_visible)


@dataclass
class AuthorIdsBlock(Block):
BLOCK_TYPE: tp.ClassVar = 0x09
Expand Down Expand Up @@ -164,6 +192,12 @@ def to_stream(self, writer: TaggedBlockWriter):
class TreeNodeBlock(Block):
BLOCK_TYPE: tp.ClassVar = 0x02

def version_info(self, writer: TaggedBlockWriter) -> tuple[int, int]:
"""Return (min_version, current_version) to use when writing."""
version = writer.options.get("version", Version("9999"))
# XXX this is a guess about which version this changed in
return (1, 2) if (version >= Version("3.4")) else (1, 1)

group: si.Group

@classmethod
Expand Down Expand Up @@ -217,7 +251,7 @@ def version_info(self, _) -> tuple[int, int]:
merges_count: int
text_chars_count: int
text_lines_count: int
_unknown: int = 0
type_folio_use_count: int = 0

@classmethod
def from_stream(cls, stream: TaggedBlockReader) -> PageInfoBlock:
Expand All @@ -230,7 +264,7 @@ def from_stream(cls, stream: TaggedBlockReader) -> PageInfoBlock:
text_lines_count=stream.read_int(4),
)
if stream.bytes_remaining_in_block():
info._unknown = stream.read_int(5)
info.type_folio_use_count = stream.read_int(5)
return info

def to_stream(self, writer: TaggedBlockWriter):
Expand All @@ -241,7 +275,7 @@ def to_stream(self, writer: TaggedBlockWriter):
writer.write_int(4, self.text_lines_count)
version = writer.options.get("version", Version("9999"))
if version >= Version("3.2.2"):
writer.write_int(5, self._unknown)
writer.write_int(5, self.type_folio_use_count)


@dataclass
Expand Down Expand Up @@ -355,7 +389,12 @@ def line_from_stream(stream: TaggedBlockReader, version: int = 2) -> si.Line:
# XXX unused
timestamp = stream.read_id(6)

return si.Line(color, tool, points, thickness_scale, starting_length)
if stream.bytes_remaining_in_block() >= 3:
move_id = stream.read_id(7)
else:
move_id = None

return si.Line(color, tool, points, thickness_scale, starting_length, move_id)


def line_to_stream(line: si.Line, writer: TaggedBlockWriter, version: int = 2):
Expand All @@ -371,6 +410,8 @@ def line_to_stream(line: si.Line, writer: TaggedBlockWriter, version: int = 2):
# XXX didn't save
timestamp = CrdtId(0, 1)
writer.write_id(6, timestamp)
if line.move_id is not None:
writer.write_id(7, line.move_id)


@dataclass
Expand All @@ -395,6 +436,8 @@ def from_stream(cls, stream: TaggedBlockReader) -> SceneItemBlock:
subclass = SceneLineItemBlock
elif block_type == SceneTextItemBlock.BLOCK_TYPE:
subclass = SceneTextItemBlock
elif block_type == SceneTombstoneItemBlock.BLOCK_TYPE:
subclass = SceneTombstoneItemBlock
else:
raise ValueError(
"unknown scene type %d in %s" % (block_type, stream.current_block)
Expand Down Expand Up @@ -500,6 +543,17 @@ def glyph_range_to_stream(stream: TaggedBlockWriter, item: si.GlyphRange):
stream.data.write_float64(rect.h)


class SceneTombstoneItemBlock(SceneItemBlock):
BLOCK_TYPE: tp.ClassVar = 0x08

@classmethod
def value_from_stream(cls, reader: TaggedBlockReader):
pass

def value_to_stream(self, writer: TaggedBlockWriter, value):
pass


class SceneGlyphItemBlock(SceneItemBlock):
BLOCK_TYPE: tp.ClassVar = 0x03
ITEM_TYPE: tp.ClassVar = 0x01
Expand Down
Binary file added tests/data/With_SceneInfo_Block.rm
Binary file not shown.
12 changes: 8 additions & 4 deletions tests/test_scene_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def _hex_lines(b, n=32):
("Lines_v2_updated.rm", "3.2"), # extra 7fXXXX part of Line data was added
("Wikipedia_highlighted_p1.rm", "3.1"),
("Wikipedia_highlighted_p2.rm", "3.1"),
("With_SceneInfo_Block.rm", "3.4"), # XXX version?
],
)
def test_full_roundtrip(test_file, version):
Expand Down Expand Up @@ -259,15 +260,17 @@ def test_write_blocks():


def test_blocks_keep_unknown_data():
# The "7f 010f" is new, unknown data
# The "8f 010f" is represents new, unknown data -- note that this might need
# to be changed in future if the next id starts to actually be used in a
# future update!
data_hex = """
56000000 00020205
59000000 00020205
1f 0219
2f 021e
3f 0000
4f 0000
54 0000 0000
6c 4000 0000
6c 4300 0000
03
14 0f000000
24 00000000
Expand All @@ -278,11 +281,12 @@ def test_blocks_keep_unknown_data():
83c2622d 30c30000 08000000
6f 0001
7f 010f
8f 0101
"""
buf = BytesIO(HEADER_V6 + bytes.fromhex(data_hex))
block = next(read_blocks(buf))
assert isinstance(block, SceneLineItemBlock)
assert block.extra_data == bytes.fromhex("7f 010f")
assert block.extra_data == bytes.fromhex("8f 0101")


def test_error_in_block_contained():
Expand Down

0 comments on commit 7331e6d

Please sign in to comment.