Peter Siebel - Practical Common Lisp

Здесь есть возможность читать онлайн «Peter Siebel - Practical Common Lisp» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Год выпуска: 2005, ISBN: 2005, Издательство: Apress, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Practical Common Lisp: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Practical Common Lisp»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

Practical Common Lisp — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Practical Common Lisp», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

(defun non-terminated-type (encoding)

(ecase encoding

(0 'iso-8859-1-string)

(1 'ucs-2-string)))

(defun terminated-type (encoding)

(ecase encoding

(0 'iso-8859-1-terminated-string)

(1 'ucs-2-terminated-string)))

Then string-argsuses the encoding byte, the length, and the terminator to determine several of the arguments to be passed to read-valueand write-valueby the :readerand :writerof id3-encoded-string. One of the length and terminator arguments to string-argsshould always be NIL .

(defun string-args (encoding length terminator)

(cond

(length

(values (non-terminated-type encoding) :length length))

(terminator

(values (terminated-type encoding) :terminator terminator))))

With those helpers, the definition of id3-encoded-stringis simple. One detail to note is that the keyword—either :lengthor :terminator—used in the call to read-valueand write-valueis just another piece of data returned by string-args. Although keywords in arguments lists are almost always literal keywords, they don't have to be.

(define-binary-type id3-encoded-string (encoding length terminator)

(:reader (in)

(multiple-value-bind (type keyword arg)

(string-args encoding length terminator)

(read-value type in keyword arg)))

(:writer (out string)

(multiple-value-bind (type keyword arg)

(string-args encoding length terminator)

(write-value type out string keyword arg))))

Now you can define a text-infomixin class, much the way you defined generic-frameearlier.

(define-binary-class text-info-frame ()

((encoding u1)

(information (id3-encoded-string :encoding encoding :length (bytes-left 1)))))

As when you defined generic-frame, you need access to the size of the frame, in this case to compute the :lengthargument to pass to id3-encoded-string. Because you'll need to do a similar computation in the next class you define, you can go ahead and define a helper function, bytes-left, that uses current-binary-objectto get at the size of the frame.

(defun bytes-left (bytes-read)

(- (size (current-binary-object)) bytes-read))

Now, as you did with the generic-framemixin, you can define two version-specific concrete classes with a minimum of duplicated code.

(define-binary-class text-info-frame-v2.2 (id3v2.2-frame text-info-frame) ())

(define-binary-class text-info-frame-v2.3 (id3v2.3-frame text-info-frame) ())

To wire these classes in, you need to modify find-frame-classto return the appropriate class name when the ID indicates the frame is a text information frame, namely, whenever the ID starts with T and isn't TXX or TXXX .

(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)))

(t

(ecase (length name)

(3 'generic-frame-v2.2)

(4 'generic-frame-v2.3)))))

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-infomixin, you can use bytes-leftto compute the size of the final string. However, since the descriptionfield is a variable-length string, the number of bytes read prior to the start of textisn't a constant. To make matters worse, the number of bytes used to encode descriptionis 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)))))

Extracting Information from an ID3 Tag

Now that you have the basic ability to read and write ID3 tags, you have a lot of directions you could take this code. If you want to develop a complete ID3 tag editor, you'll need to implement specific classes for all the frame types. You'd also need to define methods for manipulating the tag and frame objects in a consistent way (for instance, if you change the value of a string in a text-info-frame, you'll likely need to adjust the size); as the code stands, there's nothing to make sure that happens. [279] Ensuring that kind of interfield consistency would be a fine application for :after methods on the accessor generic functions. For instance, you could define this :after method to keep size in sync with the information string: (defmethod (setf information) :after (value (frame text-info-frame)) (declare (ignore value)) (with-slots (encoding size information) frame (setf size (encoded-string-length information encoding nil))))

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «Practical Common Lisp»

Представляем Вашему вниманию похожие книги на «Practical Common Lisp» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «Practical Common Lisp»

Обсуждение, отзывы о книге «Practical Common Lisp» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x