# 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. 老漏洞easy击:CVE-2012 0158占顶!

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaXF1c2hp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/d ...

  2. java通过jsp的Excel导出

    在项目中一般导出报表用poi,可是假设你不想用框架就用简单的jsp也能够实现报表导出.并且实现起来还特别简单. 先看一下效果截图: 点击导出后的效果截图: 详细实现: 第一:在页面的列表页面中就是普通 ...

  3. 如何给你的Android 安装文件(APK)瘦身

    如何给你的Android 安装文件(APK)瘦身 本文翻译自:Putting Your APKs on Diet           原作者:Cyril Mottier Android的apk文件越来 ...

  4. android studio 报ambiguous method call

    如题,在android studio中调用this.toString时,提示的错误信息是ambiguous method call. both get class () in object and g ...

  5. [.NET | 發佈] 如何指定固定的目錄給程式調用的外部DLL?

    1.OverView 一般程式只會查找與主程式同目錄的DLL檔案 解決方案主要可以參考這篇:http://support.microsoft.com/kb/837908 2.實作app.config方 ...

  6. 我的django之旅(三)数据库和模型

    我的django之旅(三)模型和数据库 标签(空格分隔):模型 数据库 ORM 1.django ORM django内置了一套完整的解决方案,其中就包括他自己的ORM.可惜没有使用SQLAlchem ...

  7. Oracle11g R2学习系列 之七安全性

    其实,对于目前我使用的Oracle的水平来看,还达不到使用安全管理的高度,只是作为一个学习来看一下. 关于Oracle的安全管理,一般使用OEM来操作完成好了,入口是:OEM的“服务器”属性页中,选择 ...

  8. Strange Grid

    def main(): r,c = map(int, raw_input().split(' ')) if r % 2 != 0: base = 5*(r-1) else: base = 5*(r-2 ...

  9. HDU Today--hdu2112

    HDU Today Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  10. 更改AngularJS的语法解析符号

    // 更改AngularJS的语法解析符号 app.config(function ($interpolateProvider) { $interpolateProvider.startSymbol( ...