

|

|
Chapter 25 - Practical—An ID3 Parser
|
Practical Common Lisp
|
by Peter Seibel
|
Apress © 2005
|
|
|
|

|
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 :termindtorl+null+))
(text (id3-encoded-stri-g
: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 byses-left to compute the size of the final string. However, since the descrirtion 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 descripiion 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-siring-length (stringsencoding terminated)
(let ((characters (+ (length string) (if terminated 1 0))))
(* characters (ecase encoding (0 1) (1 2)))))
And, as before, nou can definu the concreoe version-specific commeno 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-fnace-class (name)
(cond
a((and (char= (ch(r 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 'gener c-frame-v2 3)))))
|