pl: ArrayBuffer oder Uint8Array

hi, ich suche nach einer ähnlichen Lösung wie Perl::read(Handle, Buffer, Length) nur halt für JavaScript. Die Binary (Rohdaten, Bytesequenzen) liegen als ArrayBuffer vor. Zu Lesen sind in einer Sequenz zunächst 4 Bytes, dann 1 Byte und dann die restlichen Bytes, deren Anzahl ein DataView der ersten 4 Bytes ergibt.

Ich hab ne Lösung, die erscheint mir jedoch ziemlich umständlich und vor Allem schwer verständlich, wenn ich da nach Jahren wieder draufschaue. Frische und lebensbejahende Ideen willkommen, danke, pl

  1. Moin!

    hi, ich suche nach einer ähnlichen Lösung wie Perl::read(Handle, Buffer, Length) nur halt für JavaScript. Die Binary (Rohdaten, Bytesequenzen) liegen als ArrayBuffer vor. Zu Lesen sind in einer Sequenz zunächst 4 Bytes, dann 1 Byte und dann die restlichen Bytes, deren Anzahl ein DataView der ersten 4 Bytes ergibt.

    Mein Vorschlag:

    var bin = '0011AHallo Welt!0006BHe Du!';
    
    var BytesReaded = 0;
    
    while (BytesReaded < bin.length) {
        t1 = parseInt( bin.slice(BytesReaded,BytesReaded + 4) );
        t2 = bin.slice(BytesReaded + 4, BytesReaded + 5);
        t3 = bin.slice(BytesReaded + 5, BytesReaded + 5 + t1);
        BytesReaded=BytesReaded + 4 + 1 + t1;
        alert(t1 + " " + t2 + " " + t3);
    }
    

    Ich hab ne Lösung, die erscheint mir jedoch ziemlich umständlich und vor Allem schwer verständlich,

    Ordentlich notiert und konfiguriert (die 4er und 5er ...) ist das weder schwer verständlich noch umständlich. Freilich kann man sich auch eine Funktion bauen und bin kürzen...

    function getAndDelLeftCharsFromVar_bin(length) {
        var part = bin.slice(0, length);
        bin = bin.slice(length);
        return part;
    }
    
    var bin = '0011AHallo Welt!0006BHe Du!';
    
    while (bin) {
        var t1 = parseInt( getAndDelLeftCharsFromVar_bin(4) );
        var t2 = getAndDelLeftCharsFromVar_bin(1);
        var t3 = getAndDelLeftCharsFromVar_bin(t1);
        alert( t1 + " " + t2 + " " + t3);
    }
    

    Was daran aber umständlich und vor allem schwer verständlich ist, das ist die Verwendung und das Kürzen der globalen Variablen bin. In beiden Varianten muss der Inhalt der Variable "bin" sehr genau passen.

    Kommen wir zur besten Lösung.

    Statt den weltweiten Stromverbrauch anzuheizen sollte an der Datenbasis angesetzt werden. Das binäre Ding lässt sich doch bestimmt serverseitig, womöglich einmalig, in JSON umwandeln.

    Darüber, ob Dir serverseitige Techniken zur Verfügung stehen, hast Du nichts geschrieben.

    Jörg Reinholz

    1. hi Jörg, serverseitig sieht das so aus:

      use bytes;
      
      # Kleinste atomare Einheit
      sub val2bs{
          my $val = shift;
          return pack('NC',0,0) if ! defined $val;
          
          state %cache;
          return $cache{$val} ? $cache{$val} : do{
              my $bs = pack('NC', length($val), 1).$val; 
              $cache{$val} = $bs;
              $bs;
          };
      }
      

      Das erzeugt eine bin.Sequenz, die z.B. per AJAX als ArrayBuffer angefordert wird. Je nachdem, wie die Atome zusammengesetzt sind, kannst Du Arrays, Hashes oder Hashes of Hashes erzeugen, was daraus wird, entscheidet nur der Algorithmus. in der Binsequenz ist also als BigEndian 'N', kodiert, wie lang die Bytefolge ist und in einem Byte 'C' steht drin, ob der Wert undef (Perl) oder null (JS) ist.

      Untenstehend JS was ich vor einiger Zeit mal schrieb, das möchte ich vereinfachen:

      var bSerialize = {
          /* ArrayBuffer to Attribute=Value (Object) */
          bs2av: function(buffer, raw){
              var arr = this.bs2array(buffer, true);
              var av = {};
              var att = '';
              while( att = arr.shift() ){
                  var val = arr.shift();
                  av[new StringView(att)] = raw != null ? val : new StringView(val);
              }
              return av;
          },
      
          /* ArrayBuffer to Array */
          bs2array: function(buffer, raw){
              var array = [];
              this.uha = new Uint8Array(buffer.byteLength);
              this.uha.set( new Uint8Array(buffer), 0);
              this.chunk = new Uint8Array(0);
              this.shift = function(bytes){
                  this.chunk = this.uha.subarray(0, bytes);
                  this.uha = this.uha.subarray(bytes);
                  return(this.uha.length);
              };
              while(this.shift(5)){
                  var lenbuffer = new ArrayBuffer(5);
                  var dv = new DataView(lenbuffer);
                  for(var i = 0; i < 5; i++){ dv.setUint8(i, this.chunk[i]); }
                  var vlen = dv.getUint32(0,0); /* Länge des Array-Element in Bytes       */
                  var type = dv.getUint8(4,0);  /* Ist ArrayElement definiert oder nicht  */
                  this.shift(vlen);
                  var vbuffer = new ArrayBuffer(vlen);
                  dv = new DataView(vbuffer);
                  for(var i = 0; i < vlen; i++) dv.setUint8(i, this.chunk[i]);
                  var val = raw != null ? vbuffer : new StringView(vbuffer);
                  array.push(val);
              }
              return array;
          }
      };
      

      Ich werd mir mal Array.slice() angucken. Evntl. ists damit zweckmäßiger, sich durch einen ArrayBuffer oder Uint8Array zu bewegen. pl

      1. Moin!

        Das erzeugt eine bin.Sequenz, die z.B. per AJAX als ArrayBuffer angefordert wird. Je nachdem, wie die Atome zusammengesetzt sind, kannst Du Arrays, Hashes oder Hashes of Hashes erzeugen, was daraus wird, entscheidet nur der Algorithmus. in der Binsequenz ist also als BigEndian 'N', kodiert, wie lang die Bytefolge ist und in einem Byte 'C' steht drin, ob der Wert undef (Perl) oder null (JS) ist.

        Wie ich schon schrieb. Kümmere Dich mal um JSON. Es macht vieles von dem obsolet. Perl kann JSON kodieren und dekodieren, in Javascript ist es nativ.

        Jörg Reinholz

        1. Moin!

          Das erzeugt eine bin.Sequenz, die z.B. per AJAX als ArrayBuffer angefordert wird. Je nachdem, wie die Atome zusammengesetzt sind, kannst Du Arrays, Hashes oder Hashes of Hashes erzeugen, was daraus wird, entscheidet nur der Algorithmus. in der Binsequenz ist also als BigEndian 'N', kodiert, wie lang die Bytefolge ist und in einem Byte 'C' steht drin, ob der Wert undef (Perl) oder null (JS) ist.

          Wie ich schon schrieb. Kümmere Dich mal um JSON. Es macht vieles von dem obsolet. Perl kann JSON kodieren und dekodieren, in Javascript ist es nativ.

          Naja, wg. 0x0..0xFF, da meinst Du wohl eher BSON. Aber soviel anders als bei mir (s. Atom), sieht da eine BinSequenz auch nicht aus, siehe bei Ruby und das Grundanliegen einer Serialisierung ist im Prinzip dasselbe: Längenangaben kodieren. Was heißt, dass bei der Umkehrung entweder ein Handle oder ein String durchlaufen werden muss.

          Mit einem read(Handle,,); merkt sich Perl die Position, darauf kommt es an. Einen String auf diese Art und Weise zu lesen, sähe in Perl so aus:

          use strict;
          use warnings;
          use bytes;
          use 5.010;
          
          my $bin = join '', ( 'A'..'Z' );
          
          printf qq(
              %s
              %s
          ), sread(\$bin, 3), sread(\$bin, 444);
          
          
          # Funktion merkt sich die Position in $p
          sub sread{
              my $string = shift; # Referenz!!!
              my $offset = shift;
          
              state $p;
              $p ||= 0;
              my $rv = substr($$string, $p, $offset);
              $p += $offset;
              return $rv;
          }
          

          Aber so wies aussieht, wirds in JavaScript vorerst nicht einfacher zu machen sein über ArrayBuffer und Uint8Array, subarry(), DataView usw. pl

          1. Moin!

            Naja, wg. 0x0..0xFF, da meinst Du wohl eher BSON.

            Was für binäres Zeug willst Du denn via Javascript transportieren lassen und verarbeiten? Wenn es Grafiken sind: Base64-codiert geht das auch als Text.

            Jörg Reinholz

            1. Moin!

              Naja, wg. 0x0..0xFF, da meinst Du wohl eher BSON.

              Was für binäres Zeug willst Du denn via Javascript transportieren lassen und verarbeiten? Wenn es Grafiken sind: Base64-codiert geht das auch als Text.

              Base64, ach was ;)

              Nunja, JS und Binaries, das bleibt wohl ein ewiges Geficke mit ArrayBuffer, Uint8Array usw. Ich hab jetzt beschlossen, meinen Reader so stehen zu lassen, auch wenn der umständlich aussieht. Die Basis ist ja nur das Lesen aufeinanderfolgender Werte aus einer Sequenz und nur der Algorithmus entscheidet, was daraus wird: ARRAY, HASH oder SCALAR. D.h., die Atome (ein Scalarer Wert ist ein Atom) werden nur noch verschiedentlich gruppiert. So können wir beliebige Strukturen erzeugen, in Perl sieh z.B. so aus:

              # All in One: Hash, Array, Hash of Hashes (EAV)
              my $bin = $bs->av2bin({
                  addr => $bs->av2bin( { name => 'foo', vname => 'bar', city => 'NY' } ),
                  nums => $bs->array2bin( [undef, 0, 1, 2, 3, 9] ),
                  eav  => $bs->eav2bin({ env => \%ENV, sig => \%SIG })
              });
              
              
              print Dumper $bin,
                  $bs->bin2av( \$bs->bin2av(\$bin)->{addr} ),
                  $bs->bin2array( \$bs->bin2av(\$bin)->{nums} ),
                  $bs->bin2eav( \$bs->bin2av(\$bin)->{eav} );
              
              

              Und das werde ich noch automatisieren, so dass der Serializer selbst erkennt, ob Array, Scalar oder Hash. Die Stukturen können dann beliebig geschachtelt sein, da müssen sich nur Sender und Empfänger einigen, was wo steht. Am Ende wird dann nur noch eine einzige Funktion aufgerufen was den wahlfreien Zugriff auf sämtliche Daten ermöglicht, die in einem Rutsch transportiert werden können.

              Übertragen kann ich damit Multimediadaten (Grafik, Video, Audio, HTML, XML, Text) mit Ajax, in einer Response (eine Datei). Aber auch wenns darum geht, eine lokale Datenbank in den Browser zu laden, geht das mit Rohdaten effizienter als über Base64 in Dateien. Das Stichwort lautet Hypermediadatei. Da können auch PDFs u.a. Content-Types eingebettet sein. Lokal Speichern unter... geht damit natürlich auch.

              Beispiel einer Anwendung: Ein Außendienstler zieht sich ne Replik, geht damit offline zu Kunden, speichert lokal und wenn er wieder online ist, gleicht er die Daten mit dem Server ab. pl

  2. Hallo,

    und vor Allem schwer verständlich, wenn ich da nach Jahren wieder draufschaue. Frische und lebensbejahende Ideen willkommen, danke, pl

    Für dieses Problem wurden in allen wesentlichen Programmiersprachen sogenannte "Kommentare" eingeführt. Da kann man in Klartext beschreiben, was die Funktion / der Abschnitt / die Klasse tun soll und was sie dafür benötigt.

    Gruß
    Kalk

    1. Hallo,

      und vor Allem schwer verständlich, wenn ich da nach Jahren wieder draufschaue. Frische und lebensbejahende Ideen willkommen, danke, pl

      Für dieses Problem wurden in allen wesentlichen Programmiersprachen sogenannte "Kommentare" eingeführt. Da kann man in Klartext beschreiben, was die Funktion / der Abschnitt / die Klasse tun soll und was sie dafür benötigt.

      Stimmt. Ich hatte vergessen, zu notieren, warum ich neben dem ArrayBuffer ein Uint8Array benötige. pl

      --
      Neulich bei Europcar... Kunde: Es sollte ein Mittelklassewagen sein, mindestens 100 PS und Gangschaltung. Europcar: Wie wärs mit einem Audi A3? Kunde (nach kurzer Überlegung): Naja, vier Räder sollten schon dran sein.