File: afs.py

package info (click to toggle)
python-mediafile 0.14.0-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 1,968 kB
  • sloc: python: 2,953; makefile: 193
file content (78 lines) | stat: -rw-r--r-- 2,254 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import struct

import mutagen
import mutagen.asf

from mediafile.utils import Image

from .base import ListStorageStyle


def _unpack_asf_image(data):
    """Unpack image data from a WM/Picture tag. Return a tuple
    containing the MIME type, the raw image data, a type indicator, and
    the image's description.

    This function is treated as "untrusted" and could throw all manner
    of exceptions (out-of-bounds, etc.). We should clean this up
    sometime so that the failure modes are well-defined.
    """
    type, size = struct.unpack_from("<bi", data)
    pos = 5
    mime = b""
    while data[pos : pos + 2] != b"\x00\x00":
        mime += data[pos : pos + 2]
        pos += 2
    pos += 2
    description = b""
    while data[pos : pos + 2] != b"\x00\x00":
        description += data[pos : pos + 2]
        pos += 2
    pos += 2
    image_data = data[pos : pos + size]
    return (mime.decode("utf-16-le"), image_data, type, description.decode("utf-16-le"))


def _pack_asf_image(mime, data, type=3, description=""):
    """Pack image data for a WM/Picture tag."""
    tag_data = struct.pack("<bi", type, len(data))
    tag_data += mime.encode("utf-16-le") + b"\x00\x00"
    tag_data += description.encode("utf-16-le") + b"\x00\x00"
    tag_data += data
    return tag_data


class ASFStorageStyle(ListStorageStyle):
    """A general storage style for Windows Media/ASF files."""

    formats = ["ASF"]

    def deserialize(self, data):
        if isinstance(data, mutagen.asf.ASFBaseAttribute):
            data = data.value
        return data


class ASFImageStorageStyle(ListStorageStyle):
    """Store images packed into Windows Media/ASF byte array attributes.
    Values are `Image` objects.
    """

    formats = ["ASF"]

    def __init__(self):
        super().__init__(key="WM/Picture")

    def deserialize(self, asf_picture):
        mime, data, type, desc = _unpack_asf_image(asf_picture.value)
        return Image(data, desc=desc, type=type)

    def serialize(self, image):
        pic = mutagen.asf.ASFByteArrayAttribute()
        pic.value = _pack_asf_image(
            image.mime_type,
            image.data,
            type=image.type_index,
            description=image.desc or "",
        )
        return pic