# Vorbis comment support for Mutagen

# Copyright 2005-2006 Joe Wreschnig

#

# This program is free software; you can redistribute it and/or modify

# it under the terms of version 2 of the GNU General Public License as

# published by the Free Software Foundation.

"""Read and write Vorbis comment data.

Vorbis comments are freeform key/value pairs; keys are

case-insensitive ASCII and values are Unicode strings. A key may have

multiple values.

The specification is at http://www.xiph.org/vorbis/doc/v-comment.html.

"""

import sys

from cStringIO import StringIO

import mutagen

from mutagen._util import DictMixin, cdata

try: set

except NameError:

from sets import Set as set

def is_valid_key(key):

"""Return true if a string is a valid Vorbis comment key.

Valid Vorbis comment keys are printable ASCII between 0x20 (space)

and 0x7D ('}'), excluding '='.

"""

for c in key:

if c < " " or c > "}" or c == "=": return False

else: return bool(key)

istag = is_valid_key

class error(IOError): pass

class VorbisUnsetFrameError(error): pass

class VorbisEncodingError(error): pass

class VComment(mutagen.Metadata, list):

"""A Vorbis comment parser, accessor, and renderer.

All comment ordering is preserved. A VComment is a list of

key/value pairs, and so any Python list method can be used on it.

Vorbis comments are always wrapped in something like an Ogg Vorbis

bitstream or a FLAC metadata block, so this loads string data or a

file-like object, not a filename.

Attributes:

vendor -- the stream 'vendor' (i.e. writer); default 'Mutagen'

"""

vendor = u"Mutagen " + mutagen.version_string

def __init__(self, data=None, *args, **kwargs):

# Collect the args to pass to load, this lets child classes

# override just load and get equivalent magic for the

# constructor.

if data is not None:

if isinstance(data, str):

data = StringIO(data)

elif not hasattr(data, 'read'):

raise TypeError("VComment requires string data or a file-like")

self.load(data, *args, **kwargs)

def load(self, fileobj, errors='replace', framing=True):

"""Parse a Vorbis comment from a file-like object.

Keyword arguments:

errors:

'strict', 'replace', or 'ignore'. This affects Unicode decoding

and how other malformed content is interpreted.

framing -- if true, fail if a framing bit is not present

Framing bits are required by the Vorbis comment specification,

but are not used in FLAC Vorbis comment blocks.

"""

try:

vendor_length = cdata.uint_le(fileobj.read(4))

self.vendor = fileobj.read(vendor_length).decode('utf-8', errors)

count = cdata.uint_le(fileobj.read(4))

for i in range(count):

length = cdata.uint_le(fileobj.read(4))

try: string = fileobj.read(length).decode('utf-8', errors)

except (OverflowError, MemoryError):

raise error("cannot read %d bytes, too large" % length)

try: tag, value = string.split('=', 1)

except ValueError, err:

if errors == "ignore":

continue

elif errors == "replace":

tag, value = u"unknown%d" % i, string

else:

raise VorbisEncodingError, str(err), sys.exc_info()[2]

try: tag = tag.encode('ascii', errors)

except UnicodeEncodeError:

raise VorbisEncodingError, "invalid tag name %r" % tag

else:

if is_valid_key(tag): self.append((tag, value))

if framing and not ord(fileobj.read(1)) & 0x01:

raise VorbisUnsetFrameError("framing bit was unset")

except (cdata.error, TypeError):

raise error("file is not a valid Vorbis comment")

def validate(self):

"""Validate keys and values.

Check to make sure every key used is a valid Vorbis key, and

that every value used is a valid Unicode or UTF-8 string. If

any invalid keys or values are found, a ValueError is raised.

"""

if not isinstance(self.vendor, unicode):

try: self.vendor.decode('utf-8')

except UnicodeDecodeError: raise ValueError

for key, value in self:

try:

if not is_valid_key(key): raise ValueError

except: raise ValueError("%r is not a valid key" % key)

if not isinstance(value, unicode):

try: value.encode("utf-8")

except: raise ValueError("%r is not a valid value" % value)

else: return True

def clear(self):

"""Clear all keys from the comment."""

del(self[:])

def write(self, framing=True):

"""Return a string representation of the data.

Validation is always performed, so calling this function on

invalid data may raise a ValueError.

Keyword arguments:

framing -- if true, append a framing bit (see load)

"""

self.validate()

f = StringIO()

f.write(cdata.to_uint_le(len(self.vendor.encode('utf-8'))))

f.write(self.vendor.encode('utf-8'))

f.write(cdata.to_uint_le(len(self)))

for tag, value in self:

comment = "%s=%s" % (tag, value.encode('utf-8'))

f.write(cdata.to_uint_le(len(comment)))

f.write(comment)

if framing: f.write("\x01")

return f.getvalue()

def pprint(self):

return "\n".join(["%s=%s" % (k.lower(), v) for k, v in self])

class VCommentDict(VComment, DictMixin):

"""A VComment that looks like a dictionary.

This object differs from a dictionary in two ways. First,

len(comment) will still return the number of values, not the

number of keys. Secondly, iterating through the object will

iterate over (key, value) pairs, not keys. Since a key may have

multiple values, the same value may appear multiple times while

iterating.

Since Vorbis comment keys are case-insensitive, all keys are

normalized to lowercase ASCII.

"""

def __getitem__(self, key):

"""A list of values for the key.

This is a copy, so comment['title'].append('a title') will not

work.

"""

key = key.lower().encode('ascii')

values = [value for (k, value) in self if k.lower() == key]

if not values: raise KeyError, key

else: return values

def __delitem__(self, key):

"""Delete all values associated with the key."""

key = key.lower().encode('ascii')

to_delete = filter(lambda x: x[0].lower() == key, self)

if not to_delete:raise KeyError, key

else: map(self.remove, to_delete)

def __contains__(self, key):

"""Return true if the key has any values."""

key = key.lower().encode('ascii')

for k, value in self:

if k.lower() == key: return True

else: return False

def __setitem__(self, key, values):

"""Set a key's value or values.

Setting a value overwrites all old ones. The value may be a

list of Unicode or UTF-8 strings, or a single Unicode or UTF-8

string.

"""

key = key.lower().encode('ascii')

if not isinstance(values, list):

values = [values]

try: del(self[key])

except KeyError: pass

for value in values:

self.append((key, value))

def keys(self):

"""Return all keys in the comment."""

return self and list(set([k.lower() for k, v in self]))

def as_dict(self):

"""Return a copy of the comment data in a real dict."""

return dict((key, self[key]) for key in self.keys())

cStringIO模块例子的更多相关文章

  1. python标准库介绍——20 cStringIO 模块详解

    ==cStringIO 模块== ``cStringIO`` 是一个可选的模块, 是 ``StringIO`` 的更快速实现. 它的工作方式和 ``StringIO`` 基本相同, 但是它不可以被继承 ...

  2. Python random模块 例子

    最近用到随机数,就查询资料总结了一下Python random模块(获取随机数)常用方法和使用例子. 1.random.random  random.random()用于生成一个0到1的随机符点数: ...

  3. StringIO 模块用于在内存缓冲区中读写数据

    模块是用类编写的,只有一个StringIO类,所以它的可用方法都在类中.此类中的大部分函数都与对文件的操作方法类似. 例: #coding=gbk import StringIO s=StringIO ...

  4. python 各模块

    01 关于本书 02 代码约定 03 关于例子 04 如何联系我们 1 核心模块 11 介绍 111 内建函数和异常 112 操作系统接口模块 113 类型支持模块 114 正则表达式 115 语言支 ...

  5. Python进阶之模块

    在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很 ...

  6. 学习Python:StringIO与cStringIO

    StringIO的行为与file对象非常像,但它不是磁盘上文件,而是一个内存里的“文件”,我们可以将操作磁盘文件那样来操作StringIO.一个简单的例子,让你对StringIO有一个感性的认识: f ...

  7. python PIL Image模块

    原地址:http://hi.baidu.com/drunkdream/item/9c9ac638dfc46ec6382ffac5 实验环境: windows7+python2.6+pycrust+PI ...

  8. day--6_python常用模块

    常用模块: time和datetime shutil模块 radom string shelve模块 xml处理 configparser处理 hashlib subprocess logging模块 ...

  9. Poco C++库网络模块例子解析2-------HttpServer

    //下面程序取自 Poco 库的Net模块例子----HTTPServer 下面开始解析代码 #include "Poco/Net/HTTPServer.h" //继承自TCPSe ...

随机推荐

  1. python calendar标准库基础学习

    # -*- coding: utf-8 -*-# 作者:新手__author__ = 'Administrator'#标准库:日期时间基础学习:calendar:处理日期#例1import calen ...

  2. android 点击桌面图标,打开手机浏览器进入对应的站点

    做一个假的adnroid app.要实现点击桌面图标.打开手机浏览器进入对应的站点,实现方法非常easy import android.app.Activity; import android.con ...

  3. windows系统还原

    windows系统还原 windows 系统还原有两种方法: 方法一.开始-控制面板-系统和安全-备份和还原 (或者开始—所有程序—附件—系统工具—系统还原) 详细请看下面的截图说明 方法二.开机的时 ...

  4. Win7访问局域网内共享文件夹

    \\192.168.1.102\\IP地址

  5. Eclipse汉化后怎么改回英文版 (中文 改 英文)

    Eclipse汉化后怎么改回英文版(可切换中英文) 很多朋友将MyEclipse汉化后还想改回英文的,其实只要修改MyEclipse的配置文件就可以了,这里我以MyEclipse7.0为例演示一下如何 ...

  6. javascript 生成UUID

    代码一: /*! Math.uuid.js (v1.4) http://www.broofa.com mailto:robert@broofa.com Copyright (c) 2010 Rober ...

  7. cell的各种使用和赋值 总结

    cell可以分为:自定义cell,系统的cell ,cell的自适应,.xib的cell //第一种cell:系统cell 在 UIViewController下创建UITableView //1.0 ...

  8. 费马小定理&欧拉定理

    在p是素数的情况下,对任意整数x都有xp≡x(mod p).这个定理被称作费马小定理其中如果x无法被p整除,我们有xp-1≡1(mod p).利用这条性质,在p是素数的情况下,就很容易求出一个数的逆元 ...

  9. Linux下使用多线程模拟异步网络通信

    服务器 /* socket server * 2014-12-15 CopyRight (c) arbboter */ #include <unistd.h> #include <s ...

  10. Python提取图片的ROI

    图像处理经常需要提取图片的ROI,本文使用Python提取图片的ROI. 使用的Module是PIL (Pillow),一个图像处理库,用到的函数为类 Image 中的 crop 方法. 函数原型为: ...