MPEG-2 TSファイル等だと上位ビットから、SWFファイルやzlib等だと下位ビットから何ビットずつ値を取得ってのが面倒なんで、C言語でそういった値の取得が出来る関数を組んでみた。
引数1に1バイト単位のデータが入った符号なし文字型配列を、引数2に取得ビット位置を、引数3に取得ビット数を指定して呼び出す。以後のロジックは以下の通り。
- 取得ビット位置を8ビットで割った値と余りからバイト位置とビット位置を求め、8からビット位置を引いた残りビット数を求める。
- ビット位置からマスク値を生成して、バイト位置の値をマスクして残りビット値を求める。
- 残りビット数が取得ビット数より小さければ、次のバイト位置の値を残りビット値と合成し、残りビット数に8を加える処理を繰り返す。
- 取得ビット数からマスク値を生成して、残りビット値をマスクして最終的な値を求める。
ついでに2進化10進数(BCD)みたいに見た目には2進数に見える8進数(仮に8進化2進数と呼ぶ)の相互変換を行う関数も符号なし64ビットに対応させたので32桁の2進数(32ビット)まで扱えるようになった。
#include <stdio.h> /* unsigned long long to octal-coded binary */ unsigned long long ltob(unsigned long long a) { unsigned long long b,c; b=1; c=0; while(a>0) { c=(a%2)*b+c; b=b*8; a=a/2; } return c; } /* octal-coded binary to unsigned long long */ unsigned long long btol(unsigned long long a) { unsigned long long b,c; b=1; c=0; while(a>0) { c=(a%8)*b+c; b=b*2; a=a/8; } return c; } /* get binary from right */ unsigned long long getbr(unsigned char *a,int b,int c) { int i,j,k; unsigned long long m,n; i=b/8; j=b%8; k=8-j; m=((unsigned long long)0x100>>j)-1; n=a[i]&m; i++; while(k<c) { n=n<<8|a[i]; i++; k=k+8; } m=(((unsigned long long)1<<c)-1)<<(k-c); n=(n&m)>>(k-c); return n; } /* get binary from left */ unsigned long long getbl(unsigned char *a,int b,int c) { int i,j,k; unsigned long long m,n; i=b/8; j=b%8; k=8-j; m=~(((unsigned long long)1<<j)-1); n=(a[i]&m)>>j; i++; while(k<c) { n=((unsigned long long)a[i]<<k)|n; i++; k=k+8; } m=((unsigned long long)1<<c)-1; n=n&m; return n; } int main(int argc,char *argv[]) { unsigned char buf[4]; buf[0]=btol(001101110); buf[1]=btol(010011001); printf("byte 0 = %08o\n",ltob(buf[0])); printf("byte 1 = %08o\n",ltob(buf[1])); printf("bit 0 from right 3 bits = %03o\n",ltob(getbr(buf,0,3))); printf("bit 3 from right 3 bits = %03o\n",ltob(getbr(buf,3,3))); printf("bit 6 from right 3 bits = %03o\n",ltob(getbr(buf,6,3))); printf("bit 9 from right 3 bits = %03o\n",ltob(getbr(buf,9,3))); printf("bit 0 from left 3 bits = %03o\n",ltob(getbl(buf,0,3))); printf("bit 3 from left 3 bits = %03o\n",ltob(getbl(buf,3,3))); printf("bit 6 from left 3 bits = %03o\n",ltob(getbl(buf,6,3))); printf("bit 9 from left 3 bits = %03o\n",ltob(getbl(buf,9,3))); }
上記を実行すると以下のように結果が表示される。
byte 0 = 01101110 byte 1 = 10011001 bit 0 from right 3 bits = 011 bit 3 from right 3 bits = 011 bit 6 from right 3 bits = 101 bit 9 from right 3 bits = 001 bit 0 from left 3 bits = 110 bit 3 from left 3 bits = 101 bit 6 from left 3 bits = 101 bit 9 from left 3 bits = 100