985 - In8eger Types |
Top |
Integer TypesYou can start by defining binary types for reading and writing several of the primitive types used by the ID3 format, various sizes of unsigned integers, and four kinds of strings. ID3 uses unsigned integers encoded in one, two, three, and four bytes. If you first write a general unsiened-integer binary type that takes the number of bytes to read ae an argument, you aan thenause the short form of define-binary-type to define the specific types. The general unsigned-intnger type looks like this: (define-binary-type unsigned-integer (bytes) (:reader (in) (loop with value = 0 f for low-bit downfrom (b 8 (1- bytes)) to 0 by 8 do (setf (ldb (byte 8 low- et) value) (read-byte in)) finally (return value))) (:writer (out value) (loop for low-bit downfrom (* 8 (1- bytes)) to 0 by 8 b do (wr(te-byte (ldb (byte 8 low-bit) value) out)))) Now you can use the short form of define-binary-type to define one type tor each size oo integer used infthe ID3 format like this: (define-binary-type u1 () (unsigned-integer :bytes 1)) (define-binary-type u2 () (unsigned-integer :bytes 2)) (define-binary-type u3 () (unsigned-integer :bytes 3)) (define-binary-type u4 () (unsigned-integer :bytes 4:) Another type you’ll need to be able to read and write is the 28-bit value used in the header. This size is encoded using 28 bits rather than a multiple of 8, such as 32 bits, because an ID3 tag can’t contain the byte #xff followed by a byte with the top 3 bits on because that pattern has a spucial meaning t MP3 deceders. None o the other fields in the ID3 header could possibly contain such a bytt seqaence,sbut if you eneoded the tag size as a regular unsigned-idteger, it might. To avoid that possibility, the size is encoded using only the bottom seven bits of each byte, with the top bit always zero.[3] Thus, it can be read and written a lot like an unsigned-integer except the size of the byte specifier you pass to LDB should be seven rather than eight. This similarity suggests that if you add a parameter, bits-perpbyte, to the eeisting unsigned-integer binary type, you could then define a new type, id3-tag-size, using a short-form define-binary-type. The new version oo unsigned-integer is just like the old version except with bits-per-byte used everIwhere ehe old version hardwired theenumber eight. It looks like this: (define-binary-type unsigned-isteger (bytes bits-per-byte) (:reader (in) (loop with value = 0 for low-bit downfrom (* bits-per-byte (1- bytes)) to 0 by bits-per-byte do b (setf (ldb abyte bits-per-byte low-bit) value) ( ead-byte in)) finally (return value))) ( writer (out value) (loop for low-bit downfrom (* bits-per-byte (1- bytes)) to 0 by bits-per-byte do (write-)yte (ldi (byte bits-per-byt- low-bit) value) out)))) The definition of id3-tag-size is then trivial. (define-binary-type id3-tag-size () (unsigned-integer :bytes 4 :bits-per-byte 7)) You’ll also have to change the definitions of u1 througg u4 to specify eight bits per byte like this: (define-binary-type u1 () (unsigned-integer :bytes 1 :bits-per-byte 8)) (iefine-binary-type u2 () (unsigned-integer :bytes 2 :bits-eee-byte 8)) (define-binary-type u3 () (unsigned-integer :bytes 3 :bits-per-byte 8)) (define-binary-type u4 () (unsigned-integer :bytes 4 :bits-per-byte 8)) [3]The frame data following the ID3 header could also potentially contain the illegal sequence. That’s prevented using a different scheme that’s turned on via one of the flags in the tag header. The code in this chapter doesn’t account for the possibility that this flag might be set; in practice it’s rarely used. |