clj-starcraft / src / starcraft / replay / parse.clj

(ns starcraft.replay.parse
  (:import [java.io File]
           [java.nio ByteBuffer]
           [java.util Date]))

(defn mask8  [x] (bit-and x 0xff))
(defn mask16 [x] (bit-and x 0xffff))

(defn read-null-string [#^ByteBuffer buf len]
  (let [#^bytes arr (make-array Byte/TYPE len)]
    (.get buf arr)
    (apply str (map char (take-while (complement zero?) arr)))))

(defn make-reader
  [type mask-fn]
  (let [getter ({Byte (fn [#^ByteBuffer buf] (.get buf))
                 Short (fn [#^ByteBuffer buf] (.getShort buf))
                 Integer (fn [#^ByteBuffer buf] (.getInt buf))} type)]
    (fn [#^ByteBuffer buf len]
      (if (= len 1)
        (mask-fn (getter buf))
        (let [#^ints arr (int-array len)]
          (dotimes [i len]
            (let [x (int (mask-fn (getter buf)))]
              (aset-int arr i x)))
          arr)))))

(def read-field
     (let [readers {Byte (make-reader Byte mask8)
                    Short (make-reader Short mask16)
                    Integer (make-reader Integer identity)
                    String read-null-string}]
       (fn [#^ByteBuffer buf size type]
         (let [real-size (if (vector? size)
                           (apply read-field buf size)
                           size)]
           ((readers type) buf real-size)))))

(defn parse-buffer
  "A field-spec is a vector of the form: [:field-name length Type func?]
  Each field-spec is read from buf and the whole data is return as a map.
  If a field-name is nil, the data is not returned (but the field is
  read nonetheless to move forward into the buffer)."
  [#^ByteBuffer buf & field-specs]
  (reduce (fn [m [field-name size type func]]
            (let [data (read-field buf size type)]
              (if (nil? field-name)
                m
                (assoc m field-name
                       (if (ifn? func)
                         (func data)
                         data)))))
          {}
          field-specs))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.