(ns cljam.io.cram.itf8
  (:require [cljam.io.util.byte-buffer :as bb]))

Decodes ITF-8 integer from ByteBuffer.

(defn decode-itf8
  ^long [bb]
  (let [b (long (bb/read-ubyte bb))]
    (cond (zero? (bit-and b 0x80))
          b
          (zero? (bit-and b 0x40))
          (bit-or (bit-shift-left (bit-and b 0x7f) 8)
                  (long (bb/read-ubyte bb)))
          (zero? (bit-and b 0x20))
          (bit-or (bit-shift-left (bit-and b 0x3f) 16)
                  (bit-shift-left (long (bb/read-ubyte bb)) 8)
                  (long (bb/read-ubyte bb)))
          (zero? (bit-and b 0x10))
          (bit-or (bit-shift-left (bit-and b 0x1f) 24)
                  (bit-shift-left (long (bb/read-ubyte bb)) 16)
                  (bit-shift-left (long (bb/read-ubyte bb)) 8)
                  (long (bb/read-ubyte bb)))
          :else
          (unchecked-int
           (bit-or (bit-shift-left (bit-and b 0x0f) 28)
                   (bit-shift-left (long (bb/read-ubyte bb)) 20)
                   (bit-shift-left (long (bb/read-ubyte bb)) 12)
                   (bit-shift-left (long (bb/read-ubyte bb)) 4)
                   (bit-and (long (bb/read-ubyte bb)) 0x0f))))))

Decodes LTF-8 integer from ByteBuffer.

(defn decode-ltf8
  ^long [bb]
  (let [b (long (bb/read-ubyte bb))]
    (cond (zero? (bit-and b 0x80))
          b
          (zero? (bit-and b 0x40))
          (bit-or (bit-shift-left (bit-and b 0x7f) 8)
                  (long (bb/read-ubyte bb)))
          (zero? (bit-and b 0x20))
          (bit-or (bit-shift-left (bit-and b 0x3f) 16)
                  (bit-shift-left (long (bb/read-ubyte bb)) 8)
                  (long (bb/read-ubyte bb)))
          (zero? (bit-and b 0x10))
          (bit-or (bit-shift-left (bit-and b 0x1f) 24)
                  (bit-shift-left (long (bb/read-ubyte bb)) 16)
                  (bit-shift-left (long (bb/read-ubyte bb)) 8)
                  (long (bb/read-ubyte bb)))
          (zero? (bit-and b 0x08))
          (bit-or (bit-shift-left (bit-and b 0x07) 32)
                  (bit-shift-left (long (bb/read-ubyte bb)) 24)
                  (bit-shift-left (long (bb/read-ubyte bb)) 16)
                  (bit-shift-left (long (bb/read-ubyte bb)) 8)
                  (long (bb/read-ubyte bb)))
          (zero? (bit-and b 0x04))
          (bit-or (bit-shift-left (bit-and b 0x03) 40)
                  (bit-shift-left (long (bb/read-ubyte bb)) 32)
                  (bit-shift-left (long (bb/read-ubyte bb)) 24)
                  (bit-shift-left (long (bb/read-ubyte bb)) 16)
                  (bit-shift-left (long (bb/read-ubyte bb)) 8)
                  (long (bb/read-ubyte bb)))
          (zero? (bit-and b 0x02))
          (bit-or (bit-shift-left (bit-and b 0x01) 48)
                  (bit-shift-left (long (bb/read-ubyte bb)) 40)
                  (bit-shift-left (long (bb/read-ubyte bb)) 32)
                  (bit-shift-left (long (bb/read-ubyte bb)) 24)
                  (bit-shift-left (long (bb/read-ubyte bb)) 16)
                  (bit-shift-left (long (bb/read-ubyte bb)) 8)
                  (long (bb/read-ubyte bb)))
          (zero? (bit-and b 0x01))
          (bit-or (bit-shift-left (long (bb/read-ubyte bb)) 48)
                  (bit-shift-left (long (bb/read-ubyte bb)) 40)
                  (bit-shift-left (long (bb/read-ubyte bb)) 32)
                  (bit-shift-left (long (bb/read-ubyte bb)) 24)
                  (bit-shift-left (long (bb/read-ubyte bb)) 16)
                  (bit-shift-left (long (bb/read-ubyte bb)) 8)
                  (long (bb/read-ubyte bb)))
          :else
          (bit-or (bit-shift-left (long (bb/read-ubyte bb)) 56)
                  (bit-shift-left (long (bb/read-ubyte bb)) 48)
                  (bit-shift-left (long (bb/read-ubyte bb)) 40)
                  (bit-shift-left (long (bb/read-ubyte bb)) 32)
                  (bit-shift-left (long (bb/read-ubyte bb)) 24)
                  (bit-shift-left (long (bb/read-ubyte bb)) 16)
                  (bit-shift-left (long (bb/read-ubyte bb)) 8)
                  (long (bb/read-ubyte bb))))))