2222 StructNodeObj = object
2323 case kind* : StructKind
2424 of StructChar :
25- chr* : char
25+ chr: char
2626 of StructBool :
27- bval* : bool
27+ bval: bool
2828 of StructShort :
2929 sval: int16
3030 of StructUShort :
4242 of StructDouble :
4343 dval: float64
4444 of StructString :
45- str* : string
45+ str: string
46+
47+ Struct * = ref StructObj
48+ StructObj = object
49+ fmt: string
50+ vars: seq [StructNode ]
4651
4752 StructContext = ref object of RootObj
4853 byteOrder: Endianness
5459
5560
5661const
57- VERSION * = " 0.1.0 "
62+ VERSION * = " 0.0.2 "
5863
5964 TYPE_LENGTHS = {
6065 'x' : sizeof (char ),
@@ -73,57 +78,57 @@ const
7378 '?' : sizeof (bool )
7479 }.toTable
7580
76- proc newStructChar (c: char ): StructNode =
81+ proc newStructChar * (c: char ): StructNode =
7782 new (result )
7883 result .kind = StructChar
7984 result .chr = c
8085
81- proc newStructBool (b: bool ): StructNode =
86+ proc newStructBool * (b: bool ): StructNode =
8287 new (result )
8388 result .kind = StructBool
8489 result .bval = b
8590
86- proc newStructShort (i: int16 ): StructNode =
91+ proc newStructShort * (i: int16 ): StructNode =
8792 new (result )
8893 result .kind = StructShort
8994 result .sval = i
9095
91- proc newStructUShort (i: uint16 ): StructNode =
96+ proc newStructUShort * (i: uint16 ): StructNode =
9297 new (result )
9398 result .kind = StructUShort
9499 result .usval = i
95100
96- proc newStructInt (i: int32 ): StructNode =
101+ proc newStructInt * (i: int32 ): StructNode =
97102 new (result )
98103 result .kind = StructInt
99104 result .ival = i
100105
101- proc newStructUInt (i: uint32 ): StructNode =
106+ proc newStructUInt * (i: uint32 ): StructNode =
102107 new (result )
103108 result .kind = StructUInt
104109 result .uival = i
105110
106- proc newStructQuad (i: int64 ): StructNode =
111+ proc newStructQuad * (i: int64 ): StructNode =
107112 new (result )
108113 result .kind = StructQuad
109114 result .qval = i
110115
111- proc newStructUQuad (i: uint64 ): StructNode =
116+ proc newStructUQuad * (i: uint64 ): StructNode =
112117 new (result )
113118 result .kind = StructUQuad
114119 result .uqval = i
115120
116- proc newStructFloat (f: float32 ): StructNode =
121+ proc newStructFloat * (f: float32 ): StructNode =
117122 new (result )
118123 result .kind = StructFloat
119124 result .fval = f
120125
121- proc newStructDouble (d: float64 ): StructNode =
126+ proc newStructDouble * (d: float64 ): StructNode =
122127 new (result )
123128 result .kind = StructDouble
124129 result .dval = d
125130
126- proc newStructString (s: string ): StructNode =
131+ proc newStructString * (s: string ): StructNode =
127132 new (result )
128133 result .kind = StructString
129134 result .str = s
@@ -280,7 +285,37 @@ proc load_64f*(s: string, endian: Endianness): float64 {.inline.} =
280285 else :
281286 o[i] = s[8 - i - 1 ]
282287
283- proc unpack_byte (vars: var seq [StructNode ], ctx: StructContext ) =
288+ proc extract_16 * [T:int16 | uint16 ](v: T, endian: Endianness ): string {.inline .} =
289+ result = " "
290+ var v = v
291+ var o = cast [cstring ](addr v)
292+
293+ if endian == littleEndian:
294+ result &= $ o[0 ] & $ o[1 ]
295+ else :
296+ result &= $ o[1 ] & $ o[0 ]
297+
298+ proc extract_32 * [T:float32 | int32 | uint32 ](v: T, endian: Endianness ): string {.inline .} =
299+ result = " "
300+ var v = v
301+ var o = cast [cstring ](addr v)
302+ for i in 0 .. 3 :
303+ if endian == littleEndian:
304+ result &= $ o[i]
305+ else :
306+ result &= $ o[3 - i]
307+
308+ proc extract_64 * [T:float64 | int64 | uint64 ](v: T, endian: Endianness ): string {.inline .} =
309+ result = " "
310+ var v = v
311+ var o = cast [cstring ](addr v)
312+ for i in 0 .. 7 :
313+ if endian == littleEndian:
314+ result &= $ o[i]
315+ else :
316+ result &= $ o[7 - i]
317+
318+ proc unpack_char (vars: var seq [StructNode ], ctx: StructContext ) =
284319 for i in 0 .. ctx.repeat- 1 :
285320 vars.add (newStructChar (ctx.buffer[ctx.offset]))
286321 ctx.offset += 1
@@ -317,7 +352,6 @@ proc unpack_quad(vars: var seq[StructNode], ctx: StructContext, f: char, signed:
317352 vars.add (newStructUQuad (value.uint64 ))
318353 ctx.offset += TYPE_LENGTHS [f]
319354
320-
321355proc unpack_float (vars: var seq [StructNode ], ctx: StructContext ) =
322356 for i in 0 .. ctx.repeat- 1 :
323357 var value = load_32f (ctx.buffer[ctx.offset], ctx.buffer[ctx.offset+ 1 ], ctx.buffer[ctx.offset+ 2 ], ctx.buffer[ctx.offset+ 3 ], ctx.byteOrder)
@@ -341,6 +375,8 @@ proc unpack_string(vars: var seq[StructNode], ctx: StructContext) =
341375 vars.add (newStructString (value))
342376 ctx.offset += ctx.repeat
343377
378+
379+
344380proc unpack * (fmt, buf: string ): seq [StructNode ] =
345381 result = @ []
346382
@@ -350,7 +386,6 @@ proc unpack*(fmt, buf: string): seq[StructNode] =
350386
351387 var context = newStructContext ()
352388 context.buffer = buf
353- var fmt = fmt
354389
355390 var repeat = " "
356391 for i in 0 .. fmt.len- 1 :
@@ -370,7 +405,7 @@ proc unpack*(fmt, buf: string): seq[StructNode] =
370405 of '=' , '<' , '>' , '!' , '@' :
371406 context.parse_prefix (f)
372407 of 'b' :
373- unpack_byte (result , context)
408+ unpack_char (result , context)
374409 of '?' :
375410 unpack_bool (result , context)
376411 of 'h' :
@@ -396,6 +431,172 @@ proc unpack*(fmt, buf: string): seq[StructNode] =
396431 else :
397432 raise newException (ValueError , " bad char in struct format" )
398433
434+ proc pack_char (vars: varargs [StructNode ], ctx: StructContext ): string =
435+ result = " "
436+ for i in 0 .. ctx.repeat- 1 :
437+ assert vars[ctx.offset].kind == StructChar
438+ result &= $ vars[ctx.offset].chr
439+ ctx.offset += 1
440+
441+ proc pack_bool (vars: varargs [StructNode ], ctx: StructContext ): string =
442+ result = " "
443+ for i in 0 .. ctx.repeat- 1 :
444+ assert vars[ctx.offset].kind == StructBool
445+ if vars[ctx.offset].bval == true :
446+ result &= " \x01 "
447+ else :
448+ result &= " \x00 "
449+ ctx.offset += 1
450+
451+ proc pack_16 (vars: varargs [StructNode ], ctx: StructContext ): string =
452+ result = " "
453+ for i in 0 .. ctx.repeat- 1 :
454+ case vars[ctx.offset].kind:
455+ of StructShort :
456+ result &= extract_16 (vars[ctx.offset].sval, ctx.byteOrder)
457+ of StructUShort :
458+ result &= extract_16 (vars[ctx.offset].usval, ctx.byteOrder)
459+ else :
460+ raise newException (ValueError , " not supported" )
461+ ctx.offset += 1
462+
463+
464+ proc pack_32 (vars: varargs [StructNode ], ctx: StructContext ): string =
465+ result = " "
466+ for i in 0 .. ctx.repeat- 1 :
467+ case vars[ctx.offset].kind:
468+ of StructFloat :
469+ result &= extract_32 (vars[ctx.offset].fval, ctx.byteOrder)
470+ of StructInt :
471+ result &= extract_32 (vars[ctx.offset].ival, ctx.byteOrder)
472+ of StructUInt :
473+ result &= extract_32 (vars[ctx.offset].uival, ctx.byteOrder)
474+ else :
475+ raise newException (ValueError , " not supported" )
476+ ctx.offset += 1
477+
478+ proc pack_64 (vars: varargs [StructNode ], ctx: StructContext ): string =
479+ result = " "
480+ for i in 0 .. ctx.repeat- 1 :
481+ case vars[ctx.offset].kind:
482+ of StructDouble :
483+ result &= extract_64 (vars[ctx.offset].dval, ctx.byteOrder)
484+ of StructQuad :
485+ result &= extract_64 (vars[ctx.offset].qval, ctx.byteOrder)
486+ of StructUQuad :
487+ result &= extract_64 (vars[ctx.offset].uqval, ctx.byteOrder)
488+ else :
489+ raise newException (ValueError , " not supported" )
490+ ctx.offset += 1
491+
492+ proc pack_string (vars: varargs [StructNode ], ctx: StructContext ): string =
493+ result = " "
494+ assert vars[ctx.offset].kind == StructString
495+ result &= vars[ctx.offset].str[0 .. ctx.repeat- 1 ]
496+
497+ var pad = ctx.repeat - vars[ctx.offset].str.len
498+ if pad > 0 :
499+ result &= " \x00 " .repeat (pad)
500+
501+ ctx.offset += 1
502+
503+ proc pack_pad (ctx: StructContext ): string =
504+ result = " "
505+ for i in 0 .. ctx.repeat- 1 :
506+ result &= " \x00 "
507+
508+ proc pack * (fmt: string , vars: varargs [StructNode ]): string =
509+ result = " "
510+ var context = newStructContext ()
511+
512+ var repeat = " "
513+ for i in 0 .. fmt.len- 1 :
514+ let f: char = fmt[i]
515+
516+ if f in '0' .. '9' :
517+ repeat.add ($ f)
518+ continue
519+ else :
520+ if repeat == " " :
521+ context.repeat = 1
522+ else :
523+ context.repeat = parseInt (repeat)
524+ repeat = " "
525+
526+ case f
527+ of '=' , '<' , '>' , '!' , '@' :
528+ context.parse_prefix (f)
529+ of 'b' :
530+ result &= pack_char (vars, context)
531+ of '?' :
532+ result &= pack_bool (vars, context)
533+ of 'h' , 'H' :
534+ result &= pack_16 (vars, context)
535+ of 'i' , 'I' , 'f' :
536+ result &= pack_32 (vars, context)
537+ of 'q' , 'Q' , 'd' :
538+ result &= pack_64 (vars, context)
539+ of 's' :
540+ result &= pack_string (vars, context)
541+ of 'x' :
542+ result &= pack_pad (context)
543+ else :
544+ raise newException (ValueError , " bad char in struct format" )
545+
546+
547+ proc newStruct (fmt: string ): Struct =
548+ new (result )
549+ result .fmt = fmt
550+ result .vars = @ []
551+
552+ proc add (s: Struct , c: char ): Struct =
553+ result = s
554+ s.vars.add (newStructChar (c))
555+
556+ proc add (s: Struct , b: bool ): Struct =
557+ result = s
558+ s.vars.add (newStructBool (b))
559+
560+ proc add (s: Struct , i: int16 ): Struct =
561+ result = s
562+ s.vars.add (newStructShort (i))
563+
564+ proc add (s: Struct , i: uint16 ): Struct =
565+ result = s
566+ s.vars.add (newStructUShort (i))
567+
568+ proc add (s: Struct , i: int32 ): Struct =
569+ result = s
570+ s.vars.add (newStructInt (i))
571+
572+ proc add (s: Struct , i: uint32 ): Struct =
573+ result = s
574+ s.vars.add (newStructUint (i))
575+
576+ proc add (s: Struct , i: int64 ): Struct =
577+ result = s
578+ s.vars.add (newStructQuad (i))
579+
580+ proc add (s: Struct , i: uint64 ): Struct =
581+ result = s
582+ s.vars.add (newStructUQuad (i))
583+
584+ proc add (s: Struct , f: float32 ): Struct =
585+ result = s
586+ s.vars.add (newStructFloat (f))
587+
588+ proc add (s: Struct , d: float64 ): Struct =
589+ result = s
590+ s.vars.add (newStructDouble (d))
591+
592+ proc add (s: Struct , str: string ): Struct =
593+ result = s
594+ s.vars.add (newStructString (str))
595+
596+ proc pack * (s: Struct ): string =
597+ result = pack (s.fmt, s.vars)
598+
599+
399600when isMainModule :
400601 let buf = " \x41\x42\x43\x44\x45\x01\x00\x07\x08\x01\x02\x03\x04\x0D\x00\x00\x00 "
401602 let result1 = unpack (" <5b2?h2i" , buf)
@@ -418,3 +619,16 @@ when isMainModule:
418619 assert result4[0 ].getString == " Viet"
419620 assert result4[1 ].getString == " Nam"
420621 echo result4
622+
623+ # echo pack("<fi?c", newStructFloat(5.2), newStructInt(8), newStructBool(true), newStructChar('a'))
624+ var format = " <ffb2?biQdH"
625+ var st = newStruct (format)
626+ discard st.add (5.2 'f32 ).add (6.4 'f32 ).add ('A' ).add (true ).add (false )
627+ var out1 = st.add ('a' ).add (8 'i32 ).add (8589934591 ).add (10.4 'f64 ).add (32767 .int16 ).pack ()
628+ echo out1
629+ echo unpack (format, out1)
630+
631+ assert newStruct (" h" ).add (32767 .int16 ).pack () == " \xff\x7f "
632+
633+ assert newStruct (" 4s3s" ).add (" Viet" ).add (" Nam" ).pack () == " VietNam"
634+ assert newStruct (" 6sxxxxx3s" ).add (" Viet" ).add (" Nam" ).pack ().len == 14
0 commit comments