From 4220f9dc0c4a79fce3346e712d82f79a0a9ccc4a Mon Sep 17 00:00:00 2001 From: Doug Coleman Date: Wed, 21 Sep 2011 16:04:17 -0500 Subject: [PATCH] Add c-types in alien.endian for making endian-aware STRUCTs. --- basis/alien/endian/authors.txt | 1 + basis/alien/endian/endian-docs.factor | 90 ++++++++++++++++++++++++ basis/alien/endian/endian-tests.factor | 96 ++++++++++++++++++++++++++ basis/alien/endian/endian.factor | 84 ++++++++++++++++++++++ 4 files changed, 271 insertions(+) create mode 100644 basis/alien/endian/authors.txt create mode 100644 basis/alien/endian/endian-docs.factor create mode 100644 basis/alien/endian/endian-tests.factor create mode 100644 basis/alien/endian/endian.factor diff --git a/basis/alien/endian/authors.txt b/basis/alien/endian/authors.txt new file mode 100644 index 0000000000..7c1b2f2279 --- /dev/null +++ b/basis/alien/endian/authors.txt @@ -0,0 +1 @@ +Doug Coleman diff --git a/basis/alien/endian/endian-docs.factor b/basis/alien/endian/endian-docs.factor new file mode 100644 index 0000000000..4351c17f4e --- /dev/null +++ b/basis/alien/endian/endian-docs.factor @@ -0,0 +1,90 @@ +! Copyright (C) 2011 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax kernel math quotations ; +IN: alien.endian + +HELP: be16 +{ $var-description "Signed bit-endian 16-bit." } ; + +HELP: be32 +{ $var-description "Signed bit-endian 32-bit." } ; + +HELP: be64 +{ $var-description "Signed bit-endian 64-bit." } ; + +HELP: be8 +{ $var-description "Signed bit-endian 8-bit." } ; + +HELP: byte-reverse +{ $values + { "n" integer } { "signed?" boolean } + { "quot" quotation } +} +{ $description "Reverses the " { $snippet "n" } " bytes in an integer with bitwise operations. The second parameter only works for 1, 2, 4, or 8 byte signed numbers." } ; + +HELP: le16 +{ $var-description "Signed little-endian 16-bit." } ; + +HELP: le32 +{ $var-description "Signed little-endian 32-bit." } ; + +HELP: le64 +{ $var-description "Signed little-endian 64-bit." } ; + +HELP: le8 +{ $var-description "Signed little-endian 8-bit." } ; + +HELP: ube16 +{ $var-description "Unsigned big-endian 16-bit." } ; + +HELP: ube32 +{ $var-description "Unsigned big-endian 32-bit." } ; + +HELP: ube64 +{ $var-description "Unsigned big-endian 64-bit." } ; + +HELP: ube8 +{ $var-description "Unsigned big-endian 8-bit." } ; + +HELP: ule16 +{ $var-description "Unsigned little-endian 16-bit." } ; + +HELP: ule32 +{ $var-description "Unsigned little-endian 32-bit." } ; + +HELP: ule64 +{ $var-description "Unsigned little-endian 64-bit." } ; + +HELP: ule8 +{ $var-description "Unsigned little-endian 8-bit." } ; + +ARTICLE: "alien.endian" "Alien endian-aware types" +"The " { $vocab-link "alien.endian" } " vocabulary defines c-types that are endian-aware for use in structs. These types will cause the bytes in a byte-array to be interpreted as little or big-endian transparently when reading or writing. There are both signed and unsigned types defined; signed is the default while unsigned are prefixed with a " { $snippet "u" } ". The intended use-case is for network protocols in network-byte-order (big-endian)." $nl +"Byte-reversal of integers:" +{ $subsections + byte-reverse +} +"The big-endian c-types are:" +{ $subsections + be8 + be16 + be32 + be64 + ube8 + ube16 + ube32 + ube64 +} +"The little-endian c-types are:" +{ $subsections + le8 + le16 + le32 + le64 + ule8 + ule16 + ule32 + ule64 +} ; + +ABOUT: "alien.endian" diff --git a/basis/alien/endian/endian-tests.factor b/basis/alien/endian/endian-tests.factor new file mode 100644 index 0000000000..2b440cc66d --- /dev/null +++ b/basis/alien/endian/endian-tests.factor @@ -0,0 +1,96 @@ +! Copyright (C) 2011 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors alien.endian classes.struct io +io.encodings.binary io.streams.byte-array kernel tools.test ; +IN: alien.endian.tests + +STRUCT: endian-struct + { a ule16 } + { b le16 } + { c ube16 } + { d be16 } + { e ule32 } + { f le32 } + { g ube32 } + { h be32 } + { i ule64 } + { j le64 } + { k ube64 } + { l be64 } ; + +CONSTANT: endian-bytes-0f B{ + HEX: 0 HEX: ff + HEX: 0 HEX: ff + HEX: 0 HEX: ff + HEX: 0 HEX: ff + + HEX: 0 HEX: 0 HEX: 0 HEX: ff + HEX: 0 HEX: 0 HEX: 0 HEX: ff + HEX: 0 HEX: 0 HEX: 0 HEX: ff + HEX: 0 HEX: 0 HEX: 0 HEX: ff + + HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: ff + HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: ff + HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: ff + HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: ff + } + +CONSTANT: endian-bytes-f0 B{ + HEX: ff HEX: 0 + HEX: ff HEX: 0 + HEX: ff HEX: 0 + HEX: ff HEX: 0 + + HEX: ff HEX: 0 HEX: 0 HEX: 0 + HEX: ff HEX: 0 HEX: 0 HEX: 0 + HEX: ff HEX: 0 HEX: 0 HEX: 0 + HEX: ff HEX: 0 HEX: 0 HEX: 0 + + HEX: ff HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 + HEX: ff HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 + HEX: ff HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 + HEX: ff HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 HEX: 0 + } + +: endian-test-struct-0f ( -- obj ) + endian-bytes-0f endian-struct memory>struct ; + +: endian-test-struct-f0 ( -- obj ) + endian-bytes-f0 endian-struct memory>struct ; + +[ HEX: ff00 ] [ endian-test-struct-0f a>> ] unit-test +[ -256 ] [ endian-test-struct-0f b>> ] unit-test +[ HEX: 00ff ] [ endian-test-struct-0f c>> ] unit-test +[ HEX: 00ff ] [ endian-test-struct-0f d>> ] unit-test + +[ HEX: ff000000 ] [ endian-test-struct-0f e>> ] unit-test +[ -16777216 ] [ endian-test-struct-0f f>> ] unit-test +[ HEX: 000000ff ] [ endian-test-struct-0f g>> ] unit-test +[ HEX: 000000ff ] [ endian-test-struct-0f h>> ] unit-test + +[ HEX: ff00000000000000 ] [ endian-test-struct-0f i>> ] unit-test +[ -72057594037927936 ] [ endian-test-struct-0f j>> ] unit-test +[ HEX: 00000000000000ff ] [ endian-test-struct-0f k>> ] unit-test +[ HEX: 00000000000000ff ] [ endian-test-struct-0f l>> ] unit-test + + +[ HEX: ff00 ] [ endian-test-struct-f0 c>> ] unit-test +[ -256 ] [ endian-test-struct-f0 d>> ] unit-test +[ HEX: 00ff ] [ endian-test-struct-f0 a>> ] unit-test +[ HEX: 00ff ] [ endian-test-struct-f0 b>> ] unit-test + +[ HEX: ff000000 ] [ endian-test-struct-f0 g>> ] unit-test +[ -16777216 ] [ endian-test-struct-f0 h>> ] unit-test +[ HEX: 000000ff ] [ endian-test-struct-f0 e>> ] unit-test +[ HEX: 000000ff ] [ endian-test-struct-f0 f>> ] unit-test + +[ HEX: ff00000000000000 ] [ endian-test-struct-f0 k>> ] unit-test +[ -72057594037927936 ] [ endian-test-struct-f0 l>> ] unit-test +[ HEX: 00000000000000ff ] [ endian-test-struct-f0 i>> ] unit-test +[ HEX: 00000000000000ff ] [ endian-test-struct-f0 j>> ] unit-test + +[ t ] +[ endian-test-struct-0f binary [ write ] with-byte-writer endian-bytes-0f = ] unit-test + +[ t ] +[ endian-test-struct-f0 binary [ write ] with-byte-writer endian-bytes-f0 = ] unit-test diff --git a/basis/alien/endian/endian.factor b/basis/alien/endian/endian.factor new file mode 100644 index 0000000000..a00c9ac6fe --- /dev/null +++ b/basis/alien/endian/endian.factor @@ -0,0 +1,84 @@ +! Copyright (C) 2011 Doug Coleman. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors alien.accessors alien.c-types combinators +compiler.units endian fry generalizations kernel macros math +namespaces sequences words alien.data ; +QUALIFIED-WITH: alien.c-types ac +IN: alien.endian + +ERROR: invalid-signed-conversion n ; + +: convert-signed-quot ( n -- quot ) + { + { 1 [ [ char char deref ] ] } + { 2 [ [ ac:short ac:short deref ] ] } + { 4 [ [ int int deref ] ] } + { 8 [ [ longlong longlong deref ] ] } + [ invalid-signed-conversion ] + } case ; inline + +MACRO: byte-reverse ( n signed? -- quot ) + [ + drop + [ + dup iota [ + [ 1 + - -8 * ] [ nip 8 * ] 2bi + '[ _ shift HEX: ff bitand _ shift ] + ] with map + ] [ 1 - [ bitor ] n*quot ] bi + ] [ + [ convert-signed-quot ] [ drop [ ] ] if + ] 2bi + '[ _ cleave @ @ ] ; + +SYMBOLS: le8 be8 ule8 ube8 +ule16 ule32 ule64 ube16 ube32 ube64 +le16 le32 le64 be16 be32 be64 ; + +ERROR: unknown-endian-c-type symbol ; + +: endian-c-type>c-type-symbol ( symbol -- symbol' ) + { + { [ dup { ule16 ube16 } member? ] [ drop ushort ] } + { [ dup { le16 be16 } member? ] [ drop ac:short ] } + { [ dup { ule32 ube32 } member? ] [ drop uint ] } + { [ dup { le32 be32 } member? ] [ drop int ] } + { [ dup { ule64 ube64 } member? ] [ drop ulonglong ] } + { [ dup { le64 be64 } member? ] [ drop longlong ] } + [ unknown-endian-c-type ] + } cond ; + +: change-c-type-accessors ( n ? c-type -- c-type' ) + endian-c-type>c-type-symbol "c-type" word-prop clone + -rot + [ '[ [ _ _ byte-reverse ] compose ] change-getter drop ] + [ '[ [ [ _ _ byte-reverse ] 2dip ] prepose ] change-setter ] 3bi ; + +: typedef-endian ( n ? c-type endian -- ) + native-endianness get = [ + 2nip [ endian-c-type>c-type-symbol ] keep typedef + ] [ + [ change-c-type-accessors ] keep typedef + ] if ; + +: typedef-le ( n ? c-type -- ) little-endian typedef-endian ; +: typedef-be ( n ? c-type -- ) big-endian typedef-endian ; + +[ + \ char \ le8 typedef + \ char \ be8 typedef + \ uchar \ ule8 typedef + \ uchar \ ube8 typedef + 2 f \ ule16 typedef-le + 2 f \ ube16 typedef-be + 2 t \ le16 typedef-le + 2 t \ be16 typedef-be + 4 f \ ule32 typedef-le + 4 f \ ube32 typedef-be + 4 t \ le32 typedef-le + 4 t \ be32 typedef-be + 8 f \ ule64 typedef-le + 8 f \ ube64 typedef-be + 8 t \ le64 typedef-le + 8 t \ be64 typedef-be +] with-compilation-unit