Книга: Practical Common Lisp

Comment Frames

Comment Frames

Another commonly used frame type is the comment frame, which is like a text information frame with a few extra fields. Like a text information frame, it starts with a single byte indicating the string encoding used in the frame. That byte is followed by a three-character ISO 8859-1 string (regardless of the value of the string encoding byte), which indicates what language the comment is in using an ISO-639-2 code, for example, "eng" for English or "jpn" for Japanese. That field is followed by two strings encoded as indicated by the first byte. The first is a null-terminated string containing a description of the comment. The second, which takes up the remainder of the frame, is the comment text itself.

(define-binary-class comment-frame ()
((encoding u1)
(language (iso-8859-1-string :length 3))
(description (id3-encoded-string :encoding encoding :terminator +null+))
(text (id3-encoded-string
:encoding encoding
:length (bytes-left
(+ 1 ; encoding
3 ; language
(encoded-string-length description encoding t)))))))

As in the definition of the text-info mixin, you can use bytes-left to compute the size of the final string. However, since the description field is a variable-length string, the number of bytes read prior to the start of text isn't a constant. To make matters worse, the number of bytes used to encode description is dependent on the encoding. So, you should define a helper function that returns the number of bytes used to encode a string given the string, the encoding code, and a boolean indicating whether the string is terminated with an extra character.

(defun encoded-string-length (string encoding terminated)
(let ((characters (+ (length string) (if terminated 1 0))))
(* characters (ecase encoding (0 1) (1 2)))))

And, as before, you can define the concrete version-specific comment frame classes and wire them into find-frame-class.

(define-binary-class comment-frame-v2.2 (id3v2.2-frame comment-frame) ())
(define-binary-class comment-frame-v2.3 (id3v2.3-frame comment-frame) ())
(defun find-frame-class (name)
(cond
((and (char= (char name 0) #T)
(not (member name '("TXX" "TXXX") :test #'string=)))
(ecase (length name)
(3 'text-info-frame-v2.2)
(4 'text-info-frame-v2.3)))
((string= name "COM") 'comment-frame-v2.2)
((string= name "COMM") 'comment-frame-v2.3)
(t
(ecase (length name)
(3 'generic-frame-v2.2)
(4 'generic-frame-v2.3)))))

Оглавление книги


Генерация: 1.211. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз