Update code to v1.0.14 (10)

This commit is contained in:
Caten
2024-02-29 19:35:00 +08:00
parent c2ee3b694c
commit a956d26f6d
3188 changed files with 2317293 additions and 146 deletions

View File

@@ -0,0 +1,2 @@
#define BACKGROUND_LOOP_TEST
#include "../examples/example.c"

389
android/extern/libvncserver/test/bmp.c vendored Normal file
View File

@@ -0,0 +1,389 @@
/* Copyright (C)2004 Landmark Graphics Corporation
* Copyright (C)2005 Sun Microsystems, Inc.
* Copyright (C)2010, 2012 D. R. Commander
*
* This library is free software and may be redistributed and/or modified under
* the terms of the wxWindows Library License, Version 3.1 or (at your option)
* any later version. The full license is in the LICENSE.txt file included
* with this distribution.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* wxWindows Library License for more details.
*/
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include "./tjutil.h"
#include "./bmp.h"
#define byteswap(i) ( \
(((i) & 0xff000000) >> 24) | \
(((i) & 0x00ff0000) >> 8) | \
(((i) & 0x0000ff00) << 8) | \
(((i) & 0x000000ff) << 24) )
#define byteswap16(i) ( \
(((i) & 0xff00) >> 8) | \
(((i) & 0x00ff) << 8) )
static __inline int littleendian(void)
{
unsigned int value=1;
unsigned char *ptr=(unsigned char *)(&value);
if(ptr[0]==1 && ptr[3]==0) return 1;
else return 0;
}
#ifndef BI_BITFIELDS
#define BI_BITFIELDS 3L
#endif
#ifndef BI_RGB
#define BI_RGB 0L
#endif
#define BMPHDRSIZE 54
typedef struct _bmphdr
{
unsigned short bfType;
unsigned int bfSize;
unsigned short bfReserved1, bfReserved2;
unsigned int bfOffBits;
unsigned int biSize;
int biWidth, biHeight;
unsigned short biPlanes, biBitCount;
unsigned int biCompression, biSizeImage;
int biXPelsPerMeter, biYPelsPerMeter;
unsigned int biClrUsed, biClrImportant;
} bmphdr;
static const char *__bmperr="No error";
static const int ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
static const int roffset[BMPPIXELFORMATS]={0, 0, 2, 2, 3, 1};
static const int goffset[BMPPIXELFORMATS]={1, 1, 1, 1, 2, 2};
static const int boffset[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3};
#define _throw(m) {__bmperr=m; retcode=-1; goto finally;}
#define _unix(f) {if((f)==-1) _throw(strerror(errno));}
#define _catch(f) {if((f)==-1) {retcode=-1; goto finally;}}
#define readme(fd, addr, size) \
if((bytesread=read(fd, addr, (size)))==-1) _throw(strerror(errno)); \
if(bytesread!=(size)) _throw("Read error");
void pixelconvert(unsigned char *srcbuf, enum BMPPIXELFORMAT srcformat,
int srcpitch, unsigned char *dstbuf, enum BMPPIXELFORMAT dstformat, int dstpitch,
int w, int h, int flip)
{
unsigned char *srcptr, *srcptr0, *dstptr, *dstptr0;
int i, j;
srcptr=flip? &srcbuf[srcpitch*(h-1)]:srcbuf;
for(j=0, dstptr=dstbuf; j<h; j++,
srcptr+=flip? -srcpitch:srcpitch, dstptr+=dstpitch)
{
for(i=0, srcptr0=srcptr, dstptr0=dstptr; i<w; i++,
srcptr0+=ps[srcformat], dstptr0+=ps[dstformat])
{
dstptr0[roffset[dstformat]]=srcptr0[roffset[srcformat]];
dstptr0[goffset[dstformat]]=srcptr0[goffset[srcformat]];
dstptr0[boffset[dstformat]]=srcptr0[boffset[srcformat]];
}
}
}
int loadppm(int *fd, unsigned char **buf, int *w, int *h,
enum BMPPIXELFORMAT f, int align, int dstbottomup, int ascii)
{
FILE *fs=NULL; int retcode=0, scalefactor, dstpitch;
unsigned char *tempbuf=NULL; char temps[255], temps2[255];
int numread=0, totalread=0, pixel[3], i, j;
if((fs=fdopen(*fd, "r"))==NULL) _throw(strerror(errno));
do
{
if(!fgets(temps, 255, fs)) _throw("Read error");
if(strlen(temps)==0 || temps[0]=='\n') continue;
if(sscanf(temps, "%s", temps2)==1 && temps2[1]=='#') continue;
switch(totalread)
{
case 0:
if((numread=sscanf(temps, "%d %d %d", w, h, &scalefactor))==EOF)
_throw("Read error");
break;
case 1:
if((numread=sscanf(temps, "%d %d", h, &scalefactor))==EOF)
_throw("Read error");
break;
case 2:
if((numread=sscanf(temps, "%d", &scalefactor))==EOF)
_throw("Read error");
break;
}
totalread+=numread;
} while(totalread<3);
if((*w)<1 || (*h)<1 || scalefactor<1) _throw("Corrupt PPM header");
dstpitch=(((*w)*ps[f])+(align-1))&(~(align-1));
if((*buf=(unsigned char *)malloc(dstpitch*(*h)))==NULL)
_throw("Memory allocation error");
if(ascii)
{
for(j=0; j<*h; j++)
{
for(i=0; i<*w; i++)
{
if(fscanf(fs, "%d%d%d", &pixel[0], &pixel[1], &pixel[2])!=3)
_throw("Read error");
(*buf)[j*dstpitch+i*ps[f]+roffset[f]]=(unsigned char)(pixel[0]*255/scalefactor);
(*buf)[j*dstpitch+i*ps[f]+goffset[f]]=(unsigned char)(pixel[1]*255/scalefactor);
(*buf)[j*dstpitch+i*ps[f]+boffset[f]]=(unsigned char)(pixel[2]*255/scalefactor);
}
}
}
else
{
if(scalefactor!=255)
_throw("Binary PPMs must have 8-bit components");
if((tempbuf=(unsigned char *)malloc((*w)*(*h)*3))==NULL)
_throw("Memory allocation error");
if(fread(tempbuf, (*w)*(*h)*3, 1, fs)!=1) _throw("Read error");
pixelconvert(tempbuf, BMP_RGB, (*w)*3, *buf, f, dstpitch, *w, *h, dstbottomup);
}
finally:
if(fs) {fclose(fs); *fd=-1;}
if(tempbuf) free(tempbuf);
return retcode;
}
int loadbmp(char *filename, unsigned char **buf, int *w, int *h,
enum BMPPIXELFORMAT f, int align, int dstbottomup)
{
int fd=-1, bytesread, srcpitch, srcbottomup=1, srcps, dstpitch,
retcode=0;
unsigned char *tempbuf=NULL;
bmphdr bh; int flags=O_RDONLY;
dstbottomup=dstbottomup? 1:0;
#ifdef _WIN32
flags|=O_BINARY;
#endif
if(!filename || !buf || !w || !h || f<0 || f>BMPPIXELFORMATS-1 || align<1)
_throw("invalid argument to loadbmp()");
if((align&(align-1))!=0)
_throw("Alignment must be a power of 2");
_unix(fd=open(filename, flags));
readme(fd, &bh.bfType, sizeof(unsigned short));
if(!littleendian()) bh.bfType=byteswap16(bh.bfType);
if(bh.bfType==0x3650)
{
_catch(loadppm(&fd, buf, w, h, f, align, dstbottomup, 0));
goto finally;
}
if(bh.bfType==0x3350)
{
_catch(loadppm(&fd, buf, w, h, f, align, dstbottomup, 1));
goto finally;
}
readme(fd, &bh.bfSize, sizeof(unsigned int));
readme(fd, &bh.bfReserved1, sizeof(unsigned short));
readme(fd, &bh.bfReserved2, sizeof(unsigned short));
readme(fd, &bh.bfOffBits, sizeof(unsigned int));
readme(fd, &bh.biSize, sizeof(unsigned int));
readme(fd, &bh.biWidth, sizeof(int));
readme(fd, &bh.biHeight, sizeof(int));
readme(fd, &bh.biPlanes, sizeof(unsigned short));
readme(fd, &bh.biBitCount, sizeof(unsigned short));
readme(fd, &bh.biCompression, sizeof(unsigned int));
readme(fd, &bh.biSizeImage, sizeof(unsigned int));
readme(fd, &bh.biXPelsPerMeter, sizeof(int));
readme(fd, &bh.biYPelsPerMeter, sizeof(int));
readme(fd, &bh.biClrUsed, sizeof(unsigned int));
readme(fd, &bh.biClrImportant, sizeof(unsigned int));
if(!littleendian())
{
bh.bfSize=byteswap(bh.bfSize);
bh.bfOffBits=byteswap(bh.bfOffBits);
bh.biSize=byteswap(bh.biSize);
bh.biWidth=byteswap(bh.biWidth);
bh.biHeight=byteswap(bh.biHeight);
bh.biPlanes=byteswap16(bh.biPlanes);
bh.biBitCount=byteswap16(bh.biBitCount);
bh.biCompression=byteswap(bh.biCompression);
bh.biSizeImage=byteswap(bh.biSizeImage);
bh.biXPelsPerMeter=byteswap(bh.biXPelsPerMeter);
bh.biYPelsPerMeter=byteswap(bh.biYPelsPerMeter);
bh.biClrUsed=byteswap(bh.biClrUsed);
bh.biClrImportant=byteswap(bh.biClrImportant);
}
if(bh.bfType!=0x4d42 || bh.bfOffBits<BMPHDRSIZE
|| bh.biWidth<1 || bh.biHeight==0)
_throw("Corrupt bitmap header");
if((bh.biBitCount!=24 && bh.biBitCount!=32) || bh.biCompression!=BI_RGB)
_throw("Only uncompessed RGB bitmaps are supported");
*w=bh.biWidth; *h=bh.biHeight; srcps=bh.biBitCount/8;
if(*h<0) {*h=-(*h); srcbottomup=0;}
srcpitch=(((*w)*srcps)+3)&(~3);
dstpitch=(((*w)*ps[f])+(align-1))&(~(align-1));
if(srcpitch*(*h)+bh.bfOffBits!=bh.bfSize) _throw("Corrupt bitmap header");
if((tempbuf=(unsigned char *)malloc(srcpitch*(*h)))==NULL
|| (*buf=(unsigned char *)malloc(dstpitch*(*h)))==NULL)
_throw("Memory allocation error");
if(lseek(fd, (long)bh.bfOffBits, SEEK_SET)!=(long)bh.bfOffBits)
_throw(strerror(errno));
_unix(bytesread=read(fd, tempbuf, srcpitch*(*h)));
if(bytesread!=srcpitch*(*h)) _throw("Read error");
pixelconvert(tempbuf, BMP_BGR, srcpitch, *buf, f, dstpitch, *w, *h,
srcbottomup!=dstbottomup);
finally:
if(tempbuf) free(tempbuf);
if(fd!=-1) close(fd);
return retcode;
}
#define writeme(fd, addr, size) \
if((byteswritten=write(fd, addr, (size)))==-1) _throw(strerror(errno)); \
if(byteswritten!=(size)) _throw("Write error");
int saveppm(char *filename, unsigned char *buf, int w, int h,
enum BMPPIXELFORMAT f, int srcpitch, int srcbottomup)
{
FILE *fs=NULL; int retcode=0;
unsigned char *tempbuf=NULL;
if((fs=fopen(filename, "wb"))==NULL) _throw(strerror(errno));
if(fprintf(fs, "P6\n")<1) _throw("Write error");
if(fprintf(fs, "%d %d\n", w, h)<1) _throw("Write error");
if(fprintf(fs, "255\n")<1) _throw("Write error");
if((tempbuf=(unsigned char *)malloc(w*h*3))==NULL)
_throw("Memory allocation error");
pixelconvert(buf, f, srcpitch, tempbuf, BMP_RGB, w*3, w, h,
srcbottomup);
if((fwrite(tempbuf, w*h*3, 1, fs))!=1) _throw("Write error");
finally:
if(tempbuf) free(tempbuf);
if(fs) fclose(fs);
return retcode;
}
int savebmp(char *filename, unsigned char *buf, int w, int h,
enum BMPPIXELFORMAT f, int srcpitch, int srcbottomup)
{
int fd=-1, byteswritten, dstpitch, retcode=0;
int flags=O_RDWR|O_CREAT|O_TRUNC;
unsigned char *tempbuf=NULL; char *temp;
bmphdr bh; int mode;
#ifdef _WIN32
flags|=O_BINARY; mode=_S_IREAD|_S_IWRITE;
#else
mode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
#endif
if(!filename || !buf || w<1 || h<1 || f<0 || f>BMPPIXELFORMATS-1 || srcpitch<0)
_throw("bad argument to savebmp()");
if(srcpitch==0) srcpitch=w*ps[f];
if((temp=strrchr(filename, '.'))!=NULL)
{
if(!strcasecmp(temp, ".ppm"))
return saveppm(filename, buf, w, h, f, srcpitch, srcbottomup);
}
_unix(fd=open(filename, flags, mode));
dstpitch=((w*3)+3)&(~3);
bh.bfType=0x4d42;
bh.bfSize=BMPHDRSIZE+dstpitch*h;
bh.bfReserved1=0; bh.bfReserved2=0;
bh.bfOffBits=BMPHDRSIZE;
bh.biSize=40;
bh.biWidth=w; bh.biHeight=h;
bh.biPlanes=0; bh.biBitCount=24;
bh.biCompression=BI_RGB; bh.biSizeImage=0;
bh.biXPelsPerMeter=0; bh.biYPelsPerMeter=0;
bh.biClrUsed=0; bh.biClrImportant=0;
if(!littleendian())
{
bh.bfType=byteswap16(bh.bfType);
bh.bfSize=byteswap(bh.bfSize);
bh.bfOffBits=byteswap(bh.bfOffBits);
bh.biSize=byteswap(bh.biSize);
bh.biWidth=byteswap(bh.biWidth);
bh.biHeight=byteswap(bh.biHeight);
bh.biPlanes=byteswap16(bh.biPlanes);
bh.biBitCount=byteswap16(bh.biBitCount);
bh.biCompression=byteswap(bh.biCompression);
bh.biSizeImage=byteswap(bh.biSizeImage);
bh.biXPelsPerMeter=byteswap(bh.biXPelsPerMeter);
bh.biYPelsPerMeter=byteswap(bh.biYPelsPerMeter);
bh.biClrUsed=byteswap(bh.biClrUsed);
bh.biClrImportant=byteswap(bh.biClrImportant);
}
writeme(fd, &bh.bfType, sizeof(unsigned short));
writeme(fd, &bh.bfSize, sizeof(unsigned int));
writeme(fd, &bh.bfReserved1, sizeof(unsigned short));
writeme(fd, &bh.bfReserved2, sizeof(unsigned short));
writeme(fd, &bh.bfOffBits, sizeof(unsigned int));
writeme(fd, &bh.biSize, sizeof(unsigned int));
writeme(fd, &bh.biWidth, sizeof(int));
writeme(fd, &bh.biHeight, sizeof(int));
writeme(fd, &bh.biPlanes, sizeof(unsigned short));
writeme(fd, &bh.biBitCount, sizeof(unsigned short));
writeme(fd, &bh.biCompression, sizeof(unsigned int));
writeme(fd, &bh.biSizeImage, sizeof(unsigned int));
writeme(fd, &bh.biXPelsPerMeter, sizeof(int));
writeme(fd, &bh.biYPelsPerMeter, sizeof(int));
writeme(fd, &bh.biClrUsed, sizeof(unsigned int));
writeme(fd, &bh.biClrImportant, sizeof(unsigned int));
if((tempbuf=(unsigned char *)malloc(dstpitch*h))==NULL)
_throw("Memory allocation error");
pixelconvert(buf, f, srcpitch, tempbuf, BMP_BGR, dstpitch, w, h,
!srcbottomup);
if((byteswritten=write(fd, tempbuf, dstpitch*h))!=dstpitch*h)
_throw(strerror(errno));
finally:
if(tempbuf) free(tempbuf);
if(fd!=-1) close(fd);
return retcode;
}
const char *bmpgeterr(void)
{
return __bmperr;
}

53
android/extern/libvncserver/test/bmp.h vendored Normal file
View File

@@ -0,0 +1,53 @@
/* Copyright (C)2004 Landmark Graphics Corporation
* Copyright (C)2005 Sun Microsystems, Inc.
* Copyright (C)2011 D. R. Commander
*
* This library is free software and may be redistributed and/or modified under
* the terms of the wxWindows Library License, Version 3.1 or (at your option)
* any later version. The full license is in the LICENSE.txt file included
* with this distribution.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* wxWindows Library License for more details.
*/
/* This provides rudimentary facilities for loading and saving true color */
/* BMP and PPM files */
#ifndef __BMP_H__
#define __BMP_H__
#define BMPPIXELFORMATS 6
enum BMPPIXELFORMAT {BMP_RGB=0, BMP_RGBX, BMP_BGR, BMP_BGRX, BMP_XBGR, BMP_XRGB};
#ifdef __cplusplus
extern "C" {
#endif
/*
* This will load a Windows bitmap from a file and return a buffer with the
* specified pixel format, scanline alignment, and orientation. The width and
* height are returned in w and h.
*/
int loadbmp(char *filename, unsigned char **buf, int *w, int *h,
enum BMPPIXELFORMAT f, int align, int dstbottomup);
/*
* This will save a buffer with the specified pixel format, pitch, orientation,
* width, and height as a 24-bit Windows bitmap or PPM (the filename determines
* which format to use)
*/
int savebmp(char *filename, unsigned char *buf, int w, int h,
enum BMPPIXELFORMAT f, int srcpitch, int srcbottomup);
const char *bmpgeterr(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,32 @@
#include <rfb/rfb.h>
int main(int argc,char** argv)
{
int fake_argc=6;
char* fake_argv[6]={
"dummy_program","-alwaysshared","-httpport","3002","-nothing","-dontdisconnect"
};
rfbScreenInfoPtr screen;
rfbBool ret=0;
screen = rfbGetScreen(&fake_argc,fake_argv,1024,768,8,3,1);
if(!screen)
return 0;
#define CHECK(a,b) if(screen->a!=b) { fprintf(stderr,#a " is %d (should be " #b ")\n",screen->a); ret=1; }
CHECK(width,1024);
CHECK(height,768);
CHECK(alwaysShared,TRUE);
CHECK(httpPort,3002);
CHECK(dontDisconnect,TRUE);
if(fake_argc!=2) {
fprintf(stderr,"fake_argc is %d (should be 2)\n",fake_argc);
ret=1;
}
if(strcmp(fake_argv[1],"-nothing")) {
fprintf(stderr,"fake_argv[1] is %s (should be -nothing)\n",fake_argv[1]);
ret=1;
}
return ret;
}

View File

@@ -0,0 +1,56 @@
#ifdef __STRICT_ANSI__
#define _BSD_SOURCE
#endif
#include <rfb/rfb.h>
#define _USE_MATH_DEFINES
#include <math.h>
static void initBackground(rfbScreenInfoPtr server)
{
unsigned int i,j;
for(i=0;i<server->width;i++)
for(j=0;j<server->height;j++) {
server->frameBuffer[(j*server->width+i)*4+0]=i&0xff;
server->frameBuffer[(j*server->width+i)*4+1]=j&0xff;
server->frameBuffer[(j*server->width+i)*4+2]=(i*j)&0xff;
}
}
int main(int argc,char** argv)
{
int width=400,height=300,w=20,x,y;
double r,phi=0;
rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,width,height,8,3,4);
if(!server)
return 0;
server->frameBuffer=(char*)malloc(width*height*4);
initBackground(server);
server->deferUpdateTime=0;
rfbInitServer(server);
r=0;
while(1) {
if(r<=0) {
initBackground(server);
rfbMarkRectAsModified(server,0,0,width,height);
r=0.43;
phi=0;
} else {
r-=0.0001;
phi+=0.02;
if(phi>2*M_PI)
phi-=2*M_PI;
}
x=width*(0.5+cos(phi)*r);
y=height*(0.5+sin(phi)*r);
if(x>=0 && y>=0 && x+w<=width && y+w<=height) {
unsigned int dx=width*0.5*(1-cos(phi)*r)-x,
dy=height*0.5*(1-sin(phi)*r)-y;
rfbDoCopyRect(server,x,y,x+w,y+w,-dx,-dy);
}
rfbProcessEvents(server,50000);
}
return(0);
}

View File

@@ -0,0 +1,353 @@
#ifdef __STRICT_ANSI__
#define _BSD_SOURCE
#endif
#include <time.h>
#include <stdarg.h>
#include <rfb/rfb.h>
#include <rfb/rfbclient.h>
#if !defined(LIBVNCSERVER_HAVE_LIBPTHREAD) && !defined(LIBVNCSERVER_HAVE_WIN32THREADS)
#error "I need pthreads or win32 threads for that."
#endif
#define ALL_AT_ONCE
/*#define VERY_VERBOSE*/
static MUTEX(frameBufferMutex);
typedef struct { int id; char* str; } encoding_t;
static encoding_t testEncodings[]={
{ rfbEncodingRaw, "raw" },
{ rfbEncodingRRE, "rre" },
{ rfbEncodingCoRRE, "corre" },
{ rfbEncodingHextile, "hextile" },
{ rfbEncodingUltra, "ultra" },
#ifdef LIBVNCSERVER_HAVE_LIBZ
{ rfbEncodingZlib, "zlib" },
{ rfbEncodingZlibHex, "zlibhex" },
{ rfbEncodingZRLE, "zrle" },
{ rfbEncodingZYWRLE, "zywrle" },
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
{ rfbEncodingTight, "tight" },
#endif
#endif
{ 0, NULL }
};
#define NUMBER_OF_ENCODINGS_TO_TEST (sizeof(testEncodings)/sizeof(encoding_t)-1)
/*#define NUMBER_OF_ENCODINGS_TO_TEST 1*/
/* Here come the variables/functions to handle the test output */
static const int width=400,height=300;
static unsigned int statistics[2][NUMBER_OF_ENCODINGS_TO_TEST];
static unsigned int totalFailed,totalCount;
static unsigned int countGotUpdate;
static MUTEX(statisticsMutex);
static void initStatistics(void) {
memset(statistics[0],0,sizeof(int)*NUMBER_OF_ENCODINGS_TO_TEST);
memset(statistics[1],0,sizeof(int)*NUMBER_OF_ENCODINGS_TO_TEST);
totalFailed=totalCount=0;
INIT_MUTEX(statisticsMutex);
}
static void updateStatistics(int encodingIndex,rfbBool failed) {
LOCK(statisticsMutex);
if(failed) {
statistics[1][encodingIndex]++;
totalFailed++;
}
statistics[0][encodingIndex]++;
totalCount++;
countGotUpdate++;
UNLOCK(statisticsMutex);
}
/* Here begin the functions for the client. They will be called in a
* thread. */
/* maxDelta=0 means they are expected to match exactly;
* maxDelta>0 means that the average difference must be lower than maxDelta */
static rfbBool doFramebuffersMatch(rfbScreenInfo* server,rfbClient* client,
int maxDelta)
{
int i,j,k;
unsigned int total=0,diff=0;
if(server->width!=client->width || server->height!=client->height)
return FALSE;
LOCK(frameBufferMutex);
/* TODO: write unit test for colour transformation, use here, too */
for(i=0;i<server->width;i++)
for(j=0;j<server->height;j++)
for(k=0;k<3/*server->serverFormat.bitsPerPixel/8*/;k++) {
unsigned char s=server->frameBuffer[k+i*4+j*server->paddedWidthInBytes];
unsigned char cl=client->frameBuffer[k+i*4+j*client->width*4];
if(maxDelta==0 && s!=cl) {
UNLOCK(frameBufferMutex);
return FALSE;
} else {
total++;
diff+=(s>cl?s-cl:cl-s);
}
}
UNLOCK(frameBufferMutex);
if(maxDelta>0 && diff/total>=maxDelta)
return FALSE;
return TRUE;
}
static rfbBool resize(rfbClient* cl) {
if(cl->frameBuffer)
free(cl->frameBuffer);
cl->frameBuffer=malloc(cl->width*cl->height*cl->format.bitsPerPixel/8);
if(!cl->frameBuffer)
return FALSE;
SendFramebufferUpdateRequest(cl,0,0,cl->width,cl->height,FALSE);
return TRUE;
}
static THREAD_ROUTINE_RETURN_TYPE clientLoop(void* data);
typedef struct clientData {
int encodingIndex;
rfbScreenInfo* server;
char display[8];
} clientData;
static void update(rfbClient* client,int x,int y,int w,int h) {
#ifndef VERY_VERBOSE
static const char progress[]={'|','/','-','\\'};
static int counter=0;
if(++counter>=sizeof(progress)) counter=0;
fprintf(stderr,"%c\r",progress[counter]);
#else
clientData* cd = (clientData*)rfbClientGetClientData(client, clientLoop);
rfbClientLog("Got update (encoding=%s): (%d,%d)-(%d,%d)\n",
testEncodings[cd->encodingIndex].str,
x,y,x+w,y+h);
#endif
}
static void update_finished(rfbClient* client) {
clientData* cd = (clientData*)rfbClientGetClientData(client, clientLoop);
int maxDelta=0;
#ifdef LIBVNCSERVER_HAVE_LIBZ
if(testEncodings[cd->encodingIndex].id==rfbEncodingZYWRLE)
maxDelta=5;
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
if(testEncodings[cd->encodingIndex].id==rfbEncodingTight)
maxDelta=5;
#endif
#endif
updateStatistics(cd->encodingIndex,
!doFramebuffersMatch(cd->server,client,maxDelta));
}
static THREAD_ROUTINE_RETURN_TYPE clientLoop(void* data) {
rfbClient* client=(rfbClient*)data;
clientData* cd = (clientData*)rfbClientGetClientData(client, clientLoop);
client->appData.encodingsString=strdup(testEncodings[cd->encodingIndex].str);
client->appData.qualityLevel = 7; /* ZYWRLE fails the test with standard settings */
THREAD_SLEEP_MS(1000);
rfbClientLog("Starting client (encoding %s, display %s)\n",
testEncodings[cd->encodingIndex].str,
cd->display);
if(!rfbInitClient(client,NULL,NULL)) {
rfbClientErr("Had problems starting client (encoding %s)\n",
testEncodings[cd->encodingIndex].str);
updateStatistics(cd->encodingIndex,TRUE);
free(cd);
return THREAD_ROUTINE_RETURN_VALUE;
}
while(1) {
if(WaitForMessage(client,50)>=0)
if(!HandleRFBServerMessage(client))
break;
}
if(client->frameBuffer)
free(client->frameBuffer);
rfbClientCleanup(client);
free(cd);
return THREAD_ROUTINE_RETURN_VALUE;
}
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD)
static pthread_t all_threads[NUMBER_OF_ENCODINGS_TO_TEST];
#elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
static uintptr_t all_threads[NUMBER_OF_ENCODINGS_TO_TEST];
#endif
static int thread_counter;
static void startClient(int encodingIndex,rfbScreenInfo* server) {
rfbClient* client=rfbGetClient(8,3,4);
clientData* cd;
cd=calloc(sizeof(clientData), 1);
if (!cd) return;
client->MallocFrameBuffer=resize;
client->GotFrameBufferUpdate=update;
client->FinishedFrameBufferUpdate=update_finished;
cd->encodingIndex=encodingIndex;
cd->server=server;
sprintf(cd->display,":%d",server->port-5900);
rfbClientSetClientData(client, clientLoop, cd);
#if defined(LIBVNCSERVER_HAVE_LIBPTHREAD)
pthread_create(&all_threads[thread_counter++],NULL,clientLoop,(void*)client);
#elif defined(LIBVNCSERVER_HAVE_WIN32THREADS)
all_threads[thread_counter++] = _beginthread(clientLoop, 0, client);
#endif
}
/* Here begin the server functions */
static void idle(rfbScreenInfo* server)
{
int c;
rfbBool goForward;
LOCK(statisticsMutex);
#ifdef ALL_AT_ONCE
goForward=(countGotUpdate==NUMBER_OF_ENCODINGS_TO_TEST);
#else
goForward=(countGotUpdate==1);
#endif
UNLOCK(statisticsMutex);
if(!goForward)
return;
countGotUpdate=0;
LOCK(frameBufferMutex);
{
int i,j;
int x1=(rand()%(server->width-1)),x2=(rand()%(server->width-1)),
y1=(rand()%(server->height-1)),y2=(rand()%(server->height-1));
if(x1>x2) { i=x1; x1=x2; x2=i; }
if(y1>y2) { i=y1; y1=y2; y2=i; }
x2++; y2++;
for(c=0;c<3;c++) {
for(i=x1;i<x2;i++)
for(j=y1;j<y2;j++)
server->frameBuffer[i*4+c+j*server->paddedWidthInBytes]=255*(i-x1+j-y1)/(x2-x1+y2-y1);
}
rfbMarkRectAsModified(server,x1,y1,x2,y2);
#ifdef VERY_VERBOSE
rfbLog("Sent update (%d,%d)-(%d,%d)\n",x1,y1,x2,y2);
#endif
}
UNLOCK(frameBufferMutex);
}
/* log function (to show what messages are from the client) */
static void
rfbTestLog(const char *format, ...)
{
va_list args;
char buf[256];
time_t log_clock;
if(!rfbEnableClientLogging)
return;
va_start(args, format);
time(&log_clock);
strftime(buf, 255, "%d/%m/%Y %X (client) ", localtime(&log_clock));
fprintf(stderr,"%s",buf);
vfprintf(stderr, format, args);
fflush(stderr);
va_end(args);
}
/* the main function */
int main(int argc,char** argv)
{
int i,j;
time_t t;
rfbScreenInfoPtr server;
rfbClientLog=rfbTestLog;
rfbClientErr=rfbTestLog;
/* Initialize server */
server=rfbGetScreen(&argc,argv,width,height,8,3,4);
if(!server)
return 1;
server->frameBuffer=malloc(400*300*4);
if (!server->frameBuffer)
return 1;
server->cursor=NULL;
for(j=0;j<400*300*4;j++)
server->frameBuffer[j]=j;
rfbInitServer(server);
rfbProcessEvents(server,0);
INIT_MUTEX(frameBufferMutex);
initStatistics();
#ifndef ALL_AT_ONCE
for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++) {
#else
/* Initialize clients */
for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++)
#endif
startClient(i,server);
t=time(NULL);
/* test 20 seconds */
while(time(NULL)-t<20) {
idle(server);
rfbProcessEvents(server,1);
}
rfbLog("%d failed, %d received\n",totalFailed,totalCount);
#ifndef ALL_AT_ONCE
{
rfbClientPtr cl;
rfbClientIteratorPtr iter=rfbGetClientIterator(server);
while((cl=rfbClientIteratorNext(iter)))
rfbCloseClient(cl);
rfbReleaseClientIterator(iter);
}
}
#endif
/* shut down server, disconnecting all clients */
rfbShutdownServer(server, TRUE);
for(i=0;i<thread_counter;i++)
THREAD_JOIN(all_threads[i]);
free(server->frameBuffer);
rfbScreenCleanup(server);
rfbLog("Statistics:\n");
for(i=0;i<NUMBER_OF_ENCODINGS_TO_TEST;i++)
rfbLog("%s encoding: %d failed, %d received\n",
testEncodings[i].str,statistics[1][i],statistics[0][i]);
if(totalFailed)
return 1;
return(0);
}

View File

@@ -0,0 +1,54 @@
/*
Fuzzing server for LibVNCServer.
This is used by OSS-Fuzz at https://android.googlesource.com/platform/external/oss-fuzz/+/refs/heads/upstream-master/projects/libvnc
which is integrated into our CI at `.github/workflows/cifuzz.yaml`.
OSS-Fuzz basically runs every executable in the $OUT dir with LLVMFuzzerTestOneInput in it,
so other fuzzers can be added later on as well.
If you want to run the fuzzer locally, you have to build like that:
```
mkdir build
cd build
CC=clang LIB_FUZZING_ENGINE="-fsanitize=fuzzer" CFLAGS="-fsanitize=address,fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1" cmake ..
cmake --build .
```
and then execute `build/fuzz_server`. You can add some command line options, based on
the fuzzing engine you have used to compile it, see https://llvm.org/docs/LibFuzzer.html
*/
#include <rfb/rfb.h>
static int initialized = 0;
rfbScreenInfoPtr server;
char *fakeargv[] = {"fuzz_server"};
extern size_t fuzz_offset;
extern size_t fuzz_size;
extern const uint8_t *fuzz_data;
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (initialized == 0) {
int fakeargc=1;
server=rfbGetScreen(&fakeargc,fakeargv,400,300,8,3,4);
server->frameBuffer=malloc(400*300*4);
rfbInitServer(server);
initialized = 1;
}
rfbClientPtr cl = rfbNewClient(server, RFB_INVALID_SOCKET - 1);
fuzz_data = Data;
fuzz_offset = 0;
fuzz_size = Size;
while (cl->sock != RFB_INVALID_SOCKET) {
rfbProcessClientMessage(cl);
}
rfbClientConnectionGone(cl);
return 0;
}

View File

@@ -0,0 +1,25 @@
#!/bin/sh
#
# This tests if using the **installed** headers works.
#
# expects install prefix like /usr as an argument
PREFIX=$1
CMAKE_MAKE_PROGRAM=$2
TMPDIR=$(mktemp -d)
DESTDIR="$TMPDIR" $CMAKE_MAKE_PROGRAM install
echo \
"
#include <rfb/rfb.h>
#include <rfb/rfbclient.h>
int main()
{
return 0;
}
" > "$TMPDIR"/includetest.c
cc -I "$TMPDIR/$PREFIX" "$TMPDIR"/includetest.c

View File

@@ -0,0 +1,662 @@
/*
* Copyright (C)2009-2012 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include "./bmp.h"
#include "./tjutil.h"
#include "./turbojpeg.h"
#define _throw(op, err) { \
printf("ERROR in line %d while %s:\n%s\n", __LINE__, op, err); \
(void)retval; /* silence warning */ \
retval=-1; goto bailout;}
#define _throwunix(m) _throw(m, strerror(errno))
#define _throwtj(m) _throw(m, tjGetErrorStr())
#define _throwbmp(m) _throw(m, bmpgeterr())
int flags=0, decomponly=0, quiet=0, dotile=0, pf=TJPF_BGR;
char *ext="ppm";
const char *pixFormatStr[TJ_NUMPF]=
{
"RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY"
};
const int bmpPF[TJ_NUMPF]=
{
BMP_RGB, BMP_BGR, BMP_RGBX, BMP_BGRX, BMP_XBGR, BMP_XRGB, -1
};
const char *subNameLong[TJ_NUMSAMP]=
{
"4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0"
};
const char *subName[NUMSUBOPT]={"444", "422", "420", "GRAY", "440"};
tjscalingfactor *scalingfactors=NULL, sf={1, 1}; int nsf=0;
double benchtime=5.0;
char *sigfig(double val, int figs, char *buf, int len)
{
char format[80];
int digitsafterdecimal=figs-(int)ceil(log10(fabs(val)));
if(digitsafterdecimal<1) snprintf(format, 80, "%%.0f");
else snprintf(format, 80, "%%.%df", digitsafterdecimal);
snprintf(buf, len, format, val);
return buf;
}
/* Decompression test */
int decomptest(unsigned char *srcbuf, unsigned char **jpegbuf,
unsigned long *jpegsize, unsigned char *dstbuf, int w, int h,
int subsamp, int jpegqual, char *filename, int tilew, int tileh)
{
char tempstr[1024], sizestr[20]="\0", qualstr[6]="\0", *ptr;
FILE *file=NULL; tjhandle handle=NULL;
int row, col, i, dstbufalloc=0, retval=0;
double start, elapsed;
int ps=tjPixelSize[pf];
int bufsize;
int scaledw=TJSCALED(w, sf);
int scaledh=TJSCALED(h, sf);
int pitch=scaledw*ps;
int ntilesw=(w+tilew-1)/tilew, ntilesh=(h+tileh-1)/tileh;
unsigned char *dstptr, *dstptr2;
if(jpegqual>0)
{
snprintf(qualstr, 6, "_Q%d", jpegqual);
qualstr[5]=0;
}
if((handle=tjInitDecompress())==NULL)
_throwtj("executing tjInitDecompress()");
bufsize=pitch*scaledh;
if(dstbuf==NULL)
{
if((dstbuf=(unsigned char *)malloc(bufsize)) == NULL)
_throwunix("allocating image buffer");
dstbufalloc=1;
}
/* Set the destination buffer to gray so we know whether the decompressor
attempted to write to it */
memset(dstbuf, 127, bufsize);
/* Execute once to preload cache */
if(tjDecompress2(handle, jpegbuf[0], jpegsize[0], dstbuf, scaledw,
pitch, scaledh, pf, flags)==-1)
_throwtj("executing tjDecompress2()");
/* Benchmark */
for(i=0, start=gettime(); (elapsed=gettime()-start)<benchtime; i++)
{
int tile=0;
for(row=0, dstptr=dstbuf; row<ntilesh; row++, dstptr+=pitch*tileh)
{
for(col=0, dstptr2=dstptr; col<ntilesw; col++, tile++, dstptr2+=ps*tilew)
{
int width=dotile? min(tilew, w-col*tilew):scaledw;
int height=dotile? min(tileh, h-row*tileh):scaledh;
if(tjDecompress2(handle, jpegbuf[tile], jpegsize[tile], dstptr2, width,
pitch, height, pf, flags)==-1)
_throwtj("executing tjDecompress2()");
}
}
}
if(tjDestroy(handle)==-1) _throwtj("executing tjDestroy()");
handle=NULL;
if(quiet)
{
printf("%s\n",
sigfig((double)(w*h)/1000000.*(double)i/elapsed, 4, tempstr, 1024));
}
else
{
printf("D--> Frame rate: %f fps\n", (double)i/elapsed);
printf(" Dest. throughput: %f Megapixels/sec\n",
(double)(w*h)/1000000.*(double)i/elapsed);
}
if(sf.num!=1 || sf.denom!=1)
snprintf(sizestr, 20, "%d_%d", sf.num, sf.denom);
else if(tilew!=w || tileh!=h)
snprintf(sizestr, 20, "%dx%d", tilew, tileh);
else snprintf(sizestr, 20, "full");
if(decomponly)
snprintf(tempstr, 1024, "%s_%s.%s", filename, sizestr, ext);
else
snprintf(tempstr, 1024, "%s_%s%s_%s.%s", filename, subName[subsamp],
qualstr, sizestr, ext);
if(savebmp(tempstr, dstbuf, scaledw, scaledh, bmpPF[pf], pitch,
(flags&TJFLAG_BOTTOMUP)!=0)==-1)
_throwbmp("saving bitmap");
ptr=strrchr(tempstr, '.');
snprintf(ptr, 1024-(ptr-tempstr), "-err.%s", ext);
if(srcbuf && sf.num==1 && sf.denom==1)
{
if(!quiet) printf("Compression error written to %s.\n", tempstr);
if(subsamp==TJ_GRAYSCALE)
{
int index, index2;
for(row=0, index=0; row<h; row++, index+=pitch)
{
for(col=0, index2=index; col<w; col++, index2+=ps)
{
int rindex=index2+tjRedOffset[pf];
int gindex=index2+tjGreenOffset[pf];
int bindex=index2+tjBlueOffset[pf];
int y=(int)((double)srcbuf[rindex]*0.299
+ (double)srcbuf[gindex]*0.587
+ (double)srcbuf[bindex]*0.114 + 0.5);
if(y>255) y=255;
if(y<0) y=0;
dstbuf[rindex]=abs(dstbuf[rindex]-y);
dstbuf[gindex]=abs(dstbuf[gindex]-y);
dstbuf[bindex]=abs(dstbuf[bindex]-y);
}
}
}
else
{
for(row=0; row<h; row++)
for(col=0; col<w*ps; col++)
dstbuf[pitch*row+col]
=abs(dstbuf[pitch*row+col]-srcbuf[pitch*row+col]);
}
if(savebmp(tempstr, dstbuf, w, h, bmpPF[pf], pitch,
(flags&TJFLAG_BOTTOMUP)!=0)==-1)
_throwbmp("saving bitmap");
}
bailout:
if(file) {fclose(file); file=NULL;}
if(handle) {tjDestroy(handle); handle=NULL;}
if(dstbuf && dstbufalloc) {free(dstbuf); dstbuf=NULL;}
return retval;
}
void dotest(unsigned char *srcbuf, int w, int h, int subsamp, int jpegqual,
char *filename)
{
char tempstr[1024], tempstr2[80];
FILE *file=NULL; tjhandle handle=NULL;
unsigned char **jpegbuf=NULL, *tmpbuf=NULL, *srcptr, *srcptr2;
double start, elapsed;
int totaljpegsize=0, row, col, i, tilew=w, tileh=h, retval=0;
unsigned long *jpegsize=NULL;
int ps=tjPixelSize[pf], ntilesw=1, ntilesh=1, pitch=w*ps;
if((tmpbuf=(unsigned char *)malloc(pitch*h)) == NULL)
_throwunix("allocating temporary image buffer");
if(!quiet)
printf(">>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", pixFormatStr[pf],
(flags&TJFLAG_BOTTOMUP)? "Bottom-up":"Top-down", subNameLong[subsamp],
jpegqual);
for(tilew=dotile? 8:w, tileh=dotile? 8:h; ; tilew*=2, tileh*=2)
{
if(tilew>w) tilew=w;
if(tileh>h) tileh=h;
ntilesw=(w+tilew-1)/tilew; ntilesh=(h+tileh-1)/tileh;
if((jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *)
*ntilesw*ntilesh))==NULL)
_throwunix("allocating JPEG tile array");
memset(jpegbuf, 0, sizeof(unsigned char *)*ntilesw*ntilesh);
if((jpegsize=(unsigned long *)malloc(sizeof(unsigned long)
*ntilesw*ntilesh))==NULL)
_throwunix("allocating JPEG size array");
memset(jpegsize, 0, sizeof(unsigned long)*ntilesw*ntilesh);
for(i=0; i<ntilesw*ntilesh; i++)
{
if((jpegbuf[i]=(unsigned char *)malloc(tjBufSize(tilew, tileh,
subsamp)))==NULL)
_throwunix("allocating JPEG tiles");
}
/* Compression test */
if(quiet==1)
printf("%s\t%s\t%s\t%d\t", pixFormatStr[pf],
(flags&TJFLAG_BOTTOMUP)? "BU":"TD", subNameLong[subsamp], jpegqual);
for(i=0; i<h; i++)
memcpy(&tmpbuf[pitch*i], &srcbuf[w*ps*i], w*ps);
if((handle=tjInitCompress())==NULL)
_throwtj("executing tjInitCompress()");
/* Execute once to preload cache */
if(tjCompress2(handle, srcbuf, tilew, pitch, tileh, pf, &jpegbuf[0],
&jpegsize[0], subsamp, jpegqual, flags)==-1)
_throwtj("executing tjCompress2()");
/* Benchmark */
for(i=0, start=gettime(); (elapsed=gettime()-start)<benchtime; i++)
{
int tile=0;
totaljpegsize=0;
for(row=0, srcptr=srcbuf; row<ntilesh; row++, srcptr+=pitch*tileh)
{
for(col=0, srcptr2=srcptr; col<ntilesw; col++, tile++,
srcptr2+=ps*tilew)
{
int width=min(tilew, w-col*tilew);
int height=min(tileh, h-row*tileh);
if(tjCompress2(handle, srcptr2, width, pitch, height, pf,
&jpegbuf[tile], &jpegsize[tile], subsamp, jpegqual, flags)==-1)
_throwtj("executing tjCompress()2");
totaljpegsize+=jpegsize[tile];
}
}
}
if(tjDestroy(handle)==-1) _throwtj("executing tjDestroy()");
handle=NULL;
if(quiet==1) printf("%-4d %-4d\t", tilew, tileh);
if(quiet)
{
printf("%s%c%s%c",
sigfig((double)(w*h)/1000000.*(double)i/elapsed, 4, tempstr, 1024),
quiet==2? '\n':'\t',
sigfig((double)(w*h*ps)/(double)totaljpegsize, 4, tempstr2, 80),
quiet==2? '\n':'\t');
}
else
{
printf("\n%s size: %d x %d\n", dotile? "Tile":"Image", tilew,
tileh);
printf("C--> Frame rate: %f fps\n", (double)i/elapsed);
printf(" Output image size: %d bytes\n", totaljpegsize);
printf(" Compression ratio: %f:1\n",
(double)(w*h*ps)/(double)totaljpegsize);
printf(" Source throughput: %f Megapixels/sec\n",
(double)(w*h)/1000000.*(double)i/elapsed);
printf(" Output bit stream: %f Megabits/sec\n",
(double)totaljpegsize*8./1000000.*(double)i/elapsed);
}
if(tilew==w && tileh==h)
{
snprintf(tempstr, 1024, "%s_%s_Q%d.jpg", filename, subName[subsamp],
jpegqual);
if((file=fopen(tempstr, "wb"))==NULL)
_throwunix("opening reference image");
if(fwrite(jpegbuf[0], jpegsize[0], 1, file)!=1)
_throwunix("writing reference image");
fclose(file); file=NULL;
if(!quiet) printf("Reference image written to %s\n", tempstr);
}
/* Decompression test */
if(decomptest(srcbuf, jpegbuf, jpegsize, tmpbuf, w, h, subsamp, jpegqual,
filename, tilew, tileh)==-1)
goto bailout;
for(i=0; i<ntilesw*ntilesh; i++)
{
if(jpegbuf[i]) {free(jpegbuf[i]); jpegbuf[i]=NULL;}
}
free(jpegbuf); jpegbuf=NULL;
free(jpegsize); jpegsize=NULL;
if(tilew==w && tileh==h) break;
}
bailout:
if(file) {fclose(file); file=NULL;}
if(jpegbuf)
{
for(i=0; i<ntilesw*ntilesh; i++)
{
if(jpegbuf[i]) {free(jpegbuf[i]); jpegbuf[i]=NULL;}
}
free(jpegbuf); jpegbuf=NULL;
}
if(jpegsize) {free(jpegsize); jpegsize=NULL;}
if(tmpbuf) {free(tmpbuf); tmpbuf=NULL;}
if(handle) {tjDestroy(handle); handle=NULL;}
return;
}
void dodecomptest(char *filename)
{
FILE *file=NULL; tjhandle handle=NULL;
unsigned char **jpegbuf=NULL, *srcbuf=NULL;
unsigned long *jpegsize=NULL, srcsize;
int w=0, h=0, subsamp=-1, _w, _h, _tilew, _tileh, _subsamp;
char *temp=NULL;
int i, tilew, tileh, ntilesw=1, ntilesh=1, retval=0;
if((file=fopen(filename, "rb"))==NULL)
_throwunix("opening file");
if(fseek(file, 0, SEEK_END)<0 || (srcsize=ftell(file))<0)
_throwunix("determining file size");
if((srcbuf=(unsigned char *)malloc(srcsize))==NULL)
_throwunix("allocating memory");
if(fseek(file, 0, SEEK_SET)<0)
_throwunix("setting file position");
if(fread(srcbuf, srcsize, 1, file)<1)
_throwunix("reading JPEG data");
fclose(file); file=NULL;
temp=strrchr(filename, '.');
if(temp!=NULL) *temp='\0';
if((handle=tjInitDecompress())==NULL)
_throwtj("executing tjInitDecompress()");
if(tjDecompressHeader2(handle, srcbuf, srcsize, &w, &h, &subsamp)==-1)
_throwtj("executing tjDecompressHeader2()");
if(quiet==1)
{
printf("All performance values in Mpixels/sec\n\n");
printf("Bitmap\tBitmap\tJPEG\t%s %s \tXform\tComp\tDecomp\n",
dotile? "Tile ":"Image", dotile? "Tile ":"Image");
printf("Format\tOrder\tSubsamp\tWidth Height\tPerf \tRatio\tPerf\n\n");
}
else if(!quiet)
{
printf(">>>>> JPEG %s --> %s (%s) <<<<<\n", subNameLong[subsamp],
pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "Bottom-up":"Top-down");
}
for(tilew=dotile? 16:w, tileh=dotile? 16:h; ; tilew*=2, tileh*=2)
{
if(tilew>w) tilew=w;
if(tileh>h) tileh=h;
ntilesw=(w+tilew-1)/tilew; ntilesh=(h+tileh-1)/tileh;
if((jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *)
*ntilesw*ntilesh))==NULL)
_throwunix("allocating JPEG tile array");
memset(jpegbuf, 0, sizeof(unsigned char *)*ntilesw*ntilesh);
if((jpegsize=(unsigned long *)malloc(sizeof(unsigned long)
*ntilesw*ntilesh))==NULL)
_throwunix("allocating JPEG size array");
memset(jpegsize, 0, sizeof(unsigned long)*ntilesw*ntilesh);
for(i=0; i<ntilesw*ntilesh; i++)
{
if((jpegbuf[i]=(unsigned char *)malloc(tjBufSize(tilew, tileh,
subsamp)))==NULL)
_throwunix("allocating JPEG tiles");
}
_w=w; _h=h; _tilew=tilew; _tileh=tileh;
if(!quiet)
{
printf("\n%s size: %d x %d", dotile? "Tile":"Image", _tilew,
_tileh);
if(sf.num!=1 || sf.denom!=1)
printf(" --> %d x %d", TJSCALED(_w, sf), TJSCALED(_h, sf));
printf("\n");
}
else if(quiet==1)
{
printf("%s\t%s\t%s\t", pixFormatStr[pf],
(flags&TJFLAG_BOTTOMUP)? "BU":"TD", subNameLong[subsamp]);
printf("%-4d %-4d\t", tilew, tileh);
}
_subsamp=subsamp;
if(quiet==1) printf("N/A\tN/A\t");
jpegsize[0]=srcsize;
memcpy(jpegbuf[0], srcbuf, srcsize);
if(w==tilew) _tilew=_w;
if(h==tileh) _tileh=_h;
if(decomptest(NULL, jpegbuf, jpegsize, NULL, _w, _h, _subsamp, 0,
filename, _tilew, _tileh)==-1)
goto bailout;
else if(quiet==1) printf("N/A\n");
for(i=0; i<ntilesw*ntilesh; i++)
{
free(jpegbuf[i]); jpegbuf[i]=NULL;
}
free(jpegbuf); jpegbuf=NULL;
if(jpegsize) {free(jpegsize); jpegsize=NULL;}
if(tilew==w && tileh==h) break;
}
bailout:
if(file) {fclose(file); file=NULL;}
if(jpegbuf)
{
for(i=0; i<ntilesw*ntilesh; i++)
{
if(jpegbuf[i]) {free(jpegbuf[i]); jpegbuf[i]=NULL;}
}
free(jpegbuf); jpegbuf=NULL;
}
if(jpegsize) {free(jpegsize); jpegsize=NULL;}
if(srcbuf) {free(srcbuf); srcbuf=NULL;}
if(handle) {tjDestroy(handle); handle=NULL;}
return;
}
void usage(char *progname)
{
int i;
printf("USAGE: %s\n", progname);
printf(" <Inputfile (BMP|PPM)> <%% Quality> [options]\n\n");
printf(" %s\n", progname);
printf(" <Inputfile (JPG)> [options]\n\n");
printf("Options:\n\n");
printf("-bmp = Generate output images in Windows Bitmap format (default=PPM)\n");
printf("-bottomup = Test bottom-up compression/decompression\n");
printf("-tile = Test performance of the codec when the image is encoded as separate\n");
printf(" tiles of varying sizes.\n");
printf("-forcemmx, -forcesse, -forcesse2, -forcesse3 =\n");
printf(" Force MMX, SSE, SSE2, or SSE3 code paths in the underlying codec\n");
printf("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =\n");
printf(" Test the specified color conversion path in the codec (default: BGR)\n");
printf("-fastupsample = Use fast, inaccurate upsampling code to perform 4:2:2 and 4:2:0\n");
printf(" YUV decoding\n");
printf("-quiet = Output results in tabular rather than verbose format\n");
printf("-scale M/N = scale down the width/height of the decompressed JPEG image by a\n");
printf(" factor of M/N (M/N = ");
for(i=0; i<nsf; i++)
{
printf("%d/%d", scalingfactors[i].num, scalingfactors[i].denom);
if(nsf==2 && i!=nsf-1) printf(" or ");
else if(nsf>2)
{
if(i!=nsf-1) printf(", ");
if(i==nsf-2) printf("or ");
}
}
printf(")\n");
printf("-benchtime <t> = Run each benchmark for at least <t> seconds (default = 5.0)\n\n");
printf("NOTE: If the quality is specified as a range (e.g. 90-100), a separate\n");
printf("test will be performed for all quality values in the range.\n\n");
exit(1);
}
int main(int argc, char *argv[])
{
unsigned char *srcbuf=NULL; int w = 0, h = 0, i, j;
int minqual=-1, maxqual=-1; char *temp;
int minarg=2; int retval=0;
if((scalingfactors=tjGetScalingFactors(&nsf))==NULL || nsf==0)
_throwtj("executing tjGetScalingFactors()");
if(argc<minarg) usage(argv[0]);
temp=strrchr(argv[1], '.');
if(temp!=NULL)
{
if(!strcasecmp(temp, ".bmp")) ext="bmp";
if(!strcasecmp(temp, ".jpg") || !strcasecmp(temp, ".jpeg")) decomponly=1;
}
printf("\n");
if(!decomponly)
{
minarg=3;
if(argc<minarg) usage(argv[0]);
if((minqual=atoi(argv[2]))<1 || minqual>100)
{
puts("ERROR: Quality must be between 1 and 100.");
exit(1);
}
if((temp=strchr(argv[2], '-'))!=NULL && strlen(temp)>1
&& sscanf(&temp[1], "%d", &maxqual)==1 && maxqual>minqual && maxqual>=1
&& maxqual<=100) {}
else maxqual=minqual;
}
if(argc>minarg)
{
for(i=minarg; i<argc; i++)
{
if(!strcasecmp(argv[i], "-tile"))
{
dotile=1;
}
if(!strcasecmp(argv[i], "-forcesse3"))
{
printf("Forcing SSE3 code\n\n");
flags|=TJFLAG_FORCESSE3;
}
if(!strcasecmp(argv[i], "-forcesse2"))
{
printf("Forcing SSE2 code\n\n");
flags|=TJFLAG_FORCESSE2;
}
if(!strcasecmp(argv[i], "-forcesse"))
{
printf("Forcing SSE code\n\n");
flags|=TJFLAG_FORCESSE;
}
if(!strcasecmp(argv[i], "-forcemmx"))
{
printf("Forcing MMX code\n\n");
flags|=TJFLAG_FORCEMMX;
}
if(!strcasecmp(argv[i], "-fastupsample"))
{
printf("Using fast upsampling code\n\n");
flags|=TJFLAG_FASTUPSAMPLE;
}
if(!strcasecmp(argv[i], "-rgb")) pf=TJPF_RGB;
if(!strcasecmp(argv[i], "-rgbx")) pf=TJPF_RGBX;
if(!strcasecmp(argv[i], "-bgr")) pf=TJPF_BGR;
if(!strcasecmp(argv[i], "-bgrx")) pf=TJPF_BGRX;
if(!strcasecmp(argv[i], "-xbgr")) pf=TJPF_XBGR;
if(!strcasecmp(argv[i], "-xrgb")) pf=TJPF_XRGB;
if(!strcasecmp(argv[i], "-bottomup")) flags|=TJFLAG_BOTTOMUP;
if(!strcasecmp(argv[i], "-quiet")) quiet=1;
if(!strcasecmp(argv[i], "-qq")) quiet=2;
if(!strcasecmp(argv[i], "-scale") && i<argc-1)
{
int temp1=0, temp2=0, match=0;
if(sscanf(argv[++i], "%d/%d", &temp1, &temp2)==2)
{
for(j=0; j<nsf; j++)
{
if(temp1==scalingfactors[j].num && temp2==scalingfactors[j].denom)
{
sf=scalingfactors[j];
match=1; break;
}
}
if(!match) usage(argv[0]);
}
else usage(argv[0]);
}
if(i<argc-1 && !strcasecmp(argv[i], "-benchtime"))
{
double temp=atof(argv[++i]);
if(temp>0.0) benchtime=temp;
else usage(argv[0]);
}
if(!strcmp(argv[i], "-?")) usage(argv[0]);
if(!strcasecmp(argv[i], "-bmp")) ext="bmp";
}
}
if((sf.num!=1 || sf.denom!=1) && dotile)
{
printf("Disabling tiled compression/decompression tests, because those tests do not\n");
printf("work when scaled decompression is enabled.\n");
dotile=0;
}
if(!decomponly)
{
if(loadbmp(argv[1], &srcbuf, &w, &h, bmpPF[pf], 1,
(flags&TJFLAG_BOTTOMUP)!=0)==-1)
_throwbmp("loading bitmap");
temp=strrchr(argv[1], '.');
if(temp!=NULL) *temp='\0';
}
if(quiet==1 && !decomponly)
{
printf("All performance values in Mpixels/sec\n\n");
printf("Bitmap\tBitmap\tJPEG\tJPEG\t%s %s \tComp\tComp\tDecomp\n",
dotile? "Tile ":"Image", dotile? "Tile ":"Image");
printf("Format\tOrder\tSubsamp\tQual\tWidth Height\tPerf \tRatio\tPerf\n\n");
}
if(decomponly)
{
dodecomptest(argv[1]);
printf("\n");
goto bailout;
}
for(i=maxqual; i>=minqual; i--)
dotest(srcbuf, w, h, TJ_GRAYSCALE, i, argv[1]);
printf("\n");
for(i=maxqual; i>=minqual; i--)
dotest(srcbuf, w, h, TJ_420, i, argv[1]);
printf("\n");
for(i=maxqual; i>=minqual; i--)
dotest(srcbuf, w, h, TJ_422, i, argv[1]);
printf("\n");
for(i=maxqual; i>=minqual; i--)
dotest(srcbuf, w, h, TJ_444, i, argv[1]);
printf("\n");
bailout:
if(srcbuf) free(srcbuf);
return retval;
}

View File

@@ -0,0 +1,461 @@
/*
* Copyright (C)2009-2012 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program tests the various code paths in the TurboJPEG C Wrapper
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "./tjutil.h"
#include "./turbojpeg.h"
#ifdef _WIN32
#include <time.h>
#define random() rand()
#endif
#define _throwtj() {printf("TurboJPEG ERROR:\n%s\n", tjGetErrorStr()); \
bailout();}
#define _tj(f) {if((f)==-1) _throwtj();}
#define _throw(m) {printf("ERROR: %s\n", m); bailout();}
const char *subNameLong[TJ_NUMSAMP]=
{
"4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0"
};
const char *subName[TJ_NUMSAMP]={"444", "422", "420", "GRAY", "440"};
const char *pixFormatStr[TJ_NUMPF]=
{
"RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
"RGBA", "BGRA", "ABGR", "ARGB"
};
const int alphaOffset[TJ_NUMPF] = {-1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0};
const int _3byteFormats[]={TJPF_RGB, TJPF_BGR};
const int _4byteFormats[]={TJPF_RGBX, TJPF_BGRX, TJPF_XBGR, TJPF_XRGB};
const int _onlyGray[]={TJPF_GRAY};
const int _onlyRGB[]={TJPF_RGB};
int exitStatus=0;
#define bailout() {exitStatus=-1; goto bailout;}
void initBuf(unsigned char *buf, int w, int h, int pf, int flags)
{
int roffset=tjRedOffset[pf];
int goffset=tjGreenOffset[pf];
int boffset=tjBlueOffset[pf];
int ps=tjPixelSize[pf];
int index, row, col, halfway=16;
memset(buf, 0, w*h*ps);
if(pf==TJPF_GRAY)
{
for(row=0; row<h; row++)
{
for(col=0; col<w; col++)
{
if(flags&TJFLAG_BOTTOMUP) index=(h-row-1)*w+col;
else index=row*w+col;
if(((row/8)+(col/8))%2==0) buf[index]=(row<halfway)? 255:0;
else buf[index]=(row<halfway)? 76:226;
}
}
}
else
{
for(row=0; row<h; row++)
{
for(col=0; col<w; col++)
{
if(flags&TJFLAG_BOTTOMUP) index=(h-row-1)*w+col;
else index=row*w+col;
if(((row/8)+(col/8))%2==0)
{
if(row<halfway)
{
buf[index*ps+roffset]=255;
buf[index*ps+goffset]=255;
buf[index*ps+boffset]=255;
}
}
else
{
buf[index*ps+roffset]=255;
if(row>=halfway) buf[index*ps+goffset]=255;
}
}
}
}
}
#define checkval(v, cv) { \
if(v<cv-1 || v>cv+1) { \
printf("\nComp. %s at %d,%d should be %d, not %d\n", \
#v, row, col, cv, v); \
retval=0; exitStatus=-1; goto bailout; \
}}
#define checkval0(v) { \
if(v>1) { \
printf("\nComp. %s at %d,%d should be 0, not %d\n", #v, row, col, v); \
retval=0; exitStatus=-1; goto bailout; \
}}
#define checkval255(v) { \
if(v<254) { \
printf("\nComp. %s at %d,%d should be 255, not %d\n", #v, row, col, v); \
retval=0; exitStatus=-1; goto bailout; \
}}
int checkBuf(unsigned char *buf, int w, int h, int pf, int subsamp,
tjscalingfactor sf, int flags)
{
int roffset=tjRedOffset[pf];
int goffset=tjGreenOffset[pf];
int boffset=tjBlueOffset[pf];
int aoffset=alphaOffset[pf];
int ps=tjPixelSize[pf];
int index, row, col, retval=1;
int halfway=16*sf.num/sf.denom;
int blocksize=8*sf.num/sf.denom;
for(row=0; row<h; row++)
{
for(col=0; col<w; col++)
{
unsigned char r, g, b, a;
if(flags&TJFLAG_BOTTOMUP) index=(h-row-1)*w+col;
else index=row*w+col;
r=buf[index*ps+roffset];
g=buf[index*ps+goffset];
b=buf[index*ps+boffset];
a=aoffset>=0? buf[index*ps+aoffset]:0xFF;
if(((row/blocksize)+(col/blocksize))%2==0)
{
if(row<halfway)
{
checkval255(r); checkval255(g); checkval255(b);
}
else
{
checkval0(r); checkval0(g); checkval0(b);
}
}
else
{
if(subsamp==TJSAMP_GRAY)
{
if(row<halfway)
{
checkval(r, 76); checkval(g, 76); checkval(b, 76);
}
else
{
checkval(r, 226); checkval(g, 226); checkval(b, 226);
}
}
else
{
if(row<halfway)
{
checkval255(r); checkval0(g); checkval0(b);
}
else
{
checkval255(r); checkval255(g); checkval0(b);
}
}
}
checkval255(a);
}
}
bailout:
if(retval==0)
{
printf("\n");
for(row=0; row<h; row++)
{
for(col=0; col<w; col++)
{
printf("%.3d/%.3d/%.3d ", buf[(row*w+col)*ps+roffset],
buf[(row*w+col)*ps+goffset], buf[(row*w+col)*ps+boffset]);
}
printf("\n");
}
}
return retval;
}
void writeJPEG(unsigned char *jpegBuf, unsigned long jpegSize, char *filename)
{
FILE *file=fopen(filename, "wb");
if(!file || fwrite(jpegBuf, jpegSize, 1, file)!=1)
{
printf("ERROR: Could not write to %s.\n%s\n", filename, strerror(errno));
bailout();
}
bailout:
if(file) fclose(file);
}
void compTest(tjhandle handle, unsigned char **dstBuf,
unsigned long *dstSize, int w, int h, int pf, char *basename,
int subsamp, int jpegQual, int flags)
{
char tempStr[1024]; unsigned char *srcBuf=NULL;
double t;
printf("%s %s -> %s Q%d ... ", pixFormatStr[pf],
(flags&TJFLAG_BOTTOMUP)? "Bottom-Up":"Top-Down ", subNameLong[subsamp],
jpegQual);
if((srcBuf=(unsigned char *)malloc(w*h*tjPixelSize[pf]))==NULL)
_throw("Memory allocation failure");
initBuf(srcBuf, w, h, pf, flags);
if(*dstBuf && *dstSize>0) memset(*dstBuf, 0, *dstSize);
t=gettime();
*dstSize=tjBufSize(w, h, subsamp);
_tj(tjCompress2(handle, srcBuf, w, 0, h, pf, dstBuf, dstSize, subsamp,
jpegQual, flags));
t=gettime()-t;
snprintf(tempStr, 1024, "%s_enc_%s_%s_%s_Q%d.jpg", basename,
pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "BU":"TD", subName[subsamp],
jpegQual);
writeJPEG(*dstBuf, *dstSize, tempStr);
printf("Done.");
printf(" %f ms\n Result in %s\n", t*1000., tempStr);
bailout:
if(srcBuf) free(srcBuf);
}
void _decompTest(tjhandle handle, unsigned char *jpegBuf,
unsigned long jpegSize, int w, int h, int pf, char *basename, int subsamp,
int flags, tjscalingfactor sf)
{
unsigned char *dstBuf=NULL;
int _hdrw=0, _hdrh=0, _hdrsubsamp=-1; double t;
int scaledWidth=TJSCALED(w, sf);
int scaledHeight=TJSCALED(h, sf);
unsigned long dstSize=0;
printf("JPEG -> %s %s ", pixFormatStr[pf],
(flags&TJFLAG_BOTTOMUP)? "Bottom-Up":"Top-Down ");
if(sf.num!=1 || sf.denom!=1)
printf("%d/%d ... ", sf.num, sf.denom);
else printf("... ");
_tj(tjDecompressHeader2(handle, jpegBuf, jpegSize, &_hdrw, &_hdrh,
&_hdrsubsamp));
if(_hdrw!=w || _hdrh!=h || _hdrsubsamp!=subsamp)
_throw("Incorrect JPEG header");
dstSize=scaledWidth*scaledHeight*tjPixelSize[pf];
if((dstBuf=(unsigned char *)malloc(dstSize))==NULL)
_throw("Memory allocation failure");
memset(dstBuf, 0, dstSize);
t=gettime();
_tj(tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, scaledWidth, 0,
scaledHeight, pf, flags));
t=gettime()-t;
if(checkBuf(dstBuf, scaledWidth, scaledHeight, pf, subsamp, sf, flags))
printf("Passed.");
else printf("FAILED!");
printf(" %f ms\n", t*1000.);
bailout:
if(dstBuf) free(dstBuf);
}
void decompTest(tjhandle handle, unsigned char *jpegBuf,
unsigned long jpegSize, int w, int h, int pf, char *basename, int subsamp,
int flags)
{
int i, n=0;
tjscalingfactor *sf=tjGetScalingFactors(&n), sf1={1, 1};
if(!sf || !n) _throwtj();
if((subsamp==TJSAMP_444 || subsamp==TJSAMP_GRAY))
{
for(i=0; i<n; i++)
_decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp,
flags, sf[i]);
}
else
_decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp, flags,
sf1);
bailout:
printf("\n");
}
void doTest(int w, int h, const int *formats, int nformats, int subsamp,
char *basename)
{
tjhandle chandle=NULL, dhandle=NULL;
unsigned char *dstBuf=NULL;
unsigned long size=0; int pfi, pf, i;
size=tjBufSize(w, h, subsamp);
if((dstBuf=(unsigned char *)malloc(size))==NULL)
_throw("Memory allocation failure.");
if((chandle=tjInitCompress())==NULL || (dhandle=tjInitDecompress())==NULL)
_throwtj();
for(pfi=0; pfi<nformats; pfi++)
{
for(i=0; i<2; i++)
{
int flags=0;
if(subsamp==TJSAMP_422 || subsamp==TJSAMP_420 || subsamp==TJSAMP_440)
flags|=TJFLAG_FASTUPSAMPLE;
if(i==1) flags|=TJFLAG_BOTTOMUP;
pf=formats[pfi];
compTest(chandle, &dstBuf, &size, w, h, pf, basename, subsamp, 100,
flags);
decompTest(dhandle, dstBuf, size, w, h, pf, basename, subsamp,
flags);
if(pf>=TJPF_RGBX && pf<=TJPF_XRGB)
decompTest(dhandle, dstBuf, size, w, h, pf+(TJPF_RGBA-TJPF_RGBX),
basename, subsamp, flags);
}
}
bailout:
if(chandle) tjDestroy(chandle);
if(dhandle) tjDestroy(dhandle);
if(dstBuf) free(dstBuf);
}
void bufSizeTest(void)
{
int w, h, i, subsamp;
unsigned char *srcBuf=NULL, *jpegBuf=NULL;
tjhandle handle=NULL;
unsigned long jpegSize=0;
if((handle=tjInitCompress())==NULL) _throwtj();
printf("Buffer size regression test\n");
for(subsamp=0; subsamp<TJ_NUMSAMP; subsamp++)
{
for(w=1; w<48; w++)
{
int maxh=(w==1)? 2048:48;
for(h=1; h<maxh; h++)
{
if(h%100==0) printf("%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", w, h);
if((srcBuf=(unsigned char *)malloc(w*h*4))==NULL)
_throw("Memory allocation failure");
if((jpegBuf=(unsigned char *)malloc(tjBufSize(w, h, subsamp)))
==NULL)
_throw("Memory allocation failure");
jpegSize=tjBufSize(w, h, subsamp);
for(i=0; i<w*h*4; i++)
{
if(random()<RAND_MAX/2) srcBuf[i]=0;
else srcBuf[i]=255;
}
_tj(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &jpegBuf,
&jpegSize, subsamp, 100, 0));
free(srcBuf); srcBuf=NULL;
free(jpegBuf); jpegBuf=NULL;
if((srcBuf=(unsigned char *)malloc(h*w*4))==NULL)
_throw("Memory allocation failure");
if((jpegBuf=(unsigned char *)malloc(tjBufSize(h, w, subsamp)))
==NULL)
_throw("Memory allocation failure");
jpegSize=tjBufSize(h, w, subsamp);
for(i=0; i<h*w*4; i++)
{
if(random()<RAND_MAX/2) srcBuf[i]=0;
else srcBuf[i]=255;
}
_tj(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &jpegBuf,
&jpegSize, subsamp, 100, 0));
free(srcBuf); srcBuf=NULL;
free(jpegBuf); jpegBuf=NULL;
}
}
}
printf("Done. \n");
bailout:
if(srcBuf) free(srcBuf);
if(jpegBuf) free(jpegBuf);
if(handle) tjDestroy(handle);
}
int main(int argc, char *argv[])
{
#ifdef _WIN32
srand((unsigned int)time(NULL));
#endif
doTest(35, 39, _3byteFormats, 2, TJSAMP_444, "test");
doTest(39, 41, _4byteFormats, 4, TJSAMP_444, "test");
doTest(41, 35, _3byteFormats, 2, TJSAMP_422, "test");
doTest(35, 39, _4byteFormats, 4, TJSAMP_422, "test");
doTest(39, 41, _3byteFormats, 2, TJSAMP_420, "test");
doTest(41, 35, _4byteFormats, 4, TJSAMP_420, "test");
doTest(35, 39, _3byteFormats, 2, TJSAMP_440, "test");
doTest(39, 41, _4byteFormats, 4, TJSAMP_440, "test");
doTest(35, 39, _onlyGray, 1, TJSAMP_GRAY, "test");
doTest(39, 41, _3byteFormats, 2, TJSAMP_GRAY, "test");
doTest(41, 35, _4byteFormats, 4, TJSAMP_GRAY, "test");
bufSizeTest();
return exitStatus;
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C)2011 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef _WIN32
#include <windows.h>
static double getfreq(void)
{
LARGE_INTEGER freq;
if(!QueryPerformanceFrequency(&freq)) return 0.0;
return (double)freq.QuadPart;
}
static double f=-1.0;
double gettime(void)
{
LARGE_INTEGER t;
if(f<0.0) f=getfreq();
if(f==0.0) return (double)GetTickCount()/1000.;
else
{
QueryPerformanceCounter(&t);
return (double)t.QuadPart/f;
}
}
#else
#include <stdlib.h>
#include <sys/time.h>
double gettime(void)
{
struct timeval tv;
if(gettimeofday(&tv, NULL)<0) return 0.0;
else return (double)tv.tv_sec+((double)tv.tv_usec/1000000.);
}
#endif

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C)2011 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the libjpeg-turbo Project nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef _WIN32
#ifndef __MINGW32__
#include <stdio.h>
#define snprintf(str, n, format, ...) \
_snprintf_s(str, n, _TRUNCATE, format, __VA_ARGS__)
#define strcasecmp stricmp
#define strncasecmp strnicmp
#endif
#endif
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))
#endif
extern double gettime(void);

View File

@@ -0,0 +1,131 @@
#!/usr/bin/env python3
# Copyright (C)2017 Andreas Weigel. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import websockets
import base64
'''
Create websocket frames for the wstest websocket decoding unit test.
Generates c ws_frame_test structure definitions
included by wstest.c.
'''
def add_field(s, name, value, first=False):
deli = ",\n\t\t"
if first:
deli = "\t\t"
s += "{2}.{0}={1}".format(name, value, deli)
return s
class Testframe():
def __init__(self, frame, descr, modify_bytes={}, experrno=0, mask=True, opcode_overwrite=False):
self.frame = frame
self.descr = descr
self.modify_bytes = modify_bytes
self.experrno = experrno
self.b64 = True if frame.opcode == 1 or opcode_overwrite == 1 else False
self.mask = mask
def to_carray_initializer(self, buf):
values = []
for i in range(len(buf)):
values.append("0X{0:02X}".format(buf[i]))
if self.modify_bytes != {}:
for k in self.modify_bytes:
values[k] = "0X{0:02X}".format(self.modify_bytes[k])
return "{{{0}}}".format(",".join(values))
def set_frame_buf(self, buf):
self.frame_carray = self.to_carray_initializer(buf)
self.framelen = len(buf)
def __str__(self):
print("processing frame: {0}".format(self.descr))
the_frame = self.frame
if self.b64:
olddata = self.frame.data
newdata = base64.b64encode(self.frame.data)
#print("converting\n{0}\nto{1}\n".format(olddata, newdata))
the_frame = websockets.framing.Frame(self.frame.fin, self.frame.opcode, base64.b64encode(olddata))
websockets.framing.write_frame(the_frame, self.set_frame_buf, self.mask)
s = "\t{\n"
s = add_field(s, "frame", "{0}".format(self.frame_carray), True)
s = add_field(s, "expectedDecodeBuf", self.to_carray_initializer(self.frame.data))
s = add_field(s, "frame_len", self.framelen)
s = add_field(s, "raw_payload_len", len(self.frame.data))
s = add_field(s, "expected_errno", self.experrno)
s = add_field(s, "descr", "\"{0}\"".format(self.descr))
s = add_field(s, "i", "0")
s = add_field(s, "simulate_sock_malfunction_at", "0")
s = add_field(s, "errno_val", "0")
s = add_field(s, "close_sock_at", "0")
s += "\n\t}"
return s
### create test frames
flist = []
### standard text frames with different lengths
flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Testit", encoding="utf-8")), "Short valid text frame"))
flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Frame2 does contain much more text and even goes beyond the 126 byte len field. Frame2 does contain much more text and even goes beyond the 126 byte len field.", encoding="utf-8")),
"Mid-long valid text frame"))
#flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray([(x % 26) + 65 for x in range(100000)])), "100k text frame (ABC..YZABC..)"))
### standard binary frames with different lengths
flist.append(Testframe(websockets.framing.Frame(1, 2, bytearray("Testit", encoding="utf-8")), "Short valid binary frame"))
flist.append(Testframe(websockets.framing.Frame(1, 2, bytearray("Frame2 does contain much more text and even goes beyond the 126 byte len field. Frame2 does contain much more text and even goes beyond the 126 byte len field.", encoding="utf-8")),
"Mid-long valid binary frame"))
#flist.append(Testframe(websockets.framing.Frame(1, 2, bytearray([(x % 26) + 65 for x in range(100000)])), "100k binary frame (ABC..YZABC..)"))
### some conn reset frames, one with no close message, one with close message
flist.append(Testframe(websockets.framing.Frame(1, 8, bytearray(list([0x03, 0xEB]))), "Close frame (Reason 1003)", experrno="ECONNRESET"))
flist.append(Testframe(websockets.framing.Frame(1, 8, bytearray(list([0x03, 0xEB])) + bytearray("I'm a close reason and much more than that!", encoding="utf-8")), "Close frame (Reason 1003) and msg", experrno="ECONNRESET"))
### invalid header values
flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Testit", encoding="utf-8")), "Invalid frame: Wrong masking", experrno="EPROTO", mask=False))
flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("..Lore Ipsum", encoding="utf-8")), "Invalid frame: Length of < 126 with add. 16 bit len field", experrno="EPROTO", modify_bytes={ 1: 0xFE, 2: 0x00, 3: 0x0F}))
flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("........Lore Ipsum", encoding="utf-8")), "Invalid frame: Length of < 126 with add. 64 bit len field", experrno="EPROTO", modify_bytes={ 1: 0xFF, 2: 0x00, 3: 0x00, 4: 0x00, 5: 0x00, 6: 0x00, 7: 0x00, 8: 0x80, 9: 0x40}))
frag1 = websockets.framing.Frame(0, 1, bytearray("This is a fragmented websocket...", encoding="utf-8"))
frag2 = websockets.framing.Frame(0, 0, bytearray("... and it goes on...", encoding="utf-8"))
frag3 = websockets.framing.Frame(1, 0, bytearray("and on and stop", encoding="utf-8"))
flist.append(Testframe(frag1, "Continuation test frag1"))
flist.append(Testframe(frag2, "Continuation test frag2", opcode_overwrite=1))
flist.append(Testframe(frag3, "Continuation test frag3", opcode_overwrite=1))
s = "struct ws_frame_test tests[] = {\n"
for i in range(len(flist)):
s += flist[i].__str__()
if (i + 1 < len(flist)):
s += ","
s += "\n"
s += "};\n"
with open("wstestdata.inc", "w") as cdatafile:
cdatafile.write(s)

View File

@@ -0,0 +1,206 @@
/*
* Copyright (C)2017 Andreas Weigel. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _WIN32
#include <ws_decode.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
/* incoming data frames should not be larger than that */
#define TEST_BUF_SIZE B64LEN(131072) + WSHLENMAX
/* seed is fixed deliberately to get reproducible test cases */
#define RND_SEED 100
enum {
OK,
FAIL_DATA,
FAIL_ERRNO,
FAIL_CLOSED,
};
const char *result_descr[] = {
"",
"Data buffers do not match",
"Wrong errno",
"Wrongly reported closed socket",
"Internal test error"
};
struct ws_frame_test {
char frame[TEST_BUF_SIZE];
char *pos;
char expectedDecodeBuf[TEST_BUF_SIZE];
uint64_t n_compare;
uint64_t frame_len;
uint64_t raw_payload_len;
int expected_errno;
const char *descr;
int ret_bytes[16];
int ret_bytes_len;
int i;
int simulate_sock_malfunction_at;
int errno_val;
int close_sock_at;
};
#include "wstestdata.inc"
char el_log[1000000];
char *el_pos;
static void logtest(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
size_t left = el_log + sizeof(el_log) - el_pos;
size_t off = vsnprintf(el_pos, left, fmt, args);
el_pos += off;
va_end(args);
}
static int emu_read(void *ctx, char *dst, size_t len);
static int emu_read(void *ctx, char *dst, size_t len)
{
struct ws_frame_test *ft = (struct ws_frame_test *)ctx;
ssize_t nret;
int r;
ssize_t modu;
rfbLog("emu_read called with dst=%p and len=%lu\n", dst, len);
if (ft->simulate_sock_malfunction_at > 0 && ft->simulate_sock_malfunction_at == ft->i) {
rfbLog("simulating IO error with errno=%d\n", ft->errno_val);
errno = ft->errno_val;
return -1;
}
/* return something */
r = rand();
modu = (ft->frame + ft->frame_len) - ft->pos;
rfbLog("r=%d modu=%ld frame=%p pos=%p\n", r, modu, ft->frame, ft->pos);
nret = (r % modu) + 1;
nret = nret > len ? len : nret;
rfbLog("copy and return %ld bytes\n", nret);
memcpy(dst, ft->pos, nret);
ft->pos += nret;
rfbLog("leaving %s; pos=%p framebuf=%p nret=%ld\n", __func__, ft->pos, ft->frame, nret);
return nret;
}
static uint64_t run_test(struct ws_frame_test *ft, ws_ctx_t *ctx)
{
uint64_t nleft = ft->raw_payload_len;
char dstbuf[ft->raw_payload_len];
char *dst = dstbuf;
ssize_t n;
ft->pos = ft->frame;
ctx->ctxInfo.ctxPtr = (void *)ft;
while (nleft > 0) {
rfbLog("calling ws_decode with dst=%p, len=%lu\n", dst, nleft);
n = ctx->decode(ctx, dst, nleft);
rfbLog("read n=%ld\n", n);
if (n == 0) {
if (ft->close_sock_at > 0) {
return OK;
} else {
return FAIL_CLOSED;
}
} else if (n < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
/* ok, just call again */
} else {
if (ft->expected_errno == errno) {
rfbLog("errno=%d as expected\n", errno);
return OK;
} else {
rfbLog("errno=%d != expected(%d)\n", errno, ft->expected_errno);
return FAIL_ERRNO;
}
}
} else {
nleft -= n;
dst += n;
rfbLog("read n=%ld from decode; dst=%p, nleft=%lu\n", n, dst, nleft);
}
}
if (memcmp(ft->expectedDecodeBuf, dstbuf, ft->raw_payload_len) != 0) {
ft->expectedDecodeBuf[ft->raw_payload_len] = '\0';
dstbuf[ft->raw_payload_len] = '\0';
rfbLog("decoded result not equal:\nexpected:\n%s\ngot\n%s\n\n", ft->expectedDecodeBuf, dstbuf);
return FAIL_DATA;
}
return OK;
}
int main()
{
ws_ctx_t ctx;
int retall= 0;
int i;
srand(RND_SEED);
hybiDecodeCleanupComplete(&ctx);
ctx.decode = webSocketsDecodeHybi;
ctx.ctxInfo.readFunc = emu_read;
rfbLog = logtest;
rfbErr = logtest;
for (i = 0; i < ARRAYSIZE(tests); i++) {
int ret;
/* reset output log buffer to begin */
el_pos = el_log;
ret = run_test(&tests[i], &ctx);
printf("%s: \"%s\"\n", ret == 0 ? "PASS" : "FAIL", tests[i].descr);
if (ret != 0) {
*el_pos = '\0';
printf("%s", el_log);
retall = -1;
}
}
return retall;
}
#else
int main() {
return 0;
}
#endif

View File

@@ -0,0 +1,146 @@
struct ws_frame_test tests[] = {
{
.frame={0X81,0X88,0X2F,0X2A,0X17,0X41,0X79,0X6D,0X41,0X3B,0X4B,0X6D,0X7B,0X71},
.expectedDecodeBuf={0X54,0X65,0X73,0X74,0X69,0X74},
.frame_len=14,
.raw_payload_len=6,
.expected_errno=0,
.descr="Short valid text frame",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
},
{
.frame={0X81,0XFE,0X00,0XD4,0X66,0X27,0XE5,0X24,0X34,0X49,0XAF,0X4C,0X04,0X70,0XB0,0X5D,0X2F,0X60,0XB7,0X52,0X3C,0X7F,0XA8,0X43,0X3F,0X15,0XDC,0X51,0X02,0X60,0XA3,0X54,0X04,0X4E,0XA7,0X50,0X02,0X70,0XAB,0X4B,0X2F,0X60,0XD4,0X52,0X05,0X4A,0XB0,0X43,0X02,0X60,0XB3,0X10,0X02,0X64,0XA7,0X4C,0X04,0X4A,0XB4,0X43,0X3C,0X7F,0XBF,0X48,0X04,0X4E,0XA7,0X4A,0X04,0X15,0XB3,0X5E,0X2F,0X60,0XAF,0X48,0X03,0X70,0XDC,0X51,0X3C,0X64,0XA7,0X14,0X07,0X60,0XB0,0X43,0X2B,0X73,0XAC,0X16,0X2F,0X60,0XAF,0X11,0X02,0X60,0XB0,0X43,0X04,0X60,0XB3,0X51,0X2F,0X60,0XBF,0X54,0X3C,0X70,0X9D,0X4F,0X2A,0X4E,0XA7,0X63,0X05,0X4A,0XA3,0X50,0X3C,0X73,0XAC,0X43,0X3C,0X60,0XDC,0X48,0X05,0X5E,0XA7,0X4E,0X04,0X15,0XD0,0X14,0X3F,0X70,0X89,0X51,0X2F,0X60,0XD4,0X15,0X3F,0X15,0X82,0X43,0X04,0X70,0XDC,0X5D,0X3C,0X74,0XA7,0X14,0X3C,0X7F,0X8D,0X14,0X2F,0X60,0XA3,0X51,0X3C,0X64,0XA7,0X48,0X02,0X4A,0XB3,0X51,0X2F,0X60,0X81,0X52,0X3C,0X7F,0XA8,0X43,0X3F,0X4A,0XB3,0X11,0X04,0X15,0XD0,0X4F,0X2F,0X6F,0XB7,0X4B,0X3C,0X74,0XA4,0X5C,0X2B,0X4D,0XBC,0X43,0X3F,0X49,0X89,0X14,0X3C,0X74,0XA7,0X57,0X3C,0X70,0XD1,0X43,0X3C,0X4A,0X89,0X48,0X04,0X60,0XB4,0X51},
.expectedDecodeBuf={0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E,0X20,0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E},
.frame_len=220,
.raw_payload_len=159,
.expected_errno=0,
.descr="Mid-long valid text frame",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
},
{
.frame={0X82,0X86,0XDD,0X9B,0XD8,0X56,0X89,0XFE,0XAB,0X22,0XB4,0XEF},
.expectedDecodeBuf={0X54,0X65,0X73,0X74,0X69,0X74},
.frame_len=12,
.raw_payload_len=6,
.expected_errno=0,
.descr="Short valid binary frame",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
},
{
.frame={0X82,0XFE,0X00,0X9F,0XB5,0X6E,0X7F,0X4C,0XF3,0X1C,0X1E,0X21,0XD0,0X5C,0X5F,0X28,0XDA,0X0B,0X0C,0X6C,0XD6,0X01,0X11,0X38,0XD4,0X07,0X11,0X6C,0XD8,0X1B,0X1C,0X24,0X95,0X03,0X10,0X3E,0XD0,0X4E,0X0B,0X29,0XCD,0X1A,0X5F,0X2D,0XDB,0X0A,0X5F,0X29,0XC3,0X0B,0X11,0X6C,0XD2,0X01,0X1A,0X3F,0X95,0X0C,0X1A,0X35,0XDA,0X00,0X1B,0X6C,0XC1,0X06,0X1A,0X6C,0X84,0X5C,0X49,0X6C,0XD7,0X17,0X0B,0X29,0X95,0X02,0X1A,0X22,0X95,0X08,0X16,0X29,0XD9,0X0A,0X51,0X6C,0XF3,0X1C,0X1E,0X21,0XD0,0X5C,0X5F,0X28,0XDA,0X0B,0X0C,0X6C,0XD6,0X01,0X11,0X38,0XD4,0X07,0X11,0X6C,0XD8,0X1B,0X1C,0X24,0X95,0X03,0X10,0X3E,0XD0,0X4E,0X0B,0X29,0XCD,0X1A,0X5F,0X2D,0XDB,0X0A,0X5F,0X29,0XC3,0X0B,0X11,0X6C,0XD2,0X01,0X1A,0X3F,0X95,0X0C,0X1A,0X35,0XDA,0X00,0X1B,0X6C,0XC1,0X06,0X1A,0X6C,0X84,0X5C,0X49,0X6C,0XD7,0X17,0X0B,0X29,0X95,0X02,0X1A,0X22,0X95,0X08,0X16,0X29,0XD9,0X0A,0X51},
.expectedDecodeBuf={0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E,0X20,0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E},
.frame_len=167,
.raw_payload_len=159,
.expected_errno=0,
.descr="Mid-long valid binary frame",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
},
{
.frame={0X88,0X82,0X6B,0X33,0X77,0X94,0X68,0XD8},
.expectedDecodeBuf={0X03,0XEB},
.frame_len=8,
.raw_payload_len=2,
.expected_errno=ECONNRESET,
.descr="Close frame (Reason 1003)",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
},
{
.frame={0X88,0XAD,0X4B,0XA1,0XCE,0XE8,0X48,0X4A,0X87,0XCF,0X26,0X81,0XAF,0XC8,0X28,0XCD,0XA1,0X9B,0X2E,0X81,0XBC,0X8D,0X2A,0XD2,0XA1,0X86,0X6B,0XC0,0XA0,0X8C,0X6B,0XCC,0XBB,0X8B,0X23,0X81,0XA3,0X87,0X39,0XC4,0XEE,0X9C,0X23,0XC0,0XA0,0XC8,0X3F,0XC9,0XAF,0X9C,0X6A},
.expectedDecodeBuf={0X03,0XEB,0X49,0X27,0X6D,0X20,0X61,0X20,0X63,0X6C,0X6F,0X73,0X65,0X20,0X72,0X65,0X61,0X73,0X6F,0X6E,0X20,0X61,0X6E,0X64,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X68,0X61,0X6E,0X20,0X74,0X68,0X61,0X74,0X21},
.frame_len=51,
.raw_payload_len=45,
.expected_errno=ECONNRESET,
.descr="Close frame (Reason 1003) and msg",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
},
{
.frame={0X81,0X08,0X56,0X47,0X56,0X7A,0X64,0X47,0X6C,0X30},
.expectedDecodeBuf={0X54,0X65,0X73,0X74,0X69,0X74},
.frame_len=10,
.raw_payload_len=6,
.expected_errno=EPROTO,
.descr="Invalid frame: Wrong masking",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
},
{
.frame={0X81,0XFE,0X00,0X0F,0X71,0XE9,0X29,0X79,0X44,0XA4,0X07,0X23,0X3B,0X85,0X2C,0X55,0X1D,0X9E,0X06,0X23,0X27,0X9D},
.expectedDecodeBuf={0X2E,0XFE,0X00,0X0F,0X72,0X65,0X20,0X49,0X70,0X73,0X75,0X6D},
.frame_len=22,
.raw_payload_len=12,
.expected_errno=EPROTO,
.descr="Invalid frame: Length of < 126 with add. 16 bit len field",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
},
{
.frame={0X81,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X80,0X40,0X2F,0X40,0XF3,0X5B,0X2F,0X40,0XF2,0X63,0X01,0X1A,0X8D,0X42,0X2A,0X6C,0XAB,0X59,0X00,0X1A,0X91,0X5A},
.expectedDecodeBuf={0X2E,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X80,0X40,0X72,0X65,0X20,0X49,0X70,0X73,0X75,0X6D},
.frame_len=30,
.raw_payload_len=18,
.expected_errno=EPROTO,
.descr="Invalid frame: Length of < 126 with add. 64 bit len field",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
},
{
.frame={0X01,0XAC,0XC9,0X6E,0XC7,0X6E,0X9F,0X29,0XAF,0X1E,0XAA,0X17,0X85,0X1E,0XAA,0X17,0X85,0X06,0X80,0X29,0X9D,0X17,0X90,0X39,0XA3,0X1A,0X93,0X39,0XF2,0X5E,0X93,0X39,0X96,0X09,0XAD,0X5C,0X91,0X07,0XAA,0X5C,0XFE,0X04,0XA8,0X5C,0X91,0X5E,0X85,0X07,0XF3,0X1B},
.expectedDecodeBuf={0X54,0X68,0X69,0X73,0X20,0X69,0X73,0X20,0X61,0X20,0X66,0X72,0X61,0X67,0X6D,0X65,0X6E,0X74,0X65,0X64,0X20,0X77,0X65,0X62,0X73,0X6F,0X63,0X6B,0X65,0X74,0X2E,0X2E,0X2E},
.frame_len=50,
.raw_payload_len=33,
.expected_errno=0,
.descr="Continuation test frag1",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
},
{
.frame={0X00,0X9C,0X52,0XBC,0XD5,0X99,0X1E,0XD5,0XE1,0XEC,0X1B,0XFB,0X93,0XEC,0X08,0XFF,0X97,0XE9,0X36,0XFF,0X97,0XF7,0X30,0X8E,0X83,0XE3,0X1B,0XFB,0XEC,0XEC,0X1E,0XD5,0XE1,0XEC},
.expectedDecodeBuf={0X2E,0X2E,0X2E,0X20,0X61,0X6E,0X64,0X20,0X69,0X74,0X20,0X67,0X6F,0X65,0X73,0X20,0X6F,0X6E,0X2E,0X2E,0X2E},
.frame_len=34,
.raw_payload_len=21,
.expected_errno=0,
.descr="Continuation test frag2",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
},
{
.frame={0X80,0X94,0X3B,0X88,0XA1,0XE9,0X62,0XDF,0X94,0X82,0X72,0XCF,0X98,0X9C,0X72,0XCF,0XE7,0X9C,0X61,0XCB,0XE3,0X93,0X5F,0XCF,0X98,0X9E},
.expectedDecodeBuf={0X61,0X6E,0X64,0X20,0X6F,0X6E,0X20,0X61,0X6E,0X64,0X20,0X73,0X74,0X6F,0X70},
.frame_len=26,
.raw_payload_len=15,
.expected_errno=0,
.descr="Continuation test frag3",
.i=0,
.simulate_sock_malfunction_at=0,
.errno_val=0,
.close_sock_at=0
}
};