diff --git a/.gitignore b/.gitignore index 3f9be08..bcf0316 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ pom.xml.asc .\#* /out /*-init.clj -/doc/dist/ \ No newline at end of file +/doc/dist/ +.lsp \ No newline at end of file diff --git a/project.clj b/project.clj index 9f6f6e5..224f072 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject funcool/octet "1.1.2" +(defproject funcool/octet "1.1.3" :description "A clojure(script) library for work with binary data." :url "https://github.com/funcool/octet" :license {:name "Public Domain" diff --git a/src/octet/core.cljc b/src/octet/core.cljc index c3705bb..25fd121 100644 --- a/src/octet/core.cljc +++ b/src/octet/core.cljc @@ -39,6 +39,7 @@ (util/defalias spec spec/spec) (util/defalias size spec/size) (util/defalias repeat spec/repeat) +(util/defalias cstring string-spec/cstring) (util/defalias string string-spec/string) (util/defalias string* string-spec/string*) (util/defalias vector* coll-spec/vector*) diff --git a/src/octet/spec/string.cljc b/src/octet/spec/string.cljc index aedc758..724e6bf 100644 --- a/src/octet/spec/string.cljc +++ b/src/octet/spec/string.cljc @@ -164,3 +164,32 @@ (buffer/write-int buff pos length) (buffer/write-bytes buff (+ pos 4) length input) (+ length 4))))) + +(def ^{:doc "Arbitrary length cstring (null-terminated string) type spec."} + cstring + (reify + #?@(:clj + [clojure.lang.IFn + (invoke [s] s)] + :cljs + [cljs.core/IFn + (-invoke [s] s)]) + + spec/ISpecDynamicSize + (size* [_ data] + (let [data (string->bytes data)] + (+ 1 (count data)))) + + spec/ISpec + (read [_ buff pos] + (loop [index pos acc []] + (let [b (buffer/read-byte buff index)] + (if (zero? b) + [(inc (count acc)) (bytes->string (byte-array acc) (count acc))] + (recur (inc index) (conj acc b)))))) + + (write [_ buff pos value] + (let [input (string->bytes (str value "\0")) + length (count input)] + (buffer/write-bytes buff pos length input) + length)))) diff --git a/test/octet/tests/core.cljc b/test/octet/tests/core.cljc index c561a71..cb7abd1 100644 --- a/test/octet/tests/core.cljc +++ b/test/octet/tests/core.cljc @@ -248,6 +248,14 @@ :else (t/is (= data data'))))))))))) +(t/deftest spec-data-with-cstring-single + (let [spec (buf/spec (buf/cstring)) + buffer (buf/allocate 11)] + (buf/write! buffer ["1234567890"] spec) + (let [[readed data] (buf/read* buffer spec)] + (t/is (= readed 11)) + (t/is (= data ["1234567890"]))))) + (t/deftest spec-data-with-dynamic-types-single (let [spec (buf/spec (buf/string*)) buffer (buf/allocate 20)] @@ -264,6 +272,38 @@ (t/is (= readed 18)) (t/is (= data ["1234567890" 1000]))))) +(t/deftest spec-data-with-cstring-and-other-types-combined + (let [spec (buf/spec (buf/cstring) (buf/int32)) + buffer (buf/allocate 40)] + (buf/write! buffer ["1234567890" 1000] spec) + (let [[readed data] (buf/read* buffer spec)] + (t/is (= readed 15)) + (t/is (= data ["1234567890" 1000]))))) + +(t/deftest spec-data-with-multi-cstring + (let [spec (buf/spec buf/cstring buf/cstring) + buffer (buf/allocate 40)] + (buf/write! buffer ["1234567890" "1234567890"] spec) + (let [[readed data] (buf/read* buffer spec)] + (t/is (= readed 22)) + (t/is (= data ["1234567890" "1234567890"]))))) + +(t/deftest spec-data-with-types-and-cstring-combined + (let [spec (buf/spec buf/cstring buf/int32 buf/byte buf/cstring) + buffer (buf/allocate 40)] + (buf/write! buffer ["1234567890" 1000 1 "1234567890"] spec) + (let [[readed data] (buf/read* buffer spec)] + (t/is (= readed 27)) + (t/is (= data ["1234567890" 1000 1 "1234567890"]))))) + +(t/deftest spec-data-with-multi-cstring-and-dynamic-types-combined + (let [spec (buf/spec (buf/int32) (buf/cstring) (buf/cstring) (buf/int32)) + buffer (buf/allocate 40)] + (buf/write! buffer [9999 "12345" "67890" 1000] spec) + (let [[readed data] (buf/read* buffer spec)] + (t/is (= readed 20)) + (t/is (= data [9999 "12345" "67890" 1000]))))) + (t/deftest spec-data-with-indexed-ref-string-single (let [spec (buf/spec (buf/int32) (buf/int32)