# 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. Team Queue(多队列技巧处理)

    Team Queue Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total ...

  2. 提交App到Apple Store(Xcode4)

    昨 天终于顺利把公司的App提交了,还是很开心的.这是我第一个开发超过2个月的项目,开发期间学到了很多东西,接下来的时间我会逐渐梳理一下.来个倒叙, 今天就先说下怎么提交的吧.Xcode4以后,提交过 ...

  3. Unity怎样在Editor下运行协程(coroutine)

    在处理Unity5新的AssetBundle的时候,我有一个需求,须要在Editor下(比方一个menuitem的处理函数中,游戏没有执行.也没有MonoBehaviour)载入AssetBundle ...

  4. android实现计算器功能

    设计一个简单的计算器. 第一个Activity的界面. 第二个Activity显示算式和计算结果. 第一个Activity代码: import android.app.Activity; import ...

  5. C语言中static关键字的作用

    static的作用(精辟分析) 在C语言中,static的字面意思很容易把我们导入歧途,其实它的作用有三条. (1)先来介绍它的第一条也是最重要的一条:隐藏. 当我们同时编译多个文件时,所有未加sta ...

  6. 安装mysql时提示The host 'xxx' could not be looked up with resolveip的解决办法

    1.首先用cat查看/etc/hosts文件,会显示以下内容: 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.loca ...

  7. C# 中文转拼音类

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SU { ...

  8. UTF8转GB2312(UTF8解码)

    小弟C++上手没多久,代码不严谨之处敬请见谅.英语也不是很好,有的是直接使用的拼音. string MyUTF_8toGB2312(string str) { ,,str.c_str(),-,NULL ...

  9. C#重写Equals方法步骤

    检查传入的参数是否为null, 如果为null,那么返回false, 否则执行步骤2 调用ReferenceEquals查看是否为统一个对象,如果是,那么返回true, 否则执行步骤3 判断两者是否为 ...

  10. C/C++中define的使用

    代码: #include <iostream> using namespace std; #define a 10 void foo(); void bar(); void foo(){ ...