8

To search or to open text blocks in blend files in text editors (as a couple of examples) it would be handy to read texts from a blend file without any need of blender or bpy.

There is a module for blend file io shipped with blender addons_contrib/io_blend_utils/blend/blendfile.py

I am using blender 2.8. The tools have been added to addons_contrib (come with blender) as of July 4

Scripts at Repository

Re blender 2.79. I imagine that script to read text lines from datablocks using either would be similar and put me on the right track.

The walker script gives insights on how to read the blocks.

Test script below lists the textblock name, and how many characters are on each line. I'm sure there's a simple way to get the body string of the TextLine data block, but it escapes me.

from io_blend_utils.blend import blendfile

def get_id_name(block):
    name = block[b'id', b'name'].decode()
    return name[2:]

filepath = "/home/batfinger/Desktop/test.blend"

bf = blendfile.open_blend(filepath)
texts = bf.find_blocks_from_code(b'TX')
for t in texts:
    i = s = bf.blocks.index(t) + 1
    print(get_id_name(t))
    while bf.blocks[i].dna_type_name == 'TextLine':
        print(f"line {i - s} chars {bf.blocks[i][b'len']}")
        i += 1

How do I read the data to give me the text buffer of a text block?

CRUD EDIT.

Thankyou to @lemon re the Reading piece of the crud puzzle.

As an addendum, would very much appreciate any details on usage of the blendfile api for:

Creating, Updating and Deleting text blocks.

Ray Mairlot
  • 29,192
  • 11
  • 103
  • 125
batFINGER
  • 84,216
  • 10
  • 108
  • 233

1 Answers1

7

I did it in 2.79.

The bad is it seems there is no documentation for this module and we don't know where to go. And of course I don't know if it is the better way to do it.

But, once you have the TextLine block:

Get the length property.

Get the pointer to the block which corresponds to the line content, it is a block too.

Seek the file to the file offset of this last block.

Get the value using DNA_IO.

from io_blend_utils.blend import blendfile

def get_id_name(block):
    name = block[b'id', b'name'].decode()
    return name[2:]

filepath = "/home/batfinger/Desktop/test.blend"

bf = blendfile.open_blend(filepath)
texts = bf.find_blocks_from_code(b'TX')
for t in texts:
    i = s = bf.blocks.index(t) + 1
    print(get_id_name(t))
    while bf.blocks[i].dna_type_name == 'TextLine':

        # Get the block
        block = bf.blocks[i]
        # Get the length
        length = block[b'len']
        # Get the line data pointer (a block)
        line = block.get_pointer( b'line')

        # Search for the line block position
        bf.handle.seek( line.file_offset, 0 )

        # Get the value
        line_content = blendfile.DNA_IO.read_string( bf.handle, length )

        print( i - s )
        print( bf.blocks[i][b'len'] )
        print( line_content )


        #print( bf.blocks[i].user_data )
        #print(f"line {i - s} chars {bf.blocks[i][b'len']}")
        i += 1

bf.close()
lemon
  • 60,295
  • 3
  • 66
  • 136
  • @batFINGER, the worst was get_pointer( b'line' )... if not explicit error msg on get_pointer( b'xxx' ) never been able to find it (expected b'body'). – lemon Jul 26 '19 at 12:30
  • It achieves exactly what I need. ... a vital cog in an nvim addon / plugin. Would it be OTT to edit question re creating and writing, rather than asking as separate question? – batFINGER Jul 26 '19 at 14:14
  • @batFINGER, you're welcome to do exactly what you want. It is your question! – lemon Jul 26 '19 at 14:21
  • any idea re write, delete update? – batFINGER Mar 04 '20 at 10:27
  • @batFINGER, honnestly, I've re read a bit the source code since your second bounty, but hadn't time to go further... want to talk a bit about that in chat? – lemon Mar 04 '20 at 10:34