C Equivalente di Perl Unpack & Pack

3

Ho un codice perl che usa pack e unpack per trasformare i dati in un modo che non capisco.

$unpacked_data = pack('b*', join('', unpack('(b7)*', $packed_data)))

Dove $ packed_data = una matrice di byte di dire, 2341 byte, e con la precedente dichiarazione perl, scompatta a 2048 byte di dati.

Qualcuno può spiegarmi questa affermazione in termini di C? Finora, lo so:

  • b = Una stringa di bit (ordine dei bit ascendente all'interno di ciascun byte, come vec ()).
  • Se il conteggio delle ripetizioni è *, l'offset è relativo all'inizio della stringa compressa.
posta Meep 12.08.2013 - 22:58
fonte

2 risposte

3

pack e unpack sono funzioni all'interno di perl che possono eseguire alcune trasformazioni di dati.

La parte più interna di questo è (b7)* - e sei corretto che questa è una stringa di bit. Tuttavia, prende solo 7 bit alla volta:

Da: link

the b and B formats pack a string that's that many bits long. Each such format generates 1 bit of the result. These are typically followed by a repeat count like B8 or B64.

Stai prendendo una stringa lunga 8 bit, taglia il bit più alto e lo riscrivo come blocchi di dati a 8 bit.

Starting from the beginning of the input string, each 8-tuple of characters is converted to 1 character of output. With format b , the first character of the 8-tuple determines the least-significant bit of a character; with format B , it determines the most-significant bit of a character.

If the length of the input string is not evenly divisible by 8, the remainder is packed as if the input string were padded by null characters at the end. Similarly during unpacking, "extra" bits are ignored.

Per questo, dovresti prendere qualcosa che è probabilmente ASCII o dati a 7 bit simili che ha sempre il suo bit più alto di 0, rimuovendo il bit più a sinistra (vedi sotto), e riscrivendolo come un flusso costante di dati ( piuttosto che ogni 8 bit essendo 0).

La chiave è che legge 8 bit alla volta con b e ne usa solo 7.

Da notare, c'è un po 'di' huh 'in corso in questo codice da come si guardano tipicamente dati e numeri. Il b sta leggendo i dati little endian. Ciò significa che il bit più a sinistra è quello che viene rimosso.

Consente di prendere la stringa az e decomprimerla con b7 . Il risultato è 1000011 0101111 (ho messo uno spazio lì in modo che potessi leggerlo più facilmente e separare i bit).

'a' in binario è 01100001 e 'z' è 01111010 come grande indiano. Nota che il bit più a sinistra è 0 .

unpack('(b7)*','az') lo leggerà little endian (al contrario di quello che si pensa di solito) e rilascia il bit meno significativo (little endian) che è quello più a sinistra.

Ora che il bit sempre più a sinistra di alcuni (probabilmente) ascii è scomparso, l'intera cosa viene riscritta di nuovo.

0110000101111010
^!      ^!

diventa

11000011111010
!      !

( ^ e ! mostrano punti equivalenti tra le righe)

    
risposta data 12.08.2013 - 23:36
fonte
0

Credo che tu abbia le dimensioni delle stringhe all'indietro.

Se iniziamo con 2048 byte, questo è 16384 bit. Che viene poi suddiviso in 2341 gruppi di 7, ognuno dei quali viene inserito in un byte con il bit superiore 0. (E i bit finali nell'ultimo vengono riempiti con 0.)

Si presumerebbe che l'operazione abbia effettivamente avuto inizio con l'idea di qualcuno su come (poco) comprimere il puro testo ASCII - vale a dire poiché il bit più in alto in ogni carattere è sempre 0, basta memorizzare i primi 7 bit. Questa operazione cerca di invertire quella compressione. Ciò significa che questo perderà i dati quando viene eseguito su tutti i dati con il bit più alto impostato, ad esempio se nell'input è presente UTF8 Unicode.

Se conosci l'autore originale di quel codice, questo potrebbe essere un buon momento di insegnamento. Spiega perché la perdita di dati non è accettabile, mostra quel link e rendi il mondo un posto migliore quando il codice non funziona. t si interrompe in modo imprevisto.

    
risposta data 12.08.2013 - 23:27
fonte

Leggi altre domande sui tag